diff --git a/src/animation/client.h b/src/animation/client.h index 4bb018f9..c89f0cec 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -243,11 +243,31 @@ void scene_buffer_apply_overview_effect(struct wlr_scene_buffer *buffer, int32_t sx, int32_t sy, void *data) { BufferData *buffer_data = (BufferData *)data; - if (buffer_data->width > 0 && buffer_data->height > 0) { - wlr_scene_buffer_set_dest_size(buffer, buffer_data->width, - buffer_data->height); + if (buffer_data->width_scale >= 1.0 || buffer_data->height_scale >= 1.0) + return; + + int32_t surface_width = 0; + int32_t surface_height = 0; + bool is_subsurface = false; + + struct wlr_scene_tree *parent_tree = buffer->node.parent; + if (parent_tree->node.data != NULL) { + SnapshotMetadata *meta = (SnapshotMetadata *)parent_tree->node.data; + surface_width = meta->orig_width; + surface_height = meta->orig_height; + is_subsurface = meta->is_subsurface; } + surface_height = surface_height * buffer_data->height_scale; + surface_width = surface_width * buffer_data->width_scale; + + if (buffer_data->width > 0 && buffer_data->height > 0) { + wlr_scene_buffer_set_dest_size(buffer, surface_width, surface_height); + } + + if (is_subsurface) + return; + wlr_scene_buffer_set_corner_radius(buffer, config.border_radius, buffer_data->corner_location); } diff --git a/src/animation/common.h b/src/animation/common.h index 10b66b91..6120d79c 100644 --- a/src/animation/common.h +++ b/src/animation/common.h @@ -28,6 +28,12 @@ struct dvec2 calculate_animation_curve_at(double t, int32_t type) { return point; } +void handle_snapshot_meta_destroy(struct wl_listener *listener, void *data) { + SnapshotMetadata *meta = wl_container_of(listener, meta, destroy); + wl_list_remove(&meta->destroy.link); // 安全移除监听器 + free(meta); +} + 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)); @@ -154,12 +160,43 @@ static bool scene_node_snapshot(struct wlr_scene_node *node, int32_t lx, 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) { + // 创建中间包装树节点 + struct wlr_scene_tree *wrapper = wlr_scene_tree_create(snapshot_tree); + if (wrapper == NULL) { return false; } - snapshot_node = &snapshot_buffer->node; + snapshot_node = &wrapper->node; // 坐标位移应用在外层包装盒上 + + // 收集表面状态并保存为元数据 + SnapshotMetadata *meta = calloc(1, sizeof(SnapshotMetadata)); + if (meta == NULL) { + wlr_scene_node_destroy(&wrapper->node); + return false; + } + meta->orig_width = scene_buffer->dst_width; + meta->orig_height = scene_buffer->dst_height; + + struct wlr_scene_surface *scene_surface = + wlr_scene_surface_try_from_buffer(scene_buffer); + if (scene_surface != NULL) { + meta->is_subsurface = + !!wlr_subsurface_try_from_wlr_surface(scene_surface->surface); + } + + // 绑定销毁回调监听,随包装节点销毁而释放内存 + meta->destroy.notify = handle_snapshot_meta_destroy; + wl_signal_add(&wrapper->node.events.destroy, &meta->destroy); + wrapper->node.data = meta; + + // 将真正的 buffer 挂靠在 wrapper 下面(相对坐标0,0) + struct wlr_scene_buffer *snapshot_buffer = + wlr_scene_buffer_create(wrapper, NULL); + if (snapshot_buffer == NULL) { + wlr_scene_node_destroy(&wrapper->node); + return false; + } + + // 保留原生的 data 指针(如 Client*),防止事件派发/焦点获取失效 snapshot_buffer->node.data = scene_buffer->node.data; wlr_scene_buffer_set_dest_size(snapshot_buffer, scene_buffer->dst_width, @@ -179,16 +216,8 @@ static bool scene_node_snapshot(struct wlr_scene_node *node, int32_t lx, 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); diff --git a/src/mango.c b/src/mango.c index 25d051c1..2aa292ac 100644 --- a/src/mango.c +++ b/src/mango.c @@ -606,6 +606,13 @@ struct TagScrollerState { int count; }; +typedef struct { + int32_t orig_width; + int32_t orig_height; + bool is_subsurface; + struct wl_listener destroy; +} SnapshotMetadata; + /* function declarations */ static void applybounds( Client *c,