From 273589092d12622f5e45b7e4fa71630fcc69fae1 Mon Sep 17 00:00:00 2001 From: Window Maker Date: Tue, 2 Jun 2026 10:18:57 +0200 Subject: [PATCH] decompose wl_backend.c: extract wl_window.c (window map/unmap/move/resize/border/clear) --- src/Makefile.am | 3 +- src/backend/wayland/wl_backend.c | 370 +---------------------------- src/backend/wayland/wl_types.h | 27 +++ src/backend/wayland/wl_window.c | 391 +++++++++++++++++++++++++++++++ 4 files changed, 424 insertions(+), 367 deletions(-) create mode 100644 src/backend/wayland/wl_window.c diff --git a/src/Makefile.am b/src/Makefile.am index 860523f..f35c5b1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -161,7 +161,8 @@ wmaker_SOURCES += \ backend/wayland/wl_context.c \ backend/wayland/wl_event.c \ backend/wayland/wl_stacking.c \ - backend/wayland/wl_overlay.c + backend/wayland/wl_overlay.c \ + backend/wayland/wl_window.c endif if USE_NESTED_FUNC diff --git a/src/backend/wayland/wl_backend.c b/src/backend/wayland/wl_backend.c index 42a21e8..6f61e3d 100644 --- a/src/backend/wayland/wl_backend.c +++ b/src/backend/wayland/wl_backend.c @@ -326,7 +326,7 @@ static int wl_client_get_pid(WNativeWindow win); static void wl_update_pointer_focus(uint32_t time_msec); static void wl_pointer_warp_to(int x, int y); /* wmaker-popup-v1 helper — defined in protocol section below. */ -static void wmaker_popup_apply(struct wl_toplevel_view *view); +void wmaker_popup_apply(struct wl_toplevel_view *view); /* Phase 14: pointer event handler forward declarations. */ static void handle_pointer_motion(struct wl_listener *listener, void *data); /* Phase 24: click-to-focus helper — defined in Phase 13 pointer section. */ @@ -396,7 +396,7 @@ wl_find_view_by_id(WNativeWindow id) } /* Phase 65: look up the view for a given wlr_xdg_surface pointer. */ -static struct wl_toplevel_view * +struct wl_toplevel_view * wl_find_view_by_xdg_surface(struct wlr_xdg_surface *surf) { struct wl_toplevel_view *v; @@ -1081,7 +1081,7 @@ wmaker_popup_resource_destroy(struct wl_resource *resource) view->popup = NULL; } -static void +void wmaker_popup_apply(struct wl_toplevel_view *view) { if (!view || !view->popup) return; @@ -4062,7 +4062,7 @@ static void fb_attach_tree_listener(struct wl_frame_buf *fb) * to keep absolute-position tracking in sync after the parent moves. * Hit-testing (frame_buf_at, frame_buf_button_at) and click coordinate * translation depend on these fields being current. */ -static void +void frame_buf_update_children_abs(WNativeWindow parent_id) { struct wl_frame_buf *parent = frame_buf_find(parent_id); @@ -6339,41 +6339,7 @@ wl_prop_get_wm_class(WNativeWindow win, return 1; } -static Bool -wl_window_fetch_name(WNativeWindow win, char **name_out) -{ - /* Phase 41: XDG title / Phase 17: XWayland title. */ - struct wl_toplevel_view *v = wl_find_view_by_id(win); - const char *title = NULL; - if (v && v->xw_surface) - title = v->xw_surface->title; - else if (v && v->xdg_surface && v->xdg_surface->toplevel) - title = v->xdg_surface->toplevel->title; - if (title) { - *name_out = strdup(title); - return True; - } - *name_out = NULL; - return False; -} -static Bool -wl_window_get_icon_name(WNativeWindow win, char **name_out) -{ - /* Phase 60: return title for icon labels; Phase 17: XWayland path. */ - struct wl_toplevel_view *v = wl_find_view_by_id(win); - const char *title = NULL; - if (v && v->xw_surface) - title = v->xw_surface->title; - else if (v && v->xdg_surface && v->xdg_surface->toplevel) - title = v->xdg_surface->toplevel->title; - if (title) { - *name_out = strdup(title); - return True; - } - *name_out = NULL; - return False; -} static Bool wl_noop_screen_get_head_usable_area(WScreen *scr, int head, @@ -6384,15 +6350,6 @@ wl_noop_screen_get_head_usable_area(WScreen *scr, int head, return False; } -static void * -wl_window_get_icon_image(WNativeWindow win) -{ - /* For XWayland clients, parse _NET_WM_ICON via the Xwayland display. - * For native Wayland clients there is no equivalent (the upcoming - * xdg-toplevel-icon protocol is not yet wired). */ - if (!wl_state.x_display) return NULL; - return get_window_image_from_x11(wl_state.x_display, (WNativeWindow)win); -} static int wl_prop_get_wmaker_menu(WNativeWindow win, @@ -6459,333 +6416,14 @@ wl_prop_get_wm_state(WNativeWindow win, long **data_out) /* WNativeWindow map / unmap / geometry */ /* ------------------------------------------------------------------ */ -static void -wl_window_map(WNativeWindow win) -{ - struct wl_toplevel_view *v = wl_find_view_by_id(win); - if (v && v->scene_node) { - wlr_scene_node_set_enabled(&v->scene_node->node, true); - return; - } - if (v) - return; - /* Frame buffer: enable its scene node and children. */ - struct wl_frame_buf *fb = frame_buf_find(win); - if (fb && fb->scene_buf) { - /* If this is a child, only enable if parent is enabled */ - if (fb->parent_id) { - struct wl_frame_buf *parent = frame_buf_find(fb->parent_id); - if (parent && parent->scene_buf && - !parent->scene_buf->node.enabled) - return; /* parent not visible yet */ - } - wlr_scene_node_set_enabled(&fb->scene_buf->node, true); - /* Raise the tree (raises entire window assembly together) */ - if (fb->tree) { - wlr_scene_node_set_enabled(&fb->tree->node, true); - wlr_scene_node_raise_to_top(&fb->tree->node); - } else if (!fb->parent_id) - wlr_scene_node_raise_to_top(&fb->scene_buf->node); - /* Also enable children (and grandchildren) */ - struct wl_frame_buf *child; - wl_list_for_each(child, &wl_state.frame_list, link) { - if (child->parent_id == win && child->scene_buf) { - wlr_scene_node_set_enabled(&child->scene_buf->node, true); - struct wl_frame_buf *gc; - wl_list_for_each(gc, &wl_state.frame_list, link) { - if (gc->parent_id == child->id && gc->scene_buf) - wlr_scene_node_set_enabled(&gc->scene_buf->node, true); - } - } - } - return; - } -} -static void -wl_window_map_raised(WNativeWindow win) -{ - struct wl_toplevel_view *v = wl_find_view_by_id(win); - if (v && v->scene_node) { - wlr_scene_node_set_enabled(&v->scene_node->node, true); - if (v->frame_id) { - struct wl_frame_buf *fb = frame_buf_find(v->frame_id); - if (fb && fb->tree) { - wlr_scene_node_raise_to_top(&fb->tree->node); - return; - } - } - wlr_scene_node_raise_to_top(&v->scene_node->node); - return; - } - struct wl_frame_buf *fb = frame_buf_find(win); - if (fb && fb->scene_buf) { - wlr_scene_node_set_enabled(&fb->scene_buf->node, true); - if (fb->tree) { - /* Top-level frame: enable tree (decoration children become visible). */ - wlr_scene_node_set_enabled(&fb->tree->node, true); - wlr_scene_node_raise_to_top(&fb->tree->node); - } else { - wlr_scene_node_raise_to_top(&fb->scene_buf->node); - } - return; - } -} -static void wl_window_map_subwindows(WNativeWindow parent) -{ - (void)parent; - /* Child windows are sub-regions of the frame buffer — no-op. */ -} -static void -wl_window_unmap(WNativeWindow win) -{ - struct wl_toplevel_view *v = wl_find_view_by_id(win); - if (v && v->scene_node) { - wlr_scene_node_set_enabled(&v->scene_node->node, false); - return; - } - struct wl_frame_buf *fb = frame_buf_find(win); - if (!fb) return; - /* For top-level frames, disable the whole tree. This hides the frame - * buffer, all child scene_bufs (titlebar, resizebar, buttons), and the - * client surface reparented into fb->tree — atomically and irrevocably - * until the frame is explicitly mapped again. Disabling individual - * child nodes is insufficient because a subsequent wl_frame_paint can - * re-enable them while the window is still iconified. */ - if (fb->tree) { - wlr_scene_node_set_enabled(&fb->tree->node, false); - return; - } - /* Child frame_buf: disable its scene_buf node only. */ - if (fb->scene_buf) - wlr_scene_node_set_enabled(&fb->scene_buf->node, false); -} -static void wl_window_move(WNativeWindow win, int x, int y) -{ - struct wl_toplevel_view *v = wl_find_view_by_id(win); - if (v) { - if (v->frame_id) { - /* Client is a child of a frame — coords are relative to frame */ - v->frame_rel_x = x; - v->frame_rel_y = y; - struct wl_frame_buf *fb = frame_buf_find(v->frame_id); - if (fb) { - v->x = fb->x + x; - v->y = fb->y + y; - } - } else { - v->x = x; v->y = 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, - v->xw_surface->width, v->xw_surface->height); - /* Re-apply any popups whose parent is this toplevel so they - * track the parent's position. */ - struct wl_toplevel_view *p; - wl_list_for_each(p, &wl_state.toplevel_list, link) { - if (p->popup && p->popup_parent - && wl_find_view_by_xdg_surface(p->popup_parent->base) == v) { - wmaker_popup_apply(p); - } - } - return; - } - struct wl_frame_buf *fb = frame_buf_find(win); - if (fb) { - fb->rel_x = x; fb->rel_y = y; - if (fb->parent_id) { - struct wl_frame_buf *parent = frame_buf_find(fb->parent_id); - if (parent) { - fb->x = parent->x + x; - fb->y = parent->y + 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); - } - /* Update absolute position tracking for hit-testing — recursively - * for all descendants so grandchildren (e.g. WINGs panel inside - * a fake_leader inside a WMaker frame) stay in sync. */ - frame_buf_update_children_abs(win); - return; - } -} -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; - 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); - return; - } - 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); - return; - } - struct wl_frame_buf *fb = frame_buf_find(win); - if (fb && w > 0 && h > 0 && (w != fb->width || h != fb->height)) { - pixman_image_unref(fb->image); - fb->image = pixman_image_create_bits(PIXMAN_a8r8g8b8, w, h, NULL, 0); - fb->width = w; - fb->height = h; - fb->base.width = w; - fb->base.height = h; - /* Update scene graph's cached buffer size for hit-testing. */ - if (fb->scene_buf) - wlr_scene_buffer_set_dest_size(fb->scene_buf, w, h); - } -} -static void wl_window_set_border(WNativeWindow win, unsigned long pixel) -{ - (void)win; (void)pixel; /* borders are drawn into the frame buffer */ -} -static void wl_window_set_border_width(WNativeWindow win, int width) -{ - (void)win; (void)width; /* no-op for native frames */ -} -static void wl_window_set_save_under(WNativeWindow win, int save_under) { (void)win; (void)save_under; } -static void wl_noop_window_set_background(WNativeWindow win, unsigned long pixel) { (void)win; (void)pixel; } -extern void *W_GetViewBacking(unsigned long id); -static void wl_window_set_background_pixmap(WNativeWindow win, unsigned long pixmap) -{ - if (pixmap == 0) return; - struct wl_frame_buf *fb = frame_buf_find(win); - pixman_image_t *dst_img = NULL; - if (fb && fb->image) { - dst_img = fb->image; - fb->bg_pixmap = (pixman_image_t *)(uintptr_t)pixmap; - } else { - dst_img = (pixman_image_t *)W_GetViewBacking(win); - } - if (!dst_img) return; - pixman_image_t *src = (pixman_image_t *)(uintptr_t)pixmap; - int src_w = pixman_image_get_width(src); - int src_h = pixman_image_get_height(src); - /* Blit source pixmap into frame_buf's image */ - pixman_image_composite32(PIXMAN_OP_SRC, - src, /* src */ - NULL, /* mask */ - dst_img, /* dest */ - 0, 0, /* src x,y */ - 0, 0, /* mask x,y */ - 0, 0, /* dest x,y */ - src_w < pixman_image_get_width(dst_img) ? src_w : pixman_image_get_width(dst_img), - src_h < pixman_image_get_height(dst_img) ? src_h : pixman_image_get_height(dst_img)); - if (fb) - wlr_scene_buffer_set_buffer_with_damage(fb->scene_buf, &fb->base, NULL); -} -static void wl_pixmap_free(unsigned long pixmap) -{ - if (pixmap == 0) return; - pixman_image_t *img = (pixman_image_t *)(uintptr_t)pixmap; - pixman_image_unref(img); -} -static void wl_window_clear(WNativeWindow win) -{ - struct wl_frame_buf *fb = frame_buf_find(win); - pixman_image_t *img = NULL; - - if (fb && fb->image) { - img = fb->image; - } else { - img = (pixman_image_t *)W_GetViewBacking(win); - } - if (!img) return; - - int width = pixman_image_get_width(img); - int height = pixman_image_get_height(img); - - /* If a background pixmap is set, repaint from it (like XClearWindow) */ - if (fb && fb->bg_pixmap) { - pixman_image_composite32(PIXMAN_OP_SRC, - fb->bg_pixmap, NULL, img, - 0, 0, 0, 0, 0, 0, - width, height); - } else { - /* No background pixmap — fill with transparent black */ - int stride = pixman_image_get_stride(img); - uint32_t *data = (uint32_t *)pixman_image_get_data(img); - memset(data, 0, stride * height); - } - - /* Notify the scene buffer of the update */ - if (fb) - wlr_scene_buffer_set_buffer_with_damage(fb->scene_buf, &fb->base, NULL); -} - -static int -wl_window_get_rect(WNativeWindow win, - int *win_x, int *win_y, int *win_w, int *win_h) -{ - /* Phase 55: return real geometry for synthetic toplevel IDs. */ - if (win == WNATIVE_NONE) { - if (win_x) { *win_x = 0; } if (win_y) { *win_y = 0; } - if (win_w) { *win_w = 1; } if (win_h) { *win_h = 1; } - return 0; /* invalid/none */ - } - struct wl_toplevel_view *v = wl_find_view_by_id(win); - /* Phase 17: XWayland geometry. */ - if (v && v->xw_surface) { - if (win_x) { *win_x = v->x; } - if (win_y) { *win_y = v->y; } - if (win_w) { *win_w = v->xw_surface->width > 0 ? v->xw_surface->width : 1; } - if (win_h) { *win_h = v->xw_surface->height > 0 ? v->xw_surface->height : 1; } - return 1; - } - if (v && v->xdg_surface && v->xdg_surface->surface) { - int w = v->xdg_surface->surface->current.width; - int h = v->xdg_surface->surface->current.height; - if (win_x) { *win_x = v->x; } - if (win_y) { *win_y = v->y; } - if (win_w) { *win_w = w > 0 ? w : 1; } - if (win_h) { *win_h = h > 0 ? h : 1; } - return 1; - } - /* Frame buffer geometry. */ - struct wl_frame_buf *fb = frame_buf_find(win); - if (fb) { - if (win_x) { *win_x = fb->x; } - if (win_y) { *win_y = fb->y; } - if (win_w) { *win_w = fb->width; } - if (win_h) { *win_h = fb->height; } - return 1; - } - /* Synthetic child IDs (titlebar, buttons) — return minimal geometry. */ - if (win_x) { *win_x = 0; } if (win_y) { *win_y = 0; } - if (win_w) { *win_w = 1; } if (win_h) { *win_h = 1; } - return 0; -} - -static void wl_window_add_events(WNativeWindow win, unsigned long extra_mask) { (void)win; (void)extra_mask; } -static void wl_window_select_events(WNativeWindow win, unsigned long mask) { (void)win; (void)mask; } - -static void wl_window_shape_clear(WWindow *wwin) { (void)wwin; } -void wl_window_shape_set(WWindow *wwin) { (void)wwin; } /* ------------------------------------------------------------------ */ /* Client */ diff --git a/src/backend/wayland/wl_types.h b/src/backend/wayland/wl_types.h index e261c2b..076cc4a 100644 --- a/src/backend/wayland/wl_types.h +++ b/src/backend/wayland/wl_types.h @@ -423,3 +423,30 @@ int wl_overlay_text_width(WScreen *scr, const char *str, int n); void wl_window_shape_set(WWindow *wwin); + +/* Window module declarations (extracted to wl_window.c) */ +Bool wl_window_fetch_name(WNativeWindow win, char **name_out); +Bool wl_window_get_icon_name(WNativeWindow win, char **name_out); +void *wl_window_get_icon_image(WNativeWindow win); +void wl_window_map(WNativeWindow win); +void wl_window_map_raised(WNativeWindow win); +void wl_window_map_subwindows(WNativeWindow parent); +void wl_window_unmap(WNativeWindow win); +void wl_window_move(WNativeWindow win, int x, int y); +void wl_window_resize(WNativeWindow win, int w, int h); +void wl_window_set_border(WNativeWindow win, unsigned long pixel); +void wl_window_set_border_width(WNativeWindow win, int width); +void wl_window_set_save_under(WNativeWindow win, int save_under); +void wl_noop_window_set_background(WNativeWindow win, unsigned long pixel); +void wl_window_set_background_pixmap(WNativeWindow win, unsigned long pixmap); +void wl_pixmap_free(unsigned long pixmap); +void wl_window_clear(WNativeWindow win); +int wl_window_get_rect(WNativeWindow win, int *win_x, int *win_y, int *win_w, int *win_h); +void wl_window_add_events(WNativeWindow win, unsigned long extra_mask); +void wl_window_select_events(WNativeWindow win, unsigned long mask); +void wl_window_shape_clear(WWindow *wwin); + +/* Functions shared among wl_*.c modules */ +struct wl_toplevel_view *wl_find_view_by_xdg_surface(struct wlr_xdg_surface *surf); +void wmaker_popup_apply(struct wl_toplevel_view *view); +void frame_buf_update_children_abs(WNativeWindow parent_id); diff --git a/src/backend/wayland/wl_window.c b/src/backend/wayland/wl_window.c new file mode 100644 index 0000000..ef2ba31 --- /dev/null +++ b/src/backend/wayland/wl_window.c @@ -0,0 +1,391 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include +#include +#include +#include +#include +#include +#include +#include "../../screen.h" +#include "wl_types.h" + +/* Forward declarations from sibling modules. */ +struct wl_toplevel_view *wl_find_view_by_xdg_surface(struct wlr_xdg_surface *surf); +void wmaker_popup_apply(struct wl_toplevel_view *view); +void frame_buf_update_children_abs(WNativeWindow parent_id); +struct wl_frame_buf *frame_buf_find(WNativeWindow id); +struct wl_toplevel_view *wl_find_view_by_id(WNativeWindow id); +pixman_image_t *get_window_image_from_x11(Display *x_display, WNativeWindow win); + + +Bool +wl_window_fetch_name(WNativeWindow win, char **name_out) +{ + /* Phase 41: XDG title / Phase 17: XWayland title. */ + struct wl_toplevel_view *v = wl_find_view_by_id(win); + const char *title = NULL; + if (v && v->xw_surface) + title = v->xw_surface->title; + else if (v && v->xdg_surface && v->xdg_surface->toplevel) + title = v->xdg_surface->toplevel->title; + if (title) { + *name_out = strdup(title); + return True; + } + *name_out = NULL; + return False; +} +Bool +wl_window_get_icon_name(WNativeWindow win, char **name_out) +{ + /* Phase 60: return title for icon labels; Phase 17: XWayland path. */ + struct wl_toplevel_view *v = wl_find_view_by_id(win); + const char *title = NULL; + if (v && v->xw_surface) + title = v->xw_surface->title; + else if (v && v->xdg_surface && v->xdg_surface->toplevel) + title = v->xdg_surface->toplevel->title; + if (title) { + *name_out = strdup(title); + return True; + } + *name_out = NULL; + return False; +} +void * +wl_window_get_icon_image(WNativeWindow win) +{ + /* For XWayland clients, parse _NET_WM_ICON via the Xwayland display. + * For native Wayland clients there is no equivalent (the upcoming + * xdg-toplevel-icon protocol is not yet wired). */ + if (!wl_state.x_display) return NULL; + return get_window_image_from_x11(wl_state.x_display, (WNativeWindow)win); +} +void +wl_window_map(WNativeWindow win) +{ + struct wl_toplevel_view *v = wl_find_view_by_id(win); + if (v && v->scene_node) { + wlr_scene_node_set_enabled(&v->scene_node->node, true); + return; + } + if (v) + return; + /* Frame buffer: enable its scene node and children. */ + struct wl_frame_buf *fb = frame_buf_find(win); + if (fb && fb->scene_buf) { + /* If this is a child, only enable if parent is enabled */ + if (fb->parent_id) { + struct wl_frame_buf *parent = frame_buf_find(fb->parent_id); + if (parent && parent->scene_buf && + !parent->scene_buf->node.enabled) + return; /* parent not visible yet */ + } + wlr_scene_node_set_enabled(&fb->scene_buf->node, true); + /* Raise the tree (raises entire window assembly together) */ + if (fb->tree) { + wlr_scene_node_set_enabled(&fb->tree->node, true); + wlr_scene_node_raise_to_top(&fb->tree->node); + } else if (!fb->parent_id) + wlr_scene_node_raise_to_top(&fb->scene_buf->node); + /* Also enable children (and grandchildren) */ + struct wl_frame_buf *child; + wl_list_for_each(child, &wl_state.frame_list, link) { + if (child->parent_id == win && child->scene_buf) { + wlr_scene_node_set_enabled(&child->scene_buf->node, true); + struct wl_frame_buf *gc; + wl_list_for_each(gc, &wl_state.frame_list, link) { + if (gc->parent_id == child->id && gc->scene_buf) + wlr_scene_node_set_enabled(&gc->scene_buf->node, true); + } + } + } + return; + } +} +void +wl_window_map_raised(WNativeWindow win) +{ + struct wl_toplevel_view *v = wl_find_view_by_id(win); + if (v && v->scene_node) { + wlr_scene_node_set_enabled(&v->scene_node->node, true); + if (v->frame_id) { + struct wl_frame_buf *fb = frame_buf_find(v->frame_id); + if (fb && fb->tree) { + wlr_scene_node_raise_to_top(&fb->tree->node); + return; + } + } + wlr_scene_node_raise_to_top(&v->scene_node->node); + return; + } + struct wl_frame_buf *fb = frame_buf_find(win); + if (fb && fb->scene_buf) { + wlr_scene_node_set_enabled(&fb->scene_buf->node, true); + if (fb->tree) { + /* Top-level frame: enable tree (decoration children become visible). */ + wlr_scene_node_set_enabled(&fb->tree->node, true); + wlr_scene_node_raise_to_top(&fb->tree->node); + } else { + wlr_scene_node_raise_to_top(&fb->scene_buf->node); + } + return; + } +} + +void wl_window_map_subwindows(WNativeWindow parent) +{ + (void)parent; + /* Child windows are sub-regions of the frame buffer — no-op. */ +} +void +wl_window_unmap(WNativeWindow win) +{ + struct wl_toplevel_view *v = wl_find_view_by_id(win); + if (v && v->scene_node) { + wlr_scene_node_set_enabled(&v->scene_node->node, false); + return; + } + struct wl_frame_buf *fb = frame_buf_find(win); + if (!fb) return; + /* For top-level frames, disable the whole tree. This hides the frame + * buffer, all child scene_bufs (titlebar, resizebar, buttons), and the + * client surface reparented into fb->tree — atomically and irrevocably + * until the frame is explicitly mapped again. Disabling individual + * child nodes is insufficient because a subsequent wl_frame_paint can + * re-enable them while the window is still iconified. */ + if (fb->tree) { + wlr_scene_node_set_enabled(&fb->tree->node, false); + return; + } + /* Child frame_buf: disable its scene_buf node only. */ + if (fb->scene_buf) + wlr_scene_node_set_enabled(&fb->scene_buf->node, false); +} + +void wl_window_move(WNativeWindow win, int x, int y) +{ + struct wl_toplevel_view *v = wl_find_view_by_id(win); + if (v) { + if (v->frame_id) { + /* Client is a child of a frame — coords are relative to frame */ + v->frame_rel_x = x; + v->frame_rel_y = y; + struct wl_frame_buf *fb = frame_buf_find(v->frame_id); + if (fb) { + v->x = fb->x + x; + v->y = fb->y + y; + } + } else { + v->x = x; v->y = 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, + v->xw_surface->width, v->xw_surface->height); + /* Re-apply any popups whose parent is this toplevel so they + * track the parent's position. */ + struct wl_toplevel_view *p; + wl_list_for_each(p, &wl_state.toplevel_list, link) { + if (p->popup && p->popup_parent + && wl_find_view_by_xdg_surface(p->popup_parent->base) == v) { + wmaker_popup_apply(p); + } + } + return; + } + struct wl_frame_buf *fb = frame_buf_find(win); + if (fb) { + fb->rel_x = x; fb->rel_y = y; + if (fb->parent_id) { + struct wl_frame_buf *parent = frame_buf_find(fb->parent_id); + if (parent) { + fb->x = parent->x + x; + fb->y = parent->y + 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); + } + /* Update absolute position tracking for hit-testing — recursively + * for all descendants so grandchildren (e.g. WINGs panel inside + * a fake_leader inside a WMaker frame) stay in sync. */ + frame_buf_update_children_abs(win); + return; + } +} +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; + 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); + return; + } + 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); + return; + } + struct wl_frame_buf *fb = frame_buf_find(win); + if (fb && w > 0 && h > 0 && (w != fb->width || h != fb->height)) { + pixman_image_unref(fb->image); + fb->image = pixman_image_create_bits(PIXMAN_a8r8g8b8, w, h, NULL, 0); + fb->width = w; + fb->height = h; + fb->base.width = w; + fb->base.height = h; + /* Update scene graph's cached buffer size for hit-testing. */ + if (fb->scene_buf) + wlr_scene_buffer_set_dest_size(fb->scene_buf, w, h); + } +} + +void wl_window_set_border(WNativeWindow win, unsigned long pixel) +{ + (void)win; (void)pixel; /* borders are drawn into the frame buffer */ +} + +void wl_window_set_border_width(WNativeWindow win, int width) +{ + (void)win; (void)width; /* no-op for native frames */ +} + +void wl_window_set_save_under(WNativeWindow win, int save_under) { (void)win; (void)save_under; } +void wl_noop_window_set_background(WNativeWindow win, unsigned long pixel) { (void)win; (void)pixel; } + +extern void *W_GetViewBacking(unsigned long id); +void wl_window_set_background_pixmap(WNativeWindow win, unsigned long pixmap) +{ + if (pixmap == 0) return; + struct wl_frame_buf *fb = frame_buf_find(win); + pixman_image_t *dst_img = NULL; + + if (fb && fb->image) { + dst_img = fb->image; + fb->bg_pixmap = (pixman_image_t *)(uintptr_t)pixmap; + } else { + dst_img = (pixman_image_t *)W_GetViewBacking(win); + } + if (!dst_img) return; + + pixman_image_t *src = (pixman_image_t *)(uintptr_t)pixmap; + int src_w = pixman_image_get_width(src); + int src_h = pixman_image_get_height(src); + + /* Blit source pixmap into frame_buf's image */ + pixman_image_composite32(PIXMAN_OP_SRC, + src, /* src */ + NULL, /* mask */ + dst_img, /* dest */ + 0, 0, /* src x,y */ + 0, 0, /* mask x,y */ + 0, 0, /* dest x,y */ + src_w < pixman_image_get_width(dst_img) ? src_w : pixman_image_get_width(dst_img), + src_h < pixman_image_get_height(dst_img) ? src_h : pixman_image_get_height(dst_img)); + if (fb) + wlr_scene_buffer_set_buffer_with_damage(fb->scene_buf, &fb->base, NULL); +} +void wl_pixmap_free(unsigned long pixmap) +{ + if (pixmap == 0) return; + pixman_image_t *img = (pixman_image_t *)(uintptr_t)pixmap; + pixman_image_unref(img); +} + +void wl_window_clear(WNativeWindow win) +{ + struct wl_frame_buf *fb = frame_buf_find(win); + pixman_image_t *img = NULL; + + if (fb && fb->image) { + img = fb->image; + } else { + img = (pixman_image_t *)W_GetViewBacking(win); + } + if (!img) return; + + int width = pixman_image_get_width(img); + int height = pixman_image_get_height(img); + + /* If a background pixmap is set, repaint from it (like XClearWindow) */ + if (fb && fb->bg_pixmap) { + pixman_image_composite32(PIXMAN_OP_SRC, + fb->bg_pixmap, NULL, img, + 0, 0, 0, 0, 0, 0, + width, height); + } else { + /* No background pixmap — fill with transparent black */ + int stride = pixman_image_get_stride(img); + uint32_t *data = (uint32_t *)pixman_image_get_data(img); + memset(data, 0, stride * height); + } + + /* Notify the scene buffer of the update */ + if (fb) + wlr_scene_buffer_set_buffer_with_damage(fb->scene_buf, &fb->base, NULL); +} +int +wl_window_get_rect(WNativeWindow win, + int *win_x, int *win_y, int *win_w, int *win_h) +{ + /* Phase 55: return real geometry for synthetic toplevel IDs. */ + if (win == WNATIVE_NONE) { + if (win_x) { *win_x = 0; } if (win_y) { *win_y = 0; } + if (win_w) { *win_w = 1; } if (win_h) { *win_h = 1; } + return 0; /* invalid/none */ + } + struct wl_toplevel_view *v = wl_find_view_by_id(win); + /* Phase 17: XWayland geometry. */ + if (v && v->xw_surface) { + if (win_x) { *win_x = v->x; } + if (win_y) { *win_y = v->y; } + if (win_w) { *win_w = v->xw_surface->width > 0 ? v->xw_surface->width : 1; } + if (win_h) { *win_h = v->xw_surface->height > 0 ? v->xw_surface->height : 1; } + return 1; + } + if (v && v->xdg_surface && v->xdg_surface->surface) { + int w = v->xdg_surface->surface->current.width; + int h = v->xdg_surface->surface->current.height; + if (win_x) { *win_x = v->x; } + if (win_y) { *win_y = v->y; } + if (win_w) { *win_w = w > 0 ? w : 1; } + if (win_h) { *win_h = h > 0 ? h : 1; } + return 1; + } + /* Frame buffer geometry. */ + struct wl_frame_buf *fb = frame_buf_find(win); + if (fb) { + if (win_x) { *win_x = fb->x; } + if (win_y) { *win_y = fb->y; } + if (win_w) { *win_w = fb->width; } + if (win_h) { *win_h = fb->height; } + return 1; + } + /* Synthetic child IDs (titlebar, buttons) — return minimal geometry. */ + if (win_x) { *win_x = 0; } if (win_y) { *win_y = 0; } + if (win_w) { *win_w = 1; } if (win_h) { *win_h = 1; } + return 0; +} +void wl_window_add_events(WNativeWindow win, unsigned long extra_mask) { (void)win; (void)extra_mask; } +void wl_window_select_events(WNativeWindow win, unsigned long mask) { (void)win; (void)mask; } +void wl_window_shape_clear(WWindow *wwin) { (void)wwin; } +void wl_window_shape_set(WWindow *wwin) { (void)wwin; }