diff --git a/src/backend/wayland/wl_backend.c b/src/backend/wayland/wl_backend.c index 909a8d7..1cc5806 100644 --- a/src/backend/wayland/wl_backend.c +++ b/src/backend/wayland/wl_backend.c @@ -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; } diff --git a/src/backend/wayland/wl_screen.c b/src/backend/wayland/wl_screen.c index e0f856d..14e80f5 100644 --- a/src/backend/wayland/wl_screen.c +++ b/src/backend/wayland/wl_screen.c @@ -9,6 +9,22 @@ #include "../../dialog.h" #include #include "wl_types.h" +#include +#include +#include +#include +#include "../../framewin.h" +#include +#include "../../xmodifier.h" +#include "../../WindowMaker.h" +#include + +/* 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; }