[client] x11: split out clipboard code for maintainabillity

This commit is contained in:
Geoffrey McRae 2021-03-27 09:21:32 +11:00
parent ab4d7cb94b
commit 2f14d64289
5 changed files with 542 additions and 431 deletions

View File

@ -12,6 +12,7 @@ pkg_check_modules(DISPLAYSERVER_X11_PKGCONFIG REQUIRED
add_library(displayserver_X11 STATIC
x11.c
clipboard.c
)
add_definitions(-D GLX_GLXEXT_PROTOTYPES)

View File

@ -0,0 +1,427 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
Copyright (C) 2017-2021 Geoffrey McRae <geoff@hostfission.com>
https://looking-glass.hostfission.com
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "clipboard.h"
#include "x11.h"
#include <string.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include "app.h"
#include "common/debug.h"
struct X11ClipboardState
{
Atom aSelection;
Atom aCurSelection;
Atom aTargets;
Atom aSelData;
Atom aIncr;
Atom aTypes[LG_CLIPBOARD_DATA_NONE];
LG_ClipboardData type;
bool haveRequest;
bool incrStart;
unsigned int lowerBound;
};
static const char * atomTypes[] =
{
"UTF8_STRING",
"image/png",
"image/bmp",
"image/tiff",
"image/jpeg"
};
static struct X11ClipboardState x11cb;
// forwards
static void x11CBSelectionRequest(const XSelectionRequestEvent e);
static void x11CBSelectionClear(const XSelectionClearEvent e);
static void x11CBSelectionIncr(const XPropertyEvent e);
static void x11CBSelectionNotify(const XSelectionEvent e);
static void x11CBXFixesSelectionNotify(const XFixesSelectionNotifyEvent e);
void x11CBEventThread(const XEvent xe)
{
switch(xe.type)
{
case SelectionRequest:
x11CBSelectionRequest(xe.xselectionrequest);
break;
case SelectionClear:
x11CBSelectionClear(xe.xselectionclear);
break;
case SelectionNotify:
x11CBSelectionNotify(xe.xselection);
break;
case PropertyNotify:
if (xe.xproperty.atom == x11cb.aSelData)
{
if (x11cb.lowerBound == 0)
break;
x11CBSelectionIncr(xe.xproperty);
break;
}
break;
default:
if (xe.type == x11.eventBase + XFixesSelectionNotify)
{
XFixesSelectionNotifyEvent * sne = (XFixesSelectionNotifyEvent *)&xe;
x11CBXFixesSelectionNotify(*sne);
}
break;
}
}
bool x11CBInit()
{
x11cb.aSelection = XInternAtom(x11.display, "CLIPBOARD" , False);
x11cb.aTargets = XInternAtom(x11.display, "TARGETS" , False);
x11cb.aSelData = XInternAtom(x11.display, "SEL_DATA" , False);
x11cb.aIncr = XInternAtom(x11.display, "INCR" , False);
x11cb.aCurSelection = BadValue;
for(int i = 0; i < LG_CLIPBOARD_DATA_NONE; ++i)
{
x11cb.aTypes[i] = XInternAtom(x11.display, atomTypes[i], False);
if (x11cb.aTypes[i] == BadAlloc || x11cb.aTypes[i] == BadValue)
{
DEBUG_ERROR("failed to get atom for type: %s", atomTypes[i]);
return false;
}
}
// use xfixes to get clipboard change notifications
if (!XFixesQueryExtension(x11.display, &x11.eventBase, &x11.errorBase))
{
DEBUG_ERROR("failed to initialize xfixes");
return false;
}
XFixesSelectSelectionInput(x11.display, x11.window,
XA_PRIMARY, XFixesSetSelectionOwnerNotifyMask);
XFixesSelectSelectionInput(x11.display, x11.window,
x11cb.aSelection, XFixesSetSelectionOwnerNotifyMask);
return true;
}
static void x11CBReplyFn(void * opaque, LG_ClipboardData type,
uint8_t * data, uint32_t size)
{
XEvent *s = (XEvent *)opaque;
XChangeProperty(
x11.display ,
s->xselection.requestor,
s->xselection.property ,
s->xselection.target ,
8,
PropModeReplace,
data,
size);
XSendEvent(x11.display, s->xselection.requestor, 0, 0, s);
XFlush(x11.display);
free(s);
}
static void x11CBSelectionRequest(const XSelectionRequestEvent e)
{
XEvent * s = (XEvent *)malloc(sizeof(XEvent));
s->xselection.type = SelectionNotify;
s->xselection.requestor = e.requestor;
s->xselection.selection = e.selection;
s->xselection.target = e.target;
s->xselection.property = e.property;
s->xselection.time = e.time;
if (!x11cb.haveRequest)
goto nodata;
// target list requested
if (e.target == x11cb.aTargets)
{
Atom targets[2];
targets[0] = x11cb.aTargets;
targets[1] = x11cb.aTypes[x11cb.type];
XChangeProperty(
e.display,
e.requestor,
e.property,
XA_ATOM,
32,
PropModeReplace,
(unsigned char*)targets,
sizeof(targets) / sizeof(Atom));
goto send;
}
// look to see if we can satisfy the data type
for(int i = 0; i < LG_CLIPBOARD_DATA_NONE; ++i)
if (x11cb.aTypes[i] == e.target && x11cb.type == i)
{
// request the data
app_clipboardRequest(x11CBReplyFn, s);
return;
}
nodata:
// report no data
s->xselection.property = None;
send:
XSendEvent(x11.display, e.requestor, 0, 0, s);
XFlush(x11.display);
free(s);
}
static void x11CBSelectionClear(const XSelectionClearEvent e)
{
if (e.selection != XA_PRIMARY && e.selection != x11cb.aSelection)
return;
x11cb.aCurSelection = BadValue;
app_clipboardRelease();
return;
}
static void x11CBSelectionIncr(const XPropertyEvent e)
{
Atom type;
int format;
unsigned long itemCount, after;
unsigned char *data;
if (XGetWindowProperty(
e.display,
e.window,
e.atom,
0, ~0L, // start and length
True, // delete the property
x11cb.aIncr,
&type,
&format,
&itemCount,
&after,
&data) != Success)
{
DEBUG_INFO("GetProp Failed");
app_clipboardNotify(LG_CLIPBOARD_DATA_NONE, 0);
goto out;
}
LG_ClipboardData dataType;
for(dataType = 0; dataType < LG_CLIPBOARD_DATA_NONE; ++dataType)
if (x11cb.aTypes[dataType] == type)
break;
if (dataType == LG_CLIPBOARD_DATA_NONE)
{
DEBUG_WARN("clipboard data (%s) not in a supported format",
XGetAtomName(x11.display, type));
x11cb.lowerBound = 0;
app_clipboardNotify(LG_CLIPBOARD_DATA_NONE, 0);
goto out;
}
if (x11cb.incrStart)
{
app_clipboardNotify(dataType, x11cb.lowerBound);
x11cb.incrStart = false;
}
XFree(data);
data = NULL;
if (XGetWindowProperty(
e.display,
e.window,
e.atom,
0, ~0L, // start and length
True, // delete the property
type,
&type,
&format,
&itemCount,
&after,
&data) != Success)
{
DEBUG_ERROR("XGetWindowProperty Failed");
app_clipboardNotify(LG_CLIPBOARD_DATA_NONE, 0);
goto out;
}
app_clipboardData(dataType, data, itemCount);
x11cb.lowerBound -= itemCount;
out:
if (data)
XFree(data);
}
static void x11CBXFixesSelectionNotify(const XFixesSelectionNotifyEvent e)
{
// check if the selection is valid and it isn't ourself
if ((e.selection != XA_PRIMARY && e.selection != x11cb.aSelection) ||
e.owner == x11.window || e.owner == 0)
{
return;
}
// remember which selection we are working with
x11cb.aCurSelection = e.selection;
XConvertSelection(
x11.display,
e.selection,
x11cb.aTargets,
x11cb.aTargets,
x11.window,
CurrentTime);
return;
}
static void x11CBSelectionNotify(const XSelectionEvent e)
{
if (e.property == None)
return;
Atom type;
int format;
unsigned long itemCount, after;
unsigned char *data;
if (XGetWindowProperty(
e.display,
e.requestor,
e.property,
0, ~0L, // start and length
True , // delete the property
AnyPropertyType,
&type,
&format,
&itemCount,
&after,
&data) != Success)
{
app_clipboardNotify(LG_CLIPBOARD_DATA_NONE, 0);
goto out;
}
if (type == x11cb.aIncr)
{
x11cb.incrStart = true;
x11cb.lowerBound = *(unsigned int *)data;
goto out;
}
// the target list
if (e.property == x11cb.aTargets)
{
// the format is 32-bit and we must have data
// this is technically incorrect however as it's
// an array of padded 64-bit values
if (!data || format != 32)
goto out;
// see if we support any of the targets listed
const uint64_t * targets = (const uint64_t *)data;
for(unsigned long i = 0; i < itemCount; ++i)
{
for(int n = 0; n < LG_CLIPBOARD_DATA_NONE; ++n)
if (x11cb.aTypes[n] == targets[i])
{
// we have a match, so send the notification
app_clipboardNotify(n, 0);
goto out;
}
}
// no matches
app_clipboardNotify(LG_CLIPBOARD_DATA_NONE, 0);
goto out;
}
if (e.property == x11cb.aSelData)
{
LG_ClipboardData dataType;
for(dataType = 0; dataType < LG_CLIPBOARD_DATA_NONE; ++dataType)
if (x11cb.aTypes[dataType] == type)
break;
if (dataType == LG_CLIPBOARD_DATA_NONE)
{
DEBUG_WARN("clipboard data (%s) not in a supported format",
XGetAtomName(x11.display, type));
goto out;
}
app_clipboardData(dataType, data, itemCount);
goto out;
}
out:
if (data)
XFree(data);
}
void x11CBNotice(LG_ClipboardData type)
{
x11cb.haveRequest = true;
x11cb.type = type;
XSetSelectionOwner(x11.display, XA_PRIMARY , x11.window, CurrentTime);
XSetSelectionOwner(x11.display, x11cb.aSelection, x11.window, CurrentTime);
XFlush(x11.display);
}
void x11CBRelease(void)
{
x11cb.haveRequest = false;
XSetSelectionOwner(x11.display, XA_PRIMARY , None, CurrentTime);
XSetSelectionOwner(x11.display, x11cb.aSelection, None, CurrentTime);
XFlush(x11.display);
}
void x11CBRequest(LG_ClipboardData type)
{
if (x11cb.aCurSelection == BadValue)
return;
XConvertSelection(
x11.display,
x11cb.aCurSelection,
x11cb.aTypes[type],
x11cb.aSelData,
x11.window,
CurrentTime);
}

View File

@ -0,0 +1,35 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
Copyright (C) 2017-2021 Geoffrey McRae <geoff@hostfission.com>
https://looking-glass.hostfission.com
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _H_X11DS_CLIPBOARD_
#define _H_X11DS_CLIPBOARD_
#include <stdbool.h>
#include <X11/extensions/Xfixes.h>
#include "interface/displayserver.h"
void x11CBEventThread(const XEvent xe);
bool x11CBInit();
void x11CBNotice(LG_ClipboardData type);
void x11CBRelease(void);
void x11CBRequest(LG_ClipboardData type);
#endif

View File

@ -19,15 +19,15 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include "interface/displayserver.h"
#include <stdbool.h>
#include "x11.h"
#include "clipboard.h"
#include <string.h>
#include <unistd.h>
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/extensions/Xfixes.h>
#include <X11/extensions/XInput2.h>
#include <X11/extensions/scrnsaver.h>
#include <X11/extensions/Xfixes.h>
#include <X11/extensions/Xinerama.h>
#include <GL/glx.h>
@ -40,80 +40,14 @@ Place, Suite 330, Boston, MA 02111-1307 USA
#include "app.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
{
Display * display;
Window window;
XVisualInfo * visual;
int xinputOp;
LGThread * eventThread;
int pointerDev;
int keyboardDev;
bool pointerGrabbed;
bool keyboardGrabbed;
bool entered;
bool focused;
bool fullscreen;
struct Rect rect;
struct Border border;
Cursor blankCursor;
Cursor squareCursor;
Atom aNetReqFrameExtents;
Atom aNetFrameExtents;
Atom aNetWMState;
Atom aNetWMStateFullscreen;
Atom aNetWMWindowType;
Atom aNetWMWindowTypeNormal;
Atom aWMDeleteWindow;
// clipboard members
Atom aSelection;
Atom aCurSelection;
Atom aTargets;
Atom aSelData;
Atom aIncr;
Atom aTypes[LG_CLIPBOARD_DATA_NONE];
LG_ClipboardData type;
bool haveRequest;
bool incrStart;
unsigned int lowerBound;
// XFixes vars
int eventBase;
int errorBase;
};
static const char * atomTypes[] =
{
"UTF8_STRING",
"image/png",
"image/bmp",
"image/tiff",
"image/jpeg"
};
static struct X11DSState x11;
struct X11DSState x11;
// forwards
static void x11CBSelectionRequest(const XSelectionRequestEvent e);
static void x11CBSelectionClear(const XSelectionClearEvent e);
static void x11CBSelectionIncr(const XPropertyEvent e);
static void x11CBSelectionNotify(const XSelectionEvent e);
static void x11CBXFixesSelectionNotify(const XFixesSelectionNotifyEvent e);
static void x11SetFullscreen(bool fs);
static int x11EventThread(void * unused);
static void x11GenericEvent(XGenericEventCookie *cookie);
@ -585,24 +519,12 @@ static int x11EventThread(void * unused)
break;
}
// clipboard events
case SelectionRequest:
x11CBSelectionRequest(xe.xselectionrequest);
break;
case SelectionClear:
x11CBSelectionClear(xe.xselectionclear);
break;
case SelectionNotify:
x11CBSelectionNotify(xe.xselection);
break;
case PropertyNotify:
case PropertyNotify:
// ignore property events that are not for us
if (xe.xproperty.display != x11.display ||
xe.xproperty.window != x11.window ||
xe.xproperty.state != PropertyNewValue)
break;
continue;
if (xe.xproperty.atom == x11.aNetWMState)
{
@ -654,26 +576,11 @@ static int x11EventThread(void * unused)
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;
}
// call the clipboard handling code
x11CBEventThread(xe);
}
return 0;
@ -1165,333 +1072,6 @@ static bool x11GetFullscreen(void)
return x11.fullscreen;
}
static bool x11CBInit()
{
x11.aSelection = XInternAtom(x11.display, "CLIPBOARD" , False);
x11.aTargets = XInternAtom(x11.display, "TARGETS" , False);
x11.aSelData = XInternAtom(x11.display, "SEL_DATA" , False);
x11.aIncr = XInternAtom(x11.display, "INCR" , False);
x11.aCurSelection = BadValue;
for(int i = 0; i < LG_CLIPBOARD_DATA_NONE; ++i)
{
x11.aTypes[i] = XInternAtom(x11.display, atomTypes[i], False);
if (x11.aTypes[i] == BadAlloc || x11.aTypes[i] == BadValue)
{
DEBUG_ERROR("failed to get atom for type: %s", atomTypes[i]);
return false;
}
}
// use xfixes to get clipboard change notifications
if (!XFixesQueryExtension(x11.display, &x11.eventBase, &x11.errorBase))
{
DEBUG_ERROR("failed to initialize xfixes");
return false;
}
XFixesSelectSelectionInput(x11.display, x11.window,
XA_PRIMARY, XFixesSetSelectionOwnerNotifyMask);
XFixesSelectSelectionInput(x11.display, x11.window,
x11.aSelection, XFixesSetSelectionOwnerNotifyMask);
return true;
}
static void x11CBReplyFn(void * opaque, LG_ClipboardData type,
uint8_t * data, uint32_t size)
{
XEvent *s = (XEvent *)opaque;
XChangeProperty(
x11.display ,
s->xselection.requestor,
s->xselection.property ,
s->xselection.target ,
8,
PropModeReplace,
data,
size);
XSendEvent(x11.display, s->xselection.requestor, 0, 0, s);
XFlush(x11.display);
free(s);
}
static void x11CBSelectionRequest(const XSelectionRequestEvent e)
{
XEvent * s = (XEvent *)malloc(sizeof(XEvent));
s->xselection.type = SelectionNotify;
s->xselection.requestor = e.requestor;
s->xselection.selection = e.selection;
s->xselection.target = e.target;
s->xselection.property = e.property;
s->xselection.time = e.time;
if (!x11.haveRequest)
goto nodata;
// target list requested
if (e.target == x11.aTargets)
{
Atom targets[2];
targets[0] = x11.aTargets;
targets[1] = x11.aTypes[x11.type];
XChangeProperty(
e.display,
e.requestor,
e.property,
XA_ATOM,
32,
PropModeReplace,
(unsigned char*)targets,
sizeof(targets) / sizeof(Atom));
goto send;
}
// look to see if we can satisfy the data type
for(int i = 0; i < LG_CLIPBOARD_DATA_NONE; ++i)
if (x11.aTypes[i] == e.target && x11.type == i)
{
// request the data
app_clipboardRequest(x11CBReplyFn, s);
return;
}
nodata:
// report no data
s->xselection.property = None;
send:
XSendEvent(x11.display, e.requestor, 0, 0, s);
XFlush(x11.display);
free(s);
}
static void x11CBSelectionClear(const XSelectionClearEvent e)
{
if (e.selection != XA_PRIMARY && e.selection != x11.aSelection)
return;
x11.aCurSelection = BadValue;
app_clipboardRelease();
return;
}
static void x11CBSelectionIncr(const XPropertyEvent e)
{
Atom type;
int format;
unsigned long itemCount, after;
unsigned char *data;
if (XGetWindowProperty(
e.display,
e.window,
e.atom,
0, ~0L, // start and length
True, // delete the property
x11.aIncr,
&type,
&format,
&itemCount,
&after,
&data) != Success)
{
DEBUG_INFO("GetProp Failed");
app_clipboardNotify(LG_CLIPBOARD_DATA_NONE, 0);
goto out;
}
LG_ClipboardData dataType;
for(dataType = 0; dataType < LG_CLIPBOARD_DATA_NONE; ++dataType)
if (x11.aTypes[dataType] == type)
break;
if (dataType == LG_CLIPBOARD_DATA_NONE)
{
DEBUG_WARN("clipboard data (%s) not in a supported format",
XGetAtomName(x11.display, type));
x11.lowerBound = 0;
app_clipboardNotify(LG_CLIPBOARD_DATA_NONE, 0);
goto out;
}
if (x11.incrStart)
{
app_clipboardNotify(dataType, x11.lowerBound);
x11.incrStart = false;
}
XFree(data);
data = NULL;
if (XGetWindowProperty(
e.display,
e.window,
e.atom,
0, ~0L, // start and length
True, // delete the property
type,
&type,
&format,
&itemCount,
&after,
&data) != Success)
{
DEBUG_ERROR("XGetWindowProperty Failed");
app_clipboardNotify(LG_CLIPBOARD_DATA_NONE, 0);
goto out;
}
app_clipboardData(dataType, data, itemCount);
x11.lowerBound -= itemCount;
out:
if (data)
XFree(data);
}
static void x11CBXFixesSelectionNotify(const XFixesSelectionNotifyEvent e)
{
// check if the selection is valid and it isn't ourself
if ((e.selection != XA_PRIMARY && e.selection != x11.aSelection) ||
e.owner == x11.window || e.owner == 0)
{
return;
}
// remember which selection we are working with
x11.aCurSelection = e.selection;
XConvertSelection(
x11.display,
e.selection,
x11.aTargets,
x11.aTargets,
x11.window,
CurrentTime);
return;
}
static void x11CBSelectionNotify(const XSelectionEvent e)
{
if (e.property == None)
return;
Atom type;
int format;
unsigned long itemCount, after;
unsigned char *data;
if (XGetWindowProperty(
e.display,
e.requestor,
e.property,
0, ~0L, // start and length
True , // delete the property
AnyPropertyType,
&type,
&format,
&itemCount,
&after,
&data) != Success)
{
app_clipboardNotify(LG_CLIPBOARD_DATA_NONE, 0);
goto out;
}
if (type == x11.aIncr)
{
x11.incrStart = true;
x11.lowerBound = *(unsigned int *)data;
goto out;
}
// the target list
if (e.property == x11.aTargets)
{
// the format is 32-bit and we must have data
// this is technically incorrect however as it's
// an array of padded 64-bit values
if (!data || format != 32)
goto out;
// see if we support any of the targets listed
const uint64_t * targets = (const uint64_t *)data;
for(unsigned long i = 0; i < itemCount; ++i)
{
for(int n = 0; n < LG_CLIPBOARD_DATA_NONE; ++n)
if (x11.aTypes[n] == targets[i])
{
// we have a match, so send the notification
app_clipboardNotify(n, 0);
goto out;
}
}
// no matches
app_clipboardNotify(LG_CLIPBOARD_DATA_NONE, 0);
goto out;
}
if (e.property == x11.aSelData)
{
LG_ClipboardData dataType;
for(dataType = 0; dataType < LG_CLIPBOARD_DATA_NONE; ++dataType)
if (x11.aTypes[dataType] == type)
break;
if (dataType == LG_CLIPBOARD_DATA_NONE)
{
DEBUG_WARN("clipboard data (%s) not in a supported format",
XGetAtomName(x11.display, type));
goto out;
}
app_clipboardData(dataType, data, itemCount);
goto out;
}
out:
if (data)
XFree(data);
}
static void x11CBNotice(LG_ClipboardData type)
{
x11.haveRequest = true;
x11.type = type;
XSetSelectionOwner(x11.display, XA_PRIMARY , x11.window, CurrentTime);
XSetSelectionOwner(x11.display, x11.aSelection, x11.window, CurrentTime);
XFlush(x11.display);
}
static void x11CBRelease(void)
{
x11.haveRequest = false;
XSetSelectionOwner(x11.display, XA_PRIMARY , None, CurrentTime);
XSetSelectionOwner(x11.display, x11.aSelection, None, CurrentTime);
XFlush(x11.display);
}
static void x11CBRequest(LG_ClipboardData type)
{
if (x11.aCurSelection == BadValue)
return;
XConvertSelection(
x11.display,
x11.aCurSelection,
x11.aTypes[type],
x11.aSelData,
x11.window,
CurrentTime);
}
struct LG_DisplayServerOps LGDS_X11 =
{
.setup = x11Setup,

View File

@ -0,0 +1,68 @@
/*
Looking Glass - KVM FrameRelay (KVMFR) Client
Copyright (C) 2017-2021 Geoffrey McRae <geoff@hostfission.com>
https://looking-glass.hostfission.com
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _H_X11DS_X11_
#define _H_X11DS_X11_
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include "common/thread.h"
#include "common/types.h"
struct X11DSState
{
Display * display;
Window window;
XVisualInfo * visual;
int xinputOp;
LGThread * eventThread;
int pointerDev;
int keyboardDev;
bool pointerGrabbed;
bool keyboardGrabbed;
bool entered;
bool focused;
bool fullscreen;
struct Rect rect;
struct Border border;
Cursor blankCursor;
Cursor squareCursor;
Atom aNetReqFrameExtents;
Atom aNetFrameExtents;
Atom aNetWMState;
Atom aNetWMStateFullscreen;
Atom aNetWMWindowType;
Atom aNetWMWindowTypeNormal;
Atom aWMDeleteWindow;
// XFixes vars
int eventBase;
int errorBase;
};
extern struct X11DSState x11;
#endif