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:
parent
0615ba07ef
commit
cebeb38c1c
9 changed files with 82 additions and 7 deletions
23
src/region.h
23
src/region.h
|
@ -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.
|
||||
///
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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},
|
||||
};
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue