wayland: WMBackend vtable — port policy files off direct X11
Move X11-specific calls in policy code behind the wm_backend dispatch table so the same code paths work with both X11 and Wayland backends. backend.h — extend WMBackend vtable with new entry points event.c — route input events through backend dispatch framewin.c — title-bar rendering via backend surface ops icon.c — icon pixmap handling via backend abstraction main.c — backend selection + initialisation at startup misc.c — miscellaneous X11 helpers moved behind vtable pixmap.c — pixmap creation/destruction via backend ops resources.c — resource loading abstracted over backend screen.c — screen setup routed through WMBackend vtable startup.c — startup sequence uses backend entry points texture.c — texture rendering abstracted for both backends No functional change on X11; Wayland backend stubs return safe no-ops. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
1dde83e05e
commit
00deab12f2
|
|
@ -46,6 +46,18 @@ struct WObjDescriptor;
|
|||
*/
|
||||
typedef struct WMBackend {
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Backend identity flag (Path 1) */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
/*
|
||||
* Non-zero if this is the Wayland compositor backend.
|
||||
* Allows policy code to take the Wayland fast-path even when dpy != NULL
|
||||
* (i.e. when WindowMaker's X11 UI is bridged through XWayland).
|
||||
* X11 backend: is_wayland = 0. Wayland backend: is_wayland = 1.
|
||||
*/
|
||||
int is_wayland;
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Display lifecycle (Phase 32) */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
|
@ -95,6 +107,14 @@ typedef struct WMBackend {
|
|||
*/
|
||||
void (*event_loop_run)(void);
|
||||
|
||||
/*
|
||||
* Request the backend event loop to stop.
|
||||
* X11: no-op (X11 EventLoop exits via exit()).
|
||||
* Wayland: wl_display_terminate(display) -- causes event_loop_run() to return.
|
||||
* Called from signal handlers so that cleanup happens outside signal context.
|
||||
*/
|
||||
void (*event_loop_terminate)(void);
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Screen lifecycle (Phase 2) */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
|
|
|||
21
src/event.c
21
src/event.c
|
|
@ -159,7 +159,18 @@ void DispatchEvent(XEvent * event)
|
|||
* WMHandleEvent() can't be called from anything
|
||||
* executed inside here, or we can get in a infinite
|
||||
* recursive loop.
|
||||
*
|
||||
* In Wayland mode, calling wl_display_destroy() from a signal
|
||||
* handler while wl_event_loop_dispatch() is active causes a
|
||||
* double-free (glibc detects it as SIGABRT). Instead, write a
|
||||
* byte to the self-pipe; the event loop reads it and calls
|
||||
* wl_display_terminate() from within loop context. EventLoop()
|
||||
* then calls Exit(0) after wl_display_run() returns.
|
||||
*/
|
||||
if (!dpy) {
|
||||
wm_backend->event_loop_terminate();
|
||||
return;
|
||||
}
|
||||
Shutdown(WSExitMode);
|
||||
|
||||
} else if (WCHECK_STATE(WSTATE_NEED_RESTART)) {
|
||||
|
|
@ -368,8 +379,14 @@ noreturn void EventLoop(void)
|
|||
int retVal = 0;
|
||||
#endif
|
||||
|
||||
/* Wayland path: delegate to the backend's event loop (wl_display_run). */
|
||||
if (!dpy) {
|
||||
/* Wayland path: delegate to the backend's event loop (wl_display_run).
|
||||
* When SIGTERM is received, event_loop_terminate() writes to a self-pipe
|
||||
* which causes the event loop to call wl_display_terminate() from within
|
||||
* loop context; wl_display_run() then returns here, and Exit(0) performs
|
||||
* the final cleanup safely outside signal-handler and event-loop context.
|
||||
* Path 1: use wm_backend->is_wayland rather than !dpy because dpy is set
|
||||
* to the XWayland Display* even in Wayland-compositor mode. */
|
||||
if (!dpy || wm_backend->is_wayland) {
|
||||
wm_backend->event_loop_run();
|
||||
Exit(0);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -862,6 +862,10 @@ static void remakeTexture(WFrameWindow * fwin, int state)
|
|||
Pixmap tpmap;
|
||||
#endif
|
||||
|
||||
/* Phase 19: Wayland — no X11 rendering context; RConvertImage would crash */
|
||||
if (!fwin->screen_ptr->rcontext)
|
||||
return;
|
||||
|
||||
if (fwin->title_texture[state] && fwin->titlebar) {
|
||||
FREE_PIXMAP(fwin->title_back[state]);
|
||||
if (wPreferences.new_style == TS_NEW) {
|
||||
|
|
@ -1045,7 +1049,7 @@ void wFrameWindowPaint(WFrameWindow * fwin)
|
|||
fwin->languagebutton_image = scr->b_pixmaps[WBUT_XKBGROUP1 + fwin->languagemode];
|
||||
#endif
|
||||
|
||||
if (fwin->title) {
|
||||
if (dpy && fwin->title) {
|
||||
Drawable buf;
|
||||
char *title;
|
||||
|
||||
|
|
@ -1125,10 +1129,12 @@ static void reconfigure(WFrameWindow * fwin, int x, int y, int width, int height
|
|||
int k = (wPreferences.new_style == TS_NEW ? 4 : 3);
|
||||
int resizedHorizontally = 0;
|
||||
|
||||
if (dontMove)
|
||||
XResizeWindow(dpy, fwin->core->window, width, height);
|
||||
else
|
||||
XMoveResizeWindow(dpy, fwin->core->window, x, y, width, height);
|
||||
if (dpy) {
|
||||
if (dontMove)
|
||||
XResizeWindow(dpy, fwin->core->window, width, height);
|
||||
else
|
||||
XMoveResizeWindow(dpy, fwin->core->window, x, y, width, height);
|
||||
}
|
||||
|
||||
if (fwin->core->width != width) {
|
||||
fwin->flags.need_texture_remake = 1;
|
||||
|
|
@ -1144,12 +1150,12 @@ static void reconfigure(WFrameWindow * fwin, int x, int y, int width, int height
|
|||
*/
|
||||
if (fwin->left_button) {
|
||||
if (width < fwin->top_width * k && !fwin->flags.lbutton_dont_fit) {
|
||||
if (!fwin->flags.hide_left_button)
|
||||
if (!fwin->flags.hide_left_button && dpy)
|
||||
XUnmapWindow(dpy, fwin->left_button->window);
|
||||
|
||||
fwin->flags.lbutton_dont_fit = 1;
|
||||
} else if (width >= fwin->top_width * k && fwin->flags.lbutton_dont_fit) {
|
||||
if (!fwin->flags.hide_left_button)
|
||||
if (!fwin->flags.hide_left_button && dpy)
|
||||
XMapWindow(dpy, fwin->left_button->window);
|
||||
|
||||
fwin->flags.lbutton_dont_fit = 0;
|
||||
|
|
@ -1158,12 +1164,12 @@ static void reconfigure(WFrameWindow * fwin, int x, int y, int width, int height
|
|||
#ifdef XKB_BUTTON_HINT
|
||||
if (fwin->language_button) {
|
||||
if (width < fwin->top_width * k && !fwin->flags.languagebutton_dont_fit) {
|
||||
if (!fwin->flags.hide_language_button)
|
||||
if (!fwin->flags.hide_language_button && dpy)
|
||||
XUnmapWindow(dpy, fwin->language_button->window);
|
||||
|
||||
fwin->flags.languagebutton_dont_fit = 1;
|
||||
} else if (width >= fwin->top_width * k && fwin->flags.languagebutton_dont_fit) {
|
||||
if (!fwin->flags.hide_language_button)
|
||||
if (!fwin->flags.hide_language_button && dpy)
|
||||
XMapWindow(dpy, fwin->language_button->window);
|
||||
|
||||
fwin->flags.languagebutton_dont_fit = 0;
|
||||
|
|
@ -1173,27 +1179,29 @@ static void reconfigure(WFrameWindow * fwin, int x, int y, int width, int height
|
|||
|
||||
if (fwin->right_button) {
|
||||
if (width < fwin->top_width * 2 && !fwin->flags.rbutton_dont_fit) {
|
||||
if (!fwin->flags.hide_right_button)
|
||||
if (!fwin->flags.hide_right_button && dpy)
|
||||
XUnmapWindow(dpy, fwin->right_button->window);
|
||||
|
||||
fwin->flags.rbutton_dont_fit = 1;
|
||||
} else if (width >= fwin->top_width * 2 && fwin->flags.rbutton_dont_fit) {
|
||||
if (!fwin->flags.hide_right_button)
|
||||
if (!fwin->flags.hide_right_button && dpy)
|
||||
XMapWindow(dpy, fwin->right_button->window);
|
||||
|
||||
fwin->flags.rbutton_dont_fit = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (wPreferences.new_style == TS_NEW) {
|
||||
if (fwin->right_button)
|
||||
XMoveWindow(dpy, fwin->right_button->window,
|
||||
width - fwin->right_button->width + 1, 0);
|
||||
} else {
|
||||
if (fwin->right_button)
|
||||
XMoveWindow(dpy, fwin->right_button->window,
|
||||
width - fwin->right_button->width - 3,
|
||||
(fwin->titlebar->height - fwin->right_button->height) / 2);
|
||||
if (dpy) {
|
||||
if (wPreferences.new_style == TS_NEW) {
|
||||
if (fwin->right_button)
|
||||
XMoveWindow(dpy, fwin->right_button->window,
|
||||
width - fwin->right_button->width + 1, 0);
|
||||
} else {
|
||||
if (fwin->right_button)
|
||||
XMoveWindow(dpy, fwin->right_button->window,
|
||||
width - fwin->right_button->width - 3,
|
||||
(fwin->titlebar->height - fwin->right_button->height) / 2);
|
||||
}
|
||||
}
|
||||
updateTitlebar(fwin);
|
||||
checkTitleSize(fwin);
|
||||
|
|
@ -1237,7 +1245,7 @@ int wFrameWindowChangeTitle(WFrameWindow *fwin, const char *new_title)
|
|||
fwin->title = wstrdup(new_title);
|
||||
|
||||
if (fwin->titlebar) {
|
||||
XClearWindow(dpy, fwin->titlebar->window);
|
||||
if (dpy) XClearWindow(dpy, fwin->titlebar->window);
|
||||
|
||||
wFrameWindowPaint(fwin);
|
||||
}
|
||||
|
|
@ -1278,6 +1286,12 @@ static void checkTitleSize(WFrameWindow * fwin)
|
|||
return;
|
||||
}
|
||||
|
||||
/* Phase 19: Wayland — no wmscreen for WMWidthOfString */
|
||||
if (!fwin->screen_ptr->wmscreen) {
|
||||
fwin->flags.incomplete_title = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!fwin->titlebar) {
|
||||
fwin->flags.incomplete_title = 1;
|
||||
return;
|
||||
|
|
@ -1309,6 +1323,10 @@ static void paintButton(WCoreWindow * button, WTexture * texture, unsigned long
|
|||
{
|
||||
WScreen *scr = button->screen_ptr;
|
||||
GC copy_gc = scr->copy_gc;
|
||||
|
||||
/* Phase 19: Wayland — no X11 display or GCs for button rendering */
|
||||
if (!dpy)
|
||||
return;
|
||||
int x = 0, y = 0, d = 0;
|
||||
int left = 0, width = 0;
|
||||
|
||||
|
|
|
|||
|
|
@ -220,10 +220,10 @@ void wIconDestroy(WIcon *icon)
|
|||
if (icon->icon_name)
|
||||
XFree(icon->icon_name);
|
||||
|
||||
if (icon->pixmap)
|
||||
if (icon->pixmap && dpy)
|
||||
XFreePixmap(dpy, icon->pixmap);
|
||||
|
||||
if (icon->mini_preview)
|
||||
if (icon->mini_preview && dpy)
|
||||
XFreePixmap(dpy, icon->mini_preview);
|
||||
|
||||
unset_icon_image(icon);
|
||||
|
|
@ -621,7 +621,7 @@ void set_icon_minipreview(WIcon *icon, RImage *image)
|
|||
wPreferences.minipreview_size - 2 * MINIPREVIEW_BORDER);
|
||||
|
||||
if (RConvertImage(scr->rcontext, scaled_mini_preview, &tmp)) {
|
||||
if (icon->mini_preview != None)
|
||||
if (icon->mini_preview != None && dpy)
|
||||
XFreePixmap(dpy, icon->mini_preview);
|
||||
icon->mini_preview = tmp;
|
||||
}
|
||||
|
|
|
|||
10
src/main.c
10
src/main.c
|
|
@ -815,7 +815,15 @@ static int real_main(int argc, char **argv)
|
|||
DisplayName = XDisplayName(DisplayName);
|
||||
setenv("DISPLAY", DisplayName, 1);
|
||||
|
||||
wXModifierInitialize();
|
||||
/* Path 1: skip XGetModifierMapping() when dpy is an XWayland
|
||||
* display. XWayland can only service X11 requests when the
|
||||
* Wayland event loop (wl_display_run) is running, which has not
|
||||
* started yet at this point in main.c. Calling XGetModifierMapping
|
||||
* before EventLoop() would deadlock waiting for a reply that
|
||||
* XWayland cannot deliver. Modifier masks are handled via XKB
|
||||
* in wl_backend (wSetModifierMasks), so this call is not needed. */
|
||||
if (!wm_backend->is_wayland)
|
||||
wXModifierInitialize();
|
||||
}
|
||||
StartUp(!multiHead);
|
||||
|
||||
|
|
|
|||
37
src/misc.c
37
src/misc.c
|
|
@ -76,6 +76,10 @@ static void eatExpose(void)
|
|||
{
|
||||
XEvent event, foo;
|
||||
|
||||
/* Phase 19: Wayland — no X11 event queue to drain */
|
||||
if (!dpy)
|
||||
return;
|
||||
|
||||
/* compress all expose events into a single one */
|
||||
|
||||
if (XCheckMaskEvent(dpy, ExposureMask, &event)) {
|
||||
|
|
@ -91,6 +95,11 @@ static void eatExpose(void)
|
|||
|
||||
void move_window(Window win, int from_x, int from_y, int to_x, int to_y)
|
||||
{
|
||||
/* Phase 19: Wayland — frame windows are virtual; skip X11 move */
|
||||
if (!dpy) {
|
||||
(void) win; (void) from_x; (void) from_y; (void) to_x; (void) to_y;
|
||||
return;
|
||||
}
|
||||
#ifdef USE_ANIMATIONS
|
||||
if (wPreferences.no_animations)
|
||||
XMoveWindow(dpy, win, to_x, to_y);
|
||||
|
|
@ -110,6 +119,12 @@ void move_window(Window win, int from_x, int from_y, int to_x, int to_y)
|
|||
* following windows are going to be offset by (ICON_SIZE*i,0) */
|
||||
void slide_windows(Window wins[], int n, int from_x, int from_y, int to_x, int to_y)
|
||||
{
|
||||
/* Phase 19: Wayland — frame windows are virtual; skip X11 slide */
|
||||
if (!dpy) {
|
||||
(void)wins; (void)n; (void)from_x; (void)from_y; (void)to_x; (void)to_y;
|
||||
return;
|
||||
}
|
||||
|
||||
time_t time0 = time(NULL);
|
||||
float dx, dy, x = from_x, y = from_y, px, py;
|
||||
Bool is_dx_nul, is_dy_nul;
|
||||
|
|
@ -291,6 +306,10 @@ static char *getTextSelection(WScreen * screen, Atom selection)
|
|||
{
|
||||
int buffer = -1;
|
||||
|
||||
/* Phase 19: Wayland — no X11 selection/clipboard available */
|
||||
if (!dpy)
|
||||
return NULL;
|
||||
|
||||
switch (selection) {
|
||||
case WA_CUT_BUFFER0:
|
||||
buffer = 0;
|
||||
|
|
@ -675,15 +694,20 @@ void ExecuteInputCommand(WScreen *scr, const char *cmdline)
|
|||
|
||||
cmd = ExpandOptions(scr, cmdline);
|
||||
if (cmd) {
|
||||
XGrabPointer(dpy, scr->root_win, True, 0,
|
||||
GrabModeAsync, GrabModeAsync, None, wPreferences.cursor[WCUR_WAIT], CurrentTime);
|
||||
XSync(dpy, False);
|
||||
/* Phase 19: Wayland — skip cursor grab visual feedback */
|
||||
if (dpy) {
|
||||
XGrabPointer(dpy, scr->root_win, True, 0,
|
||||
GrabModeAsync, GrabModeAsync, None, wPreferences.cursor[WCUR_WAIT], CurrentTime);
|
||||
XSync(dpy, False);
|
||||
}
|
||||
|
||||
ExecuteShellCommand(scr, cmd);
|
||||
wfree(cmd);
|
||||
|
||||
XUngrabPointer(dpy, CurrentTime);
|
||||
XSync(dpy, False);
|
||||
if (dpy) {
|
||||
XUngrabPointer(dpy, CurrentTime);
|
||||
XSync(dpy, False);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -790,6 +814,9 @@ char *GetShortcutKey(WShortKey key)
|
|||
}
|
||||
}
|
||||
|
||||
/* Phase 19: Wayland — no X11 keycode-to-keysym mapping available */
|
||||
if (!dpy)
|
||||
return NULL;
|
||||
key_name = XKeysymToString(W_KeycodeToKeysym(dpy, key.keycode, 0));
|
||||
if (!key_name)
|
||||
return NULL;
|
||||
|
|
|
|||
|
|
@ -130,11 +130,11 @@ void wPixmapDestroy(WPixmap * pix)
|
|||
{
|
||||
if (!pix->shared) {
|
||||
if (pix->mask && !pix->client_owned_mask) {
|
||||
XFreePixmap(dpy, pix->mask);
|
||||
if (dpy) XFreePixmap(dpy, pix->mask);
|
||||
}
|
||||
|
||||
if (pix->image && !pix->client_owned) {
|
||||
XFreePixmap(dpy, pix->image);
|
||||
if (dpy) XFreePixmap(dpy, pix->image);
|
||||
}
|
||||
}
|
||||
wfree(pix);
|
||||
|
|
|
|||
|
|
@ -35,6 +35,10 @@
|
|||
|
||||
int wGetColorForColormap(Colormap colormap, const char *color_name, XColor *color)
|
||||
{
|
||||
/* Phase 19: Wayland — no X11 colormap available */
|
||||
if (!dpy)
|
||||
return False;
|
||||
|
||||
if (!XParseColor(dpy, colormap, color_name, color)) {
|
||||
wwarning(_("could not parse color \"%s\""), color_name);
|
||||
return False;
|
||||
|
|
@ -53,6 +57,9 @@ int wGetColor(WScreen *scr, const char *color_name, XColor *color)
|
|||
|
||||
void wFreeColor(WScreen * scr, unsigned long pixel)
|
||||
{
|
||||
if (!dpy)
|
||||
return; /* Phase 19: Wayland — no colormap to free from */
|
||||
|
||||
if (pixel != scr->white_pixel && pixel != scr->black_pixel) {
|
||||
unsigned long colors[1];
|
||||
|
||||
|
|
|
|||
|
|
@ -158,10 +158,11 @@ WScreen *wScreenInit(int screen_number)
|
|||
wm_backend->monitors_select_events(scr);
|
||||
wm_backend->screen_set_root_cursor(scr, WCUR_ROOT);
|
||||
|
||||
/* Wayland path: screen_open() sets geometry; X11/wrlib context not needed.
|
||||
* Allocate workspace 0 directly (wWorkspaceNew is unsafe here because it
|
||||
* calls wDockCreate which requires X11 rendering resources). */
|
||||
if (!dpy) {
|
||||
/* Pure Wayland path (no XWayland display): skip X11/wrlib context setup
|
||||
* and allocate workspace 0 directly. When XWayland is available (dpy is
|
||||
* set, Path 1), fall through to the full X11 init so WINGs, RContext,
|
||||
* GCs, and menus work correctly on the XWayland display. */
|
||||
if (wm_backend->is_wayland && !dpy) {
|
||||
WWorkspace *wspace = wmalloc(sizeof(WWorkspace));
|
||||
wspace->name = wstrdup("Workspace 1");
|
||||
wspace->clip = NULL;
|
||||
|
|
|
|||
|
|
@ -177,8 +177,8 @@ static void getOffendingModifiers(void)
|
|||
Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask
|
||||
};
|
||||
|
||||
if (!dpy)
|
||||
return; /* Wayland: no modifier mapping to query */
|
||||
if (!dpy || wm_backend->is_wayland)
|
||||
return; /* Wayland: modifier mapping handled by wlroots/XKB */
|
||||
|
||||
nlock = wm_backend->keysym_to_keycode(WM_KEY_NUM_LOCK);
|
||||
slock = wm_backend->keysym_to_keycode(WM_KEY_SCROLL_LOCK);
|
||||
|
|
@ -474,8 +474,10 @@ void StartUp(Bool defaultScreenOnly)
|
|||
/* handle X shutdowns and errors via backend */
|
||||
wm_backend->register_error_handlers();
|
||||
|
||||
/* set hook for our event dispatcher in WINGs event dispatcher (X11 only) */
|
||||
if (dpy)
|
||||
/* set hook for our event dispatcher in WINGs event dispatcher (X11 only).
|
||||
* Skip for Wayland: we run a wlroots event loop, not a WINGs/X11 loop.
|
||||
* dpy may be set (XWayland bridge), but X11 event dispatch is not used. */
|
||||
if (dpy && !wm_backend->is_wayland)
|
||||
WMHookEventHandler(DispatchEvent);
|
||||
|
||||
/* initialize defaults stuff */
|
||||
|
|
@ -550,7 +552,7 @@ void StartUp(Bool defaultScreenOnly)
|
|||
if (dpy)
|
||||
InitializeSwitchMenu();
|
||||
|
||||
/* initialize/restore state for the screens (X11 only for now) */
|
||||
/* initialize/restore state for the screens */
|
||||
if (dpy) {
|
||||
for (j = 0; j < w_global.screen_count; j++) {
|
||||
int lastDesktop;
|
||||
|
|
@ -648,7 +650,7 @@ static void manageAllWindows(WScreen * scr, int crashRecovery)
|
|||
WWindow *wwin;
|
||||
|
||||
if (!dpy)
|
||||
return; /* Wayland: no pre-existing X11 clients to adopt */
|
||||
return; /* no display — nothing to adopt */
|
||||
|
||||
wm_backend->server_grab();
|
||||
XQueryTree(dpy, scr->root_win, &root, &parent, &children, &nchildren);
|
||||
|
|
|
|||
|
|
@ -47,6 +47,12 @@ WTexSolid *wTextureMakeSolid(WScreen * scr, XColor * color)
|
|||
texture->type = WTEX_SOLID;
|
||||
texture->subtype = 0;
|
||||
|
||||
/* Phase 19: Wayland — skip X11 color allocation and GC creation */
|
||||
if (!dpy) {
|
||||
texture->normal = *color;
|
||||
return texture;
|
||||
}
|
||||
|
||||
XAllocColor(dpy, scr->w_colormap, color);
|
||||
texture->normal = *color;
|
||||
if (color->red == 0 && color->blue == 0 && color->green == 0) {
|
||||
|
|
@ -127,9 +133,11 @@ void wTextureDestroy(WScreen * scr, WTexture * texture)
|
|||
#define CANFREE(c) (c!=scr->black_pixel && c!=scr->white_pixel && c!=0)
|
||||
switch (texture->any.type) {
|
||||
case WTEX_SOLID:
|
||||
XFreeGC(dpy, texture->solid.light_gc);
|
||||
XFreeGC(dpy, texture->solid.dark_gc);
|
||||
XFreeGC(dpy, texture->solid.dim_gc);
|
||||
if (dpy) {
|
||||
XFreeGC(dpy, texture->solid.light_gc);
|
||||
XFreeGC(dpy, texture->solid.dark_gc);
|
||||
XFreeGC(dpy, texture->solid.dim_gc);
|
||||
}
|
||||
if (CANFREE(texture->solid.light.pixel))
|
||||
colors[count++] = texture->solid.light.pixel;
|
||||
if (CANFREE(texture->solid.dim.pixel))
|
||||
|
|
@ -160,7 +168,8 @@ void wTextureDestroy(WScreen * scr, WTexture * texture)
|
|||
|
||||
if (CANFREE(texture->any.color.pixel))
|
||||
colors[count++] = texture->any.color.pixel;
|
||||
if (count > 0) {
|
||||
/* Phase 19: Wayland — skip X11 color/GC cleanup when no display */
|
||||
if (dpy && count > 0) {
|
||||
XErrorHandler oldhandler;
|
||||
|
||||
/* ignore error from buggy servers that don't know how
|
||||
|
|
@ -171,7 +180,8 @@ void wTextureDestroy(WScreen * scr, WTexture * texture)
|
|||
XSync(dpy, 0);
|
||||
XSetErrorHandler(oldhandler);
|
||||
}
|
||||
XFreeGC(dpy, texture->any.gc);
|
||||
if (dpy)
|
||||
XFreeGC(dpy, texture->any.gc);
|
||||
wfree(texture);
|
||||
#undef CANFREE
|
||||
}
|
||||
|
|
@ -192,10 +202,12 @@ WTexGradient *wTextureMakeGradient(WScreen *scr, int style, const RColor *from,
|
|||
texture->normal.green = (from->green + to->green) << 7;
|
||||
texture->normal.blue = (from->blue + to->blue) << 7;
|
||||
|
||||
XAllocColor(dpy, scr->w_colormap, &texture->normal);
|
||||
gcv.background = gcv.foreground = texture->normal.pixel;
|
||||
gcv.graphics_exposures = False;
|
||||
texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
|
||||
if (dpy) {
|
||||
XAllocColor(dpy, scr->w_colormap, &texture->normal);
|
||||
gcv.background = gcv.foreground = texture->normal.pixel;
|
||||
gcv.graphics_exposures = False;
|
||||
texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
|
@ -224,10 +236,12 @@ WTexIGradient *wTextureMakeIGradient(WScreen *scr, int thickness1, const RColor
|
|||
texture->normal.green = (colors2[0].green + colors2[1].green) << 7;
|
||||
texture->normal.blue = (colors2[0].blue + colors2[1].blue) << 7;
|
||||
}
|
||||
XAllocColor(dpy, scr->w_colormap, &texture->normal);
|
||||
gcv.background = gcv.foreground = texture->normal.pixel;
|
||||
gcv.graphics_exposures = False;
|
||||
texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
|
||||
if (dpy) {
|
||||
XAllocColor(dpy, scr->w_colormap, &texture->normal);
|
||||
gcv.background = gcv.foreground = texture->normal.pixel;
|
||||
gcv.graphics_exposures = False;
|
||||
texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
|
@ -252,10 +266,12 @@ WTexMGradient *wTextureMakeMGradient(WScreen * scr, int style, RColor ** colors)
|
|||
|
||||
texture->colors = colors;
|
||||
|
||||
XAllocColor(dpy, scr->w_colormap, &texture->normal);
|
||||
gcv.background = gcv.foreground = texture->normal.pixel;
|
||||
gcv.graphics_exposures = False;
|
||||
texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
|
||||
if (dpy) {
|
||||
XAllocColor(dpy, scr->w_colormap, &texture->normal);
|
||||
gcv.background = gcv.foreground = texture->normal.pixel;
|
||||
gcv.graphics_exposures = False;
|
||||
texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
|
||||
}
|
||||
|
||||
return texture;
|
||||
}
|
||||
|
|
@ -276,10 +292,12 @@ WTexPixmap *wTextureMakePixmap(WScreen *scr, int style, const char *pixmap_file,
|
|||
|
||||
texture->normal = *color;
|
||||
|
||||
XAllocColor(dpy, scr->w_colormap, &texture->normal);
|
||||
gcv.background = gcv.foreground = texture->normal.pixel;
|
||||
gcv.graphics_exposures = False;
|
||||
texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
|
||||
if (dpy) {
|
||||
XAllocColor(dpy, scr->w_colormap, &texture->normal);
|
||||
gcv.background = gcv.foreground = texture->normal.pixel;
|
||||
gcv.graphics_exposures = False;
|
||||
texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
|
||||
}
|
||||
|
||||
texture->pixmap = image;
|
||||
|
||||
|
|
@ -309,10 +327,12 @@ WTexTGradient *wTextureMakeTGradient(WScreen *scr, int style, const RColor *from
|
|||
texture->normal.green = (from->green + to->green) << 7;
|
||||
texture->normal.blue = (from->blue + to->blue) << 7;
|
||||
|
||||
XAllocColor(dpy, scr->w_colormap, &texture->normal);
|
||||
gcv.background = gcv.foreground = texture->normal.pixel;
|
||||
gcv.graphics_exposures = False;
|
||||
texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
|
||||
if (dpy) {
|
||||
XAllocColor(dpy, scr->w_colormap, &texture->normal);
|
||||
gcv.background = gcv.foreground = texture->normal.pixel;
|
||||
gcv.graphics_exposures = False;
|
||||
texture->normal_gc = XCreateGC(dpy, scr->w_win, GCForeground | GCBackground | GCGraphicsExposures, &gcv);
|
||||
}
|
||||
|
||||
texture->pixmap = image;
|
||||
|
||||
|
|
@ -535,6 +555,10 @@ void wDrawBevel(Drawable d, unsigned width, unsigned height, WTexSolid * texture
|
|||
if (relief == WREL_FLAT)
|
||||
return;
|
||||
|
||||
/* Phase 19: Wayland — no X11 display, skip bevel drawing */
|
||||
if (!dpy)
|
||||
return;
|
||||
|
||||
light = texture->light_gc;
|
||||
dim = texture->dim_gc;
|
||||
dark = texture->dark_gc;
|
||||
|
|
|
|||
Loading…
Reference in New Issue