diff --git a/src/backend/backend.c b/src/backend/backend.c index 8351556..d102bda 100644 --- a/src/backend/backend.c +++ b/src/backend/backend.c @@ -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, ®_paint_in_bound, ®_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(®_blur, w->g.x, w->g.y); // make sure reg_blur \in reg_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, ®_blur, ®_visible); pixman_region32_fini(®_blur); diff --git a/src/compton.c b/src/compton.c index 924388d..4af886c 100644 --- a/src/compton.c +++ b/src/compton.c @@ -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; } diff --git a/src/dbus.c b/src/dbus.c index 3f2d50f..4df9f33 100644 --- a/src/dbus.c +++ b/src/dbus.c @@ -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); diff --git a/src/event.c b/src/event.c index c4f4f64..bf95171 100644 --- a/src/event.c +++ b/src/event.c @@ -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); } } diff --git a/src/win.c b/src/win.c index 52479b1..e65fc72 100644 --- a/src/win.c +++ b/src/win.c @@ -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); diff --git a/src/win.h b/src/win.h index 61f511e..78d64b2 100644 --- a/src/win.h +++ b/src/win.h @@ -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