diff --git a/src/animation/client.h b/src/animation/client.h new file mode 100644 index 0000000..9695e05 --- /dev/null +++ b/src/animation/client.h @@ -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; +} diff --git a/src/animation/common.h b/src/animation/common.h new file mode 100644 index 0000000..514165b --- /dev/null +++ b/src/animation/common.h @@ -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; +} \ No newline at end of file diff --git a/src/animation/layer.h b/src/animation/layer.h new file mode 100644 index 0000000..bd3ccc5 --- /dev/null +++ b/src/animation/layer.h @@ -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; +} diff --git a/src/maomao.c b/src/maomao.c index 1899279..137afc1 100644 --- a/src/maomao.c +++ b/src/maomao.c @@ -649,6 +649,18 @@ static void layer_actual_size(LayerSurface *l, unsigned int *width, unsigned int *height); static void get_layer_target_geometry(LayerSurface *l, struct wlr_box *target_box); +static void scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int sx, + int sy, void *data); +static double find_animation_curve_at(double t, int type); + +static void apply_opacity_to_rect_nodes(Client *c, struct wlr_scene_node *node, + double animation_passed); +static enum corner_location set_client_corner_location(Client *c); +static double output_frame_duration_ms(); +static struct wlr_scene_tree * +wlr_scene_tree_snapshot(struct wlr_scene_node *node, + struct wlr_scene_tree *parent); +static bool is_scroller_layout(Monitor *m); #include "data/static_keymap.h" #include "dispatch/dispatch.h" @@ -739,6 +751,7 @@ static struct { int hotspot_y; } last_cursor; +#include "client/client.h" #include "config/preset.h" struct Pertag { @@ -795,351 +808,14 @@ static struct wl_listener xwayland_ready = {.notify = xwaylandready}; static struct wlr_xwayland *xwayland; #endif -#include "client/client.h" +#include "animation/client.h" +#include "animation/common.h" +#include "animation/layer.h" #include "config/parse_config.h" #include "ext-protocol/all.h" #include "layout/horizontal.h" #include "layout/vertical.h" -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; -} - -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); - } - } -} - -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 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 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 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 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 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 client_change_mon(Client *c, Monitor *m) { setmon(c, m, c->tags, true); reset_foreign_tolevel(c); @@ -1168,495 +844,6 @@ bool check_hit_no_border(Client *c) { return hit_no_border; } -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 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); -} - -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; -} - -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); -} - -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 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; -} - -bool client_draw_fadeout_frame(Client *c) { - if (!c) - return false; - - fadeout_client_animation_next_tick(c); - return true; -} - -bool layer_draw_fadeout_frame(LayerSurface *l) { - if (!l) - return false; - - fadeout_layer_animation_next_tick(l); - return true; -} - void applybounds(Client *c, struct wlr_box *bbox) { /* set minimum possible */ c->geom.width = MAX(1 + 2 * (int)c->bw, c->geom.width); @@ -1708,7 +895,7 @@ void minized(const Arg *arg) { } void restore_minized(const Arg *arg) { - + Client *c; if (selmon && selmon->sel && selmon->sel->is_in_scratchpad && selmon->sel->is_scratchpad_show) { selmon->sel->isminied = 0; @@ -1719,7 +906,6 @@ void restore_minized(const Arg *arg) { return; } - Client *c; wl_list_for_each(c, &clients, link) { if (c->isminied) { show_hide_client(c); @@ -3301,86 +2487,6 @@ static void iter_layer_scene_buffers(struct wlr_scene_buffer *buffer, int sx, } } -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 maplayersurfacenotify(struct wl_listener *listener, void *data) { LayerSurface *l = wl_container_of(listener, l, map); struct wlr_layer_surface_v1 *layer_surface = l->layer_surface; @@ -3534,113 +2640,6 @@ void commitlayersurfacenotify(struct wl_listener *listener, void *data) { arrangelayers(l->mon); } -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 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; -} - -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; -} - -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); -} - -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 commitnotify(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, commit); @@ -4766,150 +3765,6 @@ void keypressmod(struct wl_listener *listener, void *data) { } } -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; -} - void pending_kill_client(Client *c) { // c->iskilling = 1; //不可以提前标记已经杀掉,因为有些客户端可能拒绝 client_send_close(c); @@ -5516,114 +4371,6 @@ void scene_buffer_apply_opacity(struct wlr_scene_buffer *buffer, int sx, int sy, wlr_scene_buffer_set_opacity(buffer, *(double *)data); } -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 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 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_set_opacity(Client *c, double opacity) { wlr_scene_node_for_each_buffer(&c->scene_surface->node, scene_buffer_apply_opacity, &opacity); @@ -5767,266 +4514,6 @@ void exchange_client(const Arg *arg) { exchange_two_client(c, direction_select(arg)); } -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_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 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 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); -} - void // 17 run(char *startup_cmd) { char autostart_temp_path[1024]; @@ -7563,136 +6050,6 @@ void unmaplayersurfacenotify(struct wl_listener *listener, void *data) { motionnotify(0, NULL, 0, 0, 0, 0); } -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 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 unmapnotify(struct wl_listener *listener, void *data) { /* Called when the surface is unmapped, and should no longer be shown. */ Client *c = wl_container_of(listener, c, unmap);