decompose wl_backend.c: extract wl_window.c (window map/unmap/move/resize/border/clear)

This commit is contained in:
Window Maker 2026-06-02 10:18:57 +02:00
parent b9450d16ad
commit 273589092d
4 changed files with 424 additions and 367 deletions

View File

@ -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

View File

@ -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 */

View File

@ -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);

View File

@ -0,0 +1,391 @@
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <string.h>
#include <stdlib.h>
#include <pixman.h>
#include <wayland-server-core.h>
#include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_xdg_shell.h>
#include <wlr/xwayland.h>
#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; }