mirror of
https://github.com/yshui/picom.git
synced 2024-10-27 05:24:17 -04:00
win: use the new transition mechanism for fading
Fading behavior is changed slightly when a window's opacity is changed while the window is already fading in/out. Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
parent
5a5716a7b1
commit
35b85155c5
6 changed files with 110 additions and 146 deletions
|
@ -10,6 +10,7 @@
|
|||
#include "config.h"
|
||||
#include "log.h"
|
||||
#include "region.h"
|
||||
#include "transition.h"
|
||||
#include "types.h"
|
||||
#include "win.h"
|
||||
#include "x.h"
|
||||
|
@ -253,45 +254,20 @@ bool paint_all_new(session_t *ps, struct managed_win *const t) {
|
|||
auto real_win_mode = w->mode;
|
||||
coord_t window_coord = {.x = w->g.x, .y = w->g.y};
|
||||
|
||||
const double window_opacity = animatable_get(&w->opacity);
|
||||
if (w->blur_background &&
|
||||
(ps->o.force_win_blend || real_win_mode == WMODE_TRANS ||
|
||||
(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.
|
||||
|
||||
double blur_opacity = 1;
|
||||
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
|
||||
// fading in.
|
||||
assert(w->opacity <= w->opacity_target);
|
||||
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.
|
||||
assert(w->opacity <= w->opacity_target_old);
|
||||
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;
|
||||
}
|
||||
}
|
||||
const double blur_opacity = animatable_get(&w->blur_opacity);
|
||||
assert(blur_opacity >= 0 && blur_opacity <= 1);
|
||||
|
||||
if (real_win_mode == WMODE_TRANS || ps->o.force_win_blend) {
|
||||
if (blur_opacity * MAX_ALPHA < 1) {
|
||||
// We don't need to blur if it would be completely
|
||||
// transparent
|
||||
} else 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(
|
||||
|
@ -404,7 +380,7 @@ bool paint_all_new(session_t *ps, struct managed_win *const t) {
|
|||
if (w->dim) {
|
||||
dim_opacity = ps->o.inactive_dim;
|
||||
if (!ps->o.inactive_dim_fixed) {
|
||||
dim_opacity *= w->opacity;
|
||||
dim_opacity *= window_opacity;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -418,7 +394,8 @@ bool paint_all_new(session_t *ps, struct managed_win *const t) {
|
|||
ps->backend_data, IMAGE_PROPERTY_DIM_LEVEL, w->win_image,
|
||||
&dim_opacity);
|
||||
ps->backend_data->ops->set_image_property(
|
||||
ps->backend_data, IMAGE_PROPERTY_OPACITY, w->win_image, &w->opacity);
|
||||
ps->backend_data, IMAGE_PROPERTY_OPACITY, w->win_image,
|
||||
&window_opacity);
|
||||
ps->backend_data->ops->set_image_property(
|
||||
ps->backend_data, IMAGE_PROPERTY_CORNER_RADIUS, w->win_image,
|
||||
(double[]){w->corner_radius});
|
||||
|
@ -440,7 +417,7 @@ bool paint_all_new(session_t *ps, struct managed_win *const t) {
|
|||
w->fg_shader ? (void *)w->fg_shader->backend_shader : NULL);
|
||||
}
|
||||
|
||||
if (w->opacity * MAX_ALPHA < 1) {
|
||||
if (window_opacity * MAX_ALPHA < 1) {
|
||||
// We don't need to paint the window body itself if it's
|
||||
// completely transparent.
|
||||
goto skip;
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "list.h"
|
||||
#include "log.h"
|
||||
#include "string_utils.h"
|
||||
#include "transition.h"
|
||||
#include "types.h"
|
||||
#include "uthash_extra.h"
|
||||
#include "utils.h"
|
||||
|
@ -991,14 +992,17 @@ static bool cdbus_process_win_get(session_t *ps, DBusMessage *msg) {
|
|||
cdbus_m_win_get_do(class_general, 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_target, 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);
|
||||
cdbus_m_win_get_do(opacity_set, cdbus_reply_double);
|
||||
|
||||
cdbus_m_win_get_do(frame_opacity, cdbus_reply_double);
|
||||
if (strcmp(target, "opacity") == 0) {
|
||||
cdbus_reply_double(ps, msg, animatable_get(&w->opacity));
|
||||
return true;
|
||||
}
|
||||
if (!strcmp("left_width", target)) {
|
||||
cdbus_reply_int32(ps, msg, w->frame_extents.left);
|
||||
return true;
|
||||
|
|
68
src/picom.c
68
src/picom.c
|
@ -48,6 +48,7 @@
|
|||
#include "inspect.h"
|
||||
#include "kernel.h"
|
||||
#include "picom.h"
|
||||
#include "transition.h"
|
||||
#include "win_defs.h"
|
||||
#ifdef CONFIG_OPENGL
|
||||
#include "opengl.h"
|
||||
|
@ -495,22 +496,25 @@ static double fade_timeout(session_t *ps) {
|
|||
* @param steps steps of fading
|
||||
* @return whether we are still in fading mode
|
||||
*/
|
||||
static bool run_fade(session_t *ps, struct managed_win **_w, long long steps) {
|
||||
static bool run_fade(session_t *ps, struct managed_win **_w, unsigned int steps) {
|
||||
auto w = *_w;
|
||||
log_trace("Process fading for window %s (%#010x), steps: %lld", w->name,
|
||||
w->base.id, steps);
|
||||
log_trace("Process fading for window %s (%#010x), steps: %u", w->name, w->base.id,
|
||||
steps);
|
||||
if (w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED) {
|
||||
// We are not fading
|
||||
assert(w->opacity_target == w->opacity);
|
||||
assert(!animatable_is_animating(&w->opacity));
|
||||
assert(!animatable_is_animating(&w->blur_opacity));
|
||||
log_trace("|- not fading");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!win_should_fade(ps, w)) {
|
||||
log_trace("|- in transition but doesn't need fading");
|
||||
w->opacity = w->opacity_target;
|
||||
animatable_early_stop(&w->opacity);
|
||||
animatable_early_stop(&w->blur_opacity);
|
||||
}
|
||||
if (w->opacity == w->opacity_target) {
|
||||
if (!animatable_is_animating(&w->opacity) &&
|
||||
!animatable_is_animating(&w->blur_opacity)) {
|
||||
// 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
|
||||
|
@ -518,20 +522,14 @@ static bool run_fade(session_t *ps, struct managed_win **_w, long long steps) {
|
|||
return false;
|
||||
}
|
||||
|
||||
log_trace("|- fading, opacity: %lf", w->opacity);
|
||||
if (steps) {
|
||||
if (w->opacity < w->opacity_target) {
|
||||
w->opacity = clamp(w->opacity + ps->o.fade_in_step * (double)steps,
|
||||
0.0, w->opacity_target);
|
||||
} else {
|
||||
w->opacity = clamp(w->opacity - ps->o.fade_out_step * (double)steps,
|
||||
w->opacity_target, 1);
|
||||
}
|
||||
log_trace("|- opacity updated: %lf", w->opacity);
|
||||
}
|
||||
log_trace("|- fading, opacity: %lf", animatable_get(&w->opacity));
|
||||
animatable_step(&w->opacity, steps);
|
||||
animatable_step(&w->blur_opacity, steps);
|
||||
log_trace("|- opacity updated: %lf (%u steps)", animatable_get(&w->opacity), steps);
|
||||
|
||||
// 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.
|
||||
// Note even if the animatable is not animating anymore at this point, we still
|
||||
// want to run preprocess one last time to finish state transition. So return true
|
||||
// in that case too.
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -918,17 +916,19 @@ static bool paint_preprocess(session_t *ps, bool *fade_running, bool *animation,
|
|||
*out_bottom = NULL;
|
||||
|
||||
// Fading step calculation
|
||||
long long steps = 0L;
|
||||
unsigned int steps = 0L;
|
||||
auto now = get_time_ms();
|
||||
if (ps->fade_time) {
|
||||
assert(now >= ps->fade_time);
|
||||
steps = (now - ps->fade_time) / ps->o.fade_delta;
|
||||
auto raw_steps = (now - ps->fade_time) / ps->o.fade_delta;
|
||||
assert(raw_steps <= UINT_MAX);
|
||||
steps = (unsigned int)raw_steps;
|
||||
ps->fade_time += raw_steps * ps->o.fade_delta;
|
||||
} else {
|
||||
// Reset fade_time if unset
|
||||
ps->fade_time = get_time_ms();
|
||||
steps = 0L;
|
||||
}
|
||||
ps->fade_time += steps * ps->o.fade_delta;
|
||||
|
||||
// First, let's process fading, and animated shaders
|
||||
// TODO(yshui) check if a window is fully obscured, and if we don't need to
|
||||
|
@ -936,7 +936,6 @@ static bool paint_preprocess(session_t *ps, bool *fade_running, bool *animation,
|
|||
win_stack_foreach_managed_safe(w, &ps->window_stack) {
|
||||
const winmode_t mode_old = w->mode;
|
||||
const bool was_painted = w->to_paint;
|
||||
const double opacity_old = w->opacity;
|
||||
|
||||
if (win_should_dim(ps, w) != w->dim) {
|
||||
w->dim = win_should_dim(ps, w);
|
||||
|
@ -948,20 +947,20 @@ static bool paint_preprocess(session_t *ps, bool *fade_running, bool *animation,
|
|||
*animation = true;
|
||||
}
|
||||
|
||||
// Add window to damaged area if its opacity changes
|
||||
// If was_painted == false, and to_paint is also false, we don't care
|
||||
// If was_painted == false, but to_paint is true, damage will be added in
|
||||
// the loop below
|
||||
if (was_painted && animatable_is_animating(&w->opacity)) {
|
||||
add_damage_from_win(ps, w);
|
||||
}
|
||||
|
||||
// Run fading
|
||||
if (run_fade(ps, &w, steps)) {
|
||||
*fade_running = true;
|
||||
}
|
||||
|
||||
// Add window to damaged area if its opacity changes
|
||||
// If was_painted == false, and to_paint is also false, we don't care
|
||||
// If was_painted == false, but to_paint is true, damage will be added in
|
||||
// the loop below
|
||||
if (was_painted && w->opacity != opacity_old) {
|
||||
add_damage_from_win(ps, w);
|
||||
}
|
||||
|
||||
if (win_check_fade_finished(ps, w)) {
|
||||
if (win_maybe_finalize_fading(ps, w)) {
|
||||
// the window has been destroyed because fading finished
|
||||
continue;
|
||||
}
|
||||
|
@ -994,6 +993,7 @@ static bool paint_preprocess(session_t *ps, bool *fade_running, bool *animation,
|
|||
bool to_paint = true;
|
||||
// w->to_paint remembers whether this window is painted last time
|
||||
const bool was_painted = w->to_paint;
|
||||
const double window_opacity = animatable_get(&w->opacity);
|
||||
|
||||
// Destroy reg_ignore if some window above us invalidated it
|
||||
if (!reg_ignore_valid) {
|
||||
|
@ -1027,7 +1027,7 @@ static bool paint_preprocess(session_t *ps, bool *fade_running, bool *animation,
|
|||
w->g.x >= ps->root_width || w->g.y >= ps->root_height)) {
|
||||
log_trace("|- is positioned outside of the screen");
|
||||
to_paint = false;
|
||||
} else if (unlikely((double)w->opacity * MAX_ALPHA < 1 && !w->blur_background)) {
|
||||
} else if (unlikely(window_opacity * MAX_ALPHA < 1 && !w->blur_background)) {
|
||||
/* TODO(yshui) for consistency, even a window has 0 opacity, we
|
||||
* still probably need to blur its background, so to_paint
|
||||
* shouldn't be false for them. */
|
||||
|
@ -1060,7 +1060,7 @@ static bool paint_preprocess(session_t *ps, bool *fade_running, bool *animation,
|
|||
log_verbose("Window %#010x (%s) will be painted", w->base.id, w->name);
|
||||
|
||||
// Calculate shadow opacity
|
||||
w->shadow_opacity = ps->o.shadow_opacity * w->opacity * ps->o.frame_opacity;
|
||||
w->shadow_opacity = ps->o.shadow_opacity * window_opacity * ps->o.frame_opacity;
|
||||
|
||||
// Generate ignore region for painting to reduce GPU load
|
||||
if (!w->reg_ignore) {
|
||||
|
|
17
src/render.c
17
src/render.c
|
@ -12,6 +12,7 @@
|
|||
|
||||
#include "common.h"
|
||||
#include "options.h"
|
||||
#include "transition.h"
|
||||
|
||||
#ifdef CONFIG_OPENGL
|
||||
#include "backend/gl/glx.h"
|
||||
|
@ -436,6 +437,7 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint)
|
|||
const int y = w->g.y;
|
||||
const uint16_t wid = to_u16_checked(w->widthb);
|
||||
const uint16_t hei = to_u16_checked(w->heightb);
|
||||
const double window_opacity = animatable_get(&w->opacity);
|
||||
|
||||
xcb_render_picture_t pict = w->paint.pict;
|
||||
|
||||
|
@ -472,7 +474,7 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint)
|
|||
}
|
||||
|
||||
if (w->frame_opacity == 1) {
|
||||
paint_region(ps, w, 0, 0, wid, hei, w->opacity, reg_paint, pict);
|
||||
paint_region(ps, w, 0, 0, wid, hei, window_opacity, reg_paint, pict);
|
||||
} else {
|
||||
// Painting parameters
|
||||
const margin_t extents = win_calc_frame_extents(w);
|
||||
|
@ -482,8 +484,8 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint)
|
|||
auto const r = extents.right;
|
||||
|
||||
#define COMP_BDR(cx, cy, cwid, chei) \
|
||||
paint_region(ps, w, (cx), (cy), (cwid), (chei), w->frame_opacity * w->opacity, \
|
||||
reg_paint, pict)
|
||||
paint_region(ps, w, (cx), (cy), (cwid), (chei), \
|
||||
w->frame_opacity *window_opacity, reg_paint, pict)
|
||||
|
||||
// Sanitize the margins, in case some broken WM makes
|
||||
// top_width + bottom_width > height in some cases.
|
||||
|
@ -542,7 +544,7 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint)
|
|||
|
||||
// body
|
||||
paint_region(ps, w, cleft, ctop, body_width, body_height,
|
||||
w->opacity, reg_paint, pict);
|
||||
window_opacity, reg_paint, pict);
|
||||
} while (0);
|
||||
}
|
||||
|
||||
|
@ -557,7 +559,7 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint)
|
|||
if (w->dim) {
|
||||
double dim_opacity = ps->o.inactive_dim;
|
||||
if (!ps->o.inactive_dim_fixed) {
|
||||
dim_opacity *= w->opacity;
|
||||
dim_opacity *= window_opacity;
|
||||
}
|
||||
|
||||
switch (ps->o.backend) {
|
||||
|
@ -899,12 +901,13 @@ win_blur_background(session_t *ps, struct managed_win *w, xcb_render_picture_t t
|
|||
auto const wid = to_u16_checked(w->widthb);
|
||||
auto const hei = to_u16_checked(w->heightb);
|
||||
const int cr = w ? w->corner_radius : 0;
|
||||
const double window_opacity = animatable_get(&w->opacity);
|
||||
|
||||
double factor_center = 1.0;
|
||||
// Adjust blur strength according to window opacity, to make it appear
|
||||
// better during fading
|
||||
if (!ps->o.blur_background_fixed) {
|
||||
double pct = 1.0 - w->opacity * (1.0 - 1.0 / 9.0);
|
||||
double pct = 1.0 - window_opacity * (1.0 - 1.0 / 9.0);
|
||||
factor_center = pct * 8.0 / (1.1 - pct);
|
||||
}
|
||||
|
||||
|
@ -1143,7 +1146,7 @@ void paint_all(session_t *ps, struct managed_win *t) {
|
|||
}
|
||||
|
||||
// Only clip shadows above visible windows
|
||||
if (w->opacity * MAX_ALPHA >= 1) {
|
||||
if (animatable_get(&w->opacity) * MAX_ALPHA >= 1) {
|
||||
if (w->clip_shadow_above) {
|
||||
// Add window bounds to shadow-clip region
|
||||
pixman_region32_union(®_shadow_clip, ®_shadow_clip,
|
||||
|
|
89
src/win.c
89
src/win.c
|
@ -27,6 +27,7 @@
|
|||
#include "region.h"
|
||||
#include "render.h"
|
||||
#include "string_utils.h"
|
||||
#include "transition.h"
|
||||
#include "types.h"
|
||||
#include "uthash_extra.h"
|
||||
#include "utils.h"
|
||||
|
@ -799,7 +800,7 @@ bool win_client_has_alpha(const struct managed_win *w) {
|
|||
}
|
||||
|
||||
winmode_t win_calc_mode(const struct managed_win *w) {
|
||||
if (w->opacity < 1.0) {
|
||||
if (animatable_get(&w->opacity) < 1.0) {
|
||||
return WMODE_TRANS;
|
||||
}
|
||||
|
||||
|
@ -846,7 +847,7 @@ winmode_t win_calc_mode(const struct managed_win *w) {
|
|||
*
|
||||
* @return target opacity
|
||||
*/
|
||||
double win_calc_opacity_target(session_t *ps, const struct managed_win *w) {
|
||||
static double win_calc_opacity_target(session_t *ps, const struct managed_win *w) {
|
||||
double opacity = 1;
|
||||
|
||||
if (w->state == WSTATE_UNMAPPED) {
|
||||
|
@ -882,6 +883,21 @@ double win_calc_opacity_target(session_t *ps, const struct managed_win *w) {
|
|||
return opacity;
|
||||
}
|
||||
|
||||
/// Call `animatable_set_target` on the opacity of a window, with appropriate
|
||||
/// target opacity and duration.
|
||||
///
|
||||
/// @return duration of the fade
|
||||
static inline unsigned int win_start_fade(session_t *ps, struct managed_win *w) {
|
||||
double current_opacity = animatable_get(&w->opacity),
|
||||
target_opacity = win_calc_opacity_target(ps, w);
|
||||
double step_size =
|
||||
target_opacity > current_opacity ? ps->o.fade_in_step : ps->o.fade_out_step;
|
||||
unsigned int duration =
|
||||
(unsigned int)(fabs(target_opacity - current_opacity) / step_size);
|
||||
animatable_set_target(&w->opacity, target_opacity, duration);
|
||||
return duration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether a window is to be dimmed.
|
||||
*/
|
||||
|
@ -1605,8 +1621,6 @@ struct win *attr_ret_nonnull maybe_allocate_managed_win(session_t *ps, struct wi
|
|||
.cache_leader = XCB_NONE,
|
||||
.window_type = WINTYPE_UNKNOWN,
|
||||
.focused = false,
|
||||
.opacity = 0,
|
||||
.opacity_target = 0,
|
||||
.has_opacity_prop = false,
|
||||
.opacity_prop = OPAQUE,
|
||||
.opacity_is_set = false,
|
||||
|
@ -1685,6 +1699,8 @@ struct win *attr_ret_nonnull maybe_allocate_managed_win(session_t *ps, struct wi
|
|||
new->base = *w;
|
||||
new->base.managed = true;
|
||||
new->a = *a;
|
||||
new->opacity = animatable_new(0, linear_interpolator, NULL);
|
||||
new->blur_opacity = animatable_new(0, linear_interpolator, NULL);
|
||||
pixman_region32_init(&new->bounding_shape);
|
||||
|
||||
free(a);
|
||||
|
@ -2386,8 +2402,8 @@ void unmap_win_start(session_t *ps, struct managed_win *w) {
|
|||
|
||||
w->a.map_state = XCB_MAP_STATE_UNMAPPED;
|
||||
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);
|
||||
auto duration = win_start_fade(ps, w);
|
||||
animatable_set_target(&w->blur_opacity, 0, duration);
|
||||
|
||||
#ifdef CONFIG_DBUS
|
||||
// Send D-Bus signal
|
||||
|
@ -2410,13 +2426,13 @@ void unmap_win_start(session_t *ps, struct managed_win *w) {
|
|||
*
|
||||
* @return whether the window is destroyed and freed
|
||||
*/
|
||||
bool win_check_fade_finished(session_t *ps, struct managed_win *w) {
|
||||
bool win_maybe_finalize_fading(session_t *ps, struct managed_win *w) {
|
||||
if (w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED) {
|
||||
// No fading in progress
|
||||
assert(w->opacity_target == w->opacity);
|
||||
assert(!animatable_is_animating(&w->opacity));
|
||||
return false;
|
||||
}
|
||||
if (w->opacity == w->opacity_target) {
|
||||
if (!animatable_is_animating(&w->opacity)) {
|
||||
switch (w->state) {
|
||||
case WSTATE_UNMAPPING: unmap_win_finish(ps, w); return false;
|
||||
case WSTATE_DESTROYING: destroy_win_finish(ps, &w->base); return true;
|
||||
|
@ -2435,12 +2451,13 @@ bool win_check_fade_finished(session_t *ps, struct managed_win *w) {
|
|||
/// @return whether the window is destroyed and freed
|
||||
bool win_skip_fading(session_t *ps, struct managed_win *w) {
|
||||
if (w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED) {
|
||||
assert(w->opacity_target == w->opacity);
|
||||
assert(!animatable_is_animating(&w->opacity));
|
||||
return false;
|
||||
}
|
||||
log_debug("Skipping fading process of window %#010x (%s)", w->base.id, w->name);
|
||||
w->opacity = w->opacity_target;
|
||||
return win_check_fade_finished(ps, w);
|
||||
animatable_early_stop(&w->opacity);
|
||||
animatable_early_stop(&w->blur_opacity);
|
||||
return win_maybe_finalize_fading(ps, w);
|
||||
}
|
||||
|
||||
// TODO(absolutelynothelix): rename to x_update_win_(randr_?)monitor and move to
|
||||
|
@ -2514,11 +2531,11 @@ void map_win_start(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_target_old = 0;
|
||||
w->opacity_target = win_calc_opacity_target(ps, w);
|
||||
auto duration = win_start_fade(ps, w);
|
||||
animatable_set_target(&w->blur_opacity, 1, duration);
|
||||
|
||||
log_debug("Window %#010x has opacity %f, opacity target is %f", w->base.id,
|
||||
w->opacity, w->opacity_target);
|
||||
animatable_get(&w->opacity), w->opacity.target);
|
||||
|
||||
// Cannot set w->ever_damaged = false here, since window mapping could be
|
||||
// delayed, so a damage event might have already arrived before this
|
||||
|
@ -2546,49 +2563,25 @@ 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);
|
||||
auto duration = win_start_fade(ps, w);
|
||||
|
||||
if (opacity_target_old == w->opacity_target) {
|
||||
if (!animatable_is_animating(&w->opacity)) {
|
||||
return;
|
||||
}
|
||||
|
||||
log_debug("Window %#010x (%s) opacity %f, opacity target %f, start %f", w->base.id,
|
||||
w->name, animatable_get(&w->opacity), w->opacity.target, w->opacity.start);
|
||||
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);
|
||||
}
|
||||
// Opacity target changed while fading in, keep the blur_opacity
|
||||
// in lock step with the opacity
|
||||
animatable_set_target(&w->blur_opacity, w->blur_opacity.target, duration);
|
||||
log_debug("Opacity changed while fading in");
|
||||
} 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);
|
||||
}
|
||||
log_debug("Opacity changed while already fading");
|
||||
}
|
||||
|
||||
if (!ps->redirected) {
|
||||
|
|
29
src/win.h
29
src/win.h
|
@ -16,6 +16,7 @@
|
|||
#include "list.h"
|
||||
#include "region.h"
|
||||
#include "render.h"
|
||||
#include "transition.h"
|
||||
#include "types.h"
|
||||
#include "utils.h"
|
||||
#include "win_defs.h"
|
||||
|
@ -204,12 +205,12 @@ struct managed_win {
|
|||
bool is_ewmh_focused;
|
||||
|
||||
// Opacity-related members
|
||||
/// Current window opacity.
|
||||
double opacity;
|
||||
/// Target window opacity.
|
||||
double opacity_target;
|
||||
/// Previous window opacity.
|
||||
double opacity_target_old;
|
||||
/// Window opacity
|
||||
struct animatable opacity;
|
||||
/// Opacity of the window's background blur
|
||||
/// Used to gracefully fade in/out the window, otherwise the blur
|
||||
/// would be at full/zero intensity immediately which will be jarring.
|
||||
struct animatable blur_opacity;
|
||||
/// true if window (or client window, for broken window managers
|
||||
/// not transferring client window's _NET_WM_WINDOW_OPACITY value) has opacity
|
||||
/// prop
|
||||
|
@ -326,20 +327,6 @@ bool attr_pure win_should_fade(session_t *ps, const struct managed_win *w);
|
|||
void win_on_factor_change(session_t *ps, struct managed_win *w);
|
||||
void win_unmark_client(session_t *ps, 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
|
||||
*
|
||||
* @return target opacity
|
||||
*/
|
||||
double attr_pure win_calc_opacity_target(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_monitor(struct x_monitors *monitors, struct managed_win *mw);
|
||||
|
@ -396,7 +383,7 @@ void restack_top(session_t *ps, struct win *w);
|
|||
/**
|
||||
* Execute fade callback of a window if fading finished.
|
||||
*/
|
||||
bool must_use win_check_fade_finished(session_t *ps, struct managed_win *w);
|
||||
bool must_use win_maybe_finalize_fading(session_t *ps, struct managed_win *w);
|
||||
|
||||
// Stop receiving events (except ConfigureNotify, XXX why?) from a window
|
||||
void win_ev_stop(session_t *ps, const struct win *w);
|
||||
|
|
Loading…
Reference in a new issue