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:
parent
9178f8a903
commit
3b3ab96597
|
|
@ -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; }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,22 @@
|
||||||
#include "../../dialog.h"
|
#include "../../dialog.h"
|
||||||
#include <WINGs/WINGsP.h>
|
#include <WINGs/WINGsP.h>
|
||||||
#include "wl_types.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 */
|
/* 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)
|
int wl_parse_color(WScreen *scr, const char *name, WMColorRGB *color_out)
|
||||||
{ (void)scr; return wl_get_color_for_colormap(0, name, 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; }
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue