303 lines
10 KiB
C
303 lines
10 KiB
C
/*
|
|
* widgets_x11.c — X11-specific WINGs platform init.
|
|
*
|
|
* Owns every Xlib call that used to live in widgets.c. The shared
|
|
* widgets.c is now backend-neutral and dispatches to this file (via
|
|
* direct function calls — ZZ TODO: vtable when adding more backends)
|
|
* for X11-specific setup.
|
|
*
|
|
* This file is the X11 counterpart to wclient_wl.c (Wayland client)
|
|
* and to the compositor-internal wl_backend.c paths.
|
|
*/
|
|
|
|
#include "WINGsP.h"
|
|
#include "WINGs/WINGsX11.h"
|
|
#include "wconfig.h"
|
|
|
|
#include <X11/Xutil.h>
|
|
#include <X11/Xatom.h>
|
|
#include <X11/keysym.h>
|
|
#include <X11/cursorfont.h>
|
|
#include <X11/Xlocale.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
/* These match the static stipple data in widgets.c (kept as fallback). */
|
|
#define STIPPLE_WIDTH 8
|
|
#define STIPPLE_HEIGHT 8
|
|
static char STIPPLE_BITS[] = {
|
|
0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55
|
|
};
|
|
|
|
/*
|
|
* W_X11PlatformInit — the GCs/cursors/atoms/IM init that the X11 view
|
|
* backend hooks via W_ViewBackendX11.platform_init. Moved from
|
|
* widgets.c so the shared file stops linking against Xlib.
|
|
*/
|
|
void W_X11PlatformInit(W_Screen *scrPtr)
|
|
{
|
|
Display *display = scrPtr->display;
|
|
XGCValues gcv;
|
|
Pixmap stipple;
|
|
int i;
|
|
static char *atomNames[] = {
|
|
"_GNUSTEP_WM_ATTR",
|
|
"WM_DELETE_WINDOW",
|
|
"WM_PROTOCOLS",
|
|
"CLIPBOARD",
|
|
"XdndAware",
|
|
"XdndSelection",
|
|
"XdndEnter",
|
|
"XdndLeave",
|
|
"XdndPosition",
|
|
"XdndDrop",
|
|
"XdndFinished",
|
|
"XdndTypeList",
|
|
"XdndActionList",
|
|
"XdndActionDescription",
|
|
"XdndStatus",
|
|
"XdndActionCopy",
|
|
"XdndActionMove",
|
|
"XdndActionLink",
|
|
"XdndActionAsk",
|
|
"XdndActionPrivate",
|
|
"_WINGS_DND_MOUSE_OFFSET",
|
|
"WM_STATE",
|
|
"UTF8_STRING",
|
|
"_NET_WM_NAME",
|
|
"_NET_WM_ICON_NAME",
|
|
"_NET_WM_ICON",
|
|
};
|
|
Atom atoms[wlengthof(atomNames)];
|
|
|
|
/* Create missing CUT_BUFFERs */
|
|
{
|
|
Atom *rootWinProps;
|
|
int exists[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
int count;
|
|
|
|
rootWinProps = XListProperties(display, scrPtr->rootWin, &count);
|
|
for (i = 0; i < count; i++) {
|
|
switch (rootWinProps[i]) {
|
|
case XA_CUT_BUFFER0: exists[0] = 1; break;
|
|
case XA_CUT_BUFFER1: exists[1] = 1; break;
|
|
case XA_CUT_BUFFER2: exists[2] = 1; break;
|
|
case XA_CUT_BUFFER3: exists[3] = 1; break;
|
|
case XA_CUT_BUFFER4: exists[4] = 1; break;
|
|
case XA_CUT_BUFFER5: exists[5] = 1; break;
|
|
case XA_CUT_BUFFER6: exists[6] = 1; break;
|
|
case XA_CUT_BUFFER7: exists[7] = 1; break;
|
|
default: break;
|
|
}
|
|
}
|
|
if (rootWinProps)
|
|
XFree(rootWinProps);
|
|
for (i = 0; i < 8; i++) {
|
|
if (!exists[i])
|
|
XStoreBuffer(display, "", 0, i);
|
|
}
|
|
}
|
|
|
|
/* Modifier mask detection */
|
|
scrPtr->ignoredModifierMask = 0;
|
|
{
|
|
XModifierKeymap *modmap;
|
|
KeyCode nlock, slock;
|
|
static int mask_table[8] = {
|
|
WM_MOD_SHIFT, WM_MOD_LOCK, WM_MOD_CONTROL, WM_MOD_MOD1,
|
|
WM_MOD_MOD2, WM_MOD_MOD3, WM_MOD_MOD4, WM_MOD_MOD5
|
|
};
|
|
unsigned int numLockMask = 0, scrollLockMask = 0;
|
|
|
|
nlock = XKeysymToKeycode(display, XK_Num_Lock);
|
|
slock = XKeysymToKeycode(display, XK_Scroll_Lock);
|
|
modmap = XGetModifierMapping(display);
|
|
if (modmap != NULL && modmap->max_keypermod > 0) {
|
|
for (i = 0; i < 8 * modmap->max_keypermod; i++) {
|
|
if (modmap->modifiermap[i] == nlock && nlock != 0)
|
|
numLockMask = mask_table[i / modmap->max_keypermod];
|
|
else if (modmap->modifiermap[i] == slock && slock != 0)
|
|
scrollLockMask = mask_table[i / modmap->max_keypermod];
|
|
}
|
|
}
|
|
if (modmap)
|
|
XFreeModifiermap(modmap);
|
|
scrPtr->ignoredModifierMask = numLockMask | scrollLockMask | WM_MOD_LOCK;
|
|
}
|
|
|
|
/* GCs */
|
|
gcv.graphics_exposures = False;
|
|
gcv.function = GXxor;
|
|
gcv.foreground = W_PIXEL(scrPtr->white);
|
|
if (gcv.foreground == 0)
|
|
gcv.foreground = 1;
|
|
scrPtr->xorGC = XCreateGC(display, W_DRAWABLE(scrPtr), GCFunction
|
|
| GCGraphicsExposures | GCForeground, &gcv);
|
|
|
|
gcv.function = GXxor;
|
|
gcv.foreground = W_PIXEL(scrPtr->gray);
|
|
gcv.subwindow_mode = IncludeInferiors;
|
|
scrPtr->ixorGC = XCreateGC(display, W_DRAWABLE(scrPtr), GCFunction
|
|
| GCGraphicsExposures | GCForeground | GCSubwindowMode, &gcv);
|
|
|
|
gcv.function = GXcopy;
|
|
scrPtr->copyGC = XCreateGC(display, W_DRAWABLE(scrPtr), GCFunction | GCGraphicsExposures, &gcv);
|
|
scrPtr->clipGC = XCreateGC(display, W_DRAWABLE(scrPtr), GCFunction | GCGraphicsExposures, &gcv);
|
|
|
|
stipple = XCreateBitmapFromData(display, W_DRAWABLE(scrPtr), STIPPLE_BITS, STIPPLE_WIDTH, STIPPLE_HEIGHT);
|
|
gcv.foreground = W_PIXEL(scrPtr->darkGray);
|
|
gcv.background = W_PIXEL(scrPtr->gray);
|
|
gcv.fill_style = FillStippled;
|
|
gcv.stipple = stipple;
|
|
scrPtr->stippleGC = XCreateGC(display, W_DRAWABLE(scrPtr),
|
|
GCForeground | GCBackground | GCStipple
|
|
| GCFillStyle | GCGraphicsExposures, &gcv);
|
|
scrPtr->drawStringGC = XCreateGC(display, W_DRAWABLE(scrPtr), GCGraphicsExposures, &gcv);
|
|
scrPtr->drawImStringGC = XCreateGC(display, W_DRAWABLE(scrPtr), GCGraphicsExposures, &gcv);
|
|
scrPtr->monoGC = XCreateGC(display, stipple, 0, NULL);
|
|
scrPtr->stipple = stipple;
|
|
|
|
/* Input method */
|
|
W_InitIM(scrPtr);
|
|
|
|
/* Cursors */
|
|
scrPtr->defaultCursor = XCreateFontCursor(display, XC_left_ptr);
|
|
scrPtr->textCursor = XCreateFontCursor(display, XC_xterm);
|
|
{
|
|
XColor bla;
|
|
Pixmap blank;
|
|
blank = XCreatePixmap(display, scrPtr->stipple, 1, 1, 1);
|
|
XSetForeground(display, scrPtr->monoGC, 0);
|
|
XFillRectangle(display, blank, scrPtr->monoGC, 0, 0, 1, 1);
|
|
scrPtr->invisibleCursor = XCreatePixmapCursor(display, blank, blank, &bla, &bla, 0, 0);
|
|
XFreePixmap(display, blank);
|
|
}
|
|
|
|
/* Atoms */
|
|
#ifdef HAVE_XINTERNATOMS
|
|
XInternAtoms(display, atomNames, wlengthof(atomNames), False, atoms);
|
|
#else
|
|
for (i = 0; i < wlengthof(atomNames); i++)
|
|
atoms[i] = XInternAtom(display, atomNames[i], False);
|
|
#endif
|
|
i = 0;
|
|
scrPtr->attribsAtom = atoms[i++];
|
|
scrPtr->deleteWindowAtom = atoms[i++];
|
|
scrPtr->protocolsAtom = atoms[i++];
|
|
scrPtr->clipboardAtom = atoms[i++];
|
|
scrPtr->xdndAwareAtom = atoms[i++];
|
|
scrPtr->xdndSelectionAtom = atoms[i++];
|
|
scrPtr->xdndEnterAtom = atoms[i++];
|
|
scrPtr->xdndLeaveAtom = atoms[i++];
|
|
scrPtr->xdndPositionAtom = atoms[i++];
|
|
scrPtr->xdndDropAtom = atoms[i++];
|
|
scrPtr->xdndFinishedAtom = atoms[i++];
|
|
scrPtr->xdndTypeListAtom = atoms[i++];
|
|
scrPtr->xdndActionListAtom = atoms[i++];
|
|
scrPtr->xdndActionDescriptionAtom = atoms[i++];
|
|
scrPtr->xdndStatusAtom = atoms[i++];
|
|
scrPtr->xdndActionCopy = atoms[i++];
|
|
scrPtr->xdndActionMove = atoms[i++];
|
|
scrPtr->xdndActionLink = atoms[i++];
|
|
scrPtr->xdndActionAsk = atoms[i++];
|
|
scrPtr->xdndActionPrivate = atoms[i++];
|
|
scrPtr->wmIconDragOffsetAtom = atoms[i++];
|
|
scrPtr->wmStateAtom = atoms[i++];
|
|
scrPtr->utf8String = atoms[i++];
|
|
scrPtr->netwmName = atoms[i++];
|
|
scrPtr->netwmIconName = atoms[i++];
|
|
scrPtr->netwmIcon = atoms[i++];
|
|
|
|
/* Application group leader */
|
|
W_InitApplication(scrPtr);
|
|
}
|
|
|
|
/*
|
|
* WMCreateScreen — public API: open a WINGs screen on an existing X11
|
|
* Display. Lives in the X11 backend file because it directly creates
|
|
* an X11 RContext via RCreateContext(). Wayland callers should use
|
|
* WMOpenScreen() instead.
|
|
*/
|
|
WMScreen *WMCreateScreen(Display * display, int screen)
|
|
{
|
|
return WMCreateScreenWithRContext(display, screen,
|
|
RCreateContext(display, screen, NULL));
|
|
}
|
|
|
|
/*
|
|
* WMCreateSimpleApplicationScreen — public API: like WMCreateScreen
|
|
* but defaults to the X server's default screen and marks the screen
|
|
* as a simple (no app-icon) application. X11-only.
|
|
*/
|
|
WMScreen *WMCreateSimpleApplicationScreen(Display * display)
|
|
{
|
|
WMScreen *scr = WMCreateScreen(display, DefaultScreen(display));
|
|
if (!scr) return NULL;
|
|
scr->aflags.hasAppIcon = 0;
|
|
scr->aflags.simpleApplication = 1;
|
|
return scr;
|
|
}
|
|
|
|
/*
|
|
* W_X11OpenDisplay — open the X11 display and return a populated WMScreen.
|
|
*
|
|
* Called by WMOpenScreen() from widgets.c when the autodetect logic
|
|
* decides this should be an X11 connection (no WAYLAND_DISPLAY env, no
|
|
* "wayland" prefix in the display string, etc.). Extracting this here
|
|
* lets widgets.c be free of XOpenDisplay.
|
|
*/
|
|
WMScreen *W_X11OpenDisplay(const char *display)
|
|
{
|
|
Display *dpy = XOpenDisplay(display && display[0] ? display : NULL);
|
|
if (!dpy) {
|
|
wwarning(_("WINGs: could not open display %s"), XDisplayName(display));
|
|
return NULL;
|
|
}
|
|
return WMCreateSimpleApplicationScreen(dpy);
|
|
}
|
|
|
|
/*
|
|
* W_PlatformBackendX11.detect — return 1 if this is an X11 connection.
|
|
*
|
|
* Rules:
|
|
* - explicit display string that does NOT start with "wayland" → X11.
|
|
* - display==NULL but DISPLAY env set → X11.
|
|
* - everything else → 0 (let the next backend try).
|
|
*
|
|
* The Wayland-client backend's detect() is consulted FIRST (registered
|
|
* earlier in W_PlatformBackends), so the typical "WAYLAND_DISPLAY set,
|
|
* DISPLAY unset" case picks Wayland. X11 is the fallback.
|
|
*/
|
|
static int x11_detect(const char *display)
|
|
{
|
|
if (display && strncmp(display, "wayland", 7) == 0)
|
|
return 0;
|
|
if (display && display[0])
|
|
return 1; /* explicit X display */
|
|
if (getenv("DISPLAY"))
|
|
return 1; /* legacy: DISPLAY set */
|
|
return 0; /* no display info; not us */
|
|
}
|
|
|
|
const W_PlatformBackend W_PlatformBackendX11 = {
|
|
.name = "x11",
|
|
.detect = x11_detect,
|
|
.open = W_X11OpenDisplay,
|
|
};
|
|
|
|
/*
|
|
* W_NativeInternAtom — atom-intern wrapper used by shared code that
|
|
* needs an Atom value at run-time (e.g. wtextfield.c's selection
|
|
* request handler). In X11 mode delegates to XInternAtom. In Wayland
|
|
* mode the stub in widgets_wl.c returns WM_NATIVE_NONE so the calling
|
|
* code falls into a "no match" branch and selection no-ops. Either
|
|
* way the shared file does not directly link against XInternAtom.
|
|
*/
|
|
WMNativeAtom W_NativeInternAtom(W_Screen *scr, const char *name)
|
|
{
|
|
if (!scr || !scr->display)
|
|
return WM_NATIVE_NONE;
|
|
return XInternAtom(scr->display, name, False);
|
|
}
|