step 3: move screen internals from wl_backend.c to wl_screen.c (alloc_gcs, create_internals, monitors_query, 293 lines)

This commit is contained in:
lkn 2026-06-06 09:42:17 +02:00
parent 9178f8a903
commit 3b3ab96597
2 changed files with 310 additions and 293 deletions

View File

@ -1544,299 +1544,6 @@ handle_new_shortcuts_inhibitor(struct wl_listener *listener, void *data)
/* ------------------------------------------------------------------ */
/* Screen internals */
int wl_screen_select_input(WScreen *scr, long mask) { (void)scr; (void)mask; return 1; }
void wl_screen_set_root_cursor(WScreen *scr, int cursor_id) { (void)scr; (void)cursor_id; }
void wl_screen_set_icon_sizes(WScreen *scr, int min_size, int max_size) { (void)scr; (void)min_size; (void)max_size; }
void wl_screen_setup_noticeboard(WScreen *scr) { (void)scr; }
#if USE_XWAYLAND
void
wl_screen_alloc_gcs(WScreen *scr)
{
XGCValues gcv;
int gcm;
static const char stipple_data[] = { 0x02, 0x01 };
/* Pre-initialise menu text colors to black so that setMenuTextColor /
* setMenuDisabledColor in wReadDefaults can safely compare them before
* both have been set from the defaults DB. */
scr->menu_title_color[0] = WMRetainColor(scr->white);
scr->mtext_color = WMCreateRGBColor(scr->wmscreen, 0, 0, 0, True);
scr->dtext_color = WMCreateRGBColor(scr->wmscreen, 0, 0, 0, True);
/* Create X11 GCs on the XWayland connection. wmaker's rendering code
* (framewin, icon, menu) uses these regardless of the display backend.
* Mirrors x11_screen_alloc_gcs exactly; without these, CopyArea and
* XRender calls use GC/drawable 0 → BadDrawable → XWayland broken pipe. */
if (!wl_state.x_display)
return;
/* Mark the wrlib drawable as override_redirect so XWayland's XWM does not
* manage it as a client window. XWM reads override_redirect from the
* CreateNotify event (already gone), but any subsequent ConfigureNotify
* updates the flag on the wlr_xwayland_surface it created. Combined with
* the explicit window-ID filter in handle_xwayland_new_surface, this
* prevents BadDrawable/RenderBadPicture cascade and the resulting broken
* pipe from the nested Wayland backend. */
#if USE_XWAYLAND
if (scr->w_win) {
wl_state.rcontext_xwin = (WNativeWindow)scr->w_win;
XSetWindowAttributes or_attr;
or_attr.override_redirect = True;
XChangeWindowAttributes(wl_state.x_display, (WNativeWindow)scr->w_win, CWOverrideRedirect, &or_attr);
XFlush(wl_state.x_display);
}
#endif
scr->stipple_bitmap = XCreateBitmapFromData(wl_state.x_display, (WNativeWindow)scr->w_win,
stipple_data, 2, 2);
gcv.stipple = scr->stipple_bitmap;
gcv.foreground = scr->white_pixel;
gcv.fill_style = FillStippled;
gcv.graphics_exposures = False;
gcm = GCForeground | GCStipple | GCFillStyle | GCGraphicsExposures;
scr->stipple_gc = XCreateGC(wl_state.x_display, (WNativeWindow)scr->w_win, gcm, &gcv);
gcv.function = GXcopy;
gcv.foreground = scr->white_pixel;
gcv.background = scr->black_pixel;
gcv.line_width = 1;
gcv.line_style = LineDoubleDash;
gcv.fill_style = FillSolid;
gcv.dash_offset = 0;
gcv.dashes = 4;
gcv.graphics_exposures = False;
gcm = GCFunction | GCGraphicsExposures | GCForeground | GCBackground
| GCLineWidth | GCLineStyle | GCFillStyle | GCDashOffset | GCDashList;
scr->icon_select_gc = XCreateGC(wl_state.x_display, (WNativeWindow)scr->w_win, gcm, &gcv);
gcv.function = GXxor;
gcv.plane_mask = AllPlanes;
gcv.foreground = scr->white_pixel;
if (gcv.foreground == 0)
gcv.foreground = 1;
gcv.line_width = DEF_FRAME_THICKNESS;
gcv.subwindow_mode = IncludeInferiors;
gcv.graphics_exposures = False;
scr->frame_gc = XCreateGC(wl_state.x_display, (WNativeWindow)scr->root_win,
GCForeground | GCGraphicsExposures | GCFunction
| GCSubwindowMode | GCLineWidth | GCPlaneMask, &gcv);
gcv.foreground = scr->white_pixel;
if (gcv.foreground == 0)
gcv.foreground = 17;
gcv.function = GXxor;
gcv.subwindow_mode = IncludeInferiors;
gcv.line_width = 1;
gcv.cap_style = CapRound;
gcv.graphics_exposures = False;
gcm = GCForeground | GCFunction | GCSubwindowMode | GCLineWidth
| GCCapStyle | GCGraphicsExposures;
scr->line_gc = XCreateGC(wl_state.x_display, (WNativeWindow)scr->root_win, gcm, &gcv);
scr->line_pixel = gcv.foreground;
gcv.foreground = scr->white_pixel;
gcv.background = scr->black_pixel;
gcv.graphics_exposures = False;
scr->copy_gc = XCreateGC(wl_state.x_display, (WNativeWindow)scr->w_win,
GCForeground | GCBackground | GCGraphicsExposures, &gcv);
gcv.graphics_exposures = False;
scr->draw_gc = XCreateGC(wl_state.x_display, (WNativeWindow)scr->w_win, GCGraphicsExposures, &gcv);
scr->mono_gc = XCreateGC(wl_state.x_display, scr->stipple_bitmap, GCGraphicsExposures, &gcv);
}
#else
void wl_screen_alloc_gcs(WScreen *scr) { (void)scr; }
#endif
void
wl_screen_create_internals(WScreen *scr)
{
wl_state.scr = scr;
{
FILE *fp = fopen("/tmp/wl_backend_trace.log", "a");
if (fp) { fprintf(fp, "wl_screen_create_internals: scr=%p\n", (void*)scr); fclose(fp); }
}
#if USE_XWAYLAND
/* Create off-screen InputOnly X window as focus sink */
if (wl_state.x_display) {
XSetWindowAttributes attribs;
int vmask = CWEventMask | CWOverrideRedirect;
attribs.event_mask = WM_EVMASK_KEY_PRESS | WM_EVMASK_FOCUS_CHANGE;
attribs.override_redirect = True;
WNativeWindow xwin = XCreateWindow(wl_state.x_display, DefaultRootWindow(wl_state.x_display),
-10, -10, 4, 4, 0,
0, InputOnly, CopyFromParent, vmask, &attribs);
if (xwin) {
XSelectInput(wl_state.x_display, xwin, WM_EVMASK_KEY_PRESS | WM_EVMASK_KEY_RELEASE);
XMapWindow(wl_state.x_display, xwin);
/* Do NOT call XSetInputFocus here: the window may not be viewable
* yet in XWayland (map is async), triggering BadMatch that perturbs
* XWayland state and causes a Wayland broken-pipe cascade.
* wl_focus_set() will clear Wayland seat focus via
* wlr_seat_keyboard_clear_focus when this window is the target. */
wl_state.no_focus_xwin = xwin;
scr->no_focus_win = (WNativeWindow)xwin;
}
}
#endif
wPreferences.auto_focus = 1;
if (wl_state.seat)
wlr_seat_keyboard_clear_focus(wl_state.seat);
wSetModifierMasks(WM_MOD_MOD1, WM_MOD_MOD1, WM_MOD_MOD4, 0);
#if USE_XWAYLAND
/* XWayland bridge: create X11 helper window for EWMH */
if (wl_state.x_display) {
XSetWindowAttributes iattr;
iattr.override_redirect = True;
WNativeWindow xwin = XCreateWindow(wl_state.x_display, DefaultRootWindow(wl_state.x_display),
-2, -2, 1, 1, 0,
0, InputOutput, CopyFromParent,
CWOverrideRedirect, &iattr);
if (xwin)
scr->info_window = (WNativeWindow)xwin;
}
#endif
/* Create dock_shadow: scene_buffer used as ghost overlay during icon drag */
if (wl_state.scene) {
int sz = wPreferences.icon_size;
struct wl_frame_buf *dsfb = wmalloc(sizeof(*dsfb));
memset(dsfb, 0, sizeof(*dsfb));
dsfb->image = pixman_image_create_bits(PIXMAN_a8r8g8b8, sz, sz, NULL, sz * 4);
if (dsfb->image) {
wlr_buffer_init(&dsfb->base, &frame_buf_impl, sz, sz);
dsfb->id = wl_state.next_synthetic_id++;
dsfb->width = sz;
dsfb->height = sz;
struct wlr_scene_tree *ds_parent = wl_state.level_trees[WL_LAYER_OVERLAY]
? wl_state.level_trees[WL_LAYER_OVERLAY] : &wl_state.scene->tree;
dsfb->tree = wlr_scene_tree_create(ds_parent);
if (dsfb->tree) {
dsfb->scene_buf = wlr_scene_buffer_create(dsfb->tree, &dsfb->base);
if (dsfb->scene_buf)
wlr_scene_node_set_enabled(&dsfb->scene_buf->node, false);
wlr_scene_node_set_enabled(&dsfb->tree->node, false);
}
wl_list_insert(&wl_state.frame_list, &dsfb->link);
scr->dock_shadow = dsfb->id;
} else {
wfree(dsfb);
}
}
/* dock/clip now uses XWayland windows for rendering.
* The WM's dock logic (dock.c) creates X11 windows on the XWayland
* Display* and draws on them with Xlib — the compositor composites
* them like any other XWayland surface. */
/* wPreferences.flags.noclip = 1; */
/* wPreferences.flags.nodock = 1; */
/* dock creation is deferred to wl_event_loop_run() (after the
* startup pump thread stops). wm_dock_create() calls wlr_scene_buffer_create
* which is not thread-safe — calling it here races with the pump thread's
* frame-timer callback that calls wlr_scene_output_commit on the same scene.
* The dock_scr pointer tells wl_event_loop_run() to create the dock once the
* compositor's single-threaded event loop is running.
* NOTE: native dock panel disabled — WM dock uses XWayland windows now. */
/* wl_state.dock_pending_scr = scr; */
/* Wayland has no X11-style window border; force to 0 so policy code
* does not offset client positions by a non-existent border. */
scr->frame_border_width = 0;
/* Create workspace name badge overlay (initially 10x10, resized on use) */
if (wl_state.scene) {
struct wl_frame_buf *fb = wmalloc(sizeof(*fb));
memset(fb, 0, sizeof(*fb));
fb->image = pixman_image_create_bits(PIXMAN_a8r8g8b8, 10, 10, NULL, 0);
if (fb->image) {
wlr_buffer_init(&fb->base, &frame_buf_impl, 10, 10);
fb->id = wl_state.next_synthetic_id++;
fb->width = 10;
fb->height = 10;
struct wlr_scene_tree *parent = wl_state.level_trees[WL_LAYER_OVERLAY]
? wl_state.level_trees[WL_LAYER_OVERLAY] : &wl_state.scene->tree;
fb->tree = wlr_scene_tree_create(parent);
if (fb->tree) {
fb_attach_tree_listener(fb);
fb->scene_buf = wlr_scene_buffer_create(fb->tree, &fb->base);
if (fb->scene_buf) {
fb_attach_scene_buf_listener(fb);
wlr_scene_node_set_enabled(&fb->scene_buf->node, false);
}
wlr_scene_node_set_enabled(&fb->tree->node, false);
}
wl_list_insert(&wl_state.frame_list, &fb->link);
W_RegisterBacking(fb->id, fb->image);
scr->workspace_name = fb->id;
} else {
wfree(fb);
}
}
}
void wl_screen_create_pixmaps(WScreen *scr) { (void)scr; }
void
wl_screen_load_tech_font(WScreen *scr)
{
if (!scr) return;
/* Wayland mode has no native font handle (overlay text is drawn via
* the embedded 5×9 bitmap font in wl_overlay_draw_string). We just
* publish the metric fields so moveres.c gets correct geometry. */
scr->tech_draw_font = NULL;
scr->tech_draw_font_ascent = OVL_GH - 2; /* 7 */
scr->tech_draw_font_descent = 2;
}
void wl_screen_show_mini_screenshot(WScreen *scr, RImage *img) { (void)scr; (void)img; }
RImage *wl_screen_capture_area(WScreen *scr) { (void)scr; return NULL; }
RImage *wl_screen_capture_window(WScreen *scr, WWindow *wwin) { (void)scr; (void)wwin; return NULL; }
void wl_refresh_desktop(WScreen *scr) { (void)scr; }
void
wl_monitors_query(WScreen *scr, WHeadGeometry **heads_out, int *count_out)
{
(void)scr;
if (!wl_state.output) {
*heads_out = NULL;
*count_out = 0;
return;
}
WHeadGeometry *heads = wmalloc(sizeof(WHeadGeometry));
if (wl_state.output_layout) {
struct wlr_box box = {0};
wlr_output_layout_get_box(wl_state.output_layout, wl_state.output, &box);
if (box.width > 0 || box.height > 0) {
heads[0].x = box.x;
heads[0].y = box.y;
heads[0].width = box.width;
heads[0].height = box.height;
} else {
heads[0].x = heads[0].y = 0;
heads[0].width = (int)wl_state.output->width;
heads[0].height = (int)wl_state.output->height;
}
} else {
heads[0].x = heads[0].y = 0;
heads[0].width = (int)wl_state.output->width;
heads[0].height = (int)wl_state.output->height;
}
*heads_out = heads;
*count_out = 1;
}
void wl_monitors_select_events(WScreen *scr) { (void)scr; }

