New backends: smoothly fade blur-texture on fade-in/-out

* Add new field `opacity_target_old` to `struct managed_win` for
tracking relevant `opacity_target` changes.
* Smoothly fade blur-texture opacity on window opacity changes (based on
window opacity), when the window was or will be fully transparent
(`w->opacity ~< 0.004`).
* Fixed alpha-clipping of the blur-texture when using `inactive-opacity` or
repeatedly setting window opacity with large fade intervals (should fix #314).
This commit is contained in:
Bernd Busse 2019-12-20 20:17:38 +01:00 committed by Yuxuan Shui
parent 32754b0262
commit ad8632b017
No known key found for this signature in database
GPG Key ID: 37C999F617EA1A47
5 changed files with 84 additions and 25 deletions

View File

@ -204,16 +204,34 @@ void paint_all_new(session_t *ps, struct managed_win *t, bool ignore_damage) {
// itself is not opaque, only the frame is. // itself is not opaque, only the frame is.
double blur_opacity = 1; double blur_opacity = 1;
if (w->state == WSTATE_MAPPING) { if (w->opacity < (1.0 / MAX_ALPHA)) {
// Hide blur for fully transparent windows.
blur_opacity = 0;
} else if (w->state == WSTATE_MAPPING) {
// Gradually increase the blur intensity during // Gradually increase the blur intensity during
// fading in. // fading in.
assert(w->opacity <= w->opacity_target);
blur_opacity = w->opacity / w->opacity_target; blur_opacity = w->opacity / w->opacity_target;
} else if (w->state == WSTATE_UNMAPPING || } else if (w->state == WSTATE_UNMAPPING ||
w->state == WSTATE_DESTROYING) { w->state == WSTATE_DESTROYING) {
// Gradually decrease the blur intensity during // Gradually decrease the blur intensity during
// fading out. // fading out.
blur_opacity = assert(w->opacity <= w->opacity_target_old);
w->opacity / win_calc_opacity_target(ps, w, true); blur_opacity = w->opacity / w->opacity_target_old;
} else if (w->state == WSTATE_FADING) {
if (w->opacity < w->opacity_target &&
w->opacity_target_old < (1.0 / MAX_ALPHA)) {
// Gradually increase the blur intensity during
// fading in.
assert(w->opacity <= w->opacity_target);
blur_opacity = w->opacity / w->opacity_target;
} else if (w->opacity > w->opacity_target &&
w->opacity_target < (1.0 / MAX_ALPHA)) {
// Gradually decrease the blur intensity during
// fading out.
assert(w->opacity <= w->opacity_target_old);
blur_opacity = w->opacity / w->opacity_target_old;
}
} }
assert(blur_opacity >= 0 && blur_opacity <= 1); assert(blur_opacity >= 0 && blur_opacity <= 1);

View File

@ -482,14 +482,7 @@ static inline void ev_property_notify(session_t *ps, xcb_property_notify_event_t
win_update_opacity_prop(ps, w); win_update_opacity_prop(ps, w);
// we cannot receive OPACITY change when window is destroyed // we cannot receive OPACITY change when window is destroyed
assert(w->state != WSTATE_DESTROYING); assert(w->state != WSTATE_DESTROYING);
w->opacity_target = win_calc_opacity_target(ps, w, false); win_update_opacity_target(ps, w);
if (w->state == WSTATE_MAPPED) {
// See the winstate_t transition table
w->state = WSTATE_FADING;
}
if (!ps->redirected) {
CHECK(!win_skip_fading(ps, w));
}
} }
} }

View File

