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:
parent
32754b0262
commit
ad8632b017
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
69
src/win.c
69
src/win.c
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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| |
|
||||||
|
|
Loading…
Reference in New Issue