diff --git a/src/backend/wayland/wl_backend.c b/src/backend/wayland/wl_backend.c index d862b93..a59aea3 100644 --- a/src/backend/wayland/wl_backend.c +++ b/src/backend/wayland/wl_backend.c @@ -892,8 +892,28 @@ wl_grab_apply_motion(void) int nx = wl_state.grab_start_win_x + dx; int ny = wl_state.grab_start_win_y + dy; v->x = nx; v->y = ny; - if (v->scene_node) + if (v->frame_id) { + /* Framed window: move the frame tree. The client scene_node + * is a child of the tree and moves with it automatically. */ + struct wl_frame_buf *fb = frame_buf_find(v->frame_id); + if (fb && fb->tree) { + int frame_x = nx - v->frame_rel_x; + int frame_y = ny - v->frame_rel_y; + fb->x = frame_x; + fb->y = frame_y; + wlr_scene_node_set_position(&fb->tree->node, frame_x, frame_y); + /* Update child absolute tracking */ + struct wl_frame_buf *child; + wl_list_for_each(child, &wl_state.frame_list, link) { + if (child->parent_id == v->frame_id) { + child->x = fb->x + child->rel_x; + child->y = fb->y + child->rel_y; + } + } + } + } else if (v->scene_node) { wlr_scene_node_set_position(&v->scene_node->node, nx, ny); + } if (v->xw_surface) wlr_xwayland_surface_configure(v->xw_surface, (int16_t)nx, (int16_t)ny, @@ -923,16 +943,41 @@ wl_grab_apply_motion(void) if (nw < 32) { nw = 32; } if (nh < 32) { nh = 32; } - v->x = nx; v->y = ny; - if (v->scene_node) - wlr_scene_node_set_position(&v->scene_node->node, nx, ny); - - if (v->xw_surface) { - wlr_xwayland_surface_configure(v->xw_surface, - (int16_t)nx, (int16_t)ny, (uint16_t)nw, (uint16_t)nh); - } else if (v->xdg_surface) { - wlr_xdg_toplevel_set_size(v->xdg_surface->toplevel, (uint32_t)nw, (uint32_t)nh); - wlr_xdg_surface_schedule_configure(v->xdg_surface); + /* Use wWindowConfigure to update the WM frame (titlebar/resizebar) + * along with the client surface. */ + WObjDescriptor *desc = wm_backend->context_find(v->id, WM_CTX_CLIENT_WIN); + if (desc && desc->parent_type == WCLASS_WINDOW) { + WWindow *wwin = (WWindow *)desc->parent; + /* Ensure client scene_node is parented under frame tree */ + if (v->scene_node && v->frame_id) { + struct wl_frame_buf *ffb = frame_buf_find(v->frame_id); + if (ffb && ffb->tree) { + if (v->scene_node->node.parent != ffb->tree) { + wwarning("REPARENT FIX: scene_node parent=%p tree=%p", + (void*)v->scene_node->node.parent, (void*)ffb->tree); + wlr_scene_node_reparent(&v->scene_node->node, ffb->tree); + wlr_scene_node_set_position(&v->scene_node->node, + v->frame_rel_x, v->frame_rel_y); + } + } + } + int frame_x = nx; + int frame_y = ny; + if (wwin->frame) + frame_y = ny - wwin->frame->top_width; + wWindowConfigure(wwin, frame_x, frame_y, nw, nh); + } else { + /* Fallback for unmanaged surfaces: direct scene manipulation. */ + v->x = nx; v->y = ny; + if (v->scene_node) + wlr_scene_node_set_position(&v->scene_node->node, nx, ny); + if (v->xw_surface) { + wlr_xwayland_surface_configure(v->xw_surface, + (int16_t)nx, (int16_t)ny, (uint16_t)nw, (uint16_t)nh); + } else if (v->xdg_surface) { + wlr_xdg_toplevel_set_size(v->xdg_surface->toplevel, (uint32_t)nw, (uint32_t)nh); + wlr_xdg_surface_schedule_configure(v->xdg_surface); + } } } } @@ -1081,9 +1126,13 @@ handle_toplevel_map(struct wl_listener *listener, void *data) if (_pfb && _pfb->tree) wlr_scene_node_reparent(&view->scene_node->node, _pfb->tree); + /* Position at relative offset within frame tree */ + wlr_scene_node_set_position(&view->scene_node->node, + view->frame_rel_x, view->frame_rel_y); + } else { + wlr_scene_node_set_position(&view->scene_node->node, + view->x, view->y); } - wlr_scene_node_set_position(&view->scene_node->node, - view->x, view->y); } } @@ -1321,8 +1370,15 @@ handle_xwayland_set_geometry(struct wl_listener *listener, void *data) wl_container_of(listener, view, xw_geometry_listener); struct wlr_xwayland_surface *xw = view->xw_surface; (void)data; - if (view->scene_node) - wlr_scene_node_set_position(&view->scene_node->node, xw->x, xw->y); + if (view->scene_node) { + if (view->frame_id) { + /* Framed: position relative to frame tree */ + wlr_scene_node_set_position(&view->scene_node->node, + view->frame_rel_x, view->frame_rel_y); + } else { + wlr_scene_node_set_position(&view->scene_node->node, xw->x, xw->y); + } + } } /* @@ -1676,7 +1732,38 @@ handle_toplevel_commit(struct wl_listener *listener, void *data) { struct wl_toplevel_view *view = wl_container_of(listener, view, surface_commit_listener); - (void)view; (void)data; + (void)data; + + /* Ensure client scene_node is parented under frame tree */ + if (view->scene_node && view->frame_id) { + struct wl_frame_buf *ffb = frame_buf_find(view->frame_id); + if (ffb && ffb->tree && view->scene_node->node.parent != ffb->tree) { + wlr_scene_node_reparent(&view->scene_node->node, ffb->tree); + wlr_scene_node_set_position(&view->scene_node->node, + view->frame_rel_x, view->frame_rel_y); + } + } + + /* When the client commits a buffer at a new size (e.g. after interactive + * resize), update the WM frame to match. */ + if (view->xdg_surface && view->xdg_surface->surface && view->frame_id) { + int cw = view->xdg_surface->surface->current.width; + int ch = view->xdg_surface->surface->current.height; + if (cw > 0 && ch > 0) { + WObjDescriptor *desc = wm_backend->context_find(view->id, WM_CTX_CLIENT_WIN); + if (desc && desc->parent_type == WCLASS_WINDOW) { + WWindow *wwin = (WWindow *)desc->parent; + if (wwin->frame && + (cw != wwin->client.width || ch != wwin->client.height)) { + wwin->client.width = cw; + wwin->client.height = ch; + int h = ch + wwin->frame->top_width + wwin->frame->bottom_width; + wFrameWindowResize(wwin->frame, cw, h); + } + } + } + } + if (wl_state.output) wlr_output_schedule_frame(wl_state.output); } @@ -4052,6 +4139,7 @@ wl_frame_create_toplevel(WScreen *scr, fb->height = height; /* Create scene buffer node under a per-window tree. + * The tree is positioned at (x,y) so all children use local offsets. * Default to WL_LAYER_NORMAL; wl_stacking_set_level() will reparent * to the correct bucket when AddToStackList() fires immediately after. */ if (wl_state.scene) { @@ -4059,10 +4147,10 @@ wl_frame_create_toplevel(WScreen *scr, ? wl_state.level_trees[WL_LAYER_NORMAL] : &wl_state.scene->tree; fb->tree = wlr_scene_tree_create(_parent); if (fb->tree) { - wlr_scene_node_set_position(&fb->tree->node, 0, 0); + wlr_scene_node_set_position(&fb->tree->node, x, y); fb->scene_buf = wlr_scene_buffer_create(fb->tree, &fb->base); if (fb->scene_buf) { - wlr_scene_node_set_position(&fb->scene_buf->node, x, y); + wlr_scene_node_set_position(&fb->scene_buf->node, 0, 0); wlr_scene_node_set_enabled(&fb->scene_buf->node, false); } wlr_scene_node_set_enabled(&fb->tree->node, true); @@ -4120,7 +4208,7 @@ wl_frame_create_child(WNativeWindow parent_win, WScreen *scr, ? parent->tree : &wl_state.scene->tree; fb->scene_buf = wlr_scene_buffer_create(ptree, &fb->base); if (fb->scene_buf) { - wlr_scene_node_set_position(&fb->scene_buf->node, abs_x, abs_y); + wlr_scene_node_set_position(&fb->scene_buf->node, x, y); wlr_scene_node_set_enabled(&fb->scene_buf->node, false); } } @@ -4149,7 +4237,7 @@ wl_frame_configure(WNativeWindow win, int x, int y, int width, int height) struct wl_frame_buf *fb = frame_buf_find(win); if (!fb) return; - /* x,y are relative to parent for child windows */ + /* Update position tracking */ fb->rel_x = x; fb->rel_y = y; if (fb->parent_id) { @@ -4161,33 +4249,38 @@ wl_frame_configure(WNativeWindow win, int x, int y, int width, int height) fb->x = x; fb->y = y; } + /* Child frame_buf: reposition scene_buf at relative offset within parent tree */ + if (fb->scene_buf) + wlr_scene_node_set_position(&fb->scene_buf->node, x, y); } else { fb->x = x; fb->y = y; + /* Top-level frame: move the tree (children follow automatically) */ + if (fb->tree) + wlr_scene_node_set_position(&fb->tree->node, x, y); } - if (fb->scene_buf) - wlr_scene_node_set_position(&fb->scene_buf->node, fb->x, fb->y); - /* Resize: reallocate the pixman image if dimensions changed. */ if (width > 0 && height > 0 && (width != fb->width || height != fb->height)) { - //pixman_image_unref(fb->image); + if (fb->image) + pixman_image_unref(fb->image); fb->image = pixman_image_create_bits(PIXMAN_a8r8g8b8, width, height, NULL, 0); fb->width = width; fb->height = height; fb->base.width = width; fb->base.height = height; + /* Detach old buffer from scene so it picks up new dimensions on next commit */ + if (fb->scene_buf) + wlr_scene_buffer_set_buffer(fb->scene_buf, NULL); } - /* Reposition client surface and child frame_bufs to follow the frame. */ + /* Update absolute position tracking for children (used by hit-testing) */ struct wl_toplevel_view *cv; wl_list_for_each(cv, &wl_state.toplevel_list, link) { if (cv->frame_id == win) { cv->x = fb->x + cv->frame_rel_x; cv->y = fb->y + cv->frame_rel_y; - if (cv->scene_node) - wlr_scene_node_set_position(&cv->scene_node->node, cv->x, cv->y); break; } } @@ -4196,8 +4289,6 @@ wl_frame_configure(WNativeWindow win, int x, int y, int width, int height) if (child->parent_id == win) { child->x = fb->x + child->rel_x; child->y = fb->y + child->rel_y; - if (child->scene_buf) - wlr_scene_node_set_position(&child->scene_buf->node, child->x, child->y); } } } @@ -4243,8 +4334,7 @@ wl_frame_paint(struct WFrameWindow *fwin) tb_fb->x = fb->x; tb_fb->y = fb->y; if (tb_fb->scene_buf) - wlr_scene_node_set_position(&tb_fb->scene_buf->node, - tb_fb->x, tb_fb->y); + wlr_scene_node_set_position(&tb_fb->scene_buf->node, 0, 0); } /* Ensure titlebar buffer is full width */ @@ -6415,8 +6505,13 @@ static void wl_window_move(WNativeWindow win, int x, int y) } else { v->x = x; v->y = y; } - if (v->scene_node) - wlr_scene_node_set_position(&v->scene_node->node, v->x, v->y); + if (v->scene_node) { + /* Scene node is a child of the frame tree — use relative coords */ + if (v->frame_id) + wlr_scene_node_set_position(&v->scene_node->node, x, y); + else + wlr_scene_node_set_position(&v->scene_node->node, v->x, v->y); + } if (v->xw_surface) wlr_xwayland_surface_configure(v->xw_surface, (int16_t)v->x, (int16_t)v->y, @@ -6434,43 +6529,29 @@ static void wl_window_move(WNativeWindow win, int x, int y) } else { fb->x = x; fb->y = y; } + /* Child frame_buf: reposition scene_buf at relative offset */ + if (fb->scene_buf) + wlr_scene_node_set_position(&fb->scene_buf->node, x, y); } else { fb->x = x; fb->y = y; + /* Top-level frame: move the tree (children follow automatically) */ + if (fb->tree) + wlr_scene_node_set_position(&fb->tree->node, x, y); } - if (fb->scene_buf) - wlr_scene_node_set_position(&fb->scene_buf->node, fb->x, fb->y); - /* Move the client surface (toplevel view) that belongs to this frame */ + /* Update absolute position tracking for hit-testing */ struct wl_toplevel_view *cv; wl_list_for_each(cv, &wl_state.toplevel_list, link) { if (cv->frame_id == win) { - cv->x = x + cv->frame_rel_x; - cv->y = y + cv->frame_rel_y; - if (cv->scene_node) - wlr_scene_node_set_position(&cv->scene_node->node, - cv->x, cv->y); + cv->x = fb->x + cv->frame_rel_x; + cv->y = fb->y + cv->frame_rel_y; break; } } - /* Move children and grandchildren */ struct wl_frame_buf *child; wl_list_for_each(child, &wl_state.frame_list, link) { if (child->parent_id == win) { - child->x = x + child->rel_x; - child->y = y + child->rel_y; - if (child->scene_buf) - wlr_scene_node_set_position(&child->scene_buf->node, - child->x, child->y); - /* Grandchildren */ - struct wl_frame_buf *gc; - wl_list_for_each(gc, &wl_state.frame_list, link) { - if (gc->parent_id == child->id) { - gc->x = child->x + gc->rel_x; - gc->y = child->y + gc->rel_y; - if (gc->scene_buf) - wlr_scene_node_set_position(&gc->scene_buf->node, - gc->x, gc->y); - } - } + child->x = fb->x + child->rel_x; + child->y = fb->y + child->rel_y; } } return; @@ -6489,25 +6570,7 @@ static void wl_window_resize(WNativeWindow win, int w, int h) } if (!v->xdg_surface || !v->xdg_surface->toplevel) return; wlr_xdg_toplevel_set_size(v->xdg_surface->toplevel, (uint32_t)w, (uint32_t)h); - wlr_xdg_toplevel_set_activated(v->xdg_surface->toplevel, true); - /* Dispatch idle so configure is sent, flush, then send frame_done - * so client can render at new size. Skip if in nested dispatch. */ - static int in_resize = 0; - if (!in_resize) { - in_resize = 1; - struct wl_event_loop *loop = wl_display_get_event_loop(wl_state.display); - wl_list_remove(&wl_state.output_frame_listener.link); - wl_event_loop_dispatch(loop, 0); - wl_state.output_frame_listener.notify = handle_output_frame; - wl_signal_add(&wl_state.output->events.frame, - &wl_state.output_frame_listener); - wl_display_flush_clients(wl_state.display); - struct timespec now; - clock_gettime(CLOCK_MONOTONIC, &now); - wlr_surface_send_frame_done(v->xdg_surface->surface, &now); - wl_display_flush_clients(wl_state.display); - in_resize = 0; - } + wlr_xdg_surface_schedule_configure(v->xdg_surface); return; } struct wl_frame_buf *fb = frame_buf_find(win); @@ -6518,6 +6581,8 @@ static void wl_window_resize(WNativeWindow win, int w, int h) fb->height = h; fb->base.width = w; fb->base.height = h; + if (fb->scene_buf) + wlr_scene_buffer_set_buffer(fb->scene_buf, NULL); } } static void wl_window_set_border(WNativeWindow win, unsigned long pixel) @@ -6768,7 +6833,8 @@ wl_client_reparent(WNativeWindow client, WNativeWindow new_parent, int x, int y) /* Move client's scene tree under the frame's tree */ if (parent_fb->tree) wlr_scene_node_reparent(&v->scene_node->node, parent_fb->tree); - wlr_scene_node_set_position(&v->scene_node->node, v->x, v->y); + /* Position at relative offset within the tree */ + wlr_scene_node_set_position(&v->scene_node->node, x, y); } } return; @@ -6791,8 +6857,7 @@ wl_client_reparent(WNativeWindow client, WNativeWindow new_parent, int x, int y) existing->x = parent_fb->x + x; existing->y = parent_fb->y + y; if (existing->scene_buf) - wlr_scene_node_set_position(&existing->scene_buf->node, - existing->x, existing->y); + wlr_scene_node_set_position(&existing->scene_buf->node, x, y); return; } @@ -6850,17 +6915,18 @@ wl_client_reparent(WNativeWindow client, WNativeWindow new_parent, int x, int y) fb->rel_y = y; fb->x = parent_fb->x + x; fb->y = parent_fb->y + y; - if (fb->scene_buf) - wlr_scene_node_set_position(&fb->scene_buf->node, fb->x, fb->y); - /* Also update children of the reparented frame_buf */ + if (fb->scene_buf) { + /* Reparent under parent's tree and use relative position */ + if (parent_fb->tree) + wlr_scene_node_reparent(&fb->scene_buf->node, parent_fb->tree); + wlr_scene_node_set_position(&fb->scene_buf->node, x, y); + } + /* Update absolute tracking for children */ struct wl_frame_buf *child; wl_list_for_each(child, &wl_state.frame_list, link) { if (child->parent_id == client) { child->x = fb->x + child->rel_x; child->y = fb->y + child->rel_y; - if (child->scene_buf) - wlr_scene_node_set_position(&child->scene_buf->node, - child->x, child->y); } } } @@ -6901,9 +6967,6 @@ wl_client_synth_configure(WNativeWindow client_win, if (!v) return; v->x = x; v->y = y; - /* Phase 18: keep scene node in sync. */ - if (v->scene_node) - wlr_scene_node_set_position(&v->scene_node->node, x, y); /* Update relative offset so frame_configure keeps us in sync. */ if (v->frame_id) { struct wl_frame_buf *pfb = frame_buf_find(v->frame_id); @@ -6911,6 +6974,14 @@ wl_client_synth_configure(WNativeWindow client_win, v->frame_rel_x = x - pfb->x; v->frame_rel_y = y - pfb->y; } + /* Scene node is child of frame tree — use relative coords */ + if (v->scene_node) + wlr_scene_node_set_position(&v->scene_node->node, + v->frame_rel_x, v->frame_rel_y); + } else { + /* No frame — use absolute coords */ + if (v->scene_node) + wlr_scene_node_set_position(&v->scene_node->node, x, y); } if (v->xw_surface) { wlr_xwayland_surface_configure(v->xw_surface,