@ -912,18 +912,7 @@ void win_on_factor_change(session_t *ps, struct managed_win *w) {
w->unredir_if_possible_excluded = w->unredir_if_possible_excluded =
c2_match(ps, w, ps->o.unredir_if_possible_blacklist, NULL); c2_match(ps, w, ps->o.unredir_if_possible_blacklist, NULL);
auto opacity_target_old = w->opacity_target; win_update_opacity_target(ps, w);
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->opacity == opacity_target_old);
w->state = WSTATE_FADING;
log_debug("Window %#010x (%s) opactiy %f, opacity target %f", w->base.id,
w->name, w->opacity, w->opacity_target);
if (!ps->redirected) {
CHECK(!win_skip_fading(ps, w));
}
}
w->reg_ignore_valid = false; w->reg_ignore_valid = false;
} }
@ -1939,6 +1928,7 @@ void unmap_win_start(session_t *ps, struct managed_win *w) {
w->a.map_state = XCB_MAP_STATE_UNMAPPED; w->a.map_state = XCB_MAP_STATE_UNMAPPED;
w->state = WSTATE_UNMAPPING; w->state = WSTATE_UNMAPPING;
w->opacity_target_old = fmax(w->opacity_target, w->opacity_target_old);
w->opacity_target = win_calc_opacity_target(ps, w, false); w->opacity_target = win_calc_opacity_target(ps, w, false);
// Clear PIXMAP_STALE flag, since the window is unmapped there is no pixmap // Clear PIXMAP_STALE flag, since the window is unmapped there is no pixmap
@ -2123,6 +2113,7 @@ void map_win_start(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_target_old = 0;
w->opacity_target = win_calc_opacity_target(ps, w, false); 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,
@ -2158,6 +2149,60 @@ void map_win_start(session_t *ps, struct managed_win *w) {
} }
} }
/**
* Update target window opacity depending on the current state.
*/
void win_update_opacity_target(session_t *ps, struct managed_win *w) {
auto opacity_target_old = w->opacity_target;
w->opacity_target = win_calc_opacity_target(ps, w, false);
if (opacity_target_old == w->opacity_target) {
return;
}
if (w->state == WSTATE_MAPPED) {
// Opacity target changed while MAPPED. Transition to FADING.
assert(w->opacity == opacity_target_old);
w->opacity_target_old = opacity_target_old;
w->state = WSTATE_FADING;
log_debug("Window %#010x (%s) opacity %f, opacity target %f, set "
"old target %f",
w->base.id, w->name, w->opacity, w->opacity_target,
w->opacity_target_old);
} else if (w->state == WSTATE_MAPPING) {
// Opacity target changed while fading in.
if (w->opacity >= w->opacity_target) {
// Already reached new target opacity. Transition to
// FADING.
map_win_finish(w);
w->opacity_target_old = fmax(opacity_target_old, w->opacity);
w->state = WSTATE_FADING;
log_debug("Window %#010x (%s) opacity %f already reached "
"new opacity target %f while mapping, set old "
"target %f",
w->base.id, w->name, w->opacity, w->opacity_target,
w->opacity_target_old);
}
} else if (w->state == WSTATE_FADING) {
// Opacity target changed while FADING.
if ((w->opacity < opacity_target_old && w->opacity > w->opacity_target) ||
(w->opacity > opacity_target_old && w->opacity < w->opacity_target)) {
// Changed while fading in and will fade out or while
// fading out and will fade in.
w->opacity_target_old = opacity_target_old;
log_debug("Window %#010x (%s) opacity %f already reached "
"new opacity target %f while fading, set "
"old target %f",
w->base.id, w->name, w->opacity, w->opacity_target,
w->opacity_target_old);
}
}
if (!ps->redirected) {
CHECK(!win_skip_fading(ps, w));
}
}
/** /**
* Find a managed window from window id in window linked list of the session. * Find a managed window from window id in window linked list of the session.
*/ */

View File

@ -192,6 +192,8 @@ struct managed_win {
double opacity; double opacity;
/// Target window opacity. /// Target window opacity.
double opacity_target; double opacity_target;
/// Previous window opacity.
double opacity_target_old;
/// 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;
@ -287,6 +289,7 @@ void win_set_focused(session_t *ps, struct managed_win *w);
bool attr_pure win_should_fade(session_t *ps, const struct managed_win *w); bool attr_pure win_should_fade(session_t *ps, const struct managed_win *w);
void win_update_prop_shadow_raw(session_t *ps, struct managed_win *w); void win_update_prop_shadow_raw(session_t *ps, struct managed_win *w);
void win_update_prop_shadow(session_t *ps, struct managed_win *w); void win_update_prop_shadow(session_t *ps, struct managed_win *w);
void win_update_opacity_target(session_t *ps, struct managed_win *w);
void win_on_factor_change(session_t *ps, struct managed_win *w); void win_on_factor_change(session_t *ps, struct managed_win *w);
/** /**
* Update cache data in struct _win that depends on window size. * Update cache data in struct _win that depends on window size.

View File

@ -40,8 +40,8 @@ typedef enum {
/// | DESTROYING | - | o | - | - | - | - | Fading | /// | DESTROYING | - | o | - | - | - | - | Fading |
/// | | | | | | | |finished | /// | | | | | | | |finished |
/// +-------------+---------+----------+-------+-------+--------+--------+---------+ /// +-------------+---------+----------+-------+-------+--------+--------+---------+
/// | MAPPING | Window | Window | o | - | - | Fading | - | /// | MAPPING | Window | Window | o |Opacity| - | Fading | - |
/// | |unmapped |destroyed | | | |finished| | /// | |unmapped |destroyed | |change | |finished| |
/// +-------------+---------+----------+-------+-------+--------+--------+---------+ /// +-------------+---------+----------+-------+-------+--------+--------+---------+
/// | FADING | Window | Window | - | o | - | Fading | - | /// | FADING | Window | Window | - | o | - | Fading | - |
/// | |unmapped |destroyed | | | |finished| | /// | |unmapped |destroyed | | | |finished| |