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:
parent
79fc36b3e3
commit
a229f34eaa
|
@ -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))) {
|
(ps->o.blur_background_frame && real_win_mode == WMODE_FRAME_TRANS))) {
|
||||||
// Minimize the region we try to blur, if the window
|
// Minimize the region we try to blur, if the window
|
||||||
// itself is not opaque, only the frame is.
|
// 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) {
|
if (real_win_mode == WMODE_TRANS || ps->o.force_win_blend) {
|
||||||
// We need to blur the bounding shape of the window
|
// We need to blur the bounding shape of the window
|
||||||
// (reg_paint_in_bound = reg_bound \cap reg_paint)
|
// (reg_paint_in_bound = reg_bound \cap reg_paint)
|
||||||
ps->backend_data->ops->blur(
|
ps->backend_data->ops->blur(
|
||||||
ps->backend_data, w->opacity, ps->backend_blur_context,
|
ps->backend_data, blur_opacity, ps->backend_blur_context,
|
||||||
®_paint_in_bound, ®_visible);
|
®_paint_in_bound, ®_visible);
|
||||||
} else {
|
} else {
|
||||||
// Window itself is solid, we only need to blur the frame
|
// 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(®_blur, w->g.x, w->g.y);
|
pixman_region32_translate(®_blur, w->g.x, w->g.y);
|
||||||
// make sure reg_blur \in reg_paint
|
// make sure reg_blur \in reg_paint
|
||||||
pixman_region32_intersect(®_blur, ®_blur, ®_paint);
|
pixman_region32_intersect(®_blur, ®_blur, ®_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,
|
ps->backend_blur_context,
|
||||||
®_blur, ®_visible);
|
®_blur, ®_visible);
|
||||||
pixman_region32_fini(®_blur);
|
pixman_region32_fini(®_blur);
|
||||||
|
|
|
@ -232,15 +232,15 @@ static bool run_fade(session_t *ps, struct managed_win **_w, long steps) {
|
||||||
auto w = *_w;
|
auto w = *_w;
|
||||||
if (w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED) {
|
if (w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED) {
|
||||||
// We are not fading
|
// We are not fading
|
||||||
assert(w->opacity_tgt == w->opacity);
|
assert(w->opacity_target == w->opacity);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!win_should_fade(ps, w)) {
|
if (!win_should_fade(ps, w)) {
|
||||||
log_debug("Window %#010x %s doesn't need fading", w->base.id, w->name);
|
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 have reached target opacity.
|
||||||
// We don't call win_check_fade_finished here because that could destroy
|
// 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
|
// 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 (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,
|
w->opacity = clamp(w->opacity + ps->o.fade_in_step * (double)steps,
|
||||||
0.0, w->opacity_tgt);
|
0.0, w->opacity_target);
|
||||||
} else {
|
} else {
|
||||||
w->opacity = clamp(w->opacity - ps->o.fade_out_step * (double)steps,
|
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.
|
// last time to finish state transition. So return true in that case too.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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(role, cdbus_reply_string);
|
||||||
|
|
||||||
cdbus_m_win_get_do(opacity, cdbus_reply_double);
|
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(has_opacity_prop, cdbus_reply_bool);
|
||||||
cdbus_m_win_get_do(opacity_prop, cdbus_reply_uint32);
|
cdbus_m_win_get_do(opacity_prop, cdbus_reply_uint32);
|
||||||
cdbus_m_win_get_do(opacity_is_set, cdbus_reply_bool);
|
cdbus_m_win_get_do(opacity_is_set, cdbus_reply_bool);
|
||||||
|
|
|
@ -455,7 +455,7 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
|
||||||
// See the winstate_t transition table
|
// See the winstate_t transition table
|
||||||
w->state = WSTATE_FADING;
|
w->state = WSTATE_FADING;
|
||||||
}
|
}
|
||||||
w->opacity_tgt = win_calc_opacity_target(ps, w);
|
w->opacity_target = win_calc_opacity_target(ps, w, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
72
src/win.c
72
src/win.c
|
@ -436,38 +436,32 @@ winmode_t win_calc_mode(const struct managed_win *w) {
|
||||||
// consider the window solid
|
// 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;
|
return WMODE_SOLID;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate and return the opacity target of a window.
|
* Calculate and return the opacity target of a window.
|
||||||
*
|
*
|
||||||
* If window is inactive and inactive_opacity_override is set, the
|
* The priority of opacity settings are:
|
||||||
* priority is: (Simulates the old behavior)
|
|
||||||
*
|
*
|
||||||
* inactive_opacity > _NET_WM_WINDOW_OPACITY (if not opaque)
|
* inactive_opacity_override (if set, and unfocused) > _NET_WM_WINDOW_OPACITY (if set) >
|
||||||
* > window type default opacity
|
* opacity-rules (if matched) > window type default opacity > active/inactive opacity
|
||||||
*
|
*
|
||||||
* Otherwise:
|
* @param ps current session
|
||||||
*
|
* @param w struct _win object representing the window
|
||||||
* _NET_WM_WINDOW_OPACITY (if not opaque)
|
* @param ignore_state whether window state should be ignored in opacity calculation
|
||||||
* > window type default opacity (if not opaque)
|
|
||||||
* > inactive_opacity
|
|
||||||
*
|
|
||||||
* @param ps current session
|
|
||||||
* @param w struct _win object representing the window
|
|
||||||
*
|
*
|
||||||
* @return target opacity
|
* @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;
|
double opacity = 1;
|
||||||
|
|
||||||
if (w->state == WSTATE_UNMAPPED) {
|
if (w->state == WSTATE_UNMAPPED && !ignore_state) {
|
||||||
// be consistent
|
// be consistent
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (w->state == WSTATE_UNMAPPING || w->state == WSTATE_DESTROYING) {
|
if ((w->state == WSTATE_UNMAPPING || w->state == WSTATE_DESTROYING) && !ignore_state) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// Try obeying opacity property and window type opacity firstly
|
// 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
|
// respect inactive override
|
||||||
if (ps->o.inactive_opacity_override && !w->focused)
|
if (ps->o.inactive_opacity_override && !w->focused) {
|
||||||
opacity = ps->o.inactive_opacity;
|
opacity = ps->o.inactive_opacity;
|
||||||
|
}
|
||||||
|
|
||||||
return 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);
|
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)
|
if (w->blur_background == blur_background_new)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1069,7 +1065,7 @@ struct win *fill_win(session_t *ps, struct win *w) {
|
||||||
.wmwin = false,
|
.wmwin = false,
|
||||||
.focused = false,
|
.focused = false,
|
||||||
.opacity = 0,
|
.opacity = 0,
|
||||||
.opacity_tgt = 0,
|
.opacity_target = 0,
|
||||||
.has_opacity_prop = false,
|
.has_opacity_prop = false,
|
||||||
.opacity_prop = OPAQUE,
|
.opacity_prop = OPAQUE,
|
||||||
.opacity_is_set = false,
|
.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
|
// Always recalculate the window target opacity, since some opacity-related
|
||||||
// options depend on the output value of win_is_focused_real() instead of
|
// options depend on the output value of win_is_focused_real() instead of
|
||||||
// w->focused
|
// w->focused
|
||||||
double opacity_tgt_old = w->opacity_tgt;
|
auto opacity_target_old = w->opacity_target;
|
||||||
w->opacity_tgt = win_calc_opacity_target(ps, w);
|
w->opacity_target = win_calc_opacity_target(ps, w, false);
|
||||||
if (opacity_tgt_old != w->opacity_tgt && w->state == WSTATE_MAPPED) {
|
if (opacity_target_old != w->opacity_target && w->state == WSTATE_MAPPED) {
|
||||||
// Only MAPPED can transition to FADING
|
// Only MAPPED can transition to FADING
|
||||||
assert(w->state != WSTATE_DESTROYING && w->state != WSTATE_UNMAPPING &&
|
|
||||||
w->state != WSTATE_UNMAPPED);
|
|
||||||
w->state = WSTATE_FADING;
|
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->a.map_state = XCB_MAP_STATE_UNMAPPED;
|
||||||
w->state = target_state;
|
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;
|
w->in_openclose = destroy;
|
||||||
|
|
||||||
|
@ -1828,10 +1822,10 @@ void win_check_fade_finished(session_t *ps, struct managed_win **_w) {
|
||||||
auto w = *_w;
|
auto w = *_w;
|
||||||
if (w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED) {
|
if (w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED) {
|
||||||
// No fading in progress
|
// No fading in progress
|
||||||
assert(w->opacity_tgt == w->opacity);
|
assert(w->opacity_target == w->opacity);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (w->opacity == w->opacity_tgt) {
|
if (w->opacity == w->opacity_target) {
|
||||||
switch (w->state) {
|
switch (w->state) {
|
||||||
case WSTATE_UNMAPPING: return finish_unmap_win(ps, _w);
|
case WSTATE_UNMAPPING: return finish_unmap_win(ps, _w);
|
||||||
case WSTATE_DESTROYING: return finish_destroy_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) {
|
void win_skip_fading(session_t *ps, struct managed_win **_w) {
|
||||||
auto w = *_w;
|
auto w = *_w;
|
||||||
if (w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED) {
|
if (w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED) {
|
||||||
assert(w->opacity_tgt == w->opacity);
|
assert(w->opacity_target == w->opacity);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
log_trace("Skipping fading process of window %#010x (%s)", w->base.id, w->name);
|
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);
|
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
|
// XXX We need to make sure that win_data is available
|
||||||
// iff `state` is MAPPED
|
// iff `state` is MAPPED
|
||||||
w->state = WSTATE_MAPPING;
|
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,
|
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);
|
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
|
* 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) {
|
static inline bool
|
||||||
xcb_get_property_cookie_t prop = xcb_get_property(c, 0, w, a->a_NET_WM_STATE, XCB_ATOM_ATOM, 0, 12);
|
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);
|
xcb_get_property_reply_t *reply = xcb_get_property_reply(c, prop, NULL);
|
||||||
if(!reply)
|
if (!reply)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if(reply->length) {
|
if (reply->length) {
|
||||||
xcb_atom_t *val = xcb_get_property_value(reply);
|
xcb_atom_t *val = xcb_get_property_value(reply);
|
||||||
for(uint32_t i = 0; i < reply->length; i++) {
|
for (uint32_t i = 0; i < reply->length; i++) {
|
||||||
if(val[i] != a->a_NET_WM_STATE_FULLSCREEN)
|
if (val[i] != a->a_NET_WM_STATE_FULLSCREEN)
|
||||||
continue;
|
continue;
|
||||||
free(reply);
|
free(reply);
|
||||||
return true;
|
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.
|
* It's not using w->border_size for performance measures.
|
||||||
*/
|
*/
|
||||||
bool win_is_fullscreen(const session_t *ps, const struct managed_win *w) {
|
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 true;
|
||||||
return rect_is_fullscreen(ps, w->g.x, w->g.y, w->widthb, w->heightb) &&
|
return rect_is_fullscreen(ps, w->g.x, w->g.y, w->widthb, w->heightb) &&
|
||||||
(!w->bounding_shaped || w->rounded_corners);
|
(!w->bounding_shaped || w->rounded_corners);
|
||||||
|
|
20
src/win.h
20
src/win.h
|
@ -263,7 +263,7 @@ struct managed_win {
|
||||||
/// Current window opacity.
|
/// Current window opacity.
|
||||||
double opacity;
|
double opacity;
|
||||||
/// Target window opacity.
|
/// Target window opacity.
|
||||||
double opacity_tgt;
|
double opacity_target;
|
||||||
/// true if window (or client window, for broken window managers
|
/// true if window (or client window, for broken window managers
|
||||||
/// not transferring client window's _NET_WM_OPACITY value) has opacity prop
|
/// not transferring client window's _NET_WM_OPACITY value) has opacity prop
|
||||||
bool 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);
|
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);
|
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);
|
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);
|
bool attr_pure win_should_dim(session_t *ps, const struct managed_win *w);
|
||||||
void win_update_screen(session_t *, struct managed_win *);
|
void win_update_screen(session_t *, struct managed_win *);
|
||||||
/// Prepare window for fading because opacity target changed
|
/// Prepare window for fading because opacity target changed
|
||||||
|
|
Loading…
Reference in New Issue