[client] x11: implemented missing functionallity

This commit is contained in:
Geoffrey McRae 2021-01-27 10:41:39 +11:00
parent 2d1e3c8022
commit 2eac3dcb56
2 changed files with 589 additions and 372 deletions

View File

@ -7,6 +7,7 @@ pkg_check_modules(DISPLAYSERVER_X11_PKGCONFIG REQUIRED
xi xi
xfixes xfixes
xscrnsaver xscrnsaver
xinerama
) )
add_library(displayserver_X11 STATIC add_library(displayserver_X11 STATIC

View File

@ -19,19 +19,28 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include "interface/displayserver.h" #include "interface/displayserver.h"
#include <SDL2/SDL.h>
#include <X11/Xlib.h>
#include <GL/glx.h>
#include <stdbool.h> #include <stdbool.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/extensions/XInput2.h> #include <X11/extensions/XInput2.h>
#include <X11/extensions/scrnsaver.h> #include <X11/extensions/scrnsaver.h>
#include <X11/extensions/Xfixes.h> #include <X11/extensions/Xfixes.h>
#include <X11/extensions/Xinerama.h>
#include <GL/glx.h>
#include <EGL/eglext.h>
#include "app.h" #include "app.h"
#include "egl_dynprocs.h"
#include "common/debug.h" #include "common/debug.h"
#include "common/thread.h"
#define _NET_WM_STATE_REMOVE 0
#define _NET_WM_STATE_ADD 1
#define _NET_WM_STATE_TOGGLE 2
struct X11DSState struct X11DSState
{ {
@ -39,6 +48,8 @@ struct X11DSState
Window window; Window window;
int xinputOp; int xinputOp;
LGThread * eventThread;
int pointerDev; int pointerDev;
int keyboardDev; int keyboardDev;
@ -49,8 +60,13 @@ struct X11DSState
struct Rect rect; struct Rect rect;
struct Border border; struct Border border;
Cursor blankCursor;
Cursor squareCursor;
Atom aNetReqFrameExtents; Atom aNetReqFrameExtents;
Atom aNetFrameExtents; Atom aNetFrameExtents;
Atom aNetWMState;
Atom aNetWMStateFullscreen;
// clipboard members // clipboard members
Atom aSelection; Atom aSelection;
@ -88,11 +104,21 @@ static void x11CBSelectionIncr(const XPropertyEvent e);
static void x11CBSelectionNotify(const XSelectionEvent e); static void x11CBSelectionNotify(const XSelectionEvent e);
static void x11CBXFixesSelectionNotify(const XFixesSelectionNotifyEvent e); static void x11CBXFixesSelectionNotify(const XFixesSelectionNotifyEvent e);
static void x11SetFullscreen(bool fs);
static int x11EventThread(void * unused);
static void x11GenericEvent(XGenericEventCookie *cookie);
static bool x11Probe(void) static bool x11Probe(void)
{ {
return getenv("DISPLAY") != NULL; return getenv("DISPLAY") != NULL;
} }
static bool x11EarlyInit(void)
{
XInitThreads();
return true;
}
static bool x11Init(const LG_DSInitParams params) static bool x11Init(const LG_DSInitParams params)
{ {
XIDeviceInfo *devinfo; XIDeviceInfo *devinfo;
@ -100,13 +126,39 @@ static bool x11Init(const LG_DSInitParams params)
int event, error; int event, error;
memset(&x11, 0, sizeof(x11)); memset(&x11, 0, sizeof(x11));
x11.display = info->info.x11.display; x11.display = XOpenDisplay(NULL);
x11.window = info->info.x11.window;
XSetWindowAttributes swa =
{
.event_mask =
StructureNotifyMask |
PropertyChangeMask |
ExposureMask
};
x11.window = XCreateWindow(
x11.display,
XDefaultRootWindow(x11.display),
params.x, params.y,
params.w, params.h,
0,
CopyFromParent, InputOutput,
CopyFromParent, CWEventMask,
&swa);
XStoreName(x11.display, x11.window, params.title);
x11.aNetReqFrameExtents = x11.aNetReqFrameExtents =
XInternAtom(x11.display, "_NET_REQUEST_FRAME_EXTENTS", True); XInternAtom(x11.display, "_NET_REQUEST_FRAME_EXTENTS", True);
x11.aNetFrameExtents = x11.aNetFrameExtents =
XInternAtom(x11.display, "_NET_FRAME_EXTENTS", True); XInternAtom(x11.display, "_NET_FRAME_EXTENTS", True);
x11.aNetWMState =
XInternAtom(x11.display, "_NET_WM_STATE", True);
x11.aNetWMStateFullscreen =
XInternAtom(x11.display, "_NET_WM_STATE_FULLSCREEN", True);
if (params.fullscreen)
x11SetFullscreen(true);
if (x11.aNetReqFrameExtents) if (x11.aNetReqFrameExtents)
{ {
@ -126,7 +178,7 @@ static bool x11Init(const LG_DSInitParams params)
} }
int major = 2; int major = 2;
int minor = 3; int minor = 0;
if (XIQueryVersion(x11.display, &major, &minor) != Success) if (XIQueryVersion(x11.display, &major, &minor) != Success)
{ {
DEBUG_ERROR("Failed to query the XInput version"); DEBUG_ERROR("Failed to query the XInput version");
@ -135,36 +187,6 @@ static bool x11Init(const LG_DSInitParams params)
DEBUG_INFO("X11 XInput %d.%d in use", major, minor); DEBUG_INFO("X11 XInput %d.%d in use", major, minor);
XQueryExtension(x11.display, "XInputExtension", &x11.xinputOp, &event, &error);
int num_masks;
XIEventMask * mask = XIGetSelectedEvents(x11.display, x11.window, &num_masks);
if (!mask)
{
DEBUG_ERROR("Failed to get the XInput event mask");
return false;
}
for(int i = 0; i < num_masks; ++i)
{
XISetMask(mask[i].mask, XI_Motion );
XISetMask(mask[i].mask, XI_FocusIn );
XISetMask(mask[i].mask, XI_FocusOut );
XISetMask(mask[i].mask, XI_Enter );
XISetMask(mask[i].mask, XI_Leave );
XISetMask(mask[i].mask, XI_KeyPress );
XISetMask(mask[i].mask, XI_KeyRelease);
}
if (XISelectEvents(x11.display, x11.window, mask, num_masks) != Success)
{
XFree(mask);
DEBUG_ERROR("Failed to select the xinput events");
return false;
}
XFree(mask);
devinfo = XIQueryDevice(x11.display, XIAllDevices, &count); devinfo = XIQueryDevice(x11.display, XIAllDevices, &count);
if (!devinfo) if (!devinfo)
{ {
@ -221,6 +243,29 @@ static bool x11Init(const LG_DSInitParams params)
XIFreeDeviceInfo(devinfo); XIFreeDeviceInfo(devinfo);
XQueryExtension(x11.display, "XInputExtension", &x11.xinputOp, &event, &error);
XIEventMask eventmask;
unsigned char mask[XIMaskLen(XI_LASTEVENT)] = { 0 };
eventmask.deviceid = XIAllMasterDevices;
eventmask.mask_len = sizeof(mask);
eventmask.mask = mask;
XISetMask(mask, XI_FocusIn );
XISetMask(mask, XI_FocusOut );
XISetMask(mask, XI_Enter );
XISetMask(mask, XI_Leave );
XISetMask(mask, XI_Motion );
XISetMask(mask, XI_KeyPress );
XISetMask(mask, XI_KeyRelease);
if (XISelectEvents(x11.display, x11.window, &eventmask, 1) != Success)
{
XFree(mask);
DEBUG_ERROR("Failed to select the xinput events");
return false;
}
Atom NETWM_BYPASS_COMPOSITOR = XInternAtom(x11.display, Atom NETWM_BYPASS_COMPOSITOR = XInternAtom(x11.display,
"NETWM_BYPASS_COMPOSITOR", False); "NETWM_BYPASS_COMPOSITOR", False);
@ -236,6 +281,52 @@ static bool x11Init(const LG_DSInitParams params)
1 1
); );
/* create the blank cursor */
{
static char data[] = { 0x00 };
XColor dummy;
Pixmap temp = XCreateBitmapFromData(x11.display, x11.window, data, 1, 1);
x11.blankCursor = XCreatePixmapCursor(x11.display, temp, temp,
&dummy, &dummy, 0, 0);
XFreePixmap(x11.display, temp);
}
/* create the square cursor */
{
static char data[] = { 0x07, 0x05, 0x07 };
static char mask[] = { 0xff, 0xff, 0xff };
Colormap cmap = DefaultColormap(x11.display, DefaultScreen(x11.display));
XColor colors[2] =
{
{ .pixel = BlackPixelOfScreen(DefaultScreenOfDisplay(x11.display)) },
{ .pixel = WhitePixelOfScreen(DefaultScreenOfDisplay(x11.display)) }
};
XQueryColors(x11.display, cmap, colors, 2);
Pixmap img = XCreateBitmapFromData(x11.display, x11.window, data, 3, 3);
Pixmap msk = XCreateBitmapFromData(x11.display, x11.window, mask, 3, 3);
x11.squareCursor = XCreatePixmapCursor(x11.display, img, msk,
&colors[0], &colors[1], 1, 1);
XFreePixmap(x11.display, img);
XFreePixmap(x11.display, msk);
}
/* default to the square cursor */
XDefineCursor(x11.display, x11.window, x11.squareCursor);
XMapWindow(x11.display, x11.window);
XFlush(x11.display);
if (!lgCreateThread("X11EventThread", x11EventThread, NULL, &x11.eventThread))
{
DEBUG_ERROR("Failed to create the x11 event thread");
return false;
}
return true; return true;
} }
@ -249,6 +340,12 @@ static void x11Shutdown(void)
static void x11Free(void) static void x11Free(void)
{ {
lgJoinThread(x11.eventThread, NULL);
XDestroyWindow(x11.display, x11.window);
XFreeCursor(x11.display, x11.squareCursor);
XFreeCursor(x11.display, x11.blankCursor);
XCloseDisplay(x11.display);
} }
static bool x11GetProp(LG_DSProperty prop, void *ret) static bool x11GetProp(LG_DSProperty prop, void *ret)
@ -274,7 +371,8 @@ static bool x11GetProp(LG_DSProperty prop, void *ret)
int res, supportsGL; int res, supportsGL;
// Some GLX visuals do not use GL, and these must be ignored in our search. // Some GLX visuals do not use GL, and these must be ignored in our search.
if ((res = glXGetConfig(dpy, visual, GLX_USE_GL, &supportsGL)) != 0 || !supportsGL) if ((res = glXGetConfig(dpy, visual, GLX_USE_GL, &supportsGL)) != 0 ||
!supportsGL)
continue; continue;
int sampleBuffers, samples; int sampleBuffers, samples;
@ -300,38 +398,31 @@ static bool x11GetProp(LG_DSProperty prop, void *ret)
return true; return true;
} }
static bool x11EventFilter(SDL_Event * event) static int x11EventThread(void * unused)
{ {
/* prevent the default processing for the following events */ fd_set in_fds;
switch(event->type) const int fd = ConnectionNumber(x11.display);
{
case SDL_WINDOWEVENT:
switch(event->window.event)
{
case SDL_WINDOWEVENT_SIZE_CHANGED:
case SDL_WINDOWEVENT_RESIZED:
case SDL_WINDOWEVENT_CLOSE:
case SDL_WINDOWEVENT_FOCUS_GAINED:
case SDL_WINDOWEVENT_FOCUS_LOST:
case SDL_WINDOWEVENT_ENTER:
case SDL_WINDOWEVENT_LEAVE:
return true;
}
return false;
case SDL_KEYDOWN: while(app_isRunning())
case SDL_KEYUP: {
case SDL_MOUSEMOTION: if (!XPending(x11.display))
case SDL_MOUSEBUTTONDOWN: {
case SDL_MOUSEBUTTONUP: FD_ZERO(&in_fds);
case SDL_MOUSEWHEEL: FD_SET(fd, &in_fds);
return true; struct timeval tv =
{
.tv_usec = 250000,
.tv_sec = 0
};
int ret = select(fd + 1, &in_fds, NULL, NULL, &tv);
if (ret == 0 || !XPending(x11.display))
continue;
} }
if (event->type != SDL_SYSWMEVENT) XEvent xe;
return false; XNextEvent(x11.display, &xe);
XEvent xe = event->syswm.msg->msg.x11.event;
switch(xe.type) switch(xe.type)
{ {
case ConfigureNotify: case ConfigureNotify:
@ -357,119 +448,196 @@ static bool x11EventFilter(SDL_Event * event)
app_updateWindowPos(x, y); app_updateWindowPos(x, y);
app_handleResizeEvent(x11.rect.w, x11.rect.h, x11.border); app_handleResizeEvent(x11.rect.w, x11.rect.h, x11.border);
return true; break;
} }
case GenericEvent: case GenericEvent:
{ {
XGenericEventCookie *cookie = (XGenericEventCookie*)&xe.xcookie; XGenericEventCookie *cookie = (XGenericEventCookie*)&xe.xcookie;
XGetEventData(x11.display, cookie);
x11GenericEvent(cookie);
XFreeEventData(x11.display, cookie);
break;
}
// clipboard events
case SelectionRequest:
x11CBSelectionRequest(xe.xselectionrequest);
break;
case SelectionClear:
x11CBSelectionClear(xe.xselectionclear);
break;
case SelectionNotify:
x11CBSelectionNotify(xe.xselection);
break;
case PropertyNotify:
if (xe.xproperty.display != x11.display ||
xe.xproperty.window != x11.window ||
xe.xproperty.state != PropertyNewValue)
break;
if (xe.xproperty.atom == x11.aNetFrameExtents)
{
Atom type;
int fmt;
unsigned long num, bytes;
unsigned char *data;
if (XGetWindowProperty(x11.display, x11.window,
x11.aNetFrameExtents, 0, 4, False, AnyPropertyType,
&type, &fmt, &num, &bytes, &data) != Success)
break;
if (num >= 4)
{
long *cardinal = (long *)data;
x11.border.left = cardinal[0];
x11.border.right = cardinal[1];
x11.border.top = cardinal[2];
x11.border.bottom = cardinal[3];
app_handleResizeEvent(x11.rect.w, x11.rect.h, x11.border);
}
XFree(data);
break;
}
if (xe.xproperty.atom == x11.aSelData)
{
if (x11.lowerBound == 0)
break;
x11CBSelectionIncr(xe.xproperty);
break;
}
break;
default:
if (xe.type == x11.eventBase + XFixesSelectionNotify)
{
XFixesSelectionNotifyEvent * sne = (XFixesSelectionNotifyEvent *)&xe;
x11CBXFixesSelectionNotify(*sne);
}
break;
}
}
return 0;
}
static void x11GenericEvent(XGenericEventCookie *cookie)
{
if (cookie->extension != x11.xinputOp) if (cookie->extension != x11.xinputOp)
return false; return;
switch(cookie->evtype) switch(cookie->evtype)
{ {
case XI_FocusIn: case XI_FocusIn:
{ {
if (x11.focused) if (x11.focused)
return true; return;
XIFocusOutEvent *xie = cookie->data; XIFocusOutEvent *xie = cookie->data;
if (xie->mode != XINotifyNormal && if (xie->mode != XINotifyNormal &&
xie->mode != XINotifyWhileGrabbed && xie->mode != XINotifyWhileGrabbed &&
xie->mode != XINotifyUngrab) xie->mode != XINotifyUngrab)
return true; return;
x11.focused = true; x11.focused = true;
app_updateCursorPos(xie->event_x, xie->event_y); app_updateCursorPos(xie->event_x, xie->event_y);
app_handleFocusEvent(true); app_handleFocusEvent(true);
return true; return;
} }
case XI_FocusOut: case XI_FocusOut:
{ {
if (!x11.focused) if (!x11.focused)
return true; return;
XIFocusOutEvent *xie = cookie->data; XIFocusOutEvent *xie = cookie->data;
if (xie->mode != XINotifyNormal && if (xie->mode != XINotifyNormal &&
xie->mode != XINotifyWhileGrabbed && xie->mode != XINotifyWhileGrabbed &&
xie->mode != XINotifyGrab) xie->mode != XINotifyGrab)
return true; return;
app_updateCursorPos(xie->event_x, xie->event_y); app_updateCursorPos(xie->event_x, xie->event_y);
app_handleFocusEvent(false); app_handleFocusEvent(false);
x11.focused = false; x11.focused = false;
return true; return;
} }
case XI_Enter: case XI_Enter:
{ {
if (x11.entered) if (x11.entered)
return true; return;
XIEnterEvent *xie = cookie->data; XIEnterEvent *xie = cookie->data;
app_updateCursorPos(xie->event_x, xie->event_y); app_updateCursorPos(xie->event_x, xie->event_y);
app_handleEnterEvent(true); app_handleEnterEvent(true);
x11.entered = true; x11.entered = true;
return true; return;
} }
case XI_Leave: case XI_Leave:
{ {
if (!x11.entered) if (!x11.entered)
return true; return;
XILeaveEvent *xie = cookie->data; XILeaveEvent *xie = cookie->data;
app_updateCursorPos(xie->event_x, xie->event_y); app_updateCursorPos(xie->event_x, xie->event_y);
app_handleEnterEvent(false); app_handleEnterEvent(false);
x11.entered = false; x11.entered = false;
return true; return;
} }
case XI_KeyPress: case XI_KeyPress:
{ {
if (!x11.focused || x11.keyboardGrabbed) if (!x11.focused || x11.keyboardGrabbed)
return true; return;
XIDeviceEvent *device = cookie->data; XIDeviceEvent *device = cookie->data;
app_handleKeyPress(device->detail - 8); app_handleKeyPress(device->detail - 8);
return true; return;
} }
case XI_KeyRelease: case XI_KeyRelease:
{ {
if (!x11.focused || x11.keyboardGrabbed) if (!x11.focused || x11.keyboardGrabbed)
return true; return;
XIDeviceEvent *device = cookie->data; XIDeviceEvent *device = cookie->data;
app_handleKeyRelease(device->detail - 8); app_handleKeyRelease(device->detail - 8);
return true; return;
} }
case XI_RawKeyPress: case XI_RawKeyPress:
{ {
if (!x11.focused) if (!x11.focused)
return true; return;
XIRawEvent *raw = cookie->data; XIRawEvent *raw = cookie->data;
app_handleKeyPress(raw->detail - 8); app_handleKeyPress(raw->detail - 8);
return true; return;
} }
case XI_RawKeyRelease: case XI_RawKeyRelease:
{ {
if (!x11.focused) if (!x11.focused)
return true; return;
XIRawEvent *raw = cookie->data; XIRawEvent *raw = cookie->data;
app_handleKeyRelease(raw->detail - 8); app_handleKeyRelease(raw->detail - 8);
return true; return;
} }
case XI_RawButtonPress: case XI_RawButtonPress:
{ {
if (!x11.focused || !x11.entered) if (!x11.focused || !x11.entered)
return true; return;
XIRawEvent *raw = cookie->data; XIRawEvent *raw = cookie->data;
@ -477,20 +645,20 @@ static bool x11EventFilter(SDL_Event * event)
static Time prev_time = 0; static Time prev_time = 0;
static unsigned int prev_detail = 0; static unsigned int prev_detail = 0;
if (raw->time == prev_time && raw->detail == prev_detail) if (raw->time == prev_time && raw->detail == prev_detail)
return true; return;
prev_time = raw->time; prev_time = raw->time;
prev_detail = raw->detail; prev_detail = raw->detail;
app_handleButtonPress( app_handleButtonPress(
raw->detail > 5 ? raw->detail - 2 : raw->detail); raw->detail > 5 ? raw->detail - 2 : raw->detail);
return true; return;
} }
case XI_RawButtonRelease: case XI_RawButtonRelease:
{ {
if (!x11.focused || !x11.entered) if (!x11.focused || !x11.entered)
return true; return;
XIRawEvent *raw = cookie->data; XIRawEvent *raw = cookie->data;
@ -498,14 +666,14 @@ static bool x11EventFilter(SDL_Event * event)
static Time prev_time = 0; static Time prev_time = 0;
static unsigned int prev_detail = 0; static unsigned int prev_detail = 0;
if (raw->time == prev_time && raw->detail == prev_detail) if (raw->time == prev_time && raw->detail == prev_detail)
return true; return;
prev_time = raw->time; prev_time = raw->time;
prev_detail = raw->detail; prev_detail = raw->detail;
app_handleButtonRelease( app_handleButtonRelease(
raw->detail > 5 ? raw->detail - 2 : raw->detail); raw->detail > 5 ? raw->detail - 2 : raw->detail);
return true; return;
} }
case XI_Motion: case XI_Motion:
@ -515,13 +683,13 @@ static bool x11EventFilter(SDL_Event * event)
if (!x11.pointerGrabbed) if (!x11.pointerGrabbed)
app_handleMouseNormal(0.0, 0.0); app_handleMouseNormal(0.0, 0.0);
return true; return;
} }
case XI_RawMotion: case XI_RawMotion:
{ {
if (!x11.focused || !x11.entered) if (!x11.focused || !x11.entered)
return true; return;
XIRawEvent *raw = cookie->data; XIRawEvent *raw = cookie->data;
double raw_axis[2]; double raw_axis[2];
@ -549,7 +717,7 @@ static bool x11EventFilter(SDL_Event * event)
/* filter out scroll wheel and other events */ /* filter out scroll wheel and other events */
if (count < 2) if (count < 2)
return true; return;
/* filter out duplicate events */ /* filter out duplicate events */
static Time prev_time = 0; static Time prev_time = 0;
@ -557,7 +725,7 @@ static bool x11EventFilter(SDL_Event * event)
if (raw->time == prev_time && if (raw->time == prev_time &&
axis[0] == prev_axis[0] && axis[0] == prev_axis[0] &&
axis[1] == prev_axis[1]) axis[1] == prev_axis[1])
return true; return;
prev_time = raw->time; prev_time = raw->time;
prev_axis[0] = axis[0]; prev_axis[0] = axis[0];
@ -574,77 +742,57 @@ static bool x11EventFilter(SDL_Event * event)
if (app_cursorInWindow()) if (app_cursorInWindow())
app_handleMouseNormal(axis[0], axis[1]); app_handleMouseNormal(axis[0], axis[1]);
return true; return;
} }
} }
}
return false; #ifdef ENABLE_EGL
} static EGLDisplay x11GetEGLDisplay(void)
{
EGLDisplay ret;
const char *early_exts = eglQueryString(NULL, EGL_EXTENSIONS);
// clipboard events if (strstr(early_exts, "EGL_KHR_platform_base") != NULL &&
case SelectionRequest: g_egl_dynProcs.eglGetPlatformDisplay)
x11CBSelectionRequest(xe.xselectionrequest);
return true;
case SelectionClear:
x11CBSelectionClear(xe.xselectionclear);
return true;
case SelectionNotify:
x11CBSelectionNotify(xe.xselection);
return true;
case PropertyNotify:
if (xe.xproperty.display != x11.display ||
xe.xproperty.window != x11.window ||
xe.xproperty.state != PropertyNewValue)
return false;
if (xe.xproperty.atom == x11.aNetFrameExtents)
{ {
Atom type; DEBUG_INFO("Using eglGetPlatformDisplay");
int fmt; ret = g_egl_dynProcs.eglGetPlatformDisplay(EGL_PLATFORM_X11_KHR,
unsigned long num, bytes; x11.display, NULL);
unsigned char *data; }
else if (strstr(early_exts, "EGL_EXT_platform_base") != NULL &&
if (XGetWindowProperty(x11.display, x11.window, g_egl_dynProcs.eglGetPlatformDisplayEXT)
x11.aNetFrameExtents, 0, 4, False, AnyPropertyType,
&type, &fmt, &num, &bytes, &data) != Success)
return true;
if (num >= 4)
{ {
long *cardinal = (long *)data; DEBUG_INFO("Using eglGetPlatformDisplayEXT");
x11.border.left = cardinal[0]; ret = g_egl_dynProcs.eglGetPlatformDisplayEXT(EGL_PLATFORM_X11_KHR,
x11.border.right = cardinal[1]; x11.display, NULL);
x11.border.top = cardinal[2];
x11.border.bottom = cardinal[3];
app_handleResizeEvent(x11.rect.w, x11.rect.h, x11.border);
} }
else
XFree(data);
return true;
}
if (xe.xproperty.atom == x11.aSelData)
{ {
if (x11.lowerBound == 0) DEBUG_INFO("Using eglGetDisplay");
return false; ret = eglGetDisplay(x11.display);
x11CBSelectionIncr(xe.xproperty);
return true;
} }
return true; return ret;
}
default: static EGLNativeWindowType x11GetEGLNativeWindow(void)
if (xe.type == x11.eventBase + XFixesSelectionNotify) {
{ return (EGLNativeWindowType)x11.window;
XFixesSelectionNotifyEvent * sne = (XFixesSelectionNotifyEvent *)&xe; }
x11CBXFixesSelectionNotify(*sne); #endif
return true;
} static void x11GLSwapBuffers(void)
return false; {
} glXSwapBuffers(x11.display, x11.window);
}
static void x11ShowPointer(bool show)
{
if (show)
XDefineCursor(x11.display, x11.window, x11.squareCursor);
else
XDefineCursor(x11.display, x11.window, x11.blankCursor);
} }
static void x11PrintGrabError(const char * type, int dev, Status ret) static void x11PrintGrabError(const char * type, int dev, Status ret)
@ -671,9 +819,9 @@ static void x11GrabPointer(void)
if (x11.pointerGrabbed) if (x11.pointerGrabbed)
return; return;
unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 }; unsigned char mask_bits[XIMaskLen(XI_LASTEVENT)] = { 0 };
XIEventMask mask = { XIEventMask mask = {
XIAllMasterDevices, x11.pointerDev,
sizeof(mask_bits), sizeof(mask_bits),
mask_bits mask_bits
}; };
@ -721,7 +869,7 @@ static void x11GrabKeyboard(void)
unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 }; unsigned char mask_bits[XIMaskLen (XI_LASTEVENT)] = { 0 };
XIEventMask mask = { XIEventMask mask = {
XIAllMasterDevices, x11.keyboardDev,
sizeof(mask_bits), sizeof(mask_bits),
mask_bits mask_bits
}; };
@ -773,6 +921,32 @@ static void x11WarpPointer(int x, int y, bool exiting)
XSync(x11.display, False); XSync(x11.display, False);
} }
static void x11RealignPointer(void)
{
app_handleMouseNormal(0, 0);
}
static bool x11IsValidPointerPos(int x, int y)
{
int screens;
XineramaScreenInfo *xinerama = XineramaQueryScreens(x11.display, &screens);
if(!xinerama)
return true;
bool ret = false;
for(int i = 0; i < screens; ++i)
if (x >= xinerama[i].x_org && x < xinerama[i].x_org + xinerama[i].width &&
y >= xinerama[i].y_org && y < xinerama[i].y_org + xinerama[i].height)
{
ret = true;
break;
}
XFree(xinerama);
return ret;
}
static void x11InhibitIdle(void) static void x11InhibitIdle(void)
{ {
XScreenSaverSuspend(x11.display, true); XScreenSaverSuspend(x11.display, true);
@ -783,6 +957,38 @@ static void x11UninhibitIdle(void)
XScreenSaverSuspend(x11.display, false); XScreenSaverSuspend(x11.display, false);
} }
static void x11Wait(unsigned int time)
{
usleep(time * 1000U);
}
static void x11SetWindowSize(int w, int h)
{
XResizeWindow(x11.display, x11.window, w, h);
}
static void x11SetFullscreen(bool fs)
{
XEvent e =
{
.xclient = {
.type = ClientMessage,
.send_event = true,
.message_type = x11.aNetWMState,
.format = 32,
.window = x11.window,
.data.l = {
fs ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE,
x11.aNetWMStateFullscreen,
0
}
}
};
XSendEvent(x11.display, DefaultRootWindow(x11.display), False,
SubstructureNotifyMask | SubstructureRedirectMask, &e);
}
static bool x11CBInit() static bool x11CBInit()
{ {
x11.aSelection = XInternAtom(x11.display, "CLIPBOARD" , False); x11.aSelection = XInternAtom(x11.display, "CLIPBOARD" , False);
@ -1113,20 +1319,30 @@ static void x11CBRequest(LG_ClipboardData type)
struct LG_DisplayServerOps LGDS_X11 = struct LG_DisplayServerOps LGDS_X11 =
{ {
.probe = x11Probe, .probe = x11Probe,
.earlyInit = x11EarlyInit,
.init = x11Init, .init = x11Init,
.startup = x11Startup, .startup = x11Startup,
.shutdown = x11Shutdown, .shutdown = x11Shutdown,
.free = x11Free, .free = x11Free,
.getProp = x11GetProp, .getProp = x11GetProp,
.eventFilter = x11EventFilter, #ifdef ENABLE_EGL
.getEGLDisplay = x11GetEGLDisplay,
.getEGLNativeWindow = x11GetEGLNativeWindow,
#endif
.glSwapBuffers = x11GLSwapBuffers,
.showPointer = x11ShowPointer,
.grabPointer = x11GrabPointer, .grabPointer = x11GrabPointer,
.ungrabPointer = x11UngrabPointer, .ungrabPointer = x11UngrabPointer,
.grabKeyboard = x11GrabKeyboard, .grabKeyboard = x11GrabKeyboard,
.ungrabKeyboard = x11UngrabKeyboard, .ungrabKeyboard = x11UngrabKeyboard,
.warpPointer = x11WarpPointer, .warpPointer = x11WarpPointer,
.realignPointer = x11RealignPointer,
.isValidPointerPos = x11IsValidPointerPos,
.inhibitIdle = x11InhibitIdle, .inhibitIdle = x11InhibitIdle,
.uninhibitIdle = x11UninhibitIdle, .uninhibitIdle = x11UninhibitIdle,
.wait = x11Wait,
.setWindowSize = x11SetWindowSize,
.setFullscreen = x11SetFullscreen,
.cbInit = x11CBInit, .cbInit = x11CBInit,
.cbNotice = x11CBNotice, .cbNotice = x11CBNotice,