View File

@ -9,6 +9,22 @@
#include "../../dialog.h"
#include <WINGs/WINGsP.h>
#include "wl_types.h"
#include <wlr/types/wlr_scene.h>
#include <wlr/types/wlr_buffer.h>
#include <wlr/interfaces/wlr_buffer.h>
#include <pixman.h>
#include "../../framewin.h"
#include <wlr/types/wlr_seat.h>
#include "../../xmodifier.h"
#include "../../WindowMaker.h"
#include <wlr/types/wlr_output_layout.h>
/* Externs from other wayland backend modules */
extern const struct wlr_buffer_impl frame_buf_impl;
extern void fb_attach_tree_listener(struct wl_frame_buf *fb);
extern void fb_attach_scene_buf_listener(struct wl_frame_buf *fb);
void *W_RegisterBacking(unsigned long id, void *img);
/* ------------------------------------------------------------------ */
/* Screen open/close */
@ -242,3 +258,297 @@ int wl_get_color_for_colormap(unsigned long colormap,
int wl_parse_color(WScreen *scr, const char *name, WMColorRGB *color_out)
{ (void)scr; return wl_get_color_for_colormap(0, name, color_out); }
/* ------------------------------------------------------------------ */
/* Screen internals */
int wl_screen_select_input(WScreen *scr, long mask) { (void)scr; (void)mask; return 1; }
void wl_screen_set_root_cursor(WScreen *scr, int cursor_id) { (void)scr; (void)cursor_id; }
void wl_screen_set_icon_sizes(WScreen *scr, int min_size, int max_size) { (void)scr; (void)min_size; (void)max_size; }
void wl_screen_setup_noticeboard(WScreen *scr) { (void)scr; }
#if USE_XWAYLAND
void
wl_screen_alloc_gcs(WScreen *scr)
{
XGCValues gcv;
int gcm;
static const char stipple_data[] = { 0x02, 0x01 };
/* Pre-initialise menu text colors to black so that setMenuTextColor /
* setMenuDisabledColor in wReadDefaults can safely compare them before
* both have been set from the defaults DB. */
scr->menu_title_color[0] = WMRetainColor(scr->white);
scr->mtext_color = WMCreateRGBColor(scr->wmscreen, 0, 0, 0, True);
scr->dtext_color = WMCreateRGBColor(scr->wmscreen, 0, 0, 0, True);
/* Create X11 GCs on the XWayland connection. wmaker's rendering code
* (framewin, icon, menu) uses these regardless of the display backend.
* Mirrors x11_screen_alloc_gcs exactly; without these, CopyArea and
* XRender calls use GC/drawable 0 → BadDrawable → XWayland broken pipe. */
if (!wl_state.x_display)
return;
/* Mark the wrlib drawable as override_redirect so XWayland's XWM does not
* manage it as a client window. XWM reads override_redirect from the
* CreateNotify event (already gone), but any subsequent ConfigureNotify
* updates the flag on the wlr_xwayland_surface it created. Combined with
* the explicit window-ID filter in handle_xwayland_new_surface, this
* prevents BadDrawable/RenderBadPicture cascade and the resulting broken
* pipe from the nested Wayland backend. */
#if USE_XWAYLAND
if (scr->w_win) {
wl_state.rcontext_xwin = (WNativeWindow)scr->w_win;
XSetWindowAttributes or_attr;
or_attr.override_redirect = True;
XChangeWindowAttributes(wl_state.x_display, (WNativeWindow)scr->w_win, CWOverrideRedirect, &or_attr);
XFlush(wl_state.x_display);
}
#endif
scr->stipple_bitmap = XCreateBitmapFromData(wl_state.x_display, (WNativeWindow)scr->w_win,
stipple_data, 2, 2);
gcv.stipple = scr->stipple_bitmap;
gcv.foreground = scr->white_pixel;
gcv.fill_style = FillStippled;
gcv.graphics_exposures = False;
gcm = GCForeground | GCStipple | GCFillStyle | GCGraphicsExposures;
scr->stipple_gc = XCreateGC(wl_state.x_display, (WNativeWindow)scr->w_win, gcm, &gcv);
gcv.function = GXcopy;
gcv.foreground = scr->white_pixel;
gcv.background = scr->black_pixel;
gcv.line_width = 1;
gcv.line_style = LineDoubleDash;
gcv.fill_style = FillSolid;
gcv.dash_offset = 0;
gcv.dashes = 4;
gcv.graphics_exposures = False;
gcm = GCFunction | GCGraphicsExposures | GCForeground | GCBackground
| GCLineWidth | GCLineStyle | GCFillStyle | GCDashOffset | GCDashList;
scr->icon_select_gc = XCreateGC(wl_state.x_display, (WNativeWindow)scr->w_win, gcm, &gcv);
gcv.function = GXxor;
gcv.plane_mask = AllPlanes;
gcv.foreground = scr->white_pixel;
if (gcv.foreground == 0)
gcv.foreground = 1;
gcv.line_width = DEF_FRAME_THICKNESS;
gcv.subwindow_mode = IncludeInferiors;
gcv.graphics_exposures = False;
scr->frame_gc = XCreateGC(wl_state.x_display, (WNativeWindow)scr->root_win,
GCForeground | GCGraphicsExposures | GCFunction
| GCSubwindowMode | GCLineWidth | GCPlaneMask, &gcv);
gcv.foreground = scr->white_pixel;
if (gcv.foreground == 0)
gcv.foreground = 17;
gcv.function = GXxor;
gcv.subwindow_mode = IncludeInferiors;
gcv.line_width = 1;
gcv.cap_style = CapRound;
gcv.graphics_exposures = False;
gcm = GCForeground | GCFunction | GCSubwindowMode | GCLineWidth
| GCCapStyle | GCGraphicsExposures;
scr->line_gc = XCreateGC(wl_state.x_display, (WNativeWindow)scr->root_win, gcm, &gcv);
scr->line_pixel = gcv.foreground;
gcv.foreground = scr->white_pixel;
gcv.background = scr->black_pixel;
gcv.graphics_exposures = False;
scr->copy_gc = XCreateGC(wl_state.x_display, (WNativeWindow)scr->w_win,
GCForeground | GCBackground | GCGraphicsExposures, &gcv);
gcv.graphics_exposures = False;
scr->draw_gc = XCreateGC(wl_state.x_display, (WNativeWindow)scr->w_win, GCGraphicsExposures, &gcv);
scr->mono_gc = XCreateGC(wl_state.x_display, scr->stipple_bitmap, GCGraphicsExposures, &gcv);
}
#else
void wl_screen_alloc_gcs(WScreen *scr) { (void)scr; }
#endif
void
wl_screen_create_internals(WScreen *scr)
{
wl_state.scr = scr;
{
FILE *fp = fopen("/tmp/wl_backend_trace.log", "a");
if (fp) { fprintf(fp, "wl_screen_create_internals: scr=%p\n", (void*)scr); fclose(fp); }
}
#if USE_XWAYLAND
/* Create off-screen InputOnly X window as focus sink */
if (wl_state.x_display) {
XSetWindowAttributes attribs;
int vmask = CWEventMask | CWOverrideRedirect;
attribs.event_mask = WM_EVMASK_KEY_PRESS | WM_EVMASK_FOCUS_CHANGE;
attribs.override_redirect = True;
WNativeWindow xwin = XCreateWindow(wl_state.x_display, DefaultRootWindow(wl_state.x_display),
-10, -10, 4, 4, 0,
0, InputOnly, CopyFromParent, vmask, &attribs);
if (xwin) {
XSelectInput(wl_state.x_display, xwin, WM_EVMASK_KEY_PRESS | WM_EVMASK_KEY_RELEASE);
XMapWindow(wl_state.x_display, xwin);
/* Do NOT call XSetInputFocus here: the window may not be viewable
* yet in XWayland (map is async), triggering BadMatch that perturbs
* XWayland state and causes a Wayland broken-pipe cascade.
* wl_focus_set() will clear Wayland seat focus via
* wlr_seat_keyboard_clear_focus when this window is the target. */
wl_state.no_focus_xwin = xwin;
scr->no_focus_win = (WNativeWindow)xwin;
}
}
#endif
wPreferences.auto_focus = 1;
if (wl_state.seat)
wlr_seat_keyboard_clear_focus(wl_state.seat);
wSetModifierMasks(WM_MOD_MOD1, WM_MOD_MOD1, WM_MOD_MOD4, 0);
#if USE_XWAYLAND
/* XWayland bridge: create X11 helper window for EWMH */
if (wl_state.x_display) {
XSetWindowAttributes iattr;
iattr.override_redirect = True;
WNativeWindow xwin = XCreateWindow(wl_state.x_display, DefaultRootWindow(wl_state.x_display),
-2, -2, 1, 1, 0,
0, InputOutput, CopyFromParent,
CWOverrideRedirect, &iattr);
if (xwin)
scr->info_window = (WNativeWindow)xwin;
}
#endif
/* Create dock_shadow: scene_buffer used as ghost overlay during icon drag */
if (wl_state.scene) {
int sz = wPreferences.icon_size;
struct wl_frame_buf *dsfb = wmalloc(sizeof(*dsfb));
memset(dsfb, 0, sizeof(*dsfb));
dsfb->image = pixman_image_create_bits(PIXMAN_a8r8g8b8, sz, sz, NULL, sz * 4);
if (dsfb->image) {
wlr_buffer_init(&dsfb->base, &frame_buf_impl, sz, sz);
dsfb->id = wl_state.next_synthetic_id++;
dsfb->width = sz;
dsfb->height = sz;
struct wlr_scene_tree *ds_parent = wl_state.level_trees[WL_LAYER_OVERLAY]
? wl_state.level_trees[WL_LAYER_OVERLAY] : &wl_state.scene->tree;
dsfb->tree = wlr_scene_tree_create(ds_parent);
if (dsfb->tree) {
dsfb->scene_buf = wlr_scene_buffer_create(dsfb->tree, &dsfb->base);
if (dsfb->scene_buf)
wlr_scene_node_set_enabled(&dsfb->scene_buf->node, false);
wlr_scene_node_set_enabled(&dsfb->tree->node, false);
}
wl_list_insert(&wl_state.frame_list, &dsfb->link);
scr->dock_shadow = dsfb->id;
} else {
wfree(dsfb);
}
}
/* dock/clip now uses XWayland windows for rendering.
* The WM's dock logic (dock.c) creates X11 windows on the XWayland
* Display* and draws on them with Xlib — the compositor composites
* them like any other XWayland surface. */
/* wPreferences.flags.noclip = 1; */
/* wPreferences.flags.nodock = 1; */
/* dock creation is deferred to wl_event_loop_run() (after the
* startup pump thread stops). wm_dock_create() calls wlr_scene_buffer_create
* which is not thread-safe — calling it here races with the pump thread's
* frame-timer callback that calls wlr_scene_output_commit on the same scene.
* The dock_scr pointer tells wl_event_loop_run() to create the dock once the
* compositor's single-threaded event loop is running.
* NOTE: native dock panel disabled — WM dock uses XWayland windows now. */
/* wl_state.dock_pending_scr = scr; */
/* Wayland has no X11-style window border; force to 0 so policy code
* does not offset client positions by a non-existent border. */
scr->frame_border_width = 0;
/* Create workspace name badge overlay (initially 10x10, resized on use) */
if (wl_state.scene) {
struct wl_frame_buf *fb = wmalloc(sizeof(*fb));
memset(fb, 0, sizeof(*fb));
fb->image = pixman_image_create_bits(PIXMAN_a8r8g8b8, 10, 10, NULL, 0);
if (fb->image) {
wlr_buffer_init(&fb->base, &frame_buf_impl, 10, 10);
fb->id = wl_state.next_synthetic_id++;
fb->width = 10;
fb->height = 10;
struct wlr_scene_tree *parent = wl_state.level_trees[WL_LAYER_OVERLAY]
? wl_state.level_trees[WL_LAYER_OVERLAY] : &wl_state.scene->tree;
fb->tree = wlr_scene_tree_create(parent);
if (fb->tree) {
fb_attach_tree_listener(fb);
fb->scene_buf = wlr_scene_buffer_create(fb->tree, &fb->base);
if (fb->scene_buf) {
fb_attach_scene_buf_listener(fb);
wlr_scene_node_set_enabled(&fb->scene_buf->node, false);
}
wlr_scene_node_set_enabled(&fb->tree->node, false);
}
wl_list_insert(&wl_state.frame_list, &fb->link);
W_RegisterBacking(fb->id, fb->image);
scr->workspace_name = fb->id;
} else {
wfree(fb);
}
}
}
void wl_screen_create_pixmaps(WScreen *scr) { (void)scr; }
void
wl_screen_load_tech_font(WScreen *scr)
{
if (!scr) return;
/* Wayland mode has no native font handle (overlay text is drawn via
* the embedded 5×9 bitmap font in wl_overlay_draw_string). We just
* publish the metric fields so moveres.c gets correct geometry. */
scr->tech_draw_font = NULL;
scr->tech_draw_font_ascent = OVL_GH - 2; /* 7 */
scr->tech_draw_font_descent = 2;
}
void wl_screen_show_mini_screenshot(WScreen *scr, RImage *img) { (void)scr; (void)img; }
RImage *wl_screen_capture_area(WScreen *scr) { (void)scr; return NULL; }
RImage *wl_screen_capture_window(WScreen *scr, WWindow *wwin) { (void)scr; (void)wwin; return NULL; }
void wl_refresh_desktop(WScreen *scr) { (void)scr; }
void
wl_monitors_query(WScreen *scr, WHeadGeometry **heads_out, int *count_out)
{
(void)scr;
if (!wl_state.output) {
*heads_out = NULL;
*count_out = 0;
return;
}
WHeadGeometry *heads = wmalloc(sizeof(WHeadGeometry));
if (wl_state.output_layout) {
struct wlr_box box = {0};
wlr_output_layout_get_box(wl_state.output_layout, wl_state.output, &box);
if (box.width > 0 || box.height > 0) {
heads[0].x = box.x;
heads[0].y = box.y;
heads[0].width = box.width;
heads[0].height = box.height;
} else {
heads[0].x = heads[0].y = 0;
heads[0].width = (int)wl_state.output->width;
heads[0].height = (int)wl_state.output->height;
}
} else {
heads[0].x = heads[0].y = 0;
heads[0].width = (int)wl_state.output->width;
heads[0].height = (int)wl_state.output->height;
}
*heads_out = heads;
*count_out = 1;
}
void wl_monitors_select_events(WScreen *scr) { (void)scr; }