1
0
Fork 0
mirror of https://github.com/yshui/picom.git synced 2024-11-11 13:51:02 -05:00

win: make window and shadow scales animatable

Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
Yuxuan Shui 2024-05-16 19:38:04 +01:00
parent 0615ba07ef
commit cebeb38c1c
No known key found for this signature in database
GPG key ID: D3A4405BE6CC17F4
9 changed files with 82 additions and 7 deletions

View file

@ -154,6 +154,29 @@ static inline void region_intersect(region_t *region, ivec2 origin, const region
pixman_region32_translate(region, origin.x, origin.y);
}
/// Scale the `region` by `scale`. The origin of scaling is `origin`.
static inline void region_scale(region_t *region, ivec2 origin, vec2 scale) {
static const vec2 SCALE_IDENTITY = {.x = 1.0, .y = 1.0};
if (vec2_eq(scale, SCALE_IDENTITY)) {
return;
}
int n;
region_t tmp = *region;
auto r = pixman_region32_rectangles(&tmp, &n);
for (int i = 0; i < n; i++) {
r[i].x1 = (int32_t)((r[i].x1 - origin.x) * scale.x + origin.x);
r[i].y1 = (int32_t)((r[i].y1 - origin.y) * scale.y + origin.y);
r[i].x2 = (int32_t)((r[i].x2 - origin.x) * scale.x + origin.x);
r[i].y2 = (int32_t)((r[i].y2 - origin.y) * scale.y + origin.y);
}
// Manipulating the rectangles could break assumptions made internally by pixman,
// so we recreate the region with the rectangles to let pixman fix them.
pixman_region32_init_rects(region, r, n);
pixman_region32_fini(&tmp);
}
/// Calculate the symmetric difference of `region1`, and `region2`, and union the result
/// into `result`. The two input regions has to be in the same coordinate space.
///

View file

