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 "config.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "region.h"
|
#include "region.h"
|
||||||
|
#include "transition.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "win.h"
|
#include "win.h"
|
||||||
#include "x.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;
|
auto real_win_mode = w->mode;
|
||||||
coord_t window_coord = {.x = w->g.x, .y = w->g.y};
|
coord_t window_coord = {.x = w->g.x, .y = w->g.y};
|
||||||
|
|
||||||
|
const double window_opacity = animatable_get(&w->opacity);
|
||||||
if (w->blur_background &&
|
if (w->blur_background &&
|
||||||
(ps->o.force_win_blend || real_win_mode == WMODE_TRANS ||
|
(ps->o.force_win_blend || real_win_mode == WMODE_TRANS ||
|
||||||
(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.
|
||||||
|
|
||||||
double blur_opacity = 1;
|
const double blur_opacity = animatable_get(&w->blur_opacity);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert(blur_opacity >= 0 && blur_opacity <= 1);
|
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
|
// 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(
|
||||||
|
@ -404,7 +380,7 @@ bool paint_all_new(session_t *ps, struct managed_win *const t) {
|
||||||
if (w->dim) {
|
if (w->dim) {
|
||||||
dim_opacity = ps->o.inactive_dim;
|
dim_opacity = ps->o.inactive_dim;
|
||||||
if (!ps->o.inactive_dim_fixed) {
|
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,
|
ps->backend_data, IMAGE_PROPERTY_DIM_LEVEL, w->win_image,
|
||||||
&dim_opacity);
|
&dim_opacity);
|
||||||
ps->backend_data->ops->set_image_property(
|
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->ops->set_image_property(
|
||||||
ps->backend_data, IMAGE_PROPERTY_CORNER_RADIUS, w->win_image,
|
ps->backend_data, IMAGE_PROPERTY_CORNER_RADIUS, w->win_image,
|
||||||
(double[]){w->corner_radius});
|
(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);
|
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
|
// We don't need to paint the window body itself if it's
|
||||||
// completely transparent.
|
// completely transparent.
|
||||||
goto skip;
|
goto skip;
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "string_utils.h"
|
#include "string_utils.h"
|
||||||
|
#include "transition.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "uthash_extra.h"
|
#include "uthash_extra.h"
|
||||||
#include "utils.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(class_general, cdbus_reply_string);
|
||||||
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.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(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);
|
||||||
cdbus_m_win_get_do(opacity_set, cdbus_reply_double);
|
cdbus_m_win_get_do(opacity_set, cdbus_reply_double);
|
||||||
|
|
||||||
cdbus_m_win_get_do(frame_opacity, 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)) {
|
if (!strcmp("left_width", target)) {
|
||||||
cdbus_reply_int32(ps, msg, w->frame_extents.left);
|
cdbus_reply_int32(ps, msg, w->frame_extents.left);
|
||||||
return true;
|
return true;
|
||||||
|
|
68
src/picom.c
68
src/picom.c
|
@ -48,6 +48,7 @@
|
||||||
#include "inspect.h"
|
#include "inspect.h"
|
||||||
#include "kernel.h"
|
#include "kernel.h"
|
||||||
#include "picom.h"
|
#include "picom.h"
|
||||||
|
#include "transition.h"
|
||||||
#include "win_defs.h"
|
#include "win_defs.h"
|
||||||
#ifdef CONFIG_OPENGL
|
#ifdef CONFIG_OPENGL
|
||||||
#include "opengl.h"
|
#include "opengl.h"
|
||||||
|
@ -495,22 +496,25 @@ static double fade_timeout(session_t *ps) {
|
||||||
* @param steps steps of fading
|
* @param steps steps of fading
|
||||||
* @return whether we are still in fading mode
|
* @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;
|
auto w = *_w;
|
||||||
log_trace("Process fading for window %s (%#010x), steps: %lld", w->name,
|
log_trace("Process fading for window %s (%#010x), steps: %u", w->name, w->base.id,
|
||||||
w->base.id, steps);
|
steps);
|
||||||
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_target == w->opacity);
|
assert(!animatable_is_animating(&w->opacity));
|
||||||
|
assert(!animatable_is_animating(&w->blur_opacity));
|
||||||
log_trace("|- not fading");
|
log_trace("|- not fading");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!win_should_fade(ps, w)) {
|
if (!win_should_fade(ps, w)) {
|
||||||
log_trace("|- in transition but doesn't need fading");
|
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 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
|
||||||
|
@ -518,20 +522,14 @@ static bool run_fade(session_t *ps, struct managed_win **_w, long long steps) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
log_trace("|- fading, opacity: %lf", w->opacity);
|
log_trace("|- fading, opacity: %lf", animatable_get(&w->opacity));
|
||||||
if (steps) {
|
animatable_step(&w->opacity, steps);
|
||||||
if (w->opacity < w->opacity_target) {
|
animatable_step(&w->blur_opacity, steps);
|
||||||
w->opacity = clamp(w->opacity + ps->o.fade_in_step * (double)steps,
|
log_trace("|- opacity updated: %lf (%u steps)", animatable_get(&w->opacity), 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note even if opacity == opacity_target here, we still want to run preprocess
|
// Note even if the animatable is not animating anymore at this point, we still
|
||||||
// one last time to finish state transition. So return true in that case too.
|
// want to run preprocess one last time to finish state transition. So return true
|
||||||
|
// in that case too.
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -918,17 +916,19 @@ static bool paint_preprocess(session_t *ps, bool *fade_running, bool *animation,
|
||||||
*out_bottom = NULL;
|
*out_bottom = NULL;
|
||||||
|
|
||||||
// Fading step calculation
|
// Fading step calculation
|
||||||
long long steps = 0L;
|
unsigned int steps = 0L;
|
||||||
auto now = get_time_ms();
|
auto now = get_time_ms();
|
||||||
if (ps->fade_time) {
|
if (ps->fade_time) {
|
||||||
assert(now >= 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 {
|
} else {
|
||||||
// Reset fade_time if unset
|
// Reset fade_time if unset
|
||||||
ps->fade_time = get_time_ms();
|
ps->fade_time = get_time_ms();
|
||||||
steps = 0L;
|
steps = 0L;
|
||||||
}
|
}
|
||||||
ps->fade_time += steps * ps->o.fade_delta;
|
|
||||||
|
|
||||||
// First, let's process fading, and animated shaders
|
// First, let's process fading, and animated shaders
|
||||||
// TODO(yshui) check if a window is fully obscured, and if we don't need to
|
// 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) {
|
win_stack_foreach_managed_safe(w, &ps->window_stack) {
|
||||||
const winmode_t mode_old = w->mode;
|
const winmode_t mode_old = w->mode;
|
||||||
const bool was_painted = w->to_paint;
|
const bool was_painted = w->to_paint;
|
||||||
const double opacity_old = w->opacity;
|
|
||||||
|
|
||||||
if (win_should_dim(ps, w) != w->dim) {
|
if (win_should_dim(ps, w) != w->dim) {
|
||||||
w->dim = win_should_dim(ps, w);
|
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;
|
*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
|
// Run fading
|
||||||
if (run_fade(ps, &w, steps)) {
|
if (run_fade(ps, &w, steps)) {
|
||||||
*fade_running = true;
|
*fade_running = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add window to damaged area if its opacity changes
|
if (win_maybe_finalize_fading(ps, w)) {
|
||||||
// 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)) {
|
|
||||||
// the window has been destroyed because fading finished
|
// the window has been destroyed because fading finished
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -994,6 +993,7 @@ static bool paint_preprocess(session_t *ps, bool *fade_running, bool *animation,
|
||||||
bool to_paint = true;
|
bool to_paint = true;
|
||||||
// w->to_paint remembers whether this window is painted last time
|
// w->to_paint remembers whether this window is painted last time
|
||||||
const bool was_painted = w->to_paint;
|
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
|
// Destroy reg_ignore if some window above us invalidated it
|
||||||
if (!reg_ignore_valid) {
|
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)) {
|
w->g.x >= ps->root_width || w->g.y >= ps->root_height)) {
|
||||||
log_trace("|- is positioned outside of the screen");
|
log_trace("|- is positioned outside of the screen");
|
||||||
to_paint = false;
|
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
|
/* TODO(yshui) for consistency, even a window has 0 opacity, we
|
||||||
* still probably need to blur its background, so to_paint
|
* still probably need to blur its background, so to_paint
|
||||||
* shouldn't be false for them. */
|
* 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);
|
log_verbose("Window %#010x (%s) will be painted", w->base.id, w->name);
|
||||||
|
|
||||||
// Calculate shadow opacity
|
// 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
|
// Generate ignore region for painting to reduce GPU load
|
||||||
if (!w->reg_ignore) {
|
if (!w->reg_ignore) {
|
||||||
|
|
17
src/render.c
17
src/render.c
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "options.h"
|
#include "options.h"
|
||||||
|
#include "transition.h"
|
||||||
|
|
||||||
#ifdef CONFIG_OPENGL
|
#ifdef CONFIG_OPENGL
|
||||||
#include "backend/gl/glx.h"
|
#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 int y = w->g.y;
|
||||||
const uint16_t wid = to_u16_checked(w->widthb);
|
const uint16_t wid = to_u16_checked(w->widthb);
|
||||||
const uint16_t hei = to_u16_checked(w->heightb);
|
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;
|
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) {
|
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 {
|
} else {
|
||||||
// Painting parameters
|
// Painting parameters
|
||||||
const margin_t extents = win_calc_frame_extents(w);
|
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;
|
auto const r = extents.right;
|
||||||
|
|
||||||
#define COMP_BDR(cx, cy, cwid, chei) \
|
#define COMP_BDR(cx, cy, cwid, chei) \
|
||||||
paint_region(ps, w, (cx), (cy), (cwid), (chei), w->frame_opacity * w->opacity, \
|
paint_region(ps, w, (cx), (cy), (cwid), (chei), \
|
||||||
reg_paint, pict)
|
w->frame_opacity *window_opacity, reg_paint, pict)
|
||||||
|
|
||||||
// Sanitize the margins, in case some broken WM makes
|
// Sanitize the margins, in case some broken WM makes
|
||||||
// top_width + bottom_width > height in some cases.
|
// 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
|
// body
|
||||||
paint_region(ps, w, cleft, ctop, body_width, body_height,
|
paint_region(ps, w, cleft, ctop, body_width, body_height,
|
||||||
w->opacity, reg_paint, pict);
|
window_opacity, reg_paint, pict);
|
||||||
} while (0);
|
} while (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -557,7 +559,7 @@ void paint_one(session_t *ps, struct managed_win *w, const region_t *reg_paint)
|
||||||
if (w->dim) {
|
if (w->dim) {
|
||||||
double dim_opacity = ps->o.inactive_dim;
|
double dim_opacity = ps->o.inactive_dim;
|
||||||
if (!ps->o.inactive_dim_fixed) {
|
if (!ps->o.inactive_dim_fixed) {
|
||||||
dim_opacity *= w->opacity;
|
dim_opacity *= window_opacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (ps->o.backend) {
|
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 wid = to_u16_checked(w->widthb);
|
||||||
auto const hei = to_u16_checked(w->heightb);
|
auto const hei = to_u16_checked(w->heightb);
|
||||||
const int cr = w ? w->corner_radius : 0;
|
const int cr = w ? w->corner_radius : 0;
|
||||||
|
const double window_opacity = animatable_get(&w->opacity);
|
||||||
|
|
||||||
double factor_center = 1.0;
|
double factor_center = 1.0;
|
||||||
// Adjust blur strength according to window opacity, to make it appear
|
// Adjust blur strength according to window opacity, to make it appear
|
||||||
// better during fading
|
// better during fading
|
||||||
if (!ps->o.blur_background_fixed) {
|
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);
|
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
|
// 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) {
|
if (w->clip_shadow_above) {
|
||||||
// Add window bounds to shadow-clip region
|
// Add window bounds to shadow-clip region
|
||||||
pixman_region32_union(®_shadow_clip, ®_shadow_clip,
|
pixman_region32_union(®_shadow_clip, ®_shadow_clip,
|
||||||
|
|
89
src/win.c
89
src/win.c
|
@ -27,6 +27,7 @@
|
||||||
#include "region.h"
|
#include "region.h"
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
#include "string_utils.h"
|
#include "string_utils.h"
|
||||||
|
#include "transition.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "uthash_extra.h"
|
#include "uthash_extra.h"
|
||||||
#include "utils.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) {
|
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;
|
return WMODE_TRANS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -846,7 +847,7 @@ winmode_t win_calc_mode(const struct managed_win *w) {
|
||||||
*
|
*
|
||||||
* @return target opacity
|
* @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;
|
double opacity = 1;
|
||||||
|
|
||||||
if (w->state == WSTATE_UNMAPPED) {
|
if (w->state == WSTATE_UNMAPPED) {
|
||||||
|
@ -882,6 +883,21 @@ double win_calc_opacity_target(session_t *ps, const struct managed_win *w) {
|
||||||
return opacity;
|
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.
|
* 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,
|
.cache_leader = XCB_NONE,
|
||||||
.window_type = WINTYPE_UNKNOWN,
|
.window_type = WINTYPE_UNKNOWN,
|
||||||
.focused = false,
|
.focused = false,
|
||||||
.opacity = 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,
|
||||||
|
@ -1685,6 +1699,8 @@ struct win *attr_ret_nonnull maybe_allocate_managed_win(session_t *ps, struct wi
|
||||||
new->base = *w;
|
new->base = *w;
|
||||||
new->base.managed = true;
|
new->base.managed = true;
|
||||||
new->a = *a;
|
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);
|
pixman_region32_init(&new->bounding_shape);
|
||||||
|
|
||||||
free(a);
|
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->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);
|
auto duration = win_start_fade(ps, w);
|
||||||
w->opacity_target = win_calc_opacity_target(ps, w);
|
animatable_set_target(&w->blur_opacity, 0, duration);
|
||||||
|
|
||||||
#ifdef CONFIG_DBUS
|
#ifdef CONFIG_DBUS
|
||||||
// Send D-Bus signal
|
// 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
|
* @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) {
|
if (w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED) {
|
||||||
// No fading in progress
|
// No fading in progress
|
||||||
assert(w->opacity_target == w->opacity);
|
assert(!animatable_is_animating(&w->opacity));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (w->opacity == w->opacity_target) {
|
if (!animatable_is_animating(&w->opacity)) {
|
||||||
switch (w->state) {
|
switch (w->state) {
|
||||||
case WSTATE_UNMAPPING: unmap_win_finish(ps, w); return false;
|
case WSTATE_UNMAPPING: unmap_win_finish(ps, w); return false;
|
||||||
case WSTATE_DESTROYING: destroy_win_finish(ps, &w->base); return true;
|
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
|
/// @return whether the window is destroyed and freed
|
||||||
bool win_skip_fading(session_t *ps, struct managed_win *w) {
|
bool win_skip_fading(session_t *ps, struct managed_win *w) {
|
||||||
if (w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED) {
|
if (w->state == WSTATE_MAPPED || w->state == WSTATE_UNMAPPED) {
|
||||||
assert(w->opacity_target == w->opacity);
|
assert(!animatable_is_animating(&w->opacity));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
log_debug("Skipping fading process of window %#010x (%s)", w->base.id, w->name);
|
log_debug("Skipping fading process of window %#010x (%s)", w->base.id, w->name);
|
||||||
w->opacity = w->opacity_target;
|
animatable_early_stop(&w->opacity);
|
||||||
return win_check_fade_finished(ps, w);
|
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
|
// 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
|
// 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;
|
auto duration = win_start_fade(ps, w);
|
||||||
w->opacity_target = win_calc_opacity_target(ps, w);
|
animatable_set_target(&w->blur_opacity, 1, duration);
|
||||||
|
|
||||||
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_target);
|
animatable_get(&w->opacity), w->opacity.target);
|
||||||
|
|
||||||
// Cannot set w->ever_damaged = false here, since window mapping could be
|
// Cannot set w->ever_damaged = false here, since window mapping could be
|
||||||
// delayed, so a damage event might have already arrived before this
|
// 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.
|
* Update target window opacity depending on the current state.
|
||||||
*/
|
*/
|
||||||
void win_update_opacity_target(session_t *ps, struct managed_win *w) {
|
void win_update_opacity_target(session_t *ps, struct managed_win *w) {
|
||||||
auto opacity_target_old = w->opacity_target;
|
auto duration = win_start_fade(ps, w);
|
||||||
w->opacity_target = win_calc_opacity_target(ps, w);
|
|
||||||
|
|
||||||
if (opacity_target_old == w->opacity_target) {
|
if (!animatable_is_animating(&w->opacity)) {
|
||||||
return;
|
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) {
|
if (w->state == WSTATE_MAPPED) {
|
||||||
// Opacity target changed while MAPPED. Transition to FADING.
|
// 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;
|
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) {
|
} else if (w->state == WSTATE_MAPPING) {
|
||||||
// Opacity target changed while fading in.
|
// Opacity target changed while fading in, keep the blur_opacity
|
||||||
if (w->opacity >= w->opacity_target) {
|
// in lock step with the opacity
|
||||||
// Already reached new target opacity. Transition to
|
animatable_set_target(&w->blur_opacity, w->blur_opacity.target, duration);
|
||||||
// FADING.
|
log_debug("Opacity changed while fading in");
|
||||||
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) {
|
} else if (w->state == WSTATE_FADING) {
|
||||||
// Opacity target changed while FADING.
|
// Opacity target changed while FADING.
|
||||||
if ((w->opacity < opacity_target_old && w->opacity > w->opacity_target) ||
|
log_debug("Opacity changed while already fading");
|
||||||
(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) {
|
if (!ps->redirected) {
|
||||||
|
|
29
src/win.h
29
src/win.h
|
@ -16,6 +16,7 @@
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "region.h"
|
#include "region.h"
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
|
#include "transition.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "win_defs.h"
|
#include "win_defs.h"
|
||||||
|
@ -204,12 +205,12 @@ struct managed_win {
|
||||||
bool is_ewmh_focused;
|
bool is_ewmh_focused;
|
||||||
|
|
||||||
// Opacity-related members
|
// Opacity-related members
|
||||||
/// Current window opacity.
|
/// Window opacity
|
||||||
double opacity;
|
struct animatable opacity;
|
||||||
/// Target window opacity.
|
/// Opacity of the window's background blur
|
||||||
double opacity_target;
|
/// Used to gracefully fade in/out the window, otherwise the blur
|
||||||
/// Previous window opacity.
|
/// would be at full/zero intensity immediately which will be jarring.
|
||||||
double opacity_target_old;
|
struct animatable blur_opacity;
|
||||||
/// 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_WINDOW_OPACITY value) has opacity
|
/// not transferring client window's _NET_WM_WINDOW_OPACITY value) has opacity
|
||||||
/// prop
|
/// 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_on_factor_change(session_t *ps, struct managed_win *w);
|
||||||
void win_unmark_client(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);
|
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);
|
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.
|
* 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
|
// Stop receiving events (except ConfigureNotify, XXX why?) from a window
|
||||||
void win_ev_stop(session_t *ps, const struct win *w);
|
void win_ev_stop(session_t *ps, const struct win *w);
|
||||||
|
|
Loading…
Reference in a new issue