#include <locale.h>\r
#include "IEventReceiver.h"\r
#include "ISceneManager.h"\r
+#include "IGUIElement.h"\r
#include "IGUIEnvironment.h"\r
#include "os.h"\r
#include "CTimer.h"\r
#include <X11/XKBlib.h>\r
#include <X11/Xatom.h>\r
\r
+#if defined(_IRR_LINUX_X11_XINPUT2_)\r
+#include <X11/extensions/XInput2.h>\r
+#endif\r
+\r
#if defined(_IRR_COMPILE_WITH_OGLES1_) || defined(_IRR_COMPILE_WITH_OGLES2_)\r
#include "CEGLManager.h"\r
#endif\r
Atom X_ATOM_CLIPBOARD;\r
Atom X_ATOM_TARGETS;\r
Atom X_ATOM_UTF8_STRING;\r
+ Atom X_ATOM_UTF8_MIME_TYPE;\r
Atom X_ATOM_TEXT;\r
Atom X_ATOM_NETWM_MAXIMIZE_VERT;\r
Atom X_ATOM_NETWM_MAXIMIZE_HORZ;\r
Atom X_ATOM_NETWM_STATE;\r
+ Atom X_ATOM_NETWM_STATE_FULLSCREEN;\r
\r
Atom X_ATOM_WM_DELETE_WINDOW;\r
-};\r
+\r
+#if defined(_IRR_LINUX_X11_XINPUT2_)\r
+ int XI_EXTENSIONS_OPCODE;\r
+#endif\r
+}\r
\r
namespace irr\r
{\r
CIrrDeviceLinux::CIrrDeviceLinux(const SIrrlichtCreationParameters& param)\r
: CIrrDeviceStub(param),\r
#ifdef _IRR_COMPILE_WITH_X11_\r
- XDisplay(0), VisualInfo(0), Screennr(0), XWindow(0), StdHints(0), SoftwareImage(0),\r
+ XDisplay(0), VisualInfo(0), Screennr(0), XWindow(0), StdHints(0),\r
XInputMethod(0), XInputContext(0),\r
HasNetWM(false),\r
+#endif\r
+#if defined(_IRR_LINUX_X11_XINPUT2_)\r
+ currentTouchedCount(0),\r
#endif\r
Width(param.WindowSize.Width), Height(param.WindowSize.Height),\r
- WindowHasFocus(false), WindowMinimized(false),\r
- UseXVidMode(false), UseXRandR(false),\r
+ WindowHasFocus(false), WindowMinimized(false), WindowMaximized(param.WindowMaximized),\r
ExternalWindow(false), AutorepeatSupport(0)\r
{\r
#ifdef _DEBUG\r
// create the window, only if we do not use the null device\r
if (!createWindow())\r
return;\r
- setResizable(param.WindowResizable);\r
+ if (param.WindowResizable < 2 )\r
+ setResizable(param.WindowResizable == 1 ? true : false);\r
+#ifdef _IRR_COMPILE_WITH_X11_\r
+ createInputContext();\r
+#endif\r
}\r
\r
// create cursor control\r
if (!VideoDriver)\r
return;\r
\r
-#ifdef _IRR_COMPILE_WITH_X11_\r
- createInputContext();\r
-#endif\r
-\r
createGUIAndScene();\r
+\r
+ if (param.WindowMaximized)\r
+ maximizeWindow();\r
}\r
\r
\r
ContextManager->destroySurface();\r
}\r
\r
- // Reset fullscreen resolution change\r
- switchToFullscreen(true);\r
-\r
- if (SoftwareImage)\r
- XDestroyImage(SoftwareImage);\r
-\r
if (!ExternalWindow)\r
{\r
XDestroyWindow(XDisplay,XWindow);\r
#endif\r
\r
\r
-bool CIrrDeviceLinux::switchToFullscreen(bool reset)\r
+bool CIrrDeviceLinux::switchToFullscreen()\r
{\r
if (!CreationParams.Fullscreen)\r
return true;\r
- if (reset)\r
- {\r
-#ifdef _IRR_LINUX_X11_VIDMODE_\r
- if (UseXVidMode && CreationParams.Fullscreen)\r
- {\r
- XF86VidModeSwitchToMode(XDisplay, Screennr, &OldVideoMode);\r
- XF86VidModeSetViewPort(XDisplay, Screennr, 0, 0);\r
- }\r
- #endif\r
- #ifdef _IRR_LINUX_X11_RANDR_\r
- if (UseXRandR && CreationParams.Fullscreen)\r
- {\r
- XRRScreenConfiguration *config=XRRGetScreenInfo(XDisplay,DefaultRootWindow(XDisplay));\r
- XRRSetScreenConfig(XDisplay,config,DefaultRootWindow(XDisplay),OldRandrMode,OldRandrRotation,CurrentTime);\r
- XRRFreeScreenConfigInfo(config);\r
- }\r
- #endif\r
- return true;\r
- }\r
-\r
- getVideoModeList();\r
- #if defined(_IRR_LINUX_X11_VIDMODE_) || defined(_IRR_LINUX_X11_RANDR_)\r
- s32 eventbase, errorbase;\r
- s32 bestMode = -1;\r
- #endif\r
\r
- #ifdef _IRR_LINUX_X11_VIDMODE_\r
- if (XF86VidModeQueryExtension(XDisplay, &eventbase, &errorbase))\r
+ if (!HasNetWM)\r
{\r
- // enumerate video modes\r
- s32 modeCount;\r
- XF86VidModeModeInfo** modes;\r
-\r
- XF86VidModeGetAllModeLines(XDisplay, Screennr, &modeCount, &modes);\r
+ os::Printer::log("NetWM support is required to allow Irrlicht to switch "\r
+ "to fullscreen mode. Running in windowed mode instead.", ELL_WARNING);\r
+ CreationParams.Fullscreen = false;\r
+ return false;\r
+ }\r
\r
- // find fitting mode\r
- for (s32 i = 0; i<modeCount; ++i)\r
- {\r
- if (bestMode==-1 && modes[i]->hdisplay >= Width && modes[i]->vdisplay >= Height)\r
- bestMode = i;\r
- else if (bestMode!=-1 &&\r
- modes[i]->hdisplay >= Width &&\r
- modes[i]->vdisplay >= Height &&\r
- modes[i]->hdisplay <= modes[bestMode]->hdisplay &&\r
- modes[i]->vdisplay <= modes[bestMode]->vdisplay)\r
- bestMode = i;\r
- }\r
- if (bestMode != -1)\r
- {\r
- os::Printer::log("Starting vidmode fullscreen mode...", ELL_INFORMATION);\r
- os::Printer::log("hdisplay: ", core::stringc(modes[bestMode]->hdisplay).c_str(), ELL_INFORMATION);\r
- os::Printer::log("vdisplay: ", core::stringc(modes[bestMode]->vdisplay).c_str(), ELL_INFORMATION);\r
+ XEvent ev = {0};\r
\r
- XF86VidModeSwitchToMode(XDisplay, Screennr, modes[bestMode]);\r
- XF86VidModeSetViewPort(XDisplay, Screennr, 0, 0);\r
- UseXVidMode=true;\r
- }\r
- else\r
- {\r
- os::Printer::log("Could not find specified video mode, running windowed.", ELL_WARNING);\r
- CreationParams.Fullscreen = false;\r
- }\r
+ ev.type = ClientMessage;\r
+ ev.xclient.window = XWindow;\r
+ ev.xclient.message_type = X_ATOM_NETWM_STATE;\r
+ ev.xclient.format = 32;\r
+ ev.xclient.data.l[0] = 1; // _NET_WM_STATE_ADD\r
+ ev.xclient.data.l[1] = X_ATOM_NETWM_STATE_FULLSCREEN;\r
\r
- XFree(modes);\r
- }\r
- else\r
- #endif\r
- #ifdef _IRR_LINUX_X11_RANDR_\r
- if (XRRQueryExtension(XDisplay, &eventbase, &errorbase))\r
- {\r
- s32 modeCount;\r
- XRRScreenConfiguration *config=XRRGetScreenInfo(XDisplay,DefaultRootWindow(XDisplay));\r
- XRRScreenSize *modes=XRRConfigSizes(config,&modeCount);\r
- for (s32 i = 0; i<modeCount; ++i)\r
- {\r
- if (bestMode==-1 && (u32)modes[i].width >= Width && (u32)modes[i].height >= Height)\r
- bestMode = i;\r
- else if (bestMode!=-1 &&\r
- (u32)modes[i].width >= Width &&\r
- (u32)modes[i].height >= Height &&\r
- modes[i].width <= modes[bestMode].width &&\r
- modes[i].height <= modes[bestMode].height)\r
- bestMode = i;\r
- }\r
- if (bestMode != -1)\r
- {\r
- os::Printer::log("Starting randr fullscreen mode...", ELL_INFORMATION);\r
- os::Printer::log("width: ", core::stringc(modes[bestMode].width).c_str(), ELL_INFORMATION);\r
- os::Printer::log("height: ", core::stringc(modes[bestMode].height).c_str(), ELL_INFORMATION);\r
+ XSendEvent(XDisplay, DefaultRootWindow(XDisplay), false,\r
+ SubstructureNotifyMask | SubstructureRedirectMask, &ev);\r
\r
- XRRSetScreenConfig(XDisplay,config,DefaultRootWindow(XDisplay),bestMode,OldRandrRotation,CurrentTime);\r
- UseXRandR=true;\r
- }\r
- XRRFreeScreenConfigInfo(config);\r
- }\r
- else\r
- #endif\r
- {\r
- os::Printer::log("VidMode or RandR extension must be installed to allow Irrlicht "\r
- "to switch to fullscreen mode. Running in windowed mode instead.", ELL_WARNING);\r
- CreationParams.Fullscreen = false;\r
- }\r
- return CreationParams.Fullscreen;\r
+ return true;\r
}\r
\r
\r
{\r
if ( grabResult == GrabSuccess )\r
{\r
-// os::Printer::log(grabCommand, ": GrabSuccess", ELL_INFORMATION);\r
+// os::Printer::log(grabCommand, "GrabSuccess", ELL_INFORMATION);\r
return;\r
}\r
\r
switch ( grabResult )\r
{\r
case AlreadyGrabbed:\r
- os::Printer::log(grabCommand, ": AlreadyGrabbed", ELL_WARNING);\r
+ os::Printer::log(grabCommand, "AlreadyGrabbed", ELL_WARNING);\r
break;\r
case GrabNotViewable:\r
- os::Printer::log(grabCommand, ": GrabNotViewable", ELL_WARNING);\r
+ os::Printer::log(grabCommand, "GrabNotViewable", ELL_WARNING);\r
break;\r
case GrabFrozen:\r
- os::Printer::log(grabCommand, ": GrabFrozen", ELL_WARNING);\r
+ os::Printer::log(grabCommand, "GrabFrozen", ELL_WARNING);\r
break;\r
case GrabInvalidTime:\r
- os::Printer::log(grabCommand, ": GrabInvalidTime", ELL_WARNING);\r
+ os::Printer::log(grabCommand, "GrabInvalidTime", ELL_WARNING);\r
break;\r
default:\r
- os::Printer::log(grabCommand, ": grab failed with unknown problem", ELL_WARNING);\r
+ os::Printer::log(grabCommand, "grab failed with unknown problem", ELL_WARNING);\r
break;\r
}\r
}\r
\r
Screennr = DefaultScreen(XDisplay);\r
\r
- switchToFullscreen();\r
+ initXAtoms();\r
+\r
+ // check netwm support\r
+ Atom WMCheck = XInternAtom(XDisplay, "_NET_SUPPORTING_WM_CHECK", True);\r
+ if (WMCheck != None)\r
+ HasNetWM = true;\r
\r
#if defined(_IRR_COMPILE_WITH_OPENGL_)\r
// don't use the XVisual with OpenGL, because it ignores all requested\r
}\r
#ifdef _DEBUG\r
else\r
- os::Printer::log("Visual chosen: ", core::stringc(static_cast<u32>(VisualInfo->visualid)).c_str(), ELL_DEBUG);\r
+ os::Printer::log("Visual chosen", core::stringc(static_cast<u32>(VisualInfo->visualid)).c_str(), ELL_DEBUG);\r
#endif\r
\r
// create color map\r
\r
// create new Window\r
// Remove window manager decoration in fullscreen\r
- WndAttributes.override_redirect = CreationParams.Fullscreen;\r
XWindow = XCreateWindow(XDisplay,\r
RootWindow(XDisplay, VisualInfo->screen),\r
x, y, Width, Height, 0, VisualInfo->depth,\r
InputOutput, VisualInfo->visual,\r
- CWBorderPixel | CWColormap | CWEventMask | CWOverrideRedirect,\r
+ CWBorderPixel | CWColormap | CWEventMask,\r
&WndAttributes);\r
\r
XMapRaised(XDisplay, XWindow);\r
CreationParams.WindowId = (void*)XWindow;\r
X_ATOM_WM_DELETE_WINDOW = XInternAtom(XDisplay, "WM_DELETE_WINDOW", True);\r
XSetWMProtocols(XDisplay, XWindow, &X_ATOM_WM_DELETE_WINDOW, 1);\r
+\r
if (CreationParams.Fullscreen)\r
{\r
- XSetInputFocus(XDisplay, XWindow, RevertToParent, CurrentTime);\r
- int grabKb = XGrabKeyboard(XDisplay, XWindow, True, GrabModeAsync,\r
- GrabModeAsync, CurrentTime);\r
- IrrPrintXGrabError(grabKb, "XGrabKeyboard");\r
- int grabPointer = XGrabPointer(XDisplay, XWindow, True, ButtonPressMask,\r
- GrabModeAsync, GrabModeAsync, XWindow, None, CurrentTime);\r
- IrrPrintXGrabError(grabPointer, "XGrabPointer");\r
- XWarpPointer(XDisplay, None, XWindow, 0, 0, 0, 0, 0, 0);\r
+ // Don't try to set window position\r
}\r
else if (CreationParams.WindowPosition.X >= 0 || CreationParams.WindowPosition.Y >= 0) // default is -1, -1\r
{\r
XWindow = (Window)CreationParams.WindowId;\r
if (!CreationParams.IgnoreInput)\r
{\r
- XCreateWindow(XDisplay,\r
+ // Note: This might be further improved by using a InputOnly window instead of InputOutput.\r
+ // I think then it should be possible to render into the given parent window instead of\r
+ // creating a child-window.\r
+ // That could also be a third option for IgnoreInput in the CreationParams.\r
+ // But we need another window variable then and have to split input/output in\r
+ // the rest of the device code.\r
+ // Also... this does possibly leak.\r
+ Window child_window = XCreateWindow(XDisplay,\r
XWindow,\r
0, 0, Width, Height, 0, VisualInfo->depth,\r
InputOutput, VisualInfo->visual,\r
CWBorderPixel | CWColormap | CWEventMask,\r
&WndAttributes);\r
+\r
+ // do not forget to map new window\r
+ XMapWindow(XDisplay, child_window);\r
+\r
+ // overwrite device window id\r
+ XWindow = child_window;\r
}\r
XWindowAttributes wa;\r
XGetWindowAttributes(XDisplay, XWindow, &wa);\r
ExternalWindow = true;\r
}\r
\r
+ switchToFullscreen();\r
+\r
WindowMinimized=false;\r
- // Currently broken in X, see Bug ID 2795321\r
- // XkbSetDetectableAutoRepeat(XDisplay, True, &AutorepeatSupport);\r
+ XkbSetDetectableAutoRepeat(XDisplay, True, &AutorepeatSupport);\r
\r
Window tmp;\r
u32 borderWidth;\r
long num;\r
XGetWMNormalHints(XDisplay, XWindow, StdHints, &num);\r
\r
- // create an XImage for the software renderer\r
- //(thx to Nadav for some clues on how to do that!)\r
-\r
- if (CreationParams.DriverType == video::EDT_SOFTWARE || CreationParams.DriverType == video::EDT_BURNINGSVIDEO)\r
- {\r
- SoftwareImage = XCreateImage(XDisplay,\r
- VisualInfo->visual, VisualInfo->depth,\r
- ZPixmap, 0, 0, Width, Height,\r
- BitmapPad(XDisplay), 0);\r
-\r
- // use malloc because X will free it later on\r
- if (SoftwareImage)\r
- SoftwareImage->data = (char*) malloc(SoftwareImage->bytes_per_line * SoftwareImage->height * sizeof(char));\r
- }\r
-\r
- initXAtoms();\r
-\r
- // check netwm support\r
- Atom WMCheck = XInternAtom(XDisplay, "_NET_SUPPORTING_WM_CHECK", true);\r
- if (WMCheck != None)\r
- HasNetWM = true;\r
+ initXInput2();\r
\r
#endif // #ifdef _IRR_COMPILE_WITH_X11_\r
return true;\r
switch(CreationParams.DriverType)\r
{\r
#ifdef _IRR_COMPILE_WITH_X11_\r
- case video::EDT_SOFTWARE:\r
-#ifdef _IRR_COMPILE_WITH_SOFTWARE_\r
- VideoDriver = video::createSoftwareDriver(CreationParams.WindowSize, CreationParams.Fullscreen, FileSystem, this);\r
-#else\r
- os::Printer::log("No Software driver support compiled in.", ELL_ERROR);\r
-#endif\r
- break;\r
- case video::EDT_BURNINGSVIDEO:\r
-#ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_\r
- VideoDriver = video::createBurningVideoDriver(CreationParams, FileSystem, this);\r
-#else\r
- os::Printer::log("Burning's video driver was not compiled in.", ELL_ERROR);\r
-#endif\r
- break;\r
case video::EDT_OPENGL:\r
#ifdef _IRR_COMPILE_WITH_OPENGL_\r
{\r
return false;\r
}\r
\r
+ // Load XMODIFIERS (e.g. for IMEs)\r
+ if (!XSetLocaleModifiers(""))\r
+ {\r
+ setlocale(LC_CTYPE, oldLocale.c_str());\r
+ os::Printer::log("XSetLocaleModifiers failed. Falling back to non-i18n input.", ELL_WARNING);\r
+ return false;\r
+ }\r
+\r
XInputMethod = XOpenIM(XDisplay, NULL, NULL, NULL);\r
if ( !XInputMethod )\r
{\r
XIMStyles *im_supported_styles;\r
XGetIMValues(XInputMethod, XNQueryInputStyle, &im_supported_styles, (char*)NULL);\r
XIMStyle bestStyle = 0;\r
- // TODO: If we want to support languages like chinese or japanese as well we probably have to work with callbacks here.\r
- XIMStyle supportedStyle = XIMPreeditNone | XIMStatusNone;\r
+ XIMStyle supportedStyle = XIMPreeditNothing | XIMStatusNothing;\r
for(int i=0; i < im_supported_styles->count_styles; ++i)\r
{\r
XIMStyle style = im_supported_styles->supported_styles[i];\r
\r
SKeyMap mp;\r
mp.X11Key = XkbKeycodeToKeysym(XDisplay, event.xkey.keycode, 0, 0);\r
- // mp.X11Key = XKeycodeToKeysym(XDisplay, event.xkey.keycode, 0); // deprecated, if we still find platforms which need that we have to use some define\r
const s32 idx = KeyMap.binary_search(mp);\r
if (idx != -1)\r
{\r
}\r
if (keyCode == 0)\r
{\r
- // Any value is better than none, that allows at least using the keys.\r
- // Worst case is that some keys will be identical, still better than _all_\r
- // unknown keys being identical.\r
+ keyCode = KEY_UNKNOWN;\r
if ( !mp.X11Key )\r
{\r
- keyCode = (EKEY_CODE)event.xkey.keycode;\r
- os::Printer::log("No such X11Key, using event keycode", core::stringc(event.xkey.keycode).c_str(), ELL_INFORMATION);\r
+ os::Printer::log("No such X11Key, event keycode", core::stringc(event.xkey.keycode).c_str(), ELL_INFORMATION);\r
}\r
else if (idx == -1)\r
{\r
- keyCode = (EKEY_CODE)mp.X11Key;\r
- os::Printer::log("EKEY_CODE not found, using orig. X11 keycode", core::stringc(mp.X11Key).c_str(), ELL_INFORMATION);\r
+ os::Printer::log("EKEY_CODE not found, X11 keycode", core::stringc(mp.X11Key).c_str(), ELL_INFORMATION);\r
}\r
else\r
{\r
- keyCode = (EKEY_CODE)mp.X11Key;\r
- os::Printer::log("EKEY_CODE is 0, using orig. X11 keycode", core::stringc(mp.X11Key).c_str(), ELL_INFORMATION);\r
+ os::Printer::log("EKEY_CODE is 0, X11 keycode", core::stringc(mp.X11Key).c_str(), ELL_INFORMATION);\r
}\r
}\r
return keyCode;\r
{\r
XEvent event;\r
XNextEvent(XDisplay, &event);\r
+ if (XFilterEvent(&event, None))\r
+ continue;\r
\r
switch (event.type)\r
{\r
Width = event.xconfigure.width;\r
Height = event.xconfigure.height;\r
\r
- // resize image data\r
- if (SoftwareImage)\r
- {\r
- XDestroyImage(SoftwareImage);\r
-\r
- SoftwareImage = XCreateImage(XDisplay,\r
- VisualInfo->visual, VisualInfo->depth,\r
- ZPixmap, 0, 0, Width, Height,\r
- BitmapPad(XDisplay), 0);\r
-\r
- // use malloc because X will free it later on\r
- if (SoftwareImage)\r
- SoftwareImage->data = (char*) malloc(SoftwareImage->bytes_per_line * SoftwareImage->height * sizeof(char));\r
- }\r
-\r
if (VideoDriver)\r
VideoDriver->OnResize(core::dimension2d<u32>(Width, Height));\r
}\r
SKeyMap mp;\r
if ( XInputContext )\r
{\r
- wchar_t buf[8]={0};\r
+ wchar_t buf[64]={0};\r
Status status;\r
- int strLen = XwcLookupString(XInputContext, &event.xkey, buf, sizeof(buf), &mp.X11Key, &status);\r
+ int strLen = XwcLookupString(XInputContext, &event.xkey, buf, sizeof(buf)/sizeof(wchar_t)-1, &mp.X11Key, &status);\r
if ( status == XBufferOverflow )\r
{\r
os::Printer::log("XwcLookupString needs a larger buffer", ELL_INFORMATION);\r
}\r
if ( strLen > 0 && (status == XLookupChars || status == XLookupBoth) )\r
{\r
- if ( strLen > 1 )\r
- os::Printer::log("Additional returned characters dropped", ELL_INFORMATION);\r
- irrevent.KeyInput.Char = buf[0];\r
+ if (strLen > 1)\r
+ {\r
+ // Multiple characters: send string event\r
+ irrevent.EventType = irr::EET_STRING_INPUT_EVENT;\r
+ irrevent.StringInput.Str = new core::stringw(buf);\r
+ postEventFromUser(irrevent);\r
+ delete irrevent.StringInput.Str;\r
+ irrevent.StringInput.Str = NULL;\r
+ break;\r
+ }\r
+ else\r
+ {\r
+ irrevent.KeyInput.Char = buf[0];\r
+ }\r
}\r
else\r
{\r
irrevent.KeyInput.Control = (event.xkey.state & ControlMask) != 0;\r
irrevent.KeyInput.Shift = (event.xkey.state & ShiftMask) != 0;\r
irrevent.KeyInput.Key = getKeyCode(event);\r
-\r
postEventFromUser(irrevent);\r
}\r
break;\r
\r
case SelectionRequest:\r
{\r
- XEvent respond;\r
XSelectionRequestEvent *req = &(event.xselectionrequest);\r
- if ( req->target == XA_STRING)\r
- {\r
- XChangeProperty (XDisplay,\r
+\r
+ auto send_response = [this, req](Atom property) {\r
+ XEvent response;\r
+ response.xselection.type = SelectionNotify;\r
+ response.xselection.display = req->display;\r
+ response.xselection.requestor = req->requestor;\r
+ response.xselection.selection = req->selection;\r
+ response.xselection.target = req->target;\r
+ response.xselection.property = property;\r
+ response.xselection.time = req->time;\r
+ XSendEvent (XDisplay, req->requestor, 0, 0, &response);\r
+ XFlush (XDisplay);\r
+ };\r
+ auto send_response_refuse = [&send_response] {\r
+ send_response(None);\r
+ };\r
+\r
+ // sets the required property to data of type type and\r
+ // sends the according response\r
+ auto set_property_and_notify = [this, req, &send_response]\r
+ (Atom type, int format, const void *data, u32 data_size) {\r
+ XChangeProperty(XDisplay,\r
req->requestor,\r
- req->property, req->target,\r
- 8, // format\r
+ req->property,\r
+ type,\r
+ format,\r
PropModeReplace,\r
- (unsigned char*) Clipboard.c_str(),\r
- Clipboard.size());\r
- respond.xselection.property = req->property;\r
+ (const unsigned char *)data,\r
+ data_size);\r
+ send_response(req->property);\r
+ };\r
+\r
+ if (req->selection != X_ATOM_CLIPBOARD ||\r
+ req->owner != XWindow) {\r
+ // we are not the owner, refuse request\r
+ send_response_refuse();\r
+ break;\r
}\r
- else if ( req->target == X_ATOM_TARGETS )\r
- {\r
- long data[2];\r
\r
- data[0] = X_ATOM_TEXT;\r
- data[1] = XA_STRING;\r
+ // for debugging:\r
+ //~ {\r
+ //~ char *target_name = XGetAtomName(XDisplay, req->target);\r
+ //~ fprintf(stderr, "CIrrDeviceLinux::run: target: %s (=%ld)\n",\r
+ //~ target_name, req->target);\r
+ //~ XFree(target_name);\r
+ //~ }\r
+\r
+ if (req->property == None) {\r
+ // req is from obsolete client, use target as property name\r
+ // and X_ATOM_UTF8_STRING as type\r
+ // Note: this was not tested and might be incorrect\r
+ os::Printer::log("CIrrDeviceLinux::run: SelectionRequest from obsolete client",\r
+ ELL_WARNING);\r
+ XChangeProperty(XDisplay,\r
+ req->requestor,\r
+ req->target, X_ATOM_UTF8_STRING,\r
+ 8, // format = 8-bit\r
+ PropModeReplace,\r
+ (unsigned char *)Clipboard.c_str(),\r
+ Clipboard.size());\r
+ send_response(req->target);\r
+ break;\r
+ }\r
\r
- XChangeProperty (XDisplay, req->requestor,\r
- req->property, req->target,\r
- 8, PropModeReplace,\r
- (unsigned char *) &data,\r
- sizeof (data));\r
- respond.xselection.property = req->property;\r
+ if (req->target == X_ATOM_TARGETS) {\r
+ Atom data[] = {\r
+ X_ATOM_TARGETS,\r
+ X_ATOM_TEXT,\r
+ X_ATOM_UTF8_STRING,\r
+ X_ATOM_UTF8_MIME_TYPE\r
+ };\r
+ set_property_and_notify(\r
+ XA_ATOM,\r
+ 32, // Atom is long, we need to set 32 for longs\r
+ &data,\r
+ sizeof(data) / sizeof(*data)\r
+ );\r
+\r
+ } else if (req->target == X_ATOM_TEXT ||\r
+ req->target == X_ATOM_UTF8_STRING ||\r
+ req->target == X_ATOM_UTF8_MIME_TYPE) {\r
+ set_property_and_notify(\r
+ X_ATOM_UTF8_STRING,\r
+ 8,\r
+ Clipboard.c_str(),\r
+ Clipboard.size()\r
+ );\r
+\r
+ } else {\r
+ // refuse the request\r
+ send_response_refuse();\r
}\r
- else\r
+ }\r
+ break;\r
+\r
+#if defined(_IRR_LINUX_X11_XINPUT2_)\r
+ case GenericEvent:\r
+ {\r
+ XGenericEventCookie *cookie = &event.xcookie;\r
+ if (XGetEventData(XDisplay, cookie) && cookie->extension == XI_EXTENSIONS_OPCODE && XI_EXTENSIONS_OPCODE\r
+ && (cookie->evtype == XI_TouchUpdate || cookie->evtype == XI_TouchBegin || cookie->evtype == XI_TouchEnd))\r
{\r
- respond.xselection.property= None;\r
+ XIDeviceEvent *de = (XIDeviceEvent *) cookie->data;\r
+\r
+ irrevent.EventType = EET_TOUCH_INPUT_EVENT;\r
+\r
+ irrevent.TouchInput.Event = cookie->evtype == XI_TouchUpdate ? ETIE_MOVED : (cookie->evtype == XI_TouchBegin ? ETIE_PRESSED_DOWN : ETIE_LEFT_UP);\r
+\r
+ irrevent.TouchInput.ID = de->detail;\r
+ irrevent.TouchInput.X = de->event_x;\r
+ irrevent.TouchInput.Y = de->event_y;\r
+\r
+ if (irrevent.TouchInput.Event == ETIE_PRESSED_DOWN) {\r
+ currentTouchedCount++;\r
+ }\r
+ irrevent.TouchInput.touchedCount = currentTouchedCount;\r
+ if (currentTouchedCount > 0 && irrevent.TouchInput.Event == ETIE_LEFT_UP) {\r
+ currentTouchedCount--;\r
+ }\r
+\r
+ postEventFromUser(irrevent);\r
}\r
- respond.xselection.type= SelectionNotify;\r
- respond.xselection.display= req->display;\r
- respond.xselection.requestor= req->requestor;\r
- respond.xselection.selection=req->selection;\r
- respond.xselection.target= req->target;\r
- respond.xselection.time = req->time;\r
- XSendEvent (XDisplay, req->requestor,0,0,&respond);\r
- XFlush (XDisplay);\r
}\r
break;\r
+#endif\r
\r
default:\r
break;\r
} // end switch\r
\r
+ // Update IME information\r
+ if (XInputContext && GUIEnvironment)\r
+ {\r
+ gui::IGUIElement *elem = GUIEnvironment->getFocus();\r
+ if (elem && elem->acceptsIME())\r
+ {\r
+ core::rect<s32> r = elem->getAbsolutePosition();\r
+ XPoint p;\r
+ p.x = (short)r.UpperLeftCorner.X;\r
+ p.y = (short)r.LowerRightCorner.Y;\r
+ XSetICFocus(XInputContext);\r
+ XVaNestedList l = XVaCreateNestedList(0, XNSpotLocation, &p, NULL);\r
+ XSetICValues(XInputContext, XNPreeditAttributes, l, NULL);\r
+ XFree(l);\r
+ } else {\r
+ XUnsetICFocus(XInputContext);\r
+ }\r
+ }\r
+\r
} // end while\r
+\r
}\r
#endif //_IRR_COMPILE_WITH_X11_\r
\r
}\r
\r
\r
-//! presents a surface in the client area\r
-bool CIrrDeviceLinux::present(video::IImage* image, void* windowId, core::rect<s32>* srcRect)\r
-{\r
-#ifdef _IRR_COMPILE_WITH_X11_\r
- // this is only necessary for software drivers.\r
- if (!SoftwareImage)\r
- return true;\r
-\r
- // thx to Nadav, who send me some clues of how to display the image\r
- // to the X Server.\r
-\r
- const u32 destwidth = SoftwareImage->width;\r
- const u32 minWidth = core::min_(image->getDimension().Width, destwidth);\r
- const u32 destPitch = SoftwareImage->bytes_per_line;\r
-\r
- video::ECOLOR_FORMAT destColor;\r
- switch (SoftwareImage->bits_per_pixel)\r
- {\r
- case 16:\r
- if (SoftwareImage->depth==16)\r
- destColor = video::ECF_R5G6B5;\r
- else\r
- destColor = video::ECF_A1R5G5B5;\r
- break;\r
- case 24: destColor = video::ECF_R8G8B8; break;\r
- case 32: destColor = video::ECF_A8R8G8B8; break;\r
- default:\r
- os::Printer::log("Unsupported screen depth.");\r
- return false;\r
- }\r
-\r
- u8* srcdata = reinterpret_cast<u8*>(image->getData());\r
- u8* destData = reinterpret_cast<u8*>(SoftwareImage->data);\r
-\r
- const u32 destheight = SoftwareImage->height;\r
- const u32 srcheight = core::min_(image->getDimension().Height, destheight);\r
- const u32 srcPitch = image->getPitch();\r
- for (u32 y=0; y!=srcheight; ++y)\r
- {\r
- video::CColorConverter::convert_viaFormat(srcdata,image->getColorFormat(), minWidth, destData, destColor);\r
- srcdata+=srcPitch;\r
- destData+=destPitch;\r
- }\r
-\r
- GC gc = DefaultGC(XDisplay, DefaultScreen(XDisplay));\r
- Window myWindow=XWindow;\r
- if (windowId)\r
- myWindow = reinterpret_cast<Window>(windowId);\r
- XPutImage(XDisplay, myWindow, gc, SoftwareImage, 0, 0, 0, 0, destwidth, destheight);\r
-#endif\r
- return true;\r
-}\r
-\r
-\r
//! notifies the device that it should close itself\r
void CIrrDeviceLinux::closeDevice()\r
{\r
}\r
\r
\r
+//! returns last state from maximizeWindow() and restoreWindow()\r
+bool CIrrDeviceLinux::isWindowMaximized() const\r
+{\r
+ return WindowMaximized;\r
+}\r
+\r
+\r
//! returns color format of the window.\r
video::ECOLOR_FORMAT CIrrDeviceLinux::getColorFormat() const\r
{\r
#endif // #ifdef _IRR_COMPILE_WITH_X11_\r
}\r
\r
-//! Return pointer to a list with all video modes supported by the gfx adapter.\r
-video::IVideoModeList* CIrrDeviceLinux::getVideoModeList()\r
-{\r
-#ifdef _IRR_COMPILE_WITH_X11_\r
- if (!VideoModeList->getVideoModeCount())\r
- {\r
- bool temporaryDisplay = false;\r
-\r
- if (!XDisplay)\r
- {\r
- XDisplay = XOpenDisplay(0);\r
- temporaryDisplay=true;\r
- }\r
- if (XDisplay)\r
- {\r
- #if defined(_IRR_LINUX_X11_VIDMODE_) || defined(_IRR_LINUX_X11_RANDR_)\r
- s32 eventbase, errorbase;\r
- s32 defaultDepth=DefaultDepth(XDisplay,Screennr);\r
- #endif\r
-\r
- #ifdef _IRR_LINUX_X11_VIDMODE_\r
- if (XF86VidModeQueryExtension(XDisplay, &eventbase, &errorbase))\r
- {\r
- // enumerate video modes\r
- int modeCount;\r
- XF86VidModeModeInfo** modes;\r
-\r
- XF86VidModeGetAllModeLines(XDisplay, Screennr, &modeCount, &modes);\r
-\r
- // save current video mode\r
- OldVideoMode = *modes[0];\r
-\r
- // find fitting mode\r
-\r
- VideoModeList->setDesktop(defaultDepth, core::dimension2d<u32>(\r
- modes[0]->hdisplay, modes[0]->vdisplay));\r
- for (int i = 0; i<modeCount; ++i)\r
- {\r
- VideoModeList->addMode(core::dimension2d<u32>(\r
- modes[i]->hdisplay, modes[i]->vdisplay), defaultDepth);\r
- }\r
- XFree(modes);\r
- }\r
- else\r
- #endif\r
- #ifdef _IRR_LINUX_X11_RANDR_\r
- if (XRRQueryExtension(XDisplay, &eventbase, &errorbase))\r
- {\r
- int modeCount;\r
- XRRScreenConfiguration *config=XRRGetScreenInfo(XDisplay,DefaultRootWindow(XDisplay));\r
- OldRandrMode=XRRConfigCurrentConfiguration(config,&OldRandrRotation);\r
- XRRScreenSize *modes=XRRConfigSizes(config,&modeCount);\r
- VideoModeList->setDesktop(defaultDepth, core::dimension2d<u32>(\r
- modes[OldRandrMode].width, modes[OldRandrMode].height));\r
- for (int i = 0; i<modeCount; ++i)\r
- {\r
- VideoModeList->addMode(core::dimension2d<u32>(\r
- modes[i].width, modes[i].height), defaultDepth);\r
- }\r
- XRRFreeScreenConfigInfo(config);\r
- }\r
- else\r
- #endif\r
- {\r
- os::Printer::log("VidMode or RandR X11 extension requireed for VideoModeList." , ELL_WARNING);\r
- }\r
- }\r
- if (XDisplay && temporaryDisplay)\r
- {\r
- XCloseDisplay(XDisplay);\r
- XDisplay=0;\r
- }\r
- }\r
-#endif\r
-\r
- return VideoModeList;\r
-}\r
-\r
\r
//! Minimize window\r
void CIrrDeviceLinux::minimizeWindow()\r
}\r
\r
XMapWindow(XDisplay, XWindow);\r
+\r
+ WindowMaximized = true;\r
#endif\r
}\r
\r
}\r
\r
XMapWindow(XDisplay, XWindow);\r
+\r
+ WindowMaximized = false;\r
#endif\r
}\r
\r
for (joystick = 0; joystick < joystickInfo.size(); ++joystick)\r
{\r
char logString[256];\r
- (void)sprintf(logString, "Found joystick %u, %u axes, %u buttons '%s'",\r
+ snprintf_irr(logString, sizeof(logString), "Found joystick %d, %d axes, %d buttons '%s'",\r
joystick, joystickInfo[joystick].Axes,\r
joystickInfo[joystick].Buttons, joystickInfo[joystick].Name.c_str());\r
os::Printer::log(logString, ELL_INFORMATION);\r
}\r
\r
\r
-//! Set the current Gamma Value for the Display\r
-bool CIrrDeviceLinux::setGammaRamp( f32 red, f32 green, f32 blue, f32 brightness, f32 contrast )\r
+//! gets text from the clipboard\r
+//! \return Returns 0 if no string is in there, otherwise utf-8 text.\r
+const c8 *CIrrDeviceLinux::getTextFromClipboard() const\r
{\r
- #if defined(_IRR_LINUX_X11_VIDMODE_) || defined(_IRR_LINUX_X11_RANDR_)\r
- s32 eventbase, errorbase;\r
- #ifdef _IRR_LINUX_X11_VIDMODE_\r
- if (XF86VidModeQueryExtension(XDisplay, &eventbase, &errorbase))\r
- {\r
- XF86VidModeGamma gamma;\r
- gamma.red=red;\r
- gamma.green=green;\r
- gamma.blue=blue;\r
- XF86VidModeSetGamma(XDisplay, Screennr, &gamma);\r
- return true;\r
- }\r
- #endif\r
- #if defined(_IRR_LINUX_X11_VIDMODE_) && defined(_IRR_LINUX_X11_RANDR_)\r
- else\r
- #endif\r
- #ifdef _IRR_LINUX_X11_RANDR_\r
- if (XRRQueryExtension(XDisplay, &eventbase, &errorbase))\r
- {\r
- XRRQueryVersion(XDisplay, &eventbase, &errorbase); // major, minor\r
- if (eventbase>=1 && errorbase>1)\r
- {\r
- #if (RANDR_MAJOR>1 || RANDR_MINOR>1)\r
- XRRCrtcGamma *gamma = XRRGetCrtcGamma(XDisplay, Screennr);\r
- if (gamma)\r
- {\r
- *gamma->red=(u16)red;\r
- *gamma->green=(u16)green;\r
- *gamma->blue=(u16)blue;\r
- XRRSetCrtcGamma(XDisplay, Screennr, gamma);\r
- XRRFreeGamma(gamma);\r
- return true;\r
- }\r
- #endif\r
- }\r
+#if defined(_IRR_COMPILE_WITH_X11_)\r
+ Window ownerWindow = XGetSelectionOwner(XDisplay, X_ATOM_CLIPBOARD);\r
+ if (ownerWindow == XWindow) {\r
+ return Clipboard.c_str();\r
}\r
- #endif\r
- #endif\r
- return false;\r
-}\r
\r
+ Clipboard = "";\r
\r
-//! Get the current Gamma Value for the Display\r
-bool CIrrDeviceLinux::getGammaRamp( f32 &red, f32 &green, f32 &blue, f32 &brightness, f32 &contrast )\r
-{\r
- brightness = 0.f;\r
- contrast = 0.f;\r
- #if defined(_IRR_LINUX_X11_VIDMODE_) || defined(_IRR_LINUX_X11_RANDR_)\r
- s32 eventbase, errorbase;\r
- #ifdef _IRR_LINUX_X11_VIDMODE_\r
- if (XF86VidModeQueryExtension(XDisplay, &eventbase, &errorbase))\r
- {\r
- XF86VidModeGamma gamma;\r
- XF86VidModeGetGamma(XDisplay, Screennr, &gamma);\r
- red = gamma.red;\r
- green = gamma.green;\r
- blue = gamma.blue;\r
- return true;\r
+ if (ownerWindow == None) {\r
+ return Clipboard.c_str();\r
}\r
- #endif\r
- #if defined(_IRR_LINUX_X11_VIDMODE_) && defined(_IRR_LINUX_X11_RANDR_)\r
- else\r
- #endif\r
- #ifdef _IRR_LINUX_X11_RANDR_\r
- if (XRRQueryExtension(XDisplay, &eventbase, &errorbase))\r
- {\r
- XRRQueryVersion(XDisplay, &eventbase, &errorbase); // major, minor\r
- if (eventbase>=1 && errorbase>1)\r
- {\r
- #if (RANDR_MAJOR>1 || RANDR_MINOR>1)\r
- XRRCrtcGamma *gamma = XRRGetCrtcGamma(XDisplay, Screennr);\r
- if (gamma)\r
- {\r
- red = *gamma->red;\r
- green = *gamma->green;\r
- blue= *gamma->blue;\r
- XRRFreeGamma(gamma);\r
- return true;\r
- }\r
- #endif\r
- }\r
+\r
+ // delete the property to be set beforehand\r
+ XDeleteProperty(XDisplay, XWindow, XA_PRIMARY);\r
+\r
+ XConvertSelection(XDisplay, X_ATOM_CLIPBOARD, X_ATOM_UTF8_STRING, XA_PRIMARY,\r
+ XWindow, CurrentTime);\r
+ XFlush(XDisplay);\r
+\r
+ // wait for event via a blocking call\r
+ XEvent event_ret;\r
+ XIfEvent(XDisplay, &event_ret, [](Display *_display, XEvent *event, XPointer arg) {\r
+ return (Bool) (event->type == SelectionNotify &&\r
+ event->xselection.requestor == *(Window *)arg &&\r
+ event->xselection.selection == X_ATOM_CLIPBOARD &&\r
+ event->xselection.target == X_ATOM_UTF8_STRING);\r
+ }, (XPointer)&XWindow);\r
+\r
+ _IRR_DEBUG_BREAK_IF(!(event_ret.type == SelectionNotify &&\r
+ event_ret.xselection.requestor == XWindow &&\r
+ event_ret.xselection.selection == X_ATOM_CLIPBOARD &&\r
+ event_ret.xselection.target == X_ATOM_UTF8_STRING));\r
+\r
+ Atom property_set = event_ret.xselection.property;\r
+ if (event_ret.xselection.property == None) {\r
+ // request failed => empty string\r
+ return Clipboard.c_str();\r
}\r
- #endif\r
- #endif\r
- return false;\r
-}\r
\r
+ // check for data\r
+ Atom type;\r
+ int format;\r
+ unsigned long numItems, bytesLeft, dummy;\r
+ unsigned char *data = nullptr;\r
+ XGetWindowProperty (XDisplay, XWindow,\r
+ property_set, // property name\r
+ 0, // offset\r
+ 0, // length (we only check for data, so 0)\r
+ 0, // Delete 0==false\r
+ AnyPropertyType, // AnyPropertyType or property identifier\r
+ &type, // return type\r
+ &format, // return format\r
+ &numItems, // number items\r
+ &bytesLeft, // remaining bytes for partial reads\r
+ &data); // data\r
+ if (data) {\r
+ XFree(data);\r
+ data = nullptr;\r
+ }\r
\r
-//! gets text from the clipboard\r
-//! \return Returns 0 if no string is in there.\r
-const c8* CIrrDeviceLinux::getTextFromClipboard() const\r
-{\r
-#if defined(_IRR_COMPILE_WITH_X11_)\r
- Window ownerWindow = XGetSelectionOwner (XDisplay, X_ATOM_CLIPBOARD);\r
- if ( ownerWindow == XWindow )\r
- {\r
+ // for debugging:\r
+ //~ {\r
+ //~ char *type_name = XGetAtomName(XDisplay, type);\r
+ //~ fprintf(stderr, "CIrrDeviceLinux::getTextFromClipboard: actual type: %s (=%ld)\n",\r
+ //~ type_name, type);\r
+ //~ XFree(type_name);\r
+ //~ }\r
+\r
+ if (type != X_ATOM_UTF8_STRING && type != X_ATOM_UTF8_MIME_TYPE) {\r
+ os::Printer::log("CIrrDeviceLinux::getTextFromClipboard: did not get utf-8 string",\r
+ ELL_WARNING);\r
return Clipboard.c_str();\r
}\r
- Clipboard = "";\r
- if (ownerWindow != None )\r
- {\r
- XConvertSelection (XDisplay, X_ATOM_CLIPBOARD, XA_STRING, XA_PRIMARY, ownerWindow, CurrentTime);\r
- XFlush (XDisplay);\r
-\r
- // check for data\r
- Atom type;\r
- int format;\r
- unsigned long numItems, bytesLeft, dummy;\r
- unsigned char *data;\r
- XGetWindowProperty (XDisplay, ownerWindow,\r
- XA_PRIMARY, // property name\r
- 0, // offset\r
- 0, // length (we only check for data, so 0)\r
- 0, // Delete 0==false\r
- AnyPropertyType, // AnyPropertyType or property identifier\r
- &type, // return type\r
- &format, // return format\r
- &numItems, // number items\r
- &bytesLeft, // remaining bytes for partial reads\r
- &data); // data\r
- if ( bytesLeft > 0 )\r
- {\r
- // there is some data to get\r
- int result = XGetWindowProperty (XDisplay, ownerWindow, XA_PRIMARY, 0,\r
- bytesLeft, 0, AnyPropertyType, &type, &format,\r
- &numItems, &dummy, &data);\r
- if (result == Success)\r
- Clipboard = (irr::c8*)data;\r
- XFree (data);\r
- }\r
+\r
+ if (bytesLeft > 0) {\r
+ // there is some data to get\r
+ int result = XGetWindowProperty (XDisplay, XWindow, property_set, 0,\r
+ bytesLeft, 0, AnyPropertyType, &type, &format,\r
+ &numItems, &dummy, &data);\r
+ if (result == Success)\r
+ Clipboard = (irr::c8 *)data;\r
+ XFree (data);\r
}\r
\r
+ // delete the property again, to inform the owner about the successful transfer\r
+ XDeleteProperty(XDisplay, XWindow, property_set);\r
+\r
return Clipboard.c_str();\r
\r
#else\r
- return 0;\r
+ return nullptr;\r
#endif\r
}\r
\r
//! copies text to the clipboard\r
-void CIrrDeviceLinux::copyToClipboard(const c8* text) const\r
+void CIrrDeviceLinux::copyToClipboard(const c8 *text) const\r
{\r
#if defined(_IRR_COMPILE_WITH_X11_)\r
// Actually there is no clipboard on X but applications just say they own the clipboard and return text when asked.\r
Clipboard = text;\r
XSetSelectionOwner (XDisplay, X_ATOM_CLIPBOARD, XWindow, CurrentTime);\r
XFlush (XDisplay);\r
+ Window owner = XGetSelectionOwner(XDisplay, X_ATOM_CLIPBOARD);\r
+ if (owner != XWindow) {\r
+ os::Printer::log("CIrrDeviceLinux::copyToClipboard: failed to set owner", ELL_WARNING);\r
+ }\r
#endif\r
}\r
\r
{\r
if ( event && event->type == *(int*)arg )\r
{\r
-// os::Printer::log("remove event:", core::stringc((int)arg).c_str(), ELL_INFORMATION);\r
+// os::Printer::log("remove event", core::stringc((int)arg).c_str(), ELL_INFORMATION);\r
return True;\r
}\r
return False;\r
#ifdef _IRR_COMPILE_WITH_X11_\r
X_ATOM_CLIPBOARD = XInternAtom(XDisplay, "CLIPBOARD", False);\r
X_ATOM_TARGETS = XInternAtom(XDisplay, "TARGETS", False);\r
- X_ATOM_UTF8_STRING = XInternAtom (XDisplay, "UTF8_STRING", False);\r
- X_ATOM_TEXT = XInternAtom (XDisplay, "TEXT", False);\r
+ X_ATOM_UTF8_STRING = XInternAtom(XDisplay, "UTF8_STRING", False);\r
+ X_ATOM_UTF8_MIME_TYPE = XInternAtom(XDisplay, "text/plain;charset=utf-8", False);\r
+ X_ATOM_TEXT = XInternAtom(XDisplay, "TEXT", False);\r
X_ATOM_NETWM_MAXIMIZE_VERT = XInternAtom(XDisplay, "_NET_WM_STATE_MAXIMIZED_VERT", true);\r
X_ATOM_NETWM_MAXIMIZE_HORZ = XInternAtom(XDisplay, "_NET_WM_STATE_MAXIMIZED_HORZ", true);\r
X_ATOM_NETWM_STATE = XInternAtom(XDisplay, "_NET_WM_STATE", true);\r
+ X_ATOM_NETWM_STATE_FULLSCREEN = XInternAtom(XDisplay, "_NET_WM_STATE_FULLSCREEN", True);\r
+#endif\r
+}\r
+\r
+void CIrrDeviceLinux::initXInput2()\r
+{\r
+#if defined(_IRR_LINUX_X11_XINPUT2_)\r
+ int ev=0;\r
+ int err=0;\r
+ if (!XQueryExtension(XDisplay, "XInputExtension", &XI_EXTENSIONS_OPCODE, &ev, &err))\r
+ {\r
+ os::Printer::log("X Input extension not available.", ELL_WARNING);\r
+ return;\r
+ }\r
+\r
+ int major = 2;\r
+ int minor = 3;\r
+ int rc = XIQueryVersion(XDisplay, &major, &minor);\r
+ if ( rc != Success )\r
+ {\r
+ os::Printer::log("No XI2 support.", ELL_WARNING);\r
+ return;\r
+ }\r
+\r
+ // So far we only use XInput2 for touch events.\r
+ // So we enable those and disable all other events for now.\r
+ XIEventMask eventMask;\r
+ unsigned char mask[XIMaskLen(XI_TouchEnd)];\r
+ memset(mask, 0, sizeof(mask));\r
+ eventMask.deviceid = XIAllMasterDevices;\r
+ eventMask.mask_len = sizeof(mask);\r
+ eventMask.mask = mask;\r
+ XISetMask(eventMask.mask, XI_TouchBegin);\r
+ XISetMask(eventMask.mask, XI_TouchUpdate);\r
+ XISetMask(eventMask.mask, XI_TouchEnd);\r
+\r
+ XISelectEvents(XDisplay, XWindow, &eventMask, 1);\r
#endif\r
}\r
\r
: Device(dev)\r
#ifdef _IRR_COMPILE_WITH_X11_\r
, PlatformBehavior(gui::ECPB_NONE), LastQuery(0)\r
+#ifdef _IRR_LINUX_X11_XINPUT2_\r
+ , DeviceId(0)\r
+#endif\r
#endif\r
, IsVisible(true), Null(null), UseReferenceRect(false)\r
, ActiveIcon(gui::ECI_NORMAL), ActiveIconStartTime(0)\r
#ifdef _IRR_COMPILE_WITH_X11_\r
if (!Null)\r
{\r
+#ifdef _IRR_LINUX_X11_XINPUT2_\r
+ // XIWarpPointer is entirely broken on multi-head setups (see also [1]),\r
+ // but behaves better in other cases so we can't just disable it outright.\r
+ // [1] https://developer.blender.org/rB165caafb99c6846e53d11c4e966990aaffc06cea\r
+ if (XScreenCount(Device->XDisplay) > 1)\r
+ {\r
+ os::Printer::log("Detected classic multi-head setup, not using XIWarpPointer");\r
+ }\r
+ else\r
+ {\r
+ XIGetClientPointer(Device->XDisplay, Device->XWindow, &DeviceId);\r
+ }\r
+#endif\r
+\r
XGCValues values;\r
unsigned long valuemask = 0;\r
\r