@ -32,7 +32,6 @@ commands_for_window_body(struct layer *layer, struct backend_command *cmd,
border_width = min3(w->frame_extents.left, w->frame_extents.right,
w->frame_extents.bottom);
}
ivec2 raw_size = {.width = w->widthb, .height = w->heightb};
pixman_region32_copy(&cmd->target_mask, &w->bounding_shape);
pixman_region32_translate(&cmd->target_mask, layer->window.origin.x,
layer->window.origin.y);
@ -50,6 +49,8 @@ commands_for_window_body(struct layer *layer, struct backend_command *cmd,
if (w->corner_radius > 0) {
win_region_remove_corners(w, layer->window.origin, &cmd->opaque_region);
}
region_scale(&cmd->target_mask, layer->window.origin, layer->scale);
region_scale(&cmd->opaque_region, layer->window.origin, layer->scale);
cmd->op = BACKEND_COMMAND_BLIT;
cmd->source = BACKEND_COMMAND_SOURCE_WINDOW;
cmd->origin = layer->window.origin;
@ -59,8 +60,8 @@ commands_for_window_body(struct layer *layer, struct backend_command *cmd,
.corner_radius = w->corner_radius,
.opacity = layer->opacity,
.dim = dim,
.scale = SCALE_IDENTITY,
.effective_size = raw_size,
.scale = layer->scale,
.effective_size = layer->window.size,
.shader = w->fg_shader ? w->fg_shader->backend_shader : NULL,
.color_inverted = w->invert_color,
.source_mask = NULL,
@ -72,6 +73,7 @@ commands_for_window_body(struct layer *layer, struct backend_command *cmd,
cmd -= 1;
pixman_region32_copy(&cmd->target_mask, frame_region);
region_scale(&cmd->target_mask, cmd->origin, layer->scale);
pixman_region32_init(&cmd->opaque_region);
cmd->op = BACKEND_COMMAND_BLIT;
cmd->origin = layer->window.origin;
@ -137,11 +139,12 @@ command_for_shadow(struct layer *layer, struct backend_command *cmd,
cmd->source_mask.origin =
ivec2_sub(layer->window.origin, layer->shadow.origin);
}
cmd->blit = (struct backend_blit_args){
.opacity = layer->shadow_opacity,
.max_brightness = 1,
.source_mask = w->corner_radius > 0 ? &cmd->source_mask : NULL,
.scale = SCALE_IDENTITY,
.scale = layer->shadow_scale,
.effective_size = layer->shadow.size,
.target_mask = &cmd->target_mask,
};
@ -166,6 +169,7 @@ command_for_blur(struct layer *layer, struct backend_command *cmd,
} else {
return 0;
}
region_scale(&cmd->target_mask, layer->window.origin, layer->scale);
cmd->op = BACKEND_COMMAND_BLUR;
cmd->origin = (ivec2){};
if (w->corner_radius > 0) {

View file

@ -22,6 +22,13 @@ layer_compare(const struct layer *past_layer, const struct backend_command *past
return false;
}
// TODO(yshui) consider window body and shadow separately.
if (!vec2_eq(past_layer->scale, curr_layer->scale) ||
!vec2_eq(past_layer->shadow_scale, curr_layer->shadow_scale)) {
// Window or shadow scale changed
return false;
}
if (!ibox_eq(past_layer->shadow, curr_layer->shadow)) {
// Shadow moved or size changed
return false;
@ -93,6 +100,7 @@ command_blit_damage(region_t *damage, region_t *scratch_region, struct backend_c
if (cmd1->source == BACKEND_COMMAND_SOURCE_WINDOW) {
layout_manager_collect_window_damage(lm, layer_index, buffer_age,
scratch_region);
region_scale(scratch_region, cmd2->origin, cmd2->blit.scale);
pixman_region32_intersect(scratch_region, scratch_region, &cmd1->target_mask);
pixman_region32_intersect(scratch_region, scratch_region, &cmd2->target_mask);
pixman_region32_union(damage, damage, scratch_region);

View file

@ -42,21 +42,32 @@ static bool layer_from_window(struct layer *out_layer, struct managed_win *w, iv
goto out;
}
out_layer->scale = (vec2){
.x = win_animatable_get(w, WIN_SCRIPT_SCALE_X),
.y = win_animatable_get(w, WIN_SCRIPT_SCALE_Y),
};
out_layer->window.origin =
vec2_as((vec2){.x = w->g.x + win_animatable_get(w, WIN_SCRIPT_OFFSET_X),
.y = w->g.y + win_animatable_get(w, WIN_SCRIPT_OFFSET_Y)});
out_layer->window.size = (ivec2){.width = w->widthb, .height = w->heightb};
out_layer->window.size = vec2_as((vec2){.width = w->widthb * out_layer->scale.x,
.height = w->heightb * out_layer->scale.y});
if (w->shadow) {
out_layer->shadow_scale = (vec2){
.x = win_animatable_get(w, WIN_SCRIPT_SHADOW_SCALE_X),
.y = win_animatable_get(w, WIN_SCRIPT_SHADOW_SCALE_Y),
};
out_layer->shadow.origin =
vec2_as((vec2){.x = w->g.x + w->shadow_dx +
win_animatable_get(w, WIN_SCRIPT_SHADOW_OFFSET_X),
.y = w->g.y + w->shadow_dy +
win_animatable_get(w, WIN_SCRIPT_SHADOW_OFFSET_Y)});
out_layer->shadow.size =
(ivec2){.width = w->shadow_width, .height = w->shadow_height};
vec2_as((vec2){.width = w->shadow_width * out_layer->shadow_scale.x,
.height = w->shadow_height * out_layer->shadow_scale.y});
} else {
out_layer->shadow.origin = (ivec2){};
out_layer->shadow.size = (ivec2){};
out_layer->shadow_scale = SCALE_IDENTITY;
}
struct ibox screen = {.origin = {0, 0}, .size = size};

View file

@ -33,6 +33,12 @@ struct layer {
struct ibox window;
/// Shadow rectangle in screen coordinates.
struct ibox shadow;
/// Scale of the window. The origin of scaling is the top left corner of the
/// window.
vec2 scale;
/// Scale of the shadow. The origin of scaling is the top left corner of the
/// shadow.
vec2 shadow_scale;
/// Opacity of this window
float opacity;
/// Opacity of the background blur of this window

View file

@ -97,6 +97,13 @@ static inline bool vec2_eq(vec2 a, vec2 b) {
return a.x == b.x && a.y == b.y;
}
static inline vec2 vec2_scale(vec2 a, vec2 scale) {
return (vec2){
.x = a.x * scale.x,
.y = a.y * scale.y,
};
}
/// Check if two boxes have a non-zero intersection area.
static inline bool ibox_overlap(struct ibox a, struct ibox b) {
if (a.size.width <= 0 || a.size.height <= 0 || b.size.width <= 0 || b.size.height <= 0) {

View file

@ -2213,6 +2213,10 @@ double win_animatable_get(const struct managed_win *w, enum win_script_output ou
case WIN_SCRIPT_OFFSET_Y:
case WIN_SCRIPT_SHADOW_OFFSET_X:
case WIN_SCRIPT_SHADOW_OFFSET_Y: return 0;
case WIN_SCRIPT_SCALE_X:
case WIN_SCRIPT_SCALE_Y:
case WIN_SCRIPT_SHADOW_SCALE_X:
case WIN_SCRIPT_SHADOW_SCALE_Y: return 1;
}
unreachable();
}

View file

@ -336,6 +336,10 @@ static const struct script_output_info win_script_outputs[] = {
[WIN_SCRIPT_OPACITY] = {"opacity"},
[WIN_SCRIPT_BLUR_OPACITY] = {"blur-opacity"},
[WIN_SCRIPT_SHADOW_OPACITY] = {"shadow-opacity"},
[WIN_SCRIPT_SCALE_X] = {"scale-x"},
[WIN_SCRIPT_SCALE_Y] = {"scale-y"},
[WIN_SCRIPT_SHADOW_SCALE_X] = {"shadow-scale-x"},
[WIN_SCRIPT_SHADOW_SCALE_Y] = {"shadow-scale-y"},
[NUM_OF_WIN_SCRIPT_OUTPUTS] = {NULL},
};

View file

@ -82,5 +82,13 @@ enum win_script_output {
WIN_SCRIPT_BLUR_OPACITY,
/// Opacity of the shadow.
WIN_SCRIPT_SHADOW_OPACITY,
/// Horizontal scale
WIN_SCRIPT_SCALE_X,
/// Vertical scale
WIN_SCRIPT_SCALE_Y,
/// Horizontal scale of the shadow
WIN_SCRIPT_SHADOW_SCALE_X,
/// Vertical scale of the shadow
WIN_SCRIPT_SHADOW_SCALE_Y,
};
#define NUM_OF_WIN_SCRIPT_OUTPUTS (WIN_SCRIPT_SHADOW_OPACITY + 1)
#define NUM_OF_WIN_SCRIPT_OUTPUTS (WIN_SCRIPT_SHADOW_SCALE_Y + 1)