Archived
project: optimize project struct
This commit is contained in:
1 parent
44adbc3b4b
commit
f67a7a1c8b
4 files changed
+1671
-1660
No files matched your search
@@ -0,0 +1,1000 @@
|
||||
void client_actual_size(Client *c, unsigned int *width, unsigned int *height) {
|
||||
*width = c->animation.current.width - c->bw;
|
||||
|
||||
*height = c->animation.current.height - c->bw;
|
||||
}
|
||||
|
||||
void set_rect_size(struct wlr_scene_rect *rect, int width, int height) {
|
||||
wlr_scene_rect_set_size(rect, GEZERO(width), GEZERO(height));
|
||||
}
|
||||
|
||||
void apply_opacity_to_rect_nodes(Client *c, struct wlr_scene_node *node,
|
||||
double animation_passed) {
|
||||
if (node->type == WLR_SCENE_NODE_RECT) {
|
||||
struct wlr_scene_rect *rect = wlr_scene_rect_from_node(node);
|
||||
// Assuming the rect has a color field and we can modify it
|
||||
rect->color[0] = 0;
|
||||
rect->color[1] = 0;
|
||||
rect->color[2] = 0;
|
||||
rect->color[3] = 0;
|
||||
wlr_scene_rect_set_color(rect, rect->color);
|
||||
}
|
||||
|
||||
// If the node is a tree, recursively traverse its children
|
||||
if (node->type == WLR_SCENE_NODE_TREE) {
|
||||
struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
|
||||
struct wlr_scene_node *child;
|
||||
wl_list_for_each(child, &scene_tree->children, link) {
|
||||
apply_opacity_to_rect_nodes(c, child, animation_passed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum corner_location set_client_corner_location(Client *c) {
|
||||
enum corner_location current_corner_location = CORNER_LOCATION_ALL;
|
||||
struct wlr_box target_geom = animations ? c->animation.current : c->geom;
|
||||
if (target_geom.x + border_radius <= c->mon->m.x) {
|
||||
current_corner_location &= ~CORNER_LOCATION_LEFT; // 清除左标志位
|
||||
}
|
||||
if (target_geom.x + target_geom.width - border_radius >=
|
||||
c->mon->m.x + c->mon->m.width) {
|
||||
current_corner_location &= ~CORNER_LOCATION_RIGHT; // 清除右标志位
|
||||
}
|
||||
if (target_geom.y + border_radius <= c->mon->m.y) {
|
||||
current_corner_location &= ~CORNER_LOCATION_TOP; // 清除上标志位
|
||||
}
|
||||
if (target_geom.y + target_geom.height - border_radius >=
|
||||
c->mon->m.y + c->mon->m.height) {
|
||||
current_corner_location &= ~CORNER_LOCATION_BOTTOM; // 清除下标志位
|
||||
}
|
||||
return current_corner_location;
|
||||
}
|
||||
|
||||
int is_special_animaiton_rule(Client *c) {
|
||||
int visible_client_number = 0;
|
||||
Client *count_c;
|
||||
wl_list_for_each(count_c, &clients, link) {
|
||||
if (count_c && VISIBLEON(count_c, selmon) && !count_c->isminied &&
|
||||
!count_c->iskilling && !count_c->isfloating) {
|
||||
visible_client_number++;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_scroller_layout(selmon) && !c->isfloating) {
|
||||
return DOWN;
|
||||
} else if (visible_client_number < 2 && !c->isfloating) {
|
||||
return DOWN;
|
||||
} else if (visible_client_number == 2 && !c->isfloating && !new_is_master) {
|
||||
return RIGHT;
|
||||
} else if (!c->isfloating && new_is_master) {
|
||||
return LEFT;
|
||||
} else {
|
||||
return UNDIR;
|
||||
}
|
||||
}
|
||||
|
||||
void set_client_open_animaiton(Client *c, struct wlr_box geo) {
|
||||
int slide_direction;
|
||||
int horizontal, horizontal_value;
|
||||
int vertical, vertical_value;
|
||||
int special_direction;
|
||||
int center_x, center_y;
|
||||
if ((!c->animation_type_open && strcmp(animation_type_open, "zoom") == 0) ||
|
||||
(c->animation_type_open &&
|
||||
strcmp(c->animation_type_open, "zoom") == 0)) {
|
||||
c->animainit_geom.width = geo.width * zoom_initial_ratio;
|
||||
c->animainit_geom.height = geo.height * zoom_initial_ratio;
|
||||
c->animainit_geom.x = geo.x + (geo.width - c->animainit_geom.width) / 2;
|
||||
c->animainit_geom.y =
|
||||
geo.y + (geo.height - c->animainit_geom.height) / 2;
|
||||
return;
|
||||
} else {
|
||||
special_direction = is_special_animaiton_rule(c);
|
||||
center_x = c->geom.x + c->geom.width / 2;
|
||||
center_y = c->geom.y + c->geom.height / 2;
|
||||
if (special_direction == UNDIR) {
|
||||
horizontal = c->mon->w.x + c->mon->w.width - center_x <
|
||||
center_x - c->mon->w.x
|
||||
? RIGHT
|
||||
: LEFT;
|
||||
horizontal_value = horizontal == LEFT
|
||||
? center_x - c->mon->w.x
|
||||
: c->mon->w.x + c->mon->w.width - center_x;
|
||||
vertical = c->mon->w.y + c->mon->w.height - center_y <
|
||||
center_y - c->mon->w.y
|
||||
? DOWN
|
||||
: UP;
|
||||
vertical_value = vertical == UP
|
||||
? center_y - c->mon->w.y
|
||||
: c->mon->w.y + c->mon->w.height - center_y;
|
||||
slide_direction =
|
||||
horizontal_value < vertical_value ? horizontal : vertical;
|
||||
} else {
|
||||
slide_direction = special_direction;
|
||||
}
|
||||
c->animainit_geom.width = c->geom.width;
|
||||
c->animainit_geom.height = c->geom.height;
|
||||
switch (slide_direction) {
|
||||
case UP:
|
||||
c->animainit_geom.x = c->geom.x;
|
||||
c->animainit_geom.y = c->mon->m.y - c->geom.height;
|
||||
break;
|
||||
case DOWN:
|
||||
c->animainit_geom.x = c->geom.x;
|
||||
c->animainit_geom.y =
|
||||
c->geom.y + c->mon->m.height - (c->geom.y - c->mon->m.y);
|
||||
break;
|
||||
case LEFT:
|
||||
c->animainit_geom.x = c->mon->m.x - c->geom.width;
|
||||
c->animainit_geom.y = c->geom.y;
|
||||
break;
|
||||
case RIGHT:
|
||||
c->animainit_geom.x =
|
||||
c->geom.x + c->mon->m.width - (c->geom.x - c->mon->m.x);
|
||||
c->animainit_geom.y = c->geom.y;
|
||||
break;
|
||||
default:
|
||||
c->animainit_geom.x = c->geom.x;
|
||||
c->animainit_geom.y = 0 - c->geom.height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void snap_scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int sx,
|
||||
int sy, void *data) {
|
||||
animationScale *scale_data = (animationScale *)data;
|
||||
wlr_scene_buffer_set_dest_size(buffer, scale_data->width,
|
||||
scale_data->height);
|
||||
}
|
||||
|
||||
void scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int sx, int sy,
|
||||
void *data) {
|
||||
animationScale *scale_data = (animationScale *)data;
|
||||
|
||||
if (scale_data->should_scale && scale_data->height_scale < 1 &&
|
||||
scale_data->width_scale < 1) {
|
||||
scale_data->should_scale = false;
|
||||
}
|
||||
|
||||
if (scale_data->should_scale && scale_data->height_scale == 1 &&
|
||||
scale_data->width_scale < 1) {
|
||||
scale_data->should_scale = false;
|
||||
}
|
||||
|
||||
if (scale_data->should_scale && scale_data->height_scale < 1 &&
|
||||
scale_data->width_scale == 1) {
|
||||
scale_data->should_scale = false;
|
||||
}
|
||||
|
||||
struct wlr_scene_surface *scene_surface =
|
||||
wlr_scene_surface_try_from_buffer(buffer);
|
||||
|
||||
if (scene_surface == NULL)
|
||||
return;
|
||||
|
||||
struct wlr_surface *surface = scene_surface->surface;
|
||||
|
||||
if (scale_data->should_scale) {
|
||||
|
||||
unsigned int surface_width = surface->current.width;
|
||||
unsigned int surface_height = surface->current.height;
|
||||
|
||||
surface_width = scale_data->width_scale < 1
|
||||
? surface_width
|
||||
: scale_data->width_scale * surface_width;
|
||||
surface_height = scale_data->height_scale < 1
|
||||
? surface_height
|
||||
: scale_data->height_scale * surface_height;
|
||||
|
||||
if (surface_width > scale_data->width &&
|
||||
wlr_subsurface_try_from_wlr_surface(surface) == NULL) {
|
||||
surface_width = scale_data->width;
|
||||
}
|
||||
|
||||
if (surface_height > scale_data->height &&
|
||||
wlr_subsurface_try_from_wlr_surface(surface) == NULL) {
|
||||
surface_height = scale_data->height;
|
||||
}
|
||||
|
||||
if (surface_width > scale_data->width &&
|
||||
wlr_subsurface_try_from_wlr_surface(surface) != NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (surface_height > scale_data->height &&
|
||||
wlr_subsurface_try_from_wlr_surface(surface) != NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (surface_height > 0 && surface_width > 0) {
|
||||
wlr_scene_buffer_set_dest_size(buffer, surface_width,
|
||||
surface_height);
|
||||
}
|
||||
}
|
||||
// TODO: blur set, opacity set
|
||||
|
||||
if (wlr_xdg_popup_try_from_wlr_surface(surface) != NULL)
|
||||
return;
|
||||
|
||||
wlr_scene_buffer_set_corner_radius(buffer, border_radius,
|
||||
scale_data->corner_location);
|
||||
|
||||
float target_opacity = scale_data->percent + fadein_begin_opacity;
|
||||
if (target_opacity > scale_data->opacity) {
|
||||
target_opacity = scale_data->opacity;
|
||||
}
|
||||
wlr_scene_buffer_set_opacity(buffer, target_opacity);
|
||||
}
|
||||
|
||||
void buffer_set_effect(Client *c, animationScale data) {
|
||||
|
||||
if (!c || c->iskilling)
|
||||
return;
|
||||
|
||||
if (c->animation.tagouting || c->animation.tagouted ||
|
||||
c->animation.tagining) {
|
||||
data.should_scale = false;
|
||||
}
|
||||
|
||||
if (c == grabc)
|
||||
data.should_scale = false;
|
||||
|
||||
if (c->isfullscreen ||
|
||||
(no_radius_when_single && c->mon && c->mon->visible_clients == 1)) {
|
||||
data.corner_location = CORNER_LOCATION_NONE;
|
||||
}
|
||||
|
||||
wlr_scene_node_for_each_buffer(&c->scene_surface->node,
|
||||
scene_buffer_apply_effect, &data);
|
||||
}
|
||||
|
||||
void client_draw_shadow(Client *c) {
|
||||
|
||||
if (c->iskilling || !client_surface(c)->mapped)
|
||||
return;
|
||||
|
||||
if (!shadows || (!c->isfloating && shadow_only_floating)) {
|
||||
wlr_scene_shadow_set_size(c->shadow, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t width, height;
|
||||
client_actual_size(c, &width, &height);
|
||||
|
||||
uint32_t delta = shadows_size + c->bw;
|
||||
|
||||
/* we calculate where to clip the shadow */
|
||||
struct wlr_box client_box = {
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = width,
|
||||
.height = height,
|
||||
};
|
||||
|
||||
struct wlr_box shadow_box = {
|
||||
.x = shadows_position_x,
|
||||
.y = shadows_position_y,
|
||||
.width = width + 2 * delta,
|
||||
.height = height + 2 * delta,
|
||||
};
|
||||
|
||||
struct wlr_box intersection_box;
|
||||
wlr_box_intersection(&intersection_box, &client_box, &shadow_box);
|
||||
/* clipped region takes shadow relative coords, so we translate everything
|
||||
* by its position */
|
||||
intersection_box.x -= shadows_position_x;
|
||||
intersection_box.y -= shadows_position_y;
|
||||
|
||||
struct clipped_region clipped_region = {
|
||||
.area = intersection_box,
|
||||
.corner_radius = border_radius,
|
||||
.corners = border_radius_location_default,
|
||||
};
|
||||
|
||||
struct wlr_box absolute_shadow_box = {
|
||||
.x = shadow_box.x + c->animation.current.x,
|
||||
.y = shadow_box.y + c->animation.current.y,
|
||||
.width = shadow_box.width,
|
||||
.height = shadow_box.height,
|
||||
};
|
||||
|
||||
int right_offset, bottom_offset, left_offset, top_offset;
|
||||
|
||||
if (c == grabc) {
|
||||
right_offset = 0;
|
||||
bottom_offset = 0;
|
||||
left_offset = 0;
|
||||
top_offset = 0;
|
||||
} else {
|
||||
right_offset =
|
||||
GEZERO(absolute_shadow_box.x + absolute_shadow_box.width -
|
||||
c->mon->m.x - c->mon->m.width);
|
||||
bottom_offset =
|
||||
GEZERO(absolute_shadow_box.y + absolute_shadow_box.height -
|
||||
c->mon->m.y - c->mon->m.height);
|
||||
|
||||
left_offset = GEZERO(c->mon->m.x - absolute_shadow_box.x);
|
||||
top_offset = GEZERO(c->mon->m.y - absolute_shadow_box.y);
|
||||
}
|
||||
|
||||
left_offset = MIN(left_offset, shadow_box.width);
|
||||
right_offset = MIN(right_offset, shadow_box.width);
|
||||
top_offset = MIN(top_offset, shadow_box.height);
|
||||
bottom_offset = MIN(bottom_offset, shadow_box.height);
|
||||
|
||||
wlr_scene_node_set_position(&c->shadow->node, shadow_box.x + left_offset,
|
||||
shadow_box.y + top_offset);
|
||||
|
||||
wlr_scene_shadow_set_size(
|
||||
c->shadow, GEZERO(shadow_box.width - left_offset - right_offset),
|
||||
GEZERO(shadow_box.height - top_offset - bottom_offset));
|
||||
wlr_scene_shadow_set_clipped_region(c->shadow, clipped_region);
|
||||
}
|
||||
|
||||
void apply_border(Client *c) {
|
||||
if (!c || c->iskilling || !client_surface(c)->mapped)
|
||||
return;
|
||||
|
||||
bool hit_no_border = check_hit_no_border(c);
|
||||
enum corner_location current_corner_location =
|
||||
c->isfullscreen || (no_radius_when_single && c->mon &&
|
||||
c->mon->visible_clients == 1)
|
||||
? CORNER_LOCATION_NONE
|
||||
: CORNER_LOCATION_ALL;
|
||||
|
||||
// Handle no-border cases
|
||||
if (hit_no_border && smartgaps) {
|
||||
c->bw = 0;
|
||||
c->fake_no_border = true;
|
||||
} else if (hit_no_border && !smartgaps) {
|
||||
wlr_scene_rect_set_size(c->border, 0, 0);
|
||||
wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw);
|
||||
c->fake_no_border = true;
|
||||
return;
|
||||
} else if (!c->isfullscreen && VISIBLEON(c, c->mon)) {
|
||||
c->bw = c->isnoborder ? 0 : borderpx;
|
||||
c->fake_no_border = false;
|
||||
}
|
||||
|
||||
struct wlr_box clip_box = c->animation.current;
|
||||
// 一但在GEZERO如果使用无符号,那么其他数据也会转换为无符号导致没有负数出错
|
||||
int bw = (int)c->bw;
|
||||
|
||||
int right_offset, bottom_offset, left_offset, top_offset;
|
||||
|
||||
if (c == grabc) {
|
||||
right_offset = 0;
|
||||
bottom_offset = 0;
|
||||
left_offset = 0;
|
||||
top_offset = 0;
|
||||
} else {
|
||||
right_offset =
|
||||
GEZERO(c->animation.current.x + c->animation.current.width -
|
||||
c->mon->m.x - c->mon->m.width);
|
||||
bottom_offset =
|
||||
GEZERO(c->animation.current.y + c->animation.current.height -
|
||||
c->mon->m.y - c->mon->m.height);
|
||||
|
||||
left_offset = GEZERO(c->mon->m.x - c->animation.current.x);
|
||||
top_offset = GEZERO(c->mon->m.y - c->animation.current.y);
|
||||
}
|
||||
|
||||
int inner_surface_width = GEZERO(clip_box.width - 2 * bw);
|
||||
int inner_surface_height = GEZERO(clip_box.height - 2 * bw);
|
||||
|
||||
int inner_surface_x = GEZERO(bw - left_offset);
|
||||
int inner_surface_y = GEZERO(bw - top_offset);
|
||||
|
||||
int rect_x = left_offset;
|
||||
int rect_y = top_offset;
|
||||
|
||||
int rect_width =
|
||||
GEZERO(c->animation.current.width - left_offset - right_offset);
|
||||
int rect_height =
|
||||
GEZERO(c->animation.current.height - top_offset - bottom_offset);
|
||||
|
||||
if (left_offset > c->bw)
|
||||
inner_surface_width = inner_surface_width - left_offset + c->bw;
|
||||
|
||||
if (top_offset > c->bw)
|
||||
inner_surface_height = inner_surface_height - top_offset + c->bw;
|
||||
|
||||
if (right_offset > 0) {
|
||||
inner_surface_width =
|
||||
MIN(clip_box.width, inner_surface_width + right_offset);
|
||||
}
|
||||
|
||||
if (bottom_offset > 0) {
|
||||
inner_surface_height =
|
||||
MIN(clip_box.height, inner_surface_height + bottom_offset);
|
||||
}
|
||||
|
||||
struct clipped_region clipped_region = {
|
||||
.area = {inner_surface_x, inner_surface_y, inner_surface_width,
|
||||
inner_surface_height},
|
||||
.corner_radius = border_radius,
|
||||
.corners = current_corner_location,
|
||||
};
|
||||
|
||||
wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw);
|
||||
wlr_scene_rect_set_size(c->border, rect_width, rect_height);
|
||||
wlr_scene_node_set_position(&c->border->node, rect_x, rect_y);
|
||||
wlr_scene_rect_set_corner_radius(c->border, border_radius,
|
||||
current_corner_location);
|
||||
wlr_scene_rect_set_clipped_region(c->border, clipped_region);
|
||||
}
|
||||
|
||||
struct ivec2 clip_to_hide(Client *c, struct wlr_box *clip_box) {
|
||||
int offsetx = 0, offsety = 0, offsetw = 0, offseth = 0;
|
||||
struct ivec2 offset = {0, 0, 0, 0};
|
||||
|
||||
if (!ISTILED(c) && !c->animation.tagining && !c->animation.tagouted &&
|
||||
!c->animation.tagouting)
|
||||
return offset;
|
||||
|
||||
int bottom_out_offset =
|
||||
GEZERO(c->animation.current.y + c->animation.current.height -
|
||||
c->mon->m.y - c->mon->m.height);
|
||||
int right_out_offset =
|
||||
GEZERO(c->animation.current.x + c->animation.current.width -
|
||||
c->mon->m.x - c->mon->m.width);
|
||||
int left_out_offset = GEZERO(c->mon->m.x - c->animation.current.x);
|
||||
int top_out_offset = GEZERO(c->mon->m.y - c->animation.current.y);
|
||||
|
||||
// 必须转换为int,否计算会没有负数导致判断错误
|
||||
int bw = (int)c->bw;
|
||||
|
||||
/*
|
||||
计算窗口表面超出屏幕四个方向的偏差,避免窗口超出屏幕
|
||||
需要主要border超出屏幕的时候不计算如偏差之内而是
|
||||
要等窗口表面超出才开始计算偏差
|
||||
*/
|
||||
if (ISTILED(c) || c->animation.tagining || c->animation.tagouted ||
|
||||
c->animation.tagouting) {
|
||||
if (left_out_offset > 0) {
|
||||
offsetx = GEZERO(left_out_offset - bw);
|
||||
clip_box->x = clip_box->x + offsetx;
|
||||
clip_box->width = clip_box->width - offsetx;
|
||||
} else if (right_out_offset > 0) {
|
||||
offsetw = GEZERO(right_out_offset - bw);
|
||||
clip_box->width = clip_box->width - offsetw;
|
||||
}
|
||||
|
||||
if (top_out_offset > 0) {
|
||||
offsety = GEZERO(top_out_offset - bw);
|
||||
clip_box->y = clip_box->y + offsety;
|
||||
clip_box->height = clip_box->height - offsety;
|
||||
} else if (bottom_out_offset > 0) {
|
||||
offseth = GEZERO(bottom_out_offset - bw);
|
||||
clip_box->height = clip_box->height - offseth;
|
||||
}
|
||||
}
|
||||
|
||||
// 窗口表面超出屏幕四个方向的偏差
|
||||
offset.x = offsetx;
|
||||
offset.y = offsety;
|
||||
offset.width = offsetw;
|
||||
offset.height = offseth;
|
||||
|
||||
if ((clip_box->width <= 0 || clip_box->height <= 0) &&
|
||||
(ISTILED(c) || c->animation.tagouting || c->animation.tagining)) {
|
||||
c->is_clip_to_hide = true;
|
||||
wlr_scene_node_set_enabled(&c->scene->node, false);
|
||||
} else if (c->is_clip_to_hide && VISIBLEON(c, c->mon)) {
|
||||
c->is_clip_to_hide = false;
|
||||
wlr_scene_node_set_enabled(&c->scene->node, true);
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
void client_apply_clip(Client *c) {
|
||||
|
||||
if (c->iskilling || !client_surface(c)->mapped)
|
||||
return;
|
||||
|
||||
struct wlr_box clip_box;
|
||||
bool should_render_client_surface = false;
|
||||
struct ivec2 offset;
|
||||
animationScale scale_data;
|
||||
|
||||
enum corner_location current_corner_location =
|
||||
set_client_corner_location(c);
|
||||
|
||||
float percent =
|
||||
c->animation.action == OPEN && animation_fade_in && !c->nofadein
|
||||
? (double)c->animation.passed_frames / c->animation.total_frames
|
||||
: 1.0;
|
||||
float opacity = c->isfullscreen ? 1
|
||||
: c == selmon->sel ? c->focused_opacity
|
||||
: c->unfocused_opacity;
|
||||
|
||||
int bw = (int)c->bw;
|
||||
|
||||
if (!animations) {
|
||||
c->animation.running = false;
|
||||
c->need_output_flush = false;
|
||||
c->animainit_geom = c->current = c->pending = c->animation.current =
|
||||
c->geom;
|
||||
|
||||
client_get_clip(c, &clip_box);
|
||||
|
||||
offset = clip_to_hide(c, &clip_box);
|
||||
|
||||
apply_border(c);
|
||||
client_draw_shadow(c);
|
||||
|
||||
scale_data.opacity = c->isfullscreen ? 1
|
||||
: c == selmon->sel ? c->focused_opacity
|
||||
: c->unfocused_opacity;
|
||||
|
||||
if (clip_box.width <= 0 || clip_box.height <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip_box);
|
||||
buffer_set_effect(c, (animationScale){0, 0, 0, 0, opacity, opacity,
|
||||
current_corner_location, false});
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取窗口动画实时位置矩形
|
||||
unsigned int width, height;
|
||||
client_actual_size(c, &width, &height);
|
||||
|
||||
// 计算出除了边框的窗口实际剪切大小
|
||||
struct wlr_box geometry;
|
||||
client_get_geometry(c, &geometry);
|
||||
clip_box = (struct wlr_box){
|
||||
.x = geometry.x,
|
||||
.y = geometry.y,
|
||||
.width = width - bw,
|
||||
.height = height - bw,
|
||||
};
|
||||
|
||||
if (client_is_x11(c)) {
|
||||
clip_box.x = 0;
|
||||
clip_box.y = 0;
|
||||
}
|
||||
|
||||
// 检测窗口是否需要剪切超出屏幕部分,如果需要就调整实际要剪切的矩形
|
||||
offset = clip_to_hide(c, &clip_box);
|
||||
|
||||
// 应用窗口装饰
|
||||
apply_border(c);
|
||||
client_draw_shadow(c);
|
||||
|
||||
// 如果窗口剪切区域已经剪切到0,则不渲染窗口表面
|
||||
if (clip_box.width <= 0 || clip_box.height <= 0) {
|
||||
should_render_client_surface = false;
|
||||
wlr_scene_node_set_enabled(&c->scene_surface->node, false);
|
||||
} else {
|
||||
should_render_client_surface = true;
|
||||
wlr_scene_node_set_enabled(&c->scene_surface->node, true);
|
||||
}
|
||||
|
||||
// 不用在执行下面的窗口表面剪切和缩放等效果操作
|
||||
if (!should_render_client_surface) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 应用窗口表面剪切
|
||||
wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip_box);
|
||||
|
||||
// 获取剪切后的表面的实际大小用于计算缩放
|
||||
int acutal_surface_width = geometry.width - offset.x - offset.width;
|
||||
int acutal_surface_height = geometry.height - offset.y - offset.height;
|
||||
|
||||
if (acutal_surface_width <= 0 || acutal_surface_height <= 0)
|
||||
return;
|
||||
|
||||
scale_data.should_scale = true;
|
||||
scale_data.width = clip_box.width;
|
||||
scale_data.height = clip_box.height;
|
||||
scale_data.width_scale = (float)scale_data.width / acutal_surface_width;
|
||||
scale_data.height_scale = (float)scale_data.height / acutal_surface_height;
|
||||
scale_data.corner_location = current_corner_location;
|
||||
scale_data.percent = percent;
|
||||
scale_data.opacity = opacity;
|
||||
buffer_set_effect(c, scale_data);
|
||||
}
|
||||
|
||||
void fadeout_client_animation_next_tick(Client *c) {
|
||||
if (!c)
|
||||
return;
|
||||
|
||||
animationScale scale_data;
|
||||
|
||||
double animation_passed =
|
||||
(double)c->animation.passed_frames / c->animation.total_frames;
|
||||
int type = c->animation.action = c->animation.action;
|
||||
double factor = find_animation_curve_at(animation_passed, type);
|
||||
unsigned int width =
|
||||
c->animation.initial.width +
|
||||
(c->current.width - c->animation.initial.width) * factor;
|
||||
unsigned int height =
|
||||
c->animation.initial.height +
|
||||
(c->current.height - c->animation.initial.height) * factor;
|
||||
|
||||
unsigned int x = c->animation.initial.x +
|
||||
(c->current.x - c->animation.initial.x) * factor;
|
||||
unsigned int y = c->animation.initial.y +
|
||||
(c->current.y - c->animation.initial.y) * factor;
|
||||
|
||||
wlr_scene_node_set_position(&c->scene->node, x, y);
|
||||
|
||||
c->animation.current = (struct wlr_box){
|
||||
.x = x,
|
||||
.y = y,
|
||||
.width = width,
|
||||
.height = height,
|
||||
};
|
||||
|
||||
double opacity = MAX(fadeout_begin_opacity - animation_passed, 0);
|
||||
|
||||
if (animation_fade_out && !c->nofadeout)
|
||||
wlr_scene_node_for_each_buffer(&c->scene->node,
|
||||
scene_buffer_apply_opacity, &opacity);
|
||||
|
||||
apply_opacity_to_rect_nodes(c, &c->scene->node, animation_passed);
|
||||
|
||||
if ((c->animation_type_close &&
|
||||
strcmp(c->animation_type_close, "zoom") == 0) ||
|
||||
(!c->animation_type_close &&
|
||||
strcmp(animation_type_close, "zoom") == 0)) {
|
||||
|
||||
scale_data.width = width;
|
||||
scale_data.height = height;
|
||||
scale_data.width_scale = animation_passed;
|
||||
scale_data.height_scale = animation_passed;
|
||||
|
||||
wlr_scene_node_for_each_buffer(
|
||||
&c->scene->node, snap_scene_buffer_apply_effect, &scale_data);
|
||||
}
|
||||
|
||||
if (animation_passed == 1.0) {
|
||||
wl_list_remove(&c->fadeout_link);
|
||||
wlr_scene_node_destroy(&c->scene->node);
|
||||
free(c);
|
||||
c = NULL;
|
||||
} else {
|
||||
c->animation.passed_frames++;
|
||||
}
|
||||
}
|
||||
|
||||
void client_animation_next_tick(Client *c) {
|
||||
double animation_passed =
|
||||
(double)c->animation.passed_frames / c->animation.total_frames;
|
||||
|
||||
int type = c->animation.action == NONE ? MOVE : c->animation.action;
|
||||
double factor = find_animation_curve_at(animation_passed, type);
|
||||
|
||||
Client *pointer_c = NULL;
|
||||
double sx = 0, sy = 0;
|
||||
struct wlr_surface *surface = NULL;
|
||||
|
||||
unsigned int width =
|
||||
c->animation.initial.width +
|
||||
(c->current.width - c->animation.initial.width) * factor;
|
||||
unsigned int height =
|
||||
c->animation.initial.height +
|
||||
(c->current.height - c->animation.initial.height) * factor;
|
||||
|
||||
unsigned int x = c->animation.initial.x +
|
||||
(c->current.x - c->animation.initial.x) * factor;
|
||||
unsigned int y = c->animation.initial.y +
|
||||
(c->current.y - c->animation.initial.y) * factor;
|
||||
|
||||
wlr_scene_node_set_position(&c->scene->node, x, y);
|
||||
c->animation.current = (struct wlr_box){
|
||||
.x = x,
|
||||
.y = y,
|
||||
.width = width,
|
||||
.height = height,
|
||||
};
|
||||
|
||||
c->is_open_animation = false;
|
||||
|
||||
if (animation_passed == 1.0) {
|
||||
|
||||
// clear the open action state
|
||||
// To prevent him from being mistaken that
|
||||
// it's still in the opening animation in resize
|
||||
c->animation.action = MOVE;
|
||||
|
||||
c->animation.tagining = false;
|
||||
c->animation.running = false;
|
||||
|
||||
if (c->animation.tagouting) {
|
||||
c->animation.tagouting = false;
|
||||
wlr_scene_node_set_enabled(&c->scene->node, false);
|
||||
client_set_suspended(c, true);
|
||||
c->animation.tagouted = true;
|
||||
c->animation.current = c->geom;
|
||||
}
|
||||
|
||||
xytonode(cursor->x, cursor->y, NULL, &pointer_c, NULL, &sx, &sy);
|
||||
|
||||
surface =
|
||||
pointer_c && pointer_c == c ? client_surface(pointer_c) : NULL;
|
||||
if (surface && pointer_c == selmon->sel) {
|
||||
wlr_seat_pointer_notify_enter(seat, surface, sx, sy);
|
||||
}
|
||||
|
||||
// end flush in next frame, not the current frame
|
||||
c->need_output_flush = false;
|
||||
} else {
|
||||
c->animation.passed_frames++;
|
||||
}
|
||||
}
|
||||
|
||||
void init_fadeout_client(Client *c) {
|
||||
|
||||
if (!c->mon || client_is_unmanaged(c))
|
||||
return;
|
||||
|
||||
if (!c->scene) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (c->animation_type_close &&
|
||||
strcmp(c->animation_type_close, "none") == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Client *fadeout_cient = ecalloc(1, sizeof(*fadeout_cient));
|
||||
|
||||
wlr_scene_node_set_enabled(&c->scene->node, true);
|
||||
client_set_border_color(c, bordercolor);
|
||||
fadeout_cient->scene =
|
||||
wlr_scene_tree_snapshot(&c->scene->node, layers[LyrFadeOut]);
|
||||
wlr_scene_node_set_enabled(&c->scene->node, false);
|
||||
|
||||
if (!fadeout_cient->scene) {
|
||||
free(fadeout_cient);
|
||||
return;
|
||||
}
|
||||
|
||||
fadeout_cient->animation.duration = animation_duration_close;
|
||||
fadeout_cient->geom = fadeout_cient->current =
|
||||
fadeout_cient->animainit_geom = fadeout_cient->animation.initial =
|
||||
c->animation.current;
|
||||
fadeout_cient->mon = c->mon;
|
||||
fadeout_cient->animation_type_close = c->animation_type_close;
|
||||
fadeout_cient->animation.action = CLOSE;
|
||||
fadeout_cient->bw = c->bw;
|
||||
fadeout_cient->nofadeout = c->nofadeout;
|
||||
|
||||
// 这里snap节点的坐标设置是使用的相对坐标,所以不能加上原来坐标
|
||||
// 这跟普通node有区别
|
||||
|
||||
fadeout_cient->animation.initial.x = 0;
|
||||
fadeout_cient->animation.initial.y = 0;
|
||||
if ((c->animation_type_close &&
|
||||
strcmp(c->animation_type_close, "slide") == 0) ||
|
||||
(!c->animation_type_close &&
|
||||
strcmp(animation_type_close, "slide") == 0)) {
|
||||
fadeout_cient->current.y =
|
||||
c->geom.y + c->geom.height / 2 > c->mon->m.y + c->mon->m.height / 2
|
||||
? c->mon->m.height -
|
||||
(c->animation.current.y - c->mon->m.y) // down out
|
||||
: c->mon->m.y - c->geom.height; // up out
|
||||
fadeout_cient->current.x = 0; // x无偏差,垂直划出
|
||||
} else {
|
||||
fadeout_cient->current.y =
|
||||
(fadeout_cient->geom.height -
|
||||
fadeout_cient->geom.height * zoom_initial_ratio) /
|
||||
2;
|
||||
fadeout_cient->current.x =
|
||||
(fadeout_cient->geom.width -
|
||||
fadeout_cient->geom.width * zoom_initial_ratio) /
|
||||
2;
|
||||
fadeout_cient->current.width =
|
||||
fadeout_cient->geom.width * zoom_initial_ratio;
|
||||
fadeout_cient->current.height =
|
||||
fadeout_cient->geom.height * zoom_initial_ratio;
|
||||
}
|
||||
|
||||
fadeout_cient->animation.passed_frames = 0;
|
||||
fadeout_cient->animation.total_frames =
|
||||
fadeout_cient->animation.duration / output_frame_duration_ms();
|
||||
wlr_scene_node_set_enabled(&fadeout_cient->scene->node, true);
|
||||
wl_list_insert(&fadeout_clients, &fadeout_cient->fadeout_link);
|
||||
}
|
||||
|
||||
void client_commit(Client *c) {
|
||||
c->current = c->pending; // 设置动画的结束位置
|
||||
|
||||
if (c->animation.should_animate) {
|
||||
if (!c->animation.running) {
|
||||
c->animation.current = c->animainit_geom;
|
||||
}
|
||||
|
||||
c->animation.initial = c->animainit_geom;
|
||||
// 设置动画速度
|
||||
c->animation.passed_frames = 0;
|
||||
c->animation.total_frames =
|
||||
c->animation.duration / output_frame_duration_ms();
|
||||
|
||||
// 标记动画开始
|
||||
c->animation.running = true;
|
||||
c->animation.should_animate = false;
|
||||
}
|
||||
// 请求刷新屏幕
|
||||
wlr_output_schedule_frame(c->mon->wlr_output);
|
||||
}
|
||||
|
||||
void client_set_pending_state(Client *c) {
|
||||
|
||||
// 判断是否需要动画
|
||||
if (!animations) {
|
||||
c->animation.should_animate = false;
|
||||
} else if (animations && c->animation.tagining) {
|
||||
c->animation.should_animate = true;
|
||||
} else if (!animations || c == grabc ||
|
||||
(!c->is_open_animation &&
|
||||
wlr_box_equal(&c->current, &c->pending))) {
|
||||
c->animation.should_animate = false;
|
||||
} else {
|
||||
c->animation.should_animate = true;
|
||||
}
|
||||
|
||||
// 开始动画
|
||||
client_commit(c);
|
||||
c->dirty = true;
|
||||
}
|
||||
|
||||
void resize(Client *c, struct wlr_box geo, int interact) {
|
||||
|
||||
// 动画设置的起始函数,这里用来计算一些动画的起始值
|
||||
// 动画起始位置大小是由于c->animainit_geom确定的
|
||||
|
||||
if (!c || !c->mon || !client_surface(c)->mapped)
|
||||
return;
|
||||
|
||||
struct wlr_box *bbox;
|
||||
struct wlr_box clip;
|
||||
|
||||
if (!c->mon)
|
||||
return;
|
||||
|
||||
c->need_output_flush = true;
|
||||
|
||||
// oldgeom = c->geom;
|
||||
bbox = (interact || c->isfloating || c->isfullscreen) ? &sgeom : &c->mon->w;
|
||||
|
||||
if (is_scroller_layout(c->mon) && (!c->isfloating || c == grabc)) {
|
||||
c->geom = geo;
|
||||
c->geom.width = MAX(1 + 2 * (int)c->bw, c->geom.width);
|
||||
c->geom.height = MAX(1 + 2 * (int)c->bw, c->geom.height);
|
||||
} else { // 这里会限制不允许窗口划出屏幕
|
||||
client_set_bounds(
|
||||
c, geo.width,
|
||||
geo.height); // 去掉这个推荐的窗口大小,因为有时推荐的窗口特别大导致平铺异常
|
||||
c->geom = geo;
|
||||
applybounds(
|
||||
c,
|
||||
bbox); // 去掉这个推荐的窗口大小,因为有时推荐的窗口特别大导致平铺异常
|
||||
}
|
||||
|
||||
if (!c->is_open_animation) {
|
||||
c->animation.begin_fade_in = false;
|
||||
}
|
||||
|
||||
if (c->animation.action == OPEN && !c->animation.tagining &&
|
||||
!c->animation.tagouting && wlr_box_equal(&c->geom, &c->current)) {
|
||||
c->animation.action = c->animation.action;
|
||||
} else if (c->animation.tagouting) {
|
||||
c->animation.duration = animation_duration_tag;
|
||||
c->animation.action = TAG;
|
||||
} else if (c->animation.tagining) {
|
||||
c->animation.duration = animation_duration_tag;
|
||||
c->animation.action = TAG;
|
||||
} else if (c->is_open_animation) {
|
||||
c->animation.duration = animation_duration_open;
|
||||
c->animation.action = OPEN;
|
||||
} else {
|
||||
c->animation.duration = animation_duration_move;
|
||||
c->animation.action = MOVE;
|
||||
}
|
||||
|
||||
// 动画起始位置大小设置
|
||||
if (c->animation.tagouting) {
|
||||
c->animainit_geom = c->animation.current;
|
||||
} else if (c->animation.tagining) {
|
||||
c->animainit_geom.height = c->animation.current.height;
|
||||
c->animainit_geom.width = c->animation.current.width;
|
||||
} else if (c->is_open_animation) {
|
||||
set_client_open_animaiton(c, c->geom);
|
||||
} else {
|
||||
c->animainit_geom = c->animation.current;
|
||||
}
|
||||
|
||||
if (c->isnoborder || c->iskilling) {
|
||||
c->bw = 0;
|
||||
}
|
||||
|
||||
// c->geom 是真实的窗口大小和位置,跟过度的动画无关,用于计算布局
|
||||
c->configure_serial = client_set_size(c, c->geom.width - 2 * c->bw,
|
||||
c->geom.height - 2 * c->bw);
|
||||
|
||||
if (c == grabc) {
|
||||
c->animation.running = false;
|
||||
c->need_output_flush = false;
|
||||
c->animainit_geom = c->current = c->pending = c->animation.current =
|
||||
c->geom;
|
||||
wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y);
|
||||
|
||||
client_draw_shadow(c);
|
||||
apply_border(c);
|
||||
client_get_clip(c, &clip);
|
||||
wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip);
|
||||
return;
|
||||
}
|
||||
// 如果不是工作区切换时划出去的窗口,就让动画的结束位置,就是上面的真实位置和大小
|
||||
// c->pending 决定动画的终点,一般在其他调用resize的函数的附近设置了
|
||||
if (!c->animation.tagouting && !c->iskilling) {
|
||||
c->pending = c->geom;
|
||||
}
|
||||
|
||||
if (c->swallowedby && c->animation.action == OPEN) {
|
||||
c->animainit_geom = c->swallowedby->animation.current;
|
||||
}
|
||||
|
||||
if (c->swallowing) {
|
||||
c->animainit_geom = c->geom;
|
||||
}
|
||||
|
||||
if ((c->isglobal || c->isunglobal) && c->isfloating &&
|
||||
c->animation.action == TAG) {
|
||||
c->animainit_geom = c->geom;
|
||||
}
|
||||
|
||||
if (c->animation_type_open && strcmp(c->animation_type_open, "none") == 0 &&
|
||||
c->animation.action == OPEN) {
|
||||
c->animainit_geom = c->geom;
|
||||
}
|
||||
|
||||
// 开始应用动画设置
|
||||
client_set_pending_state(c);
|
||||
|
||||
setborder_color(c);
|
||||
}
|
||||
|
||||
bool client_draw_fadeout_frame(Client *c) {
|
||||
if (!c)
|
||||
return false;
|
||||
|
||||
fadeout_client_animation_next_tick(c);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool client_draw_frame(Client *c) {
|
||||
|
||||
if (!c || !client_surface(c)->mapped)
|
||||
return false;
|
||||
|
||||
if (c->isfullscreen) {
|
||||
client_set_opacity(c, 1);
|
||||
} else if (c == selmon->sel && !c->animation.running) {
|
||||
client_set_opacity(c, c->focused_opacity);
|
||||
} else if (!c->animation.running) {
|
||||
client_set_opacity(c, c->unfocused_opacity);
|
||||
}
|
||||
|
||||
if (!c->need_output_flush)
|
||||
return false;
|
||||
|
||||
if (animations && c->animation.running) {
|
||||
client_animation_next_tick(c);
|
||||
client_apply_clip(c);
|
||||
} else {
|
||||
wlr_scene_node_set_position(&c->scene->node, c->pending.x,
|
||||
c->pending.y);
|
||||
c->animation.current = c->animainit_geom = c->animation.initial =
|
||||
c->pending = c->current = c->geom;
|
||||
client_apply_clip(c);
|
||||
c->need_output_flush = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,233 @@
|
||||
struct dvec2 calculate_animation_curve_at(double t, int type) {
|
||||
struct dvec2 point;
|
||||
double *animation_curve;
|
||||
if (type == MOVE) {
|
||||
animation_curve = animation_curve_move;
|
||||
} else if (type == OPEN) {
|
||||
animation_curve = animation_curve_open;
|
||||
} else if (type == TAG) {
|
||||
animation_curve = animation_curve_tag;
|
||||
} else if (type == CLOSE) {
|
||||
animation_curve = animation_curve_close;
|
||||
} else {
|
||||
animation_curve = animation_curve_move;
|
||||
}
|
||||
|
||||
point.x = 3 * t * (1 - t) * (1 - t) * animation_curve[0] +
|
||||
3 * t * t * (1 - t) * animation_curve[2] + t * t * t;
|
||||
|
||||
point.y = 3 * t * (1 - t) * (1 - t) * animation_curve[1] +
|
||||
3 * t * t * (1 - t) * animation_curve[3] + t * t * t;
|
||||
|
||||
return point;
|
||||
}
|
||||
|
||||
void init_baked_points(void) {
|
||||
baked_points_move = calloc(BAKED_POINTS_COUNT, sizeof(*baked_points_move));
|
||||
baked_points_open = calloc(BAKED_POINTS_COUNT, sizeof(*baked_points_open));
|
||||
baked_points_tag = calloc(BAKED_POINTS_COUNT, sizeof(*baked_points_tag));
|
||||
baked_points_close =
|
||||
calloc(BAKED_POINTS_COUNT, sizeof(*baked_points_close));
|
||||
|
||||
for (unsigned int i = 0; i < BAKED_POINTS_COUNT; i++) {
|
||||
baked_points_move[i] = calculate_animation_curve_at(
|
||||
(double)i / (BAKED_POINTS_COUNT - 1), MOVE);
|
||||
}
|
||||
for (unsigned int i = 0; i < BAKED_POINTS_COUNT; i++) {
|
||||
baked_points_open[i] = calculate_animation_curve_at(
|
||||
(double)i / (BAKED_POINTS_COUNT - 1), OPEN);
|
||||
}
|
||||
for (unsigned int i = 0; i < BAKED_POINTS_COUNT; i++) {
|
||||
baked_points_tag[i] = calculate_animation_curve_at(
|
||||
(double)i / (BAKED_POINTS_COUNT - 1), TAG);
|
||||
}
|
||||
for (unsigned int i = 0; i < BAKED_POINTS_COUNT; i++) {
|
||||
baked_points_close[i] = calculate_animation_curve_at(
|
||||
(double)i / (BAKED_POINTS_COUNT - 1), CLOSE);
|
||||
}
|
||||
}
|
||||
|
||||
double find_animation_curve_at(double t, int type) {
|
||||
unsigned int down = 0;
|
||||
unsigned int up = BAKED_POINTS_COUNT - 1;
|
||||
|
||||
unsigned int middle = (up + down) / 2;
|
||||
struct dvec2 *baked_points;
|
||||
if (type == MOVE) {
|
||||
baked_points = baked_points_move;
|
||||
} else if (type == OPEN) {
|
||||
baked_points = baked_points_open;
|
||||
} else if (type == TAG) {
|
||||
baked_points = baked_points_tag;
|
||||
} else if (type == CLOSE) {
|
||||
baked_points = baked_points_close;
|
||||
} else {
|
||||
baked_points = baked_points_move;
|
||||
}
|
||||
|
||||
while (up - down != 1) {
|
||||
if (baked_points[middle].x <= t) {
|
||||
down = middle;
|
||||
} else {
|
||||
up = middle;
|
||||
}
|
||||
middle = (up + down) / 2;
|
||||
}
|
||||
return baked_points[up].y;
|
||||
}
|
||||
|
||||
double output_frame_duration_ms() {
|
||||
int32_t refresh_total = 0;
|
||||
Monitor *m;
|
||||
wl_list_for_each(m, &mons, link) {
|
||||
if (!m->wlr_output->enabled) {
|
||||
continue;
|
||||
}
|
||||
refresh_total += m->wlr_output->refresh;
|
||||
}
|
||||
return 1000000.0 / refresh_total;
|
||||
}
|
||||
|
||||
static bool scene_node_snapshot(struct wlr_scene_node *node, int lx, int ly,
|
||||
struct wlr_scene_tree *snapshot_tree) {
|
||||
if (!node->enabled && node->type != WLR_SCENE_NODE_TREE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
lx += node->x;
|
||||
ly += node->y;
|
||||
|
||||
struct wlr_scene_node *snapshot_node = NULL;
|
||||
switch (node->type) {
|
||||
case WLR_SCENE_NODE_TREE: {
|
||||
struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
|
||||
|
||||
struct wlr_scene_node *child;
|
||||
wl_list_for_each(child, &scene_tree->children, link) {
|
||||
scene_node_snapshot(child, lx, ly, snapshot_tree);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WLR_SCENE_NODE_RECT: {
|
||||
struct wlr_scene_rect *scene_rect = wlr_scene_rect_from_node(node);
|
||||
|
||||
struct wlr_scene_rect *snapshot_rect =
|
||||
wlr_scene_rect_create(snapshot_tree, scene_rect->width,
|
||||
scene_rect->height, scene_rect->color);
|
||||
snapshot_rect->node.data = scene_rect->node.data;
|
||||
if (snapshot_rect == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
wlr_scene_rect_set_clipped_region(scene_rect,
|
||||
snapshot_rect->clipped_region);
|
||||
wlr_scene_rect_set_backdrop_blur(scene_rect, false);
|
||||
// wlr_scene_rect_set_backdrop_blur_optimized(
|
||||
// scene_rect, snapshot_rect->backdrop_blur_optimized);
|
||||
wlr_scene_rect_set_corner_radius(
|
||||
scene_rect, snapshot_rect->corner_radius, snapshot_rect->corners);
|
||||
wlr_scene_rect_set_color(scene_rect, snapshot_rect->color);
|
||||
|
||||
snapshot_node = &snapshot_rect->node;
|
||||
break;
|
||||
}
|
||||
case WLR_SCENE_NODE_BUFFER: {
|
||||
struct wlr_scene_buffer *scene_buffer =
|
||||
wlr_scene_buffer_from_node(node);
|
||||
|
||||
struct wlr_scene_buffer *snapshot_buffer =
|
||||
wlr_scene_buffer_create(snapshot_tree, NULL);
|
||||
if (snapshot_buffer == NULL) {
|
||||
return false;
|
||||
}
|
||||
snapshot_node = &snapshot_buffer->node;
|
||||
snapshot_buffer->node.data = scene_buffer->node.data;
|
||||
|
||||
wlr_scene_buffer_set_dest_size(snapshot_buffer, scene_buffer->dst_width,
|
||||
scene_buffer->dst_height);
|
||||
wlr_scene_buffer_set_opaque_region(snapshot_buffer,
|
||||
&scene_buffer->opaque_region);
|
||||
wlr_scene_buffer_set_source_box(snapshot_buffer,
|
||||
&scene_buffer->src_box);
|
||||
wlr_scene_buffer_set_transform(snapshot_buffer,
|
||||
scene_buffer->transform);
|
||||
wlr_scene_buffer_set_filter_mode(snapshot_buffer,
|
||||
scene_buffer->filter_mode);
|
||||
|
||||
// Effects
|
||||
wlr_scene_buffer_set_opacity(snapshot_buffer, scene_buffer->opacity);
|
||||
wlr_scene_buffer_set_corner_radius(snapshot_buffer,
|
||||
scene_buffer->corner_radius,
|
||||
scene_buffer->corners);
|
||||
|
||||
// wlr_scene_buffer_set_backdrop_blur_optimized(
|
||||
// snapshot_buffer, scene_buffer->backdrop_blur_optimized);
|
||||
// wlr_scene_buffer_set_backdrop_blur_ignore_transparent(
|
||||
// snapshot_buffer, scene_buffer->backdrop_blur_ignore_transparent);
|
||||
wlr_scene_buffer_set_backdrop_blur(snapshot_buffer, false);
|
||||
|
||||
snapshot_buffer->node.data = scene_buffer->node.data;
|
||||
|
||||
struct wlr_scene_surface *scene_surface =
|
||||
wlr_scene_surface_try_from_buffer(scene_buffer);
|
||||
if (scene_surface != NULL && scene_surface->surface->buffer != NULL) {
|
||||
wlr_scene_buffer_set_buffer(snapshot_buffer,
|
||||
&scene_surface->surface->buffer->base);
|
||||
} else {
|
||||
wlr_scene_buffer_set_buffer(snapshot_buffer, scene_buffer->buffer);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WLR_SCENE_NODE_SHADOW: {
|
||||
struct wlr_scene_shadow *scene_shadow =
|
||||
wlr_scene_shadow_from_node(node);
|
||||
|
||||
struct wlr_scene_shadow *snapshot_shadow = wlr_scene_shadow_create(
|
||||
snapshot_tree, scene_shadow->width, scene_shadow->height,
|
||||
scene_shadow->corner_radius, scene_shadow->blur_sigma,
|
||||
scene_shadow->color);
|
||||
if (snapshot_shadow == NULL) {
|
||||
return false;
|
||||
}
|
||||
snapshot_node = &snapshot_shadow->node;
|
||||
|
||||
wlr_scene_shadow_set_clipped_region(snapshot_shadow,
|
||||
scene_shadow->clipped_region);
|
||||
|
||||
snapshot_shadow->node.data = scene_shadow->node.data;
|
||||
|
||||
wlr_scene_node_set_enabled(&snapshot_shadow->node, false);
|
||||
|
||||
break;
|
||||
}
|
||||
case WLR_SCENE_NODE_OPTIMIZED_BLUR:
|
||||
return true;
|
||||
}
|
||||
|
||||
if (snapshot_node != NULL) {
|
||||
wlr_scene_node_set_position(snapshot_node, lx, ly);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct wlr_scene_tree *wlr_scene_tree_snapshot(struct wlr_scene_node *node,
|
||||
struct wlr_scene_tree *parent) {
|
||||
struct wlr_scene_tree *snapshot = wlr_scene_tree_create(parent);
|
||||
if (snapshot == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Disable and enable the snapshot tree like so to atomically update
|
||||
// the scene-graph. This will prevent over-damaging or other weirdness.
|
||||
wlr_scene_node_set_enabled(&snapshot->node, false);
|
||||
|
||||
if (!scene_node_snapshot(node, 0, 0, snapshot)) {
|
||||
wlr_scene_node_destroy(&snapshot->node);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wlr_scene_node_set_enabled(&snapshot->node, true);
|
||||
|
||||
return snapshot;
|
||||
}
|
||||
@@ -0,0 +1,421 @@
|
||||
void layer_actual_size(LayerSurface *l, unsigned int *width,
|
||||
unsigned int *height) {
|
||||
struct wlr_box box;
|
||||
|
||||
if (l->animation.running) {
|
||||
*width = l->animation.current.width;
|
||||
*height = l->animation.current.height;
|
||||
} else {
|
||||
get_layer_target_geometry(l, &box);
|
||||
*width = box.width;
|
||||
*height = box.height;
|
||||
}
|
||||
}
|
||||
|
||||
void get_layer_target_geometry(LayerSurface *l, struct wlr_box *target_box) {
|
||||
|
||||
if (!l || !l->mapped)
|
||||
return;
|
||||
|
||||
const struct wlr_layer_surface_v1_state *state = &l->layer_surface->current;
|
||||
|
||||
// 限制区域
|
||||
// waybar一般都是大于0,表示要占用多少区域,所以计算位置也要用全部区域作为基准
|
||||
// 如果是-1可能表示独占所有可用空间
|
||||
// 如果是0,应该是表示使用exclusive_zone外的可用区域
|
||||
struct wlr_box bounds;
|
||||
if (state->exclusive_zone > 0 || state->exclusive_zone == -1)
|
||||
bounds = l->mon->m;
|
||||
else
|
||||
bounds = l->mon->w;
|
||||
|
||||
// 初始化几何位置
|
||||
struct wlr_box box = {.width = state->desired_width,
|
||||
.height = state->desired_height};
|
||||
|
||||
// 水平方向定位
|
||||
const uint32_t both_horiz =
|
||||
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
|
||||
if (box.width == 0) {
|
||||
box.x = bounds.x;
|
||||
} else if ((state->anchor & both_horiz) == both_horiz) {
|
||||
box.x = bounds.x + ((bounds.width - box.width) / 2);
|
||||
} else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT) {
|
||||
box.x = bounds.x;
|
||||
} else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT) {
|
||||
box.x = bounds.x + (bounds.width - box.width);
|
||||
} else {
|
||||
box.x = bounds.x + ((bounds.width - box.width) / 2);
|
||||
}
|
||||
|
||||
// 垂直方向定位
|
||||
const uint32_t both_vert =
|
||||
ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
|
||||
if (box.height == 0) {
|
||||
box.y = bounds.y;
|
||||
} else if ((state->anchor & both_vert) == both_vert) {
|
||||
box.y = bounds.y + ((bounds.height - box.height) / 2);
|
||||
} else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) {
|
||||
box.y = bounds.y;
|
||||
} else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM) {
|
||||
box.y = bounds.y + (bounds.height - box.height);
|
||||
} else {
|
||||
box.y = bounds.y + ((bounds.height - box.height) / 2);
|
||||
}
|
||||
|
||||
// 应用边距
|
||||
if (box.width == 0) {
|
||||
box.x += state->margin.left;
|
||||
box.width = bounds.width - (state->margin.left + state->margin.right);
|
||||
} else {
|
||||
if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT) {
|
||||
box.x += state->margin.left;
|
||||
} else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT) {
|
||||
box.x -= state->margin.right;
|
||||
}
|
||||
}
|
||||
|
||||
if (box.height == 0) {
|
||||
box.y += state->margin.top;
|
||||
box.height = bounds.height - (state->margin.top + state->margin.bottom);
|
||||
} else {
|
||||
if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) {
|
||||
box.y += state->margin.top;
|
||||
} else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM) {
|
||||
box.y -= state->margin.bottom;
|
||||
}
|
||||
}
|
||||
|
||||
target_box->x = box.x;
|
||||
target_box->y = box.y;
|
||||
target_box->width = box.width;
|
||||
target_box->height = box.height;
|
||||
}
|
||||
|
||||
void set_layer_open_animaiton(LayerSurface *l, struct wlr_box geo) {
|
||||
int slide_direction;
|
||||
int horizontal, horizontal_value;
|
||||
int vertical, vertical_value;
|
||||
int center_x, center_y;
|
||||
|
||||
if (!l || !l->mapped)
|
||||
return;
|
||||
|
||||
center_x = l->geom.x + l->geom.width / 2;
|
||||
center_y = l->geom.y + l->geom.height / 2;
|
||||
horizontal =
|
||||
l->mon->w.x + l->mon->w.width - center_x < center_x - l->mon->w.x
|
||||
? RIGHT
|
||||
: LEFT;
|
||||
horizontal_value = horizontal == LEFT
|
||||
? center_x - l->mon->w.x
|
||||
: l->mon->w.x + l->mon->w.width - center_x;
|
||||
vertical =
|
||||
l->mon->w.y + l->mon->w.height - center_y < center_y - l->mon->w.y
|
||||
? DOWN
|
||||
: UP;
|
||||
vertical_value = vertical == UP ? center_y - l->mon->w.y
|
||||
: l->mon->w.y + l->mon->w.height - center_y;
|
||||
slide_direction = horizontal_value < vertical_value ? horizontal : vertical;
|
||||
|
||||
l->animainit_geom.width = l->geom.width;
|
||||
l->animainit_geom.height = l->geom.height;
|
||||
switch (slide_direction) {
|
||||
case UP:
|
||||
l->animainit_geom.x = l->geom.x;
|
||||
l->animainit_geom.y = l->mon->m.y - l->geom.height;
|
||||
break;
|
||||
case DOWN:
|
||||
l->animainit_geom.x = l->geom.x;
|
||||
l->animainit_geom.y =
|
||||
l->geom.y + l->mon->m.height - (l->geom.y - l->mon->m.y);
|
||||
break;
|
||||
case LEFT:
|
||||
l->animainit_geom.x = l->mon->m.x - l->geom.width;
|
||||
l->animainit_geom.y = l->geom.y;
|
||||
break;
|
||||
case RIGHT:
|
||||
l->animainit_geom.x =
|
||||
l->geom.x + l->mon->m.width - (l->geom.x - l->mon->m.x);
|
||||
l->animainit_geom.y = l->geom.y;
|
||||
break;
|
||||
default:
|
||||
l->animainit_geom.x = l->geom.x;
|
||||
l->animainit_geom.y = 0 - l->geom.height;
|
||||
}
|
||||
}
|
||||
|
||||
void layer_draw_shadow(LayerSurface *l) {
|
||||
|
||||
if (!l->mapped || !l->shadow)
|
||||
return;
|
||||
|
||||
if (!shadows || !layer_shadows || l->noshadow) {
|
||||
wlr_scene_shadow_set_size(l->shadow, 0, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t width, height;
|
||||
layer_actual_size(l, &width, &height);
|
||||
|
||||
uint32_t delta = shadows_size;
|
||||
|
||||
/* we calculate where to clip the shadow */
|
||||
struct wlr_box layer_box = {
|
||||
.x = 0,
|
||||
.y = 0,
|
||||
.width = width,
|
||||
.height = height,
|
||||
};
|
||||
|
||||
struct wlr_box shadow_box = {
|
||||
.x = shadows_position_x,
|
||||
.y = shadows_position_y,
|
||||
.width = width + 2 * delta,
|
||||
.height = height + 2 * delta,
|
||||
};
|
||||
|
||||
struct wlr_box intersection_box;
|
||||
wlr_box_intersection(&intersection_box, &layer_box, &shadow_box);
|
||||
/* clipped region takes shadow relative coords, so we translate everything
|
||||
* by its position */
|
||||
intersection_box.x -= shadows_position_x;
|
||||
intersection_box.y -= shadows_position_y;
|
||||
|
||||
struct clipped_region clipped_region = {
|
||||
.area = intersection_box,
|
||||
.corner_radius = border_radius,
|
||||
.corners = border_radius_location_default,
|
||||
};
|
||||
|
||||
wlr_scene_node_set_position(&l->shadow->node, shadow_box.x, shadow_box.y);
|
||||
|
||||
wlr_scene_shadow_set_size(l->shadow, shadow_box.width, shadow_box.height);
|
||||
wlr_scene_shadow_set_clipped_region(l->shadow, clipped_region);
|
||||
}
|
||||
|
||||
void fadeout_layer_animation_next_tick(LayerSurface *l) {
|
||||
if (!l)
|
||||
return;
|
||||
|
||||
double animation_passed =
|
||||
(double)l->animation.passed_frames / l->animation.total_frames;
|
||||
int type = l->animation.action = l->animation.action;
|
||||
double factor = find_animation_curve_at(animation_passed, type);
|
||||
unsigned int width =
|
||||
l->animation.initial.width +
|
||||
(l->current.width - l->animation.initial.width) * factor;
|
||||
unsigned int height =
|
||||
l->animation.initial.height +
|
||||
(l->current.height - l->animation.initial.height) * factor;
|
||||
|
||||
unsigned int x = l->animation.initial.x +
|
||||
(l->current.x - l->animation.initial.x) * factor;
|
||||
unsigned int y = l->animation.initial.y +
|
||||
(l->current.y - l->animation.initial.y) * factor;
|
||||
|
||||
wlr_scene_node_set_position(&l->scene->node, x, y);
|
||||
|
||||
l->animation.current = (struct wlr_box){
|
||||
.x = x,
|
||||
.y = y,
|
||||
.width = width,
|
||||
.height = height,
|
||||
};
|
||||
|
||||
double opacity = MAX(fadeout_begin_opacity - animation_passed, 0);
|
||||
|
||||
if (animation_fade_out)
|
||||
wlr_scene_node_for_each_buffer(&l->scene->node,
|
||||
scene_buffer_apply_opacity, &opacity);
|
||||
|
||||
if (animation_passed == 1.0) {
|
||||
wl_list_remove(&l->fadeout_link);
|
||||
wlr_scene_node_destroy(&l->scene->node);
|
||||
free(l);
|
||||
l = NULL;
|
||||
} else {
|
||||
l->animation.passed_frames++;
|
||||
}
|
||||
}
|
||||
|
||||
void layer_animation_next_tick(LayerSurface *l) {
|
||||
|
||||
if (!l || !l->mapped)
|
||||
return;
|
||||
|
||||
double animation_passed =
|
||||
(double)l->animation.passed_frames / l->animation.total_frames;
|
||||
|
||||
int type = l->animation.action == NONE ? MOVE : l->animation.action;
|
||||
double factor = find_animation_curve_at(animation_passed, type);
|
||||
|
||||
unsigned int width =
|
||||
l->animation.initial.width +
|
||||
(l->current.width - l->animation.initial.width) * factor;
|
||||
unsigned int height =
|
||||
l->animation.initial.height +
|
||||
(l->current.height - l->animation.initial.height) * factor;
|
||||
|
||||
unsigned int x = l->animation.initial.x +
|
||||
(l->current.x - l->animation.initial.x) * factor;
|
||||
unsigned int y = l->animation.initial.y +
|
||||
(l->current.y - l->animation.initial.y) * factor;
|
||||
|
||||
wlr_scene_node_set_position(&l->scene->node, x, y);
|
||||
|
||||
l->animation.current = (struct wlr_box){
|
||||
.x = x,
|
||||
.y = y,
|
||||
.width = width,
|
||||
.height = height,
|
||||
};
|
||||
|
||||
if (animation_passed == 1.0) {
|
||||
l->animation.running = false;
|
||||
l->need_output_flush = false;
|
||||
l->animation.action = MOVE;
|
||||
} else {
|
||||
l->animation.passed_frames++;
|
||||
}
|
||||
}
|
||||
|
||||
void init_fadeout_layers(LayerSurface *l) {
|
||||
|
||||
if (!layer_animations || l->noanim) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!l->mon)
|
||||
return;
|
||||
|
||||
if (!l->scene) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (l->layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM ||
|
||||
l->layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND)
|
||||
return;
|
||||
|
||||
LayerSurface *fadeout_layer = ecalloc(1, sizeof(*fadeout_layer));
|
||||
|
||||
wlr_scene_node_set_enabled(&l->scene->node, true);
|
||||
fadeout_layer->scene =
|
||||
wlr_scene_tree_snapshot(&l->scene->node, layers[LyrFadeOut]);
|
||||
wlr_scene_node_set_enabled(&l->scene->node, false);
|
||||
|
||||
if (!fadeout_layer->scene) {
|
||||
free(fadeout_layer);
|
||||
return;
|
||||
}
|
||||
|
||||
fadeout_layer->animation.duration = animation_duration_close;
|
||||
fadeout_layer->geom = fadeout_layer->current =
|
||||
fadeout_layer->animainit_geom = fadeout_layer->animation.initial =
|
||||
l->animation.current;
|
||||
fadeout_layer->mon = l->mon;
|
||||
fadeout_layer->animation.action = CLOSE;
|
||||
|
||||
// 这里snap节点的坐标设置是使用的相对坐标,所以不能加上原来坐标
|
||||
// 这跟普通node有区别
|
||||
|
||||
fadeout_layer->animation.initial.x = 0;
|
||||
fadeout_layer->animation.initial.y = 0;
|
||||
|
||||
fadeout_layer->current.y =
|
||||
l->geom.y + l->geom.height / 2 > l->mon->m.y + l->mon->m.height / 2
|
||||
? l->mon->m.height -
|
||||
(l->animation.current.y - l->mon->m.y) // down out
|
||||
: l->mon->m.y - l->geom.height; // up out
|
||||
fadeout_layer->current.x = 0; // x无偏差,垂直划出
|
||||
|
||||
fadeout_layer->animation.passed_frames = 0;
|
||||
fadeout_layer->animation.total_frames =
|
||||
fadeout_layer->animation.duration / output_frame_duration_ms();
|
||||
wlr_scene_node_set_enabled(&fadeout_layer->scene->node, true);
|
||||
wl_list_insert(&fadeout_layers, &fadeout_layer->fadeout_link);
|
||||
}
|
||||
|
||||
void layer_set_pending_state(LayerSurface *l) {
|
||||
|
||||
if (!l || !l->mapped)
|
||||
return;
|
||||
|
||||
l->pending = l->geom;
|
||||
if (l->animation.action == OPEN)
|
||||
set_layer_open_animaiton(l, l->geom);
|
||||
else
|
||||
l->animainit_geom = l->animation.current;
|
||||
// 判断是否需要动画
|
||||
if (!animations || !layer_animations || l->noanim ||
|
||||
l->layer_surface->current.layer ==
|
||||
ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND ||
|
||||
l->layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM) {
|
||||
l->animation.should_animate = false;
|
||||
} else {
|
||||
l->animation.should_animate = true;
|
||||
}
|
||||
|
||||
l->animation.duration = animation_duration_open;
|
||||
l->animation.action = OPEN;
|
||||
// 开始动画
|
||||
layer_commit(l);
|
||||
l->dirty = true;
|
||||
}
|
||||
|
||||
void layer_commit(LayerSurface *l) {
|
||||
|
||||
if (!l || !l->mapped)
|
||||
return;
|
||||
|
||||
l->current = l->pending; // 设置动画的结束位置
|
||||
|
||||
if (l->animation.should_animate) {
|
||||
if (!l->animation.running) {
|
||||
l->animation.current = l->animainit_geom;
|
||||
}
|
||||
|
||||
l->animation.initial = l->animainit_geom;
|
||||
// 设置动画速度
|
||||
l->animation.passed_frames = 0;
|
||||
l->animation.total_frames =
|
||||
l->animation.duration / output_frame_duration_ms();
|
||||
|
||||
// 标记动画开始
|
||||
l->animation.running = true;
|
||||
l->animation.should_animate = false;
|
||||
}
|
||||
// 请求刷新屏幕
|
||||
wlr_output_schedule_frame(l->mon->wlr_output);
|
||||
}
|
||||
|
||||
bool layer_draw_frame(LayerSurface *l) {
|
||||
|
||||
if (!l || !l->mapped)
|
||||
return false;
|
||||
|
||||
if (!l->need_output_flush)
|
||||
return false;
|
||||
|
||||
if (l->layer_surface->current.layer != ZWLR_LAYER_SHELL_V1_LAYER_TOP &&
|
||||
l->layer_surface->current.layer != ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (animations && layer_animations && l->animation.running && !l->noanim) {
|
||||
layer_animation_next_tick(l);
|
||||
layer_draw_shadow(l);
|
||||
} else {
|
||||
layer_draw_shadow(l);
|
||||
l->need_output_flush = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool layer_draw_fadeout_frame(LayerSurface *l) {
|
||||
if (!l)
|
||||
return false;
|
||||
|
||||
fadeout_layer_animation_next_tick(l);
|
||||
return true;
|
||||
}
|
||||
+17
-1660
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user