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_dir_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) return; center_x = l->geom.x + l->geom.width / 2; center_y = l->geom.y + l->geom.height / 2; horizontal = center_x > l->mon->m.x + l->mon->m.width / 2 ? RIGHT : LEFT; horizontal_value = horizontal == LEFT ? center_x - l->mon->m.x : l->mon->m.x + l->mon->m.width - center_x; vertical = center_y > l->mon->m.y + l->mon->m.height / 2 ? DOWN : UP; vertical_value = vertical == UP ? center_y - l->mon->w.y : l->mon->m.y + l->mon->m.height - center_y; slide_direction = horizontal_value < vertical_value ? horizontal : vertical; switch (slide_direction) { case UP: geo->x = l->geom.x; geo->y = l->mon->m.y - l->geom.height; break; case DOWN: geo->x = l->geom.x; geo->y = l->mon->m.y + l->mon->m.height; break; case LEFT: geo->x = l->mon->m.x - l->geom.width; geo->y = l->geom.y; break; case RIGHT: geo->x = l->mon->m.x + l->mon->m.width; geo->y = l->geom.y; break; default: geo->x = l->geom.x; geo->y = 0 - l->geom.height; } } 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.0f); 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; double opacity = MIN(fadein_begin_opacity + animation_passed, 1.0f); if (animation_fade_in) wlr_scene_node_for_each_buffer(&l->scene->node, scene_buffer_apply_opacity, &opacity); 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; if ((!l->animation_type_close && strcmp(layer_animation_type_close, "slide") == 0) || (l->animation_type_close && strcmp(l->animation_type_close, "slide") == 0)) { set_layer_dir_animaiton(l, &fadeout_layer->current); fadeout_layer->current.x = fadeout_layer->current.x - l->geom.x; fadeout_layer->current.y = fadeout_layer->current.y - l->geom.y; } else { fadeout_layer->current.x = 0; fadeout_layer->current.y = 0; } 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) { if ((!l->animation_type_open && strcmp(layer_animation_type_open, "slide") == 0) || (l->animation_type_open && strcmp(l->animation_type_open, "slide") == 0)) { set_layer_dir_animaiton(l, &l->animainit_geom); } else { l->animainit_geom.x = l->geom.x; l->animainit_geom.y = l->geom.y; } } 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); } else { 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; }