new backend: fix background blur of window with opacity set

Only render blur with transparency when window is fading in/out.
Otherwise, a window with a set opacity will always have a completely
blurred background.

Fixes #198

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
Yuxuan Shui 2019-07-26 23:40:30 +01:00
parent 79fc36b3e3
commit a229f34eaa
No known key found for this signature in database
GPG Key ID: 37C999F617EA1A47
6 changed files with 77 additions and 52 deletions

View File

@ -207,12 +207,25 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
(ps->o.blur_background_frame && real_win_mode == WMODE_FRAME_TRANS))) {
// Minimize the region we try to blur, if the window
// itself is not opaque, only the frame is.
// TODO resize blur region to fix black line artifact
double blur_opacity = 1;
if (w->state == WSTATE_MAPPING) {
// Gradually increase the blur intensity during
// fading in.
blur_opacity = w->opacity / w->opacity_target;
} else if (w->state == WSTATE_UNMAPPING ||
w->state == WSTATE_DESTROYING) {
// Gradually decrease the blur intensity during
// fading out.
blur_opacity =
w->opacity / win_calc_opacity_target(ps, w, true);
}
if (real_win_mode == WMODE_TRANS || ps->o.force_win_blend) {
// We need to blur the bounding shape of the window
// (reg_paint_in_bound = reg_bound \cap reg_paint)
ps->backend_data->ops->blur(
ps->backend_data, w->opacity, ps->backend_blur_context,
ps->backend_data, blur_opacity, ps->backend_blur_context,
&reg_paint_in_bound, &reg_visible);
} else {
// Window itself is solid, we only need to blur the frame
@ -226,7 +239,7 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
pixman_region32_translate(&reg_blur, w->g.x, w->g.y);
// make sure reg_blur \in reg_paint
pixman_region32_intersect(&reg_blur, &reg_blur, &reg_paint);
ps->backend_data->ops->blur(ps->backend_data, w->opacity,
ps->backend_data->ops->blur(ps->backend_data, blur_opacity,
ps->backend_blur_context,
&reg_blur, &reg_visible);
pixman_region32_fini(&reg_blur);

View File

@ -232,15 +232,15 @@ static bool run_fade(session_t *ps, struct managed_win **_w, long steps) {
auto w = *_w;
if (w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED) {
// We are not fading
assert(w->opacity_tgt == w->opacity);
assert(w->opacity_target == w->opacity);
return false;
}
if (!win_should_fade(ps, w)) {
log_debug("Window %#010x %s doesn't need fading", w->base.id, w->name);
w->opacity = w->opacity_tgt;
w->opacity = w->opacity_target;
}
if (w->opacity == w->opacity_tgt) {
if (w->opacity == w->opacity_target) {
// We have reached target opacity.
// We don't call win_check_fade_finished here because that could destroy
// the window, but we still need the damage info from this window
@ -249,16 +249,16 @@ static bool run_fade(session_t *ps, struct managed_win **_w, long steps) {
}
if (steps) {
if (w->opacity < w->opacity_tgt) {
if (w->opacity < w->opacity_target) {
w->opacity = clamp(w->opacity + ps->o.fade_in_step * (double)steps,
0.0, w->opacity_tgt);
0.0, w->opacity_target);
} else {
w->opacity = clamp(w->opacity - ps->o.fade_out_step * (double)steps,
w->opacity_tgt, 1);
w->opacity_target, 1);
}
}
// Note even if opacity == opacity_tgt here, we still want to run preprocess one
// Note even if opacity == opacity_target here, we still want to run preprocess one
// last time to finish state transition. So return true in that case too.
return true;
}

View File

@ -800,7 +800,7 @@ static bool cdbus_process_win_get(session_t *ps, DBusMessage *msg) {
cdbus_m_win_get_do(role, cdbus_reply_string);
cdbus_m_win_get_do(opacity, cdbus_reply_double);
cdbus_m_win_get_do(opacity_tgt, cdbus_reply_double);
cdbus_m_win_get_do(opacity_target, cdbus_reply_double);
cdbus_m_win_get_do(has_opacity_prop, cdbus_reply_bool);
cdbus_m_win_get_do(opacity_prop, cdbus_reply_uint32);
cdbus_m_win_get_do(opacity_is_set, cdbus_reply_bool);

View File

@ -455,7 +455,7 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
// See the winstate_t transition table
w->state = WSTATE_FADING;
}
w->opacity_tgt = win_calc_opacity_target(ps, w);
w->opacity_target = win_calc_opacity_target(ps, w, false);
}
}

View File

@ -436,38 +436,32 @@ winmode_t win_calc_mode(const struct managed_win *w) {
// consider the window solid
}
//log_trace("Window %#010x(%s) is solid", w->client_win, w->name);
// log_trace("Window %#010x(%s) is solid", w->client_win, w->name);
return WMODE_SOLID;
}
/**
* Calculate and return the opacity target of a window.
*
* If window is inactive and inactive_opacity_override is set, the
* priority is: (Simulates the old behavior)
* The priority of opacity settings are:
*
* inactive_opacity > _NET_WM_WINDOW_OPACITY (if not opaque)
* > window type default opacity
* inactive_opacity_override (if set, and unfocused) > _NET_WM_WINDOW_OPACITY (if set) >
* opacity-rules (if matched) > window type default opacity > active/inactive opacity
*
* Otherwise:
*
* _NET_WM_WINDOW_OPACITY (if not opaque)
* > window type default opacity (if not opaque)
* > inactive_opacity
*
* @param ps current session
* @param w struct _win object representing the window
* @param ps current session
* @param w struct _win object representing the window
* @param ignore_state whether window state should be ignored in opacity calculation
*
* @return target opacity
*/
double win_calc_opacity_target(session_t *ps, const struct managed_win *w) {
double win_calc_opacity_target(session_t *ps, const struct managed_win *w, bool ignore_state) {
double opacity = 1;
if (w->state == WSTATE_UNMAPPED) {
if (w->state == WSTATE_UNMAPPED && !ignore_state) {
// be consistent
return 0;
}
if (w->state == WSTATE_UNMAPPING || w->state == WSTATE_DESTROYING) {
if ((w->state == WSTATE_UNMAPPING || w->state == WSTATE_DESTROYING) && !ignore_state) {
return 0;
}
// Try obeying opacity property and window type opacity firstly
@ -487,8 +481,9 @@ double win_calc_opacity_target(session_t *ps, const struct managed_win *w) {
}
// respect inactive override
if (ps->o.inactive_opacity_override && !w->focused)
if (ps->o.inactive_opacity_override && !w->focused) {
opacity = ps->o.inactive_opacity;
}
return opacity;
}
@ -705,7 +700,8 @@ void win_determine_invert_color(session_t *ps, struct managed_win *w) {
win_set_invert_color(ps, w, invert_color_new);
}
static void win_set_blur_background(session_t *ps, struct managed_win *w, bool blur_background_new) {
static void
win_set_blur_background(session_t *ps, struct managed_win *w, bool blur_background_new) {
if (w->blur_background == blur_background_new)
return;
@ -1069,7 +1065,7 @@ struct win *fill_win(session_t *ps, struct win *w) {
.wmwin = false,
.focused = false,
.opacity = 0,
.opacity_tgt = 0,
.opacity_target = 0,
.has_opacity_prop = false,
.opacity_prop = OPAQUE,
.opacity_is_set = false,
@ -1201,12 +1197,10 @@ void win_update_focused(session_t *ps, struct managed_win *w) {
// Always recalculate the window target opacity, since some opacity-related
// options depend on the output value of win_is_focused_real() instead of
// w->focused
double opacity_tgt_old = w->opacity_tgt;
w->opacity_tgt = win_calc_opacity_target(ps, w);
if (opacity_tgt_old != w->opacity_tgt && w->state == WSTATE_MAPPED) {
auto opacity_target_old = w->opacity_target;
w->opacity_target = win_calc_opacity_target(ps, w, false);
if (opacity_target_old != w->opacity_target && w->state == WSTATE_MAPPED) {
// Only MAPPED can transition to FADING
assert(w->state != WSTATE_DESTROYING && w->state != WSTATE_UNMAPPING &&
w->state != WSTATE_UNMAPPED);
w->state = WSTATE_FADING;
}
}
@ -1796,7 +1790,7 @@ void unmap_win(session_t *ps, struct managed_win **_w, bool destroy) {
w->a.map_state = XCB_MAP_STATE_UNMAPPED;
w->state = target_state;
w->opacity_tgt = win_calc_opacity_target(ps, w);
w->opacity_target = win_calc_opacity_target(ps, w, false);
w->in_openclose = destroy;
@ -1828,10 +1822,10 @@ void win_check_fade_finished(session_t *ps, struct managed_win **_w) {
auto w = *_w;
if (w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED) {
// No fading in progress
assert(w->opacity_tgt == w->opacity);
assert(w->opacity_target == w->opacity);
return;
}
if (w->opacity == w->opacity_tgt) {
if (w->opacity == w->opacity_target) {
switch (w->state) {
case WSTATE_UNMAPPING: return finish_unmap_win(ps, _w);
case WSTATE_DESTROYING: return finish_destroy_win(ps, _w);
@ -1847,11 +1841,11 @@ void win_check_fade_finished(session_t *ps, struct managed_win **_w) {
void win_skip_fading(session_t *ps, struct managed_win **_w) {
auto w = *_w;
if (w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED) {
assert(w->opacity_tgt == w->opacity);
assert(w->opacity_target == w->opacity);
return;
}
log_trace("Skipping fading process of window %#010x (%s)", w->base.id, w->name);
w->opacity = w->opacity_tgt;
w->opacity = w->opacity_target;
win_check_fade_finished(ps, _w);
}
@ -1973,10 +1967,10 @@ void map_win(session_t *ps, struct managed_win *w) {
// XXX We need to make sure that win_data is available
// iff `state` is MAPPED
w->state = WSTATE_MAPPING;
w->opacity_tgt = win_calc_opacity_target(ps, w);
w->opacity_target = win_calc_opacity_target(ps, w, false);
log_debug("Window %#010x has opacity %f, opacity target is %f", w->base.id,
w->opacity, w->opacity_tgt);
w->opacity, w->opacity_target);
win_determine_blur_background(ps, w);
@ -2136,16 +2130,18 @@ static inline bool rect_is_fullscreen(const session_t *ps, int x, int y, int wid
/**
* Check if a window is fulscreen using EWMH
*/
static inline bool win_is_fullscreen_xcb(xcb_connection_t *c, const struct atom *a, const xcb_window_t w) {
xcb_get_property_cookie_t prop = xcb_get_property(c, 0, w, a->a_NET_WM_STATE, XCB_ATOM_ATOM, 0, 12);
static inline bool
win_is_fullscreen_xcb(xcb_connection_t *c, const struct atom *a, const xcb_window_t w) {
xcb_get_property_cookie_t prop =
xcb_get_property(c, 0, w, a->a_NET_WM_STATE, XCB_ATOM_ATOM, 0, 12);
xcb_get_property_reply_t *reply = xcb_get_property_reply(c, prop, NULL);
if(!reply)
if (!reply)
return false;
if(reply->length) {
if (reply->length) {
xcb_atom_t *val = xcb_get_property_value(reply);
for(uint32_t i = 0; i < reply->length; i++) {
if(val[i] != a->a_NET_WM_STATE_FULLSCREEN)
for (uint32_t i = 0; i < reply->length; i++) {
if (val[i] != a->a_NET_WM_STATE_FULLSCREEN)
continue;
free(reply);
return true;
@ -2161,7 +2157,7 @@ static inline bool win_is_fullscreen_xcb(xcb_connection_t *c, const struct atom
* It's not using w->border_size for performance measures.
*/
bool win_is_fullscreen(const session_t *ps, const struct managed_win *w) {
if(!ps->o.no_ewmh_fullscreen && win_is_fullscreen_xcb(ps->c, ps->atoms, w->client_win))
if (!ps->o.no_ewmh_fullscreen && win_is_fullscreen_xcb(ps->c, ps->atoms, w->client_win))
return true;
return rect_is_fullscreen(ps, w->g.x, w->g.y, w->widthb, w->heightb) &&
(!w->bounding_shaped || w->rounded_corners);

View File

@ -263,7 +263,7 @@ struct managed_win {
/// Current window opacity.
double opacity;
/// Target window opacity.
double opacity_tgt;
double opacity_target;
/// true if window (or client window, for broken window managers
/// not transferring client window's _NET_WM_OPACITY value) has opacity prop
bool has_opacity_prop;
@ -360,7 +360,23 @@ void win_unmark_client(session_t *ps, struct managed_win *w);
void win_recheck_client(session_t *ps, struct managed_win *w);
xcb_window_t win_get_leader_raw(session_t *ps, struct managed_win *w, int recursions);
bool win_get_class(session_t *ps, struct managed_win *w);
double attr_pure win_calc_opacity_target(session_t *ps, const struct managed_win *w);
/**
* Calculate and return the opacity target of a window.
*
* The priority of opacity settings are:
*
* inactive_opacity_override (if set, and unfocused) > _NET_WM_WINDOW_OPACITY (if set) >
* opacity-rules (if matched) > window type default opacity > active/inactive opacity
*
* @param ps current session
* @param w struct _win object representing the window
* @param ignore_state whether window state should be ignored in opacity calculation
*
* @return target opacity
*/
double attr_pure win_calc_opacity_target(session_t *ps, const struct managed_win *w,
bool ignore_state);
bool attr_pure win_should_dim(session_t *ps, const struct managed_win *w);
void win_update_screen(session_t *, struct managed_win *);
/// Prepare window for fading because opacity target changed