Wayland backend: native frame rendering via pixman + wlr_scene_buffer
Architecture: frames are pixman images committed to wlr_scene_buffer nodes — no XWayland dependency for WM UI rendering. Key changes: - Add wl_frame_buf struct (pixman_image_t + wlr_buffer + scene_buffer) - Implement wlr_buffer_impl for frame buffers (begin_data_ptr_access) - frame_create_toplevel: allocates pixman buffer + scene node - frame_create_child: returns synthetic ID (sub-regions of parent) - frame_configure: repositions scene node, reallocates on resize - frame_destroy: destroys scene node and drops buffer - frame_paint: renders titlebar texture (via wTextureRenderImage), title text (via WMDrawString on pixman WMDrawable), and resizebar into the pixman buffer, then commits to scene graph - Add frame_paint vtable slot to WMBackend (backend.h) - wFrameWindowPaint: calls wm_backend->frame_paint first; falls through to Xlib code only if backend returns 0 - window_map/unmap/move: handle frame buffers via scene node ops - stacking_raise/lower: handle frame buffers - window_get_rect: return frame buffer geometry - Remove all XWayland calls from frame/window lifecycle The OR (override_redirect) surface handling remains for XWayland client windows that use override_redirect (tooltips, menus from X11 apps). The WM's own UI is now pure Wayland.
This commit is contained in:
parent
9b2448dd7f
commit
499d4fac7e
|
|
@ -37,6 +37,7 @@ typedef struct _WScreen WScreen;
|
|||
typedef struct WWindow WWindow;
|
||||
typedef struct GNUstepWMAttributes GNUstepWMAttributes;
|
||||
struct WObjDescriptor;
|
||||
struct WFrameWindow;
|
||||
|
||||
/*
|
||||
* WMBackend -- vtable for all display-system operations.
|
||||
|
|
@ -168,6 +169,16 @@ typedef struct WMBackend {
|
|||
*/
|
||||
void (*frame_configure)(WNativeWindow win, int x, int y, int width, int height);
|
||||
|
||||
/*
|
||||
* Render the complete frame decoration (titlebar, buttons, resizebar)
|
||||
* into the frame's backing store and make it visible.
|
||||
* X11: uses Xlib drawing on the frame sub-windows (the traditional path).
|
||||
* Wayland: renders into a pixman buffer and commits to the scene graph.
|
||||
* Returns 1 if the backend handled painting, 0 if the caller should
|
||||
* fall through to legacy Xlib code (X11 backend returns 0).
|
||||
*/
|
||||
int (*frame_paint)(struct WFrameWindow *fwin);
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Window context table (Phase 2) */
|
||||
/* */
|
||||
|
|
|
|||
|
|
@ -182,6 +182,9 @@
|
|||
#include "../../WindowMaker.h"
|
||||
#include "../../screen.h"
|
||||
#include "../../window.h"
|
||||
#include "../../framewin.h" /* WFrameWindow for frame_paint */
|
||||
#include "../../texture.h" /* WTexture, wTextureRenderImage */
|
||||
#include "../../misc.h" /* ShrinkString */
|
||||
#include "../../actions.h" /* Phase 16: wMaximizeWindow, wIconifyWindow, etc. */
|
||||
#include "../../stacking.h" /* Phase 24: wRaiseFrame for click-to-raise */
|
||||
#include "../../xinerama.h" /* Phase 16: wGetHeadForWindow */
|
||||
|
|
@ -265,6 +268,21 @@ struct wl_or_view {
|
|||
struct wl_list link; /* wl_state.or_list */
|
||||
};
|
||||
|
||||
/*
|
||||
* wl_frame_buf — a pixman-backed scene buffer for WM frame windows.
|
||||
* Each frame (titlebar + buttons + resizebar) is rendered into a single
|
||||
* ARGB pixman image and displayed via a wlr_scene_buffer node.
|
||||
*/
|
||||
struct wl_frame_buf {
|
||||
struct wlr_buffer base; /* wlr_buffer (must be first) */
|
||||
pixman_image_t *image; /* ARGB32 pixel data */
|
||||
struct wlr_scene_buffer *scene_buf; /* scene graph node */
|
||||
WNativeWindow id; /* synthetic ID (>= 0x10000000) */
|
||||
int x, y; /* position in output coords */
|
||||
int width, height;
|
||||
struct wl_list link; /* wl_state.frame_list */
|
||||
};
|
||||
|
||||
/*
|
||||
* Phase 36: wl_layer_view — one entry per mapped zwlr_layer_shell_v1 surface.
|
||||
* Tracks the wlroots layer surface, its scene node, and lifecycle listeners.
|
||||
|
|
@ -315,6 +333,7 @@ struct wl_compositor_state {
|
|||
/* Phase 38: per-toplevel view list and context store */
|
||||
struct wl_list toplevel_list; /* wl_toplevel_view.link */
|
||||
struct wl_list or_list; /* wl_or_view.link */
|
||||
struct wl_list frame_list; /* wl_frame_buf.link */
|
||||
struct wl_list layer_list; /* wl_layer_view.link */
|
||||
struct wl_list ctx_lists[3]; /* one per WContextKey */
|
||||
unsigned long next_synthetic_id; /* >= 0x10000000 */
|
||||
|
|
@ -2353,6 +2372,7 @@ wl_display_open(const char *name)
|
|||
/* Phase 38: initialise per-toplevel tracking and context store. */
|
||||
wl_list_init(&wl_state.toplevel_list);
|
||||
wl_list_init(&wl_state.or_list);
|
||||
wl_list_init(&wl_state.frame_list);
|
||||
wl_list_init(&wl_state.layer_list);
|
||||
{
|
||||
int ki;
|
||||
|
|
@ -3429,6 +3449,50 @@ wl_screen_open(WScreen *scr)
|
|||
|
||||
static void wl_screen_close(WScreen *scr) { (void)scr; }
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Frame buffer (pixman + wlr_scene_buffer) */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static void frame_buf_destroy(struct wlr_buffer *wlr_buf)
|
||||
{
|
||||
struct wl_frame_buf *fb = wl_container_of(wlr_buf, fb, base);
|
||||
if (fb->image)
|
||||
pixman_image_unref(fb->image);
|
||||
wfree(fb);
|
||||
}
|
||||
|
||||
static bool frame_buf_begin_data_ptr_access(struct wlr_buffer *wlr_buf,
|
||||
uint32_t flags, void **data, uint32_t *format, size_t *stride)
|
||||
{
|
||||
struct wl_frame_buf *fb = wl_container_of(wlr_buf, fb, base);
|
||||
(void)flags;
|
||||
*data = pixman_image_get_data(fb->image);
|
||||
*format = DRM_FORMAT_ARGB8888;
|
||||
*stride = (size_t)pixman_image_get_stride(fb->image);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void frame_buf_end_data_ptr_access(struct wlr_buffer *wlr_buf)
|
||||
{
|
||||
(void)wlr_buf;
|
||||
}
|
||||
|
||||
static const struct wlr_buffer_impl frame_buf_impl = {
|
||||
.destroy = frame_buf_destroy,
|
||||
.begin_data_ptr_access = frame_buf_begin_data_ptr_access,
|
||||
.end_data_ptr_access = frame_buf_end_data_ptr_access,
|
||||
};
|
||||
|
||||
static struct wl_frame_buf *
|
||||
frame_buf_find(WNativeWindow id)
|
||||
{
|
||||
struct wl_frame_buf *fb;
|
||||
wl_list_for_each(fb, &wl_state.frame_list, link) {
|
||||
if (fb->id == id) return fb;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Frame / window lifecycle */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
|
@ -3441,82 +3505,239 @@ wl_frame_create_toplevel(WScreen *scr,
|
|||
unsigned long colormap,
|
||||
WMPixel border_pixel)
|
||||
{
|
||||
if (!dpy)
|
||||
(void)border_width; (void)depth; (void)visual;
|
||||
(void)colormap; (void)border_pixel; (void)scr;
|
||||
|
||||
if (width <= 0) width = 1;
|
||||
if (height <= 0) height = 1;
|
||||
|
||||
struct wl_frame_buf *fb = wmalloc(sizeof(*fb));
|
||||
memset(fb, 0, sizeof(*fb));
|
||||
|
||||
fb->image = pixman_image_create_bits(PIXMAN_a8r8g8b8,
|
||||
width, height, NULL, 0);
|
||||
if (!fb->image) {
|
||||
wfree(fb);
|
||||
return WNATIVE_NONE;
|
||||
|
||||
int vmask;
|
||||
XSetWindowAttributes attribs;
|
||||
Window win;
|
||||
|
||||
vmask = CWBorderPixel | CWCursor | CWEventMask | CWOverrideRedirect | CWColormap;
|
||||
attribs.override_redirect = True;
|
||||
attribs.cursor = wPreferences.cursor[WCUR_NORMAL];
|
||||
attribs.background_pixmap = None;
|
||||
attribs.background_pixel = scr->black_pixel;
|
||||
attribs.border_pixel = border_pixel;
|
||||
attribs.event_mask = SubstructureRedirectMask | ButtonPressMask |
|
||||
ButtonReleaseMask | ButtonMotionMask |
|
||||
ExposureMask | EnterWindowMask | LeaveWindowMask;
|
||||
attribs.colormap = (Colormap)colormap;
|
||||
|
||||
if (wPreferences.use_saveunders) {
|
||||
vmask |= CWSaveUnder;
|
||||
attribs.save_under = True;
|
||||
}
|
||||
|
||||
win = XCreateWindow(dpy, (Window)scr->root_win,
|
||||
x, y, width, height, border_width,
|
||||
depth, CopyFromParent, (Visual *)visual, vmask, &attribs);
|
||||
XClearWindow(dpy, win);
|
||||
return (WNativeWindow)win;
|
||||
wlr_buffer_init(&fb->base, &frame_buf_impl, width, height);
|
||||
|
||||
fb->id = wl_state.next_synthetic_id++;
|
||||
fb->x = x;
|
||||
fb->y = y;
|
||||
fb->width = width;
|
||||
fb->height = height;
|
||||
|
||||
/* Create scene buffer node. */
|
||||
if (wl_state.scene) {
|
||||
fb->scene_buf = wlr_scene_buffer_create(&wl_state.scene->tree,
|
||||
&fb->base);
|
||||
if (fb->scene_buf) {
|
||||
wlr_scene_node_set_position(&fb->scene_buf->node, x, y);
|
||||
wlr_scene_node_set_enabled(&fb->scene_buf->node, false);
|
||||
}
|
||||
}
|
||||
|
||||
wl_list_insert(&wl_state.frame_list, &fb->link);
|
||||
return fb->id;
|
||||
}
|
||||
|
||||
static WNativeWindow
|
||||
wl_frame_create_child(WNativeWindow parent_win, WScreen *scr,
|
||||
int x, int y, int width, int height)
|
||||
{
|
||||
if (!dpy)
|
||||
return WNATIVE_NONE;
|
||||
|
||||
int vmask;
|
||||
XSetWindowAttributes attribs;
|
||||
Window win;
|
||||
|
||||
vmask = CWBorderPixel | CWCursor | CWEventMask | CWColormap;
|
||||
attribs.cursor = wPreferences.cursor[WCUR_NORMAL];
|
||||
attribs.background_pixmap = None;
|
||||
attribs.background_pixel = scr->black_pixel;
|
||||
attribs.event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask |
|
||||
ButtonReleaseMask | ButtonMotionMask |
|
||||
ExposureMask | EnterWindowMask | LeaveWindowMask;
|
||||
attribs.colormap = scr->w_colormap;
|
||||
|
||||
win = XCreateWindow(dpy, (Window)parent_win,
|
||||
x, y, width, height, 0,
|
||||
scr->w_depth, CopyFromParent,
|
||||
scr->w_visual, vmask, &attribs);
|
||||
return (WNativeWindow)win;
|
||||
(void)parent_win; (void)scr;
|
||||
(void)x; (void)y; (void)width; (void)height;
|
||||
/* Child windows (titlebar, buttons, resizebar) are sub-regions of the
|
||||
* parent frame buffer. Return a synthetic ID so context_save works,
|
||||
* but no separate buffer is needed — frame_paint renders everything. */
|
||||
return wl_state.next_synthetic_id++;
|
||||
}
|
||||
|
||||
static void
|
||||
wl_frame_destroy(WScreen *scr, WNativeWindow win)
|
||||
{
|
||||
(void)scr;
|
||||
if (dpy && win != WNATIVE_NONE)
|
||||
XDestroyWindow(dpy, (Window)win);
|
||||
struct wl_frame_buf *fb = frame_buf_find(win);
|
||||
if (!fb) return;
|
||||
if (fb->scene_buf)
|
||||
wlr_scene_node_destroy(&fb->scene_buf->node);
|
||||
wl_list_remove(&fb->link);
|
||||
wlr_buffer_drop(&fb->base);
|
||||
}
|
||||
|
||||
static void
|
||||
wl_frame_configure(WNativeWindow win, int x, int y, int width, int height)
|
||||
{
|
||||
if (!dpy || win == WNATIVE_NONE)
|
||||
return;
|
||||
XWindowChanges xwc;
|
||||
xwc.x = x;
|
||||
xwc.y = y;
|
||||
xwc.width = width;
|
||||
xwc.height = height;
|
||||
XConfigureWindow(dpy, (Window)win, CWX | CWY | CWWidth | CWHeight, &xwc);
|
||||
struct wl_frame_buf *fb = frame_buf_find(win);
|
||||
if (!fb) return;
|
||||
|
||||
fb->x = x;
|
||||
fb->y = y;
|
||||
|
||||
if (fb->scene_buf)
|
||||
wlr_scene_node_set_position(&fb->scene_buf->node, x, 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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* wl_frame_paint — render the entire frame decoration into the pixman buffer.
|
||||
*
|
||||
* Uses wTextureRenderImage() (pure CPU) for titlebar/resizebar backgrounds,
|
||||
* pixman for bevel lines, and the WINGs font backend for title text.
|
||||
* Returns 1 (handled) so wFrameWindowPaint skips the Xlib code path.
|
||||
*/
|
||||
static int
|
||||
wl_frame_paint(struct WFrameWindow *fwin)
|
||||
{
|
||||
struct wl_frame_buf *fb = frame_buf_find(fwin->core->window);
|
||||
if (!fb || !fb->image)
|
||||
return 0; /* not our frame — shouldn't happen */
|
||||
|
||||
int state = fwin->flags.state;
|
||||
int total_w = fb->width;
|
||||
int total_h = fb->height;
|
||||
|
||||
/* Clear the buffer to transparent black. */
|
||||
pixman_color_t clear = {0, 0, 0, 0xFFFF};
|
||||
pixman_image_fill_rectangles(PIXMAN_OP_SRC, fb->image, &clear,
|
||||
1, &(pixman_rectangle16_t){0, 0, total_w, total_h});
|
||||
|
||||
/* --- Titlebar --- */
|
||||
if (fwin->titlebar && fwin->top_width > 0) {
|
||||
int tb_w = total_w;
|
||||
int tb_h = fwin->top_width;
|
||||
WTexture *tex = fwin->title_texture[state];
|
||||
|
||||
/* Render texture to RImage. */
|
||||
RImage *img = wTextureRenderImage(tex, tb_w, tb_h, WREL_RAISED);
|
||||
if (img) {
|
||||
/* Blit RImage into the pixman buffer at (0, 0).
|
||||
* RImage is RGBA (4 bytes/pixel) or RGB (3 bytes/pixel). */
|
||||
uint32_t *dst = pixman_image_get_data(fb->image);
|
||||
int dst_stride = pixman_image_get_stride(fb->image) / 4;
|
||||
int x, y;
|
||||
if (img->format == RRGBAFormat) {
|
||||
for (y = 0; y < tb_h && y < img->height; y++) {
|
||||
unsigned char *src_row = img->data + y * img->width * 4;
|
||||
uint32_t *dst_row = dst + y * dst_stride;
|
||||
for (x = 0; x < tb_w && x < img->width; x++) {
|
||||
unsigned char r = src_row[x*4+0];
|
||||
unsigned char g = src_row[x*4+1];
|
||||
unsigned char b = src_row[x*4+2];
|
||||
unsigned char a = src_row[x*4+3];
|
||||
dst_row[x] = ((uint32_t)a << 24) | ((uint32_t)r << 16) |
|
||||
((uint32_t)g << 8) | (uint32_t)b;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* RGB format */
|
||||
for (y = 0; y < tb_h && y < img->height; y++) {
|
||||
unsigned char *src_row = img->data + y * img->width * 3;
|
||||
uint32_t *dst_row = dst + y * dst_stride;
|
||||
for (x = 0; x < tb_w && x < img->width; x++) {
|
||||
unsigned char r = src_row[x*3+0];
|
||||
unsigned char g = src_row[x*3+1];
|
||||
unsigned char b = src_row[x*3+2];
|
||||
dst_row[x] = 0xFF000000U | ((uint32_t)r << 16) |
|
||||
((uint32_t)g << 8) | (uint32_t)b;
|
||||
}
|
||||
}
|
||||
}
|
||||
RReleaseImage(img);
|
||||
}
|
||||
|
||||
/* Draw title text. */
|
||||
if (fwin->title && *fwin->font && fwin->title_color[state]) {
|
||||
int lofs = 6, rofs = 6;
|
||||
int titlelen, tw, tx, ty, th;
|
||||
char *title;
|
||||
|
||||
if (fwin->left_button && !fwin->flags.hide_left_button &&
|
||||
!fwin->flags.lbutton_dont_fit)
|
||||
lofs += fwin->left_button->width + 3;
|
||||
if (fwin->right_button && !fwin->flags.hide_right_button &&
|
||||
!fwin->flags.rbutton_dont_fit)
|
||||
rofs += fwin->right_button->width + 3;
|
||||
|
||||
title = ShrinkString(*fwin->font, fwin->title, tb_w - lofs - rofs);
|
||||
titlelen = strlen(title);
|
||||
tw = WMWidthOfString(*fwin->font, title, titlelen);
|
||||
th = WMFontHeight(*fwin->font);
|
||||
|
||||
switch (fwin->flags.justification) {
|
||||
case WTJ_LEFT: tx = lofs; break;
|
||||
case WTJ_RIGHT: tx = tb_w - tw - rofs; break;
|
||||
default: tx = (tb_w - tw) / 2; break;
|
||||
}
|
||||
ty = (tb_h - th) / 2;
|
||||
|
||||
/* Draw text into the frame buffer using WMDrawable = pixman_image_t* */
|
||||
WMDrawString(fwin->screen_ptr->wmscreen, (WMDrawable)fb->image,
|
||||
fwin->title_color[state], *fwin->font,
|
||||
tx, ty, title, titlelen);
|
||||
wfree(title);
|
||||
}
|
||||
}
|
||||
|
||||
/* --- Resizebar --- */
|
||||
if (fwin->resizebar && fwin->bottom_width > 0) {
|
||||
int rb_y = total_h - fwin->bottom_width;
|
||||
int rb_w = total_w;
|
||||
int rb_h = fwin->bottom_width;
|
||||
WTexture *tex = fwin->resizebar_texture[0];
|
||||
|
||||
RImage *img = wTextureRenderImage(tex, rb_w, rb_h, WREL_RAISED);
|
||||
if (img) {
|
||||
uint32_t *dst = pixman_image_get_data(fb->image);
|
||||
int dst_stride = pixman_image_get_stride(fb->image) / 4;
|
||||
int x, y;
|
||||
if (img->format == RRGBAFormat) {
|
||||
for (y = 0; y < rb_h && y < img->height; y++) {
|
||||
unsigned char *src_row = img->data + y * img->width * 4;
|
||||
uint32_t *dst_row = dst + (rb_y + y) * dst_stride;
|
||||
for (x = 0; x < rb_w && x < img->width; x++) {
|
||||
unsigned char r = src_row[x*4+0];
|
||||
unsigned char g = src_row[x*4+1];
|
||||
unsigned char b = src_row[x*4+2];
|
||||
unsigned char a = src_row[x*4+3];
|
||||
dst_row[x] = ((uint32_t)a << 24) | ((uint32_t)r << 16) |
|
||||
((uint32_t)g << 8) | (uint32_t)b;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (y = 0; y < rb_h && y < img->height; y++) {
|
||||
unsigned char *src_row = img->data + y * img->width * 3;
|
||||
uint32_t *dst_row = dst + (rb_y + y) * dst_stride;
|
||||
for (x = 0; x < rb_w && x < img->width; x++) {
|
||||
unsigned char r = src_row[x*3+0];
|
||||
unsigned char g = src_row[x*3+1];
|
||||
unsigned char b = src_row[x*3+2];
|
||||
dst_row[x] = 0xFF000000U | ((uint32_t)r << 16) |
|
||||
((uint32_t)g << 8) | (uint32_t)b;
|
||||
}
|
||||
}
|
||||
}
|
||||
RReleaseImage(img);
|
||||
}
|
||||
}
|
||||
|
||||
/* Commit the buffer to the scene graph. */
|
||||
if (fb->scene_buf)
|
||||
wlr_scene_buffer_set_buffer(fb->scene_buf, &fb->base);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
|
@ -4702,7 +4923,6 @@ static void wl_server_ungrab(void) { overlay_flush(); }
|
|||
static void
|
||||
wl_stacking_raise(WNativeWindow win)
|
||||
{
|
||||
/* Phase 58: move view to head of list (top of Z-order). */
|
||||
struct wl_toplevel_view *v = wl_find_view_by_id(win);
|
||||
if (v) {
|
||||
wl_list_remove(&v->link);
|
||||
|
|
@ -4711,15 +4931,16 @@ wl_stacking_raise(WNativeWindow win)
|
|||
wlr_scene_node_raise_to_top(&v->scene_node->node);
|
||||
return;
|
||||
}
|
||||
/* Frame/icon windows on XWayland. */
|
||||
if (dpy && win != WNATIVE_NONE)
|
||||
XRaiseWindow(dpy, (Window)win);
|
||||
struct wl_frame_buf *fb = frame_buf_find(win);
|
||||
if (fb && fb->scene_buf) {
|
||||
wlr_scene_node_raise_to_top(&fb->scene_buf->node);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
wl_stacking_lower(WNativeWindow win)
|
||||
{
|
||||
/* Phase 58: move view to tail of list (bottom of Z-order). */
|
||||
struct wl_toplevel_view *v = wl_find_view_by_id(win);
|
||||
if (v) {
|
||||
wl_list_remove(&v->link);
|
||||
|
|
@ -4728,8 +4949,11 @@ wl_stacking_lower(WNativeWindow win)
|
|||
wlr_scene_node_lower_to_bottom(&v->scene_node->node);
|
||||
return;
|
||||
}
|
||||
if (dpy && win != WNATIVE_NONE)
|
||||
XLowerWindow(dpy, (Window)win);
|
||||
struct wl_frame_buf *fb = frame_buf_find(win);
|
||||
if (fb && fb->scene_buf) {
|
||||
wlr_scene_node_lower_to_bottom(&fb->scene_buf->node);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -4978,16 +5202,17 @@ wl_prop_get_wm_state(WNativeWindow win, long **data_out)
|
|||
static void
|
||||
wl_window_map(WNativeWindow win)
|
||||
{
|
||||
/* Show the scene node for this window (workspace switch arriving on workspace). */
|
||||
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;
|
||||
}
|
||||
/* Frame/icon/menu windows live on XWayland — map them via Xlib.
|
||||
* XWayland will fire associate → handle_or_map adds the scene node. */
|
||||
if (dpy && win != WNATIVE_NONE)
|
||||
XMapWindow(dpy, (Window)win);
|
||||
/* Frame buffer: enable its scene node. */
|
||||
struct wl_frame_buf *fb = frame_buf_find(win);
|
||||
if (fb && fb->scene_buf) {
|
||||
wlr_scene_node_set_enabled(&fb->scene_buf->node, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -4999,36 +5224,38 @@ wl_window_map_raised(WNativeWindow win)
|
|||
wlr_scene_node_raise_to_top(&v->scene_node->node);
|
||||
return;
|
||||
}
|
||||
if (dpy && win != WNATIVE_NONE)
|
||||
XMapRaised(dpy, (Window)win);
|
||||
struct wl_frame_buf *fb = frame_buf_find(win);
|
||||
if (fb && fb->scene_buf) {
|
||||
wlr_scene_node_set_enabled(&fb->scene_buf->node, true);
|
||||
wlr_scene_node_raise_to_top(&fb->scene_buf->node);
|
||||
return;
|
||||
}
|
||||
}
|
||||
static void wl_window_map_subwindows(WNativeWindow parent)
|
||||
{
|
||||
if (dpy && parent != WNATIVE_NONE)
|
||||
XMapSubwindows(dpy, (Window)parent);
|
||||
(void)parent;
|
||||
/* Child windows are sub-regions of the frame buffer — no-op. */
|
||||
}
|
||||
|
||||
static void
|
||||
wl_window_unmap(WNativeWindow win)
|
||||
{
|
||||
/* Hide the scene node for this window (workspace switch leaving workspace). */
|
||||
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;
|
||||
}
|
||||
/* Frame/icon/menu windows on XWayland. */
|
||||
if (dpy && win != WNATIVE_NONE)
|
||||
XUnmapWindow(dpy, (Window)win);
|
||||
struct wl_frame_buf *fb = frame_buf_find(win);
|
||||
if (fb && fb->scene_buf) {
|
||||
wlr_scene_node_set_enabled(&fb->scene_buf->node, false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
static void wl_window_move(WNativeWindow win, int x, int y)
|
||||
{
|
||||
/* Phase 55: record the WM-assigned position in the view struct.
|
||||
* Phase 17: also inform XWayland of the new position. */
|
||||
struct wl_toplevel_view *v = wl_find_view_by_id(win);
|
||||
if (v) {
|
||||
v->x = x; v->y = y;
|
||||
/* Phase 18: keep scene node in sync with WM position. */
|
||||
if (v->scene_node)
|
||||
wlr_scene_node_set_position(&v->scene_node->node, x, y);
|
||||
if (v->xw_surface)
|
||||
|
|
@ -5036,15 +5263,17 @@ static void wl_window_move(WNativeWindow win, int x, int y)
|
|||
(int16_t)x, (int16_t)y, v->xw_surface->width, v->xw_surface->height);
|
||||
return;
|
||||
}
|
||||
/* Frame/icon windows on XWayland. */
|
||||
if (dpy && win != WNATIVE_NONE)
|
||||
XMoveWindow(dpy, (Window)win, x, y);
|
||||
struct wl_frame_buf *fb = frame_buf_find(win);
|
||||
if (fb) {
|
||||
fb->x = x; fb->y = y;
|
||||
if (fb->scene_buf)
|
||||
wlr_scene_node_set_position(&fb->scene_buf->node, x, y);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void wl_window_resize(WNativeWindow win, int w, int h)
|
||||
{
|
||||
/* Phase 44: send a configure with the new size.
|
||||
* Phase 17: XWayland path uses wlr_xwayland_surface_configure. */
|
||||
struct wl_toplevel_view *v = wl_find_view_by_id(win);
|
||||
if (v) {
|
||||
if (w <= 0 || h <= 0) return;
|
||||
|
|
@ -5058,25 +5287,20 @@ static void wl_window_resize(WNativeWindow win, int w, int h)
|
|||
wlr_xdg_surface_schedule_configure(v->xdg_surface);
|
||||
return;
|
||||
}
|
||||
/* Frame/icon windows on XWayland. */
|
||||
if (dpy && win != WNATIVE_NONE && w > 0 && h > 0)
|
||||
XResizeWindow(dpy, (Window)win, (unsigned)w, (unsigned)h);
|
||||
/* Frame buffer resize is handled by frame_configure. */
|
||||
}
|
||||
static void wl_window_set_border(WNativeWindow win, unsigned long pixel)
|
||||
{
|
||||
if (dpy && win != WNATIVE_NONE)
|
||||
XSetWindowBorder(dpy, (Window)win, pixel);
|
||||
(void)win; (void)pixel; /* borders are drawn into the frame buffer */
|
||||
}
|
||||
static void wl_window_set_border_width(WNativeWindow win, int width)
|
||||
{
|
||||
if (dpy && win != WNATIVE_NONE)
|
||||
XSetWindowBorderWidth(dpy, (Window)win, (unsigned)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_window_clear(WNativeWindow win)
|
||||
{
|
||||
if (dpy && win != WNATIVE_NONE)
|
||||
XClearWindow(dpy, (Window)win);
|
||||
(void)win; /* frame buffer is cleared in frame_paint */
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
@ -5107,18 +5331,16 @@ wl_window_get_rect(WNativeWindow win,
|
|||
if (win_h) { *win_h = h > 0 ? h : 1; }
|
||||
return 1;
|
||||
}
|
||||
/* Non-synthetic: query XWayland for frame/icon windows. */
|
||||
if (dpy) {
|
||||
Window root_ret;
|
||||
int rx, ry;
|
||||
unsigned int rw, rh, rbw, rdepth;
|
||||
if (XGetGeometry(dpy, (Window)win, &root_ret, &rx, &ry, &rw, &rh, &rbw, &rdepth)) {
|
||||
if (win_x) { *win_x = rx; } if (win_y) { *win_y = ry; }
|
||||
if (win_w) { *win_w = (int)rw > 0 ? (int)rw : 1; }
|
||||
if (win_h) { *win_h = (int)rh > 0 ? (int)rh : 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;
|
||||
|
|
@ -5804,6 +6026,7 @@ const WMBackend wl_backend = {
|
|||
.frame_create_child = wl_frame_create_child,
|
||||
.frame_destroy = wl_frame_destroy,
|
||||
.frame_configure = wl_frame_configure,
|
||||
.frame_paint = wl_frame_paint,
|
||||
|
||||
.context_save = wl_context_save,
|
||||
.context_find = wl_context_find,
|
||||
|
|
|
|||
|
|
@ -2413,6 +2413,7 @@ const WMBackend x11_backend = {
|
|||
.frame_create_child = x11_frame_create_child,
|
||||
.frame_destroy = x11_frame_destroy,
|
||||
.frame_configure = x11_frame_configure,
|
||||
.frame_paint = NULL, /* X11: use legacy Xlib code in framewin.c */
|
||||
.context_save = x11_context_save,
|
||||
.context_find = x11_context_find,
|
||||
.context_delete = x11_context_delete,
|
||||
|
|
|
|||
|
|
@ -952,6 +952,10 @@ void wFrameWindowPaint(WFrameWindow * fwin)
|
|||
WScreen *scr = fwin->screen_ptr;
|
||||
int state;
|
||||
|
||||
/* Let the backend handle painting if it can (Wayland: pixman rendering). */
|
||||
if (wm_backend->frame_paint && wm_backend->frame_paint(fwin))
|
||||
return;
|
||||
|
||||
state = fwin->flags.state;
|
||||
|
||||
if (fwin->flags.is_client_window_frame)
|
||||
|
|
|
|||
Loading…
Reference in New Issue