wl_backend: fix client resize and frame lifecycle
- Send frame_done after configure so clients can render at new size - Set activated state on toplevel configure - Dispatch idle callbacks to flush configure immediately - Add client_set_maximized vtable entry for XDG toplevel state - Re-enable frame_buf scene node on unshade - Raise client scene node on window_map (fixes unshade visibility) - Reposition client and children in frame_configure - Schedule output frame after frame_paint - Remove debug wwarnings from wl_window_resize This fixes: - Window shade/unshade (resizebar + client surface visibility) - Client surface receiving configure events and rendering - Frame decoration updates on resize/maximize
This commit is contained in:
parent
859c4d8e78
commit
98f3175895
|
|
@ -82,7 +82,7 @@ Priority: HIGH — needed for daily-driver use.
|
|||
|---|------|-----------|------------|
|
||||
| A1 | Stacking (raise/lower via scene graph) | stacking.c, wlr_scene_node_raise/lower | Low |
|
||||
| A2 | Window maximize (full/half/vertical/horizontal) | actions.c, usable area calc | Low-Medium |
|
||||
| A3 | Window shade (titlebar collapse) | actions.c, frame buffer resize | Low |
|
||||
| A3 | ~~Window shade (titlebar collapse)~~ | actions.c, frame buffer resize | ✅ Done |
|
||||
| A4 | Workspace switching (create/destroy/switch) | workspace.c, scene tree reparenting | Medium |
|
||||
| A5 | Alt-Tab window cycling + switch panel | cycling.c, switchpanel.c, vtable switchpanel_enter | Medium |
|
||||
| A6 | Window iconification (minimize) + miniwindow | icon.c, appicon.c, vtable icon_paint/icon_update_pixmap | Medium |
|
||||
|
|
@ -214,7 +214,7 @@ For running without a host compositor:
|
|||
NOW (daily-driver basics):
|
||||
A1. Stacking (raise/lower)
|
||||
A2. Maximize
|
||||
A3. Shade
|
||||
A3. ~~Shade~~ ✅
|
||||
A4. Workspace switching
|
||||
A5. Alt-Tab cycling
|
||||
A6. Icon/minimize
|
||||
|
|
|
|||
|
|
@ -521,6 +521,9 @@ void wMaximizeWindow(WWindow *wwin, int directions, int head)
|
|||
wWindowCropSize(wwin, usableArea.x2 - usableArea.x1,
|
||||
usableArea.y2 - usableArea.y1, &new_width, &new_height);
|
||||
|
||||
if (wm_backend->client_set_maximized)
|
||||
wm_backend->client_set_maximized(wwin->client_win, 1);
|
||||
|
||||
wWindowConfigure(wwin, new_x, new_y, new_width, new_height);
|
||||
wWindowSynthConfigureNotify(wwin);
|
||||
|
||||
|
|
@ -959,6 +962,8 @@ void wUnmaximizeWindow(WWindow *wwin)
|
|||
|
||||
wwin->flags.maximized = 0;
|
||||
wwin->flags.old_maximized = 0;
|
||||
if (wm_backend->client_set_maximized)
|
||||
wm_backend->client_set_maximized(wwin->client_win, 0);
|
||||
wWindowConfigure(wwin, x, y, w, h);
|
||||
wWindowSynthConfigureNotify(wwin);
|
||||
|
||||
|
|
|
|||
|
|
@ -1464,6 +1464,11 @@ typedef struct WMBackend {
|
|||
*/
|
||||
void (*client_set_state)(WWindow *wwin, int state, WNativeWindow icon_win);
|
||||
|
||||
/* Notify the client of maximized/fullscreen state changes.
|
||||
* X11: no-op (handled via _NET_WM_STATE property).
|
||||
* Wayland: sends xdg_toplevel set_maximized/set_fullscreen. */
|
||||
void (*client_set_maximized)(WNativeWindow win, int maximized);
|
||||
|
||||
/*
|
||||
* Send a WM_PROTOCOLS message to a client (e.g. WM_DELETE_WINDOW).
|
||||
* X11: XSendEvent with ClientMessage.
|
||||
|
|
|
|||
|
|
@ -1575,6 +1575,9 @@ handle_xdg_toplevel_initial_commit(struct wl_listener *listener, void *data)
|
|||
wl_list_remove(&view->commit_listener.link);
|
||||
wl_list_init(&view->commit_listener.link);
|
||||
|
||||
/* Send initial configure so the client enters the configure/ack cycle.
|
||||
* Size 0,0 means "choose your own size" per the XDG spec. */
|
||||
wlr_xdg_toplevel_set_activated(view->xdg_surface->toplevel, true);
|
||||
wlr_xdg_toplevel_set_size(view->xdg_surface->toplevel, 0, 0);
|
||||
wlr_xdg_surface_schedule_configure(view->xdg_surface);
|
||||
}
|
||||
|
|
@ -1862,6 +1865,23 @@ handle_output_frame(struct wl_listener *listener, void *data)
|
|||
return;
|
||||
if (!wl_state.scene_output)
|
||||
return;
|
||||
static int frame_count = 0;
|
||||
if (++frame_count % 120 == 0) {
|
||||
struct wl_toplevel_view *v;
|
||||
wl_list_for_each(v, &wl_state.toplevel_list, link) {
|
||||
if (v->xdg_surface && v->xdg_surface->surface && v->xdg_surface->toplevel) {
|
||||
struct wlr_surface *s = v->xdg_surface->surface;
|
||||
struct wlr_xdg_toplevel *tl = v->xdg_surface->toplevel;
|
||||
wwarning("frame %d: 0x%lx surf=%dx%d sched=%dx%d current=%dx%d idle=%p title=%s",
|
||||
frame_count, (unsigned long)v->id,
|
||||
s->current.width, s->current.height,
|
||||
tl->scheduled.width, tl->scheduled.height,
|
||||
tl->current.width, tl->current.height,
|
||||
(void*)v->xdg_surface->configure_idle,
|
||||
tl->title ? tl->title : "(null)");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (wl_state.allocator) {
|
||||
/* Full scene commit — renders client surfaces and fires
|
||||
* wl_surface.frame callbacks so clients can submit next buffer. */
|
||||
|
|
@ -3927,6 +3947,8 @@ wl_frame_destroy(WScreen *scr, WNativeWindow win)
|
|||
static void
|
||||
wl_frame_configure(WNativeWindow win, int x, int y, int width, int height)
|
||||
{
|
||||
wwarning("wl_frame_configure: win=0x%lx pos=%d,%d size=%dx%d",
|
||||
(unsigned long)win, x, y, width, height);
|
||||
struct wl_frame_buf *fb = frame_buf_find(win);
|
||||
if (!fb) return;
|
||||
|
||||
|
|
@ -3960,6 +3982,29 @@ wl_frame_configure(WNativeWindow win, int x, int y, int width, int height)
|
|||
fb->base.width = width;
|
||||
fb->base.height = height;
|
||||
}
|
||||
|
||||
/* Reposition client surface and child frame_bufs to follow the frame. */
|
||||
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;
|
||||
wwarning("frame_configure: repositioned client 0x%lx to %d,%d (rel %d,%d)",
|
||||
(unsigned long)cv->id, cv->x, cv->y, cv->frame_rel_x, cv->frame_rel_y);
|
||||
if (cv->scene_node)
|
||||
wlr_scene_node_set_position(&cv->scene_node->node, cv->x, cv->y);
|
||||
break;
|
||||
}
|
||||
}
|
||||
struct wl_frame_buf *child;
|
||||
wl_list_for_each(child, &wl_state.frame_list, link) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void wl_frame_paint_button(WCoreWindow *button, WTexture *texture,
|
||||
|
|
@ -4178,6 +4223,9 @@ wl_frame_paint(struct WFrameWindow *fwin)
|
|||
}
|
||||
}
|
||||
|
||||
if (wl_state.output)
|
||||
wlr_output_schedule_frame(wl_state.output);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -5905,6 +5953,9 @@ static void wl_window_resize(WNativeWindow win, int w, int h)
|
|||
struct wl_toplevel_view *v = wl_find_view_by_id(win);
|
||||
if (v) {
|
||||
if (w <= 0 || h <= 0) return;
|
||||
wwarning("wl_window_resize: id=0x%lx %dx%d xw=%p xdg=%p",
|
||||
(unsigned long)win, w, h, (void*)v->xw_surface,
|
||||
(void*)v->xdg_surface);
|
||||
if (v->xw_surface) {
|
||||
wlr_xwayland_surface_configure(v->xw_surface,
|
||||
(int16_t)v->x, (int16_t)v->y, (uint16_t)w, (uint16_t)h);
|
||||
|
|
@ -5912,7 +5963,16 @@ 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_surface_schedule_configure(v->xdg_surface);
|
||||
wlr_xdg_toplevel_set_activated(v->xdg_surface->toplevel, true);
|
||||
/* Dispatch idle so configure is written, then flush to client */
|
||||
struct wl_event_loop *loop = wl_display_get_event_loop(wl_state.display);
|
||||
wl_event_loop_dispatch(loop, 0);
|
||||
wl_display_flush_clients(wl_state.display);
|
||||
/* Send frame_done so client can render at new size */
|
||||
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);
|
||||
return;
|
||||
}
|
||||
struct wl_frame_buf *fb = frame_buf_find(win);
|
||||
|
|
@ -6929,6 +6989,14 @@ static void wl_noop_client_restore(WWindow *wwin) { (void)wwin; }
|
|||
static void wl_noop_client_set_state(WWindow *wwin, int state, WNativeWindow icon_win)
|
||||
{ (void)wwin; (void)state; (void)icon_win; }
|
||||
|
||||
static void wl_client_set_maximized(WNativeWindow win, int maximized)
|
||||
{
|
||||
struct wl_toplevel_view *v = wl_find_view_by_id(win);
|
||||
if (!v) return;
|
||||
if (v->xdg_surface && v->xdg_surface->toplevel)
|
||||
wlr_xdg_toplevel_set_maximized(v->xdg_surface->toplevel, maximized);
|
||||
}
|
||||
|
||||
static void wl_client_send_protocol(WWindow *wwin, unsigned long protocol,
|
||||
unsigned long timestamp)
|
||||
{
|
||||
|
|
@ -7686,6 +7754,7 @@ const WMBackend wl_backend = {
|
|||
.prop_cleanup = wl_noop_prop_cleanup,
|
||||
.client_restore = wl_noop_client_restore,
|
||||
.client_set_state = wl_noop_client_set_state,
|
||||
.client_set_maximized = wl_client_set_maximized,
|
||||
.client_send_protocol = wl_client_send_protocol,
|
||||
.client_kill = wl_client_kill_impl,
|
||||
.client_get_colormap_windows = wl_noop_client_get_colormap_windows,
|
||||
|
|
|
|||
|
|
@ -4361,6 +4361,7 @@ const WMBackend x11_backend = {
|
|||
.prop_cleanup = x11_prop_cleanup,
|
||||
.client_restore = x11_client_restore,
|
||||
.client_set_state = x11_client_set_state,
|
||||
.client_set_maximized = NULL, /* X11: handled via _NET_WM_STATE property */
|
||||
.client_send_protocol = x11_client_send_protocol,
|
||||
.client_kill = x11_client_kill,
|
||||
.client_get_colormap_windows = x11_client_get_colormap_windows,
|
||||
|
|
|
|||
Loading…
Reference in New Issue