]> git.lizzy.rs Git - irrlicht.git/blobdiff - source/Irrlicht/CIrrDeviceLinux.cpp
Avoid undefined arithmetic on nullptr in buffer_offset function
[irrlicht.git] / source / Irrlicht / CIrrDeviceLinux.cpp
index af54946adda5f9e0dc785126bed955e33d4ac68d..3c1909917f4b5a25b53340b6ef1b516dde0ee738 100644 (file)
@@ -13,6 +13,7 @@
 #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
@@ -85,13 +90,19 @@ namespace
        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
@@ -99,13 +110,15 @@ namespace irr
 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
@@ -138,7 +151,11 @@ CIrrDeviceLinux::CIrrDeviceLinux(const SIrrlichtCreationParameters& param)
                // 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
@@ -150,11 +167,10 @@ CIrrDeviceLinux::CIrrDeviceLinux(const SIrrlichtCreationParameters& param)
        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
@@ -198,12 +214,6 @@ CIrrDeviceLinux::~CIrrDeviceLinux()
                        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
@@ -243,113 +253,32 @@ int IrrPrintXError(Display *display, XErrorEvent *event)
 #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
@@ -358,26 +287,26 @@ void IrrPrintXGrabError(int grabResult, const c8 * grabCommand )
 {\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
@@ -405,7 +334,12 @@ bool CIrrDeviceLinux::createWindow()
 \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
@@ -446,7 +380,7 @@ bool CIrrDeviceLinux::createWindow()
        }\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
@@ -478,28 +412,21 @@ bool CIrrDeviceLinux::createWindow()
 \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
@@ -513,12 +440,25 @@ bool CIrrDeviceLinux::createWindow()
                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
@@ -528,9 +468,10 @@ bool CIrrDeviceLinux::createWindow()
                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
@@ -546,27 +487,7 @@ bool CIrrDeviceLinux::createWindow()
        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
@@ -579,20 +500,6 @@ void CIrrDeviceLinux::createDriver()
        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
@@ -695,6 +602,14 @@ bool CIrrDeviceLinux::createInputContext()
                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
@@ -706,8 +621,7 @@ bool CIrrDeviceLinux::createInputContext()
        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
@@ -765,7 +679,6 @@ EKEY_CODE CIrrDeviceLinux::getKeyCode(XEvent &event)
 \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
@@ -773,23 +686,18 @@ EKEY_CODE CIrrDeviceLinux::getKeyCode(XEvent &event)
        }\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
@@ -815,6 +723,8 @@ bool CIrrDeviceLinux::run()
                {\r
                        XEvent event;\r
                        XNextEvent(XDisplay, &event);\r
+                       if (XFilterEvent(&event, None))\r
+                               continue;\r
 \r
                        switch (event.type)\r
                        {\r
@@ -826,21 +736,6 @@ bool CIrrDeviceLinux::run()
                                        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
@@ -991,18 +886,29 @@ bool CIrrDeviceLinux::run()
                                        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
@@ -1037,7 +943,6 @@ bool CIrrDeviceLinux::run()
                                        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
@@ -1062,53 +967,158 @@ bool CIrrDeviceLinux::run()
 \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
@@ -1165,60 +1175,6 @@ void CIrrDeviceLinux::setWindowCaption(const wchar_t* text)
 }\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
@@ -1247,6 +1203,13 @@ bool CIrrDeviceLinux::isWindowMinimized() const
 }\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
@@ -1299,84 +1262,6 @@ void CIrrDeviceLinux::setWindowSize(const irr::core::dimension2d<u32>& size)
 #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
@@ -1409,6 +1294,8 @@ void CIrrDeviceLinux::maximizeWindow()
        }\r
 \r
        XMapWindow(XDisplay, XWindow);\r
+\r
+       WindowMaximized = true;\r
 #endif\r
 }\r
 \r
@@ -1435,6 +1322,8 @@ void CIrrDeviceLinux::restoreWindow()
        }\r
 \r
        XMapWindow(XDisplay, XWindow);\r
+\r
+       WindowMaximized = false;\r
 #endif\r
 }\r
 \r
@@ -1725,7 +1614,7 @@ bool CIrrDeviceLinux::activateJoysticks(core::array<SJoystickInfo> & joystickInf
        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
@@ -1787,150 +1676,106 @@ void CIrrDeviceLinux::pollJoysticks()
 }\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 c8text) 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
@@ -1938,6 +1783,10 @@ void CIrrDeviceLinux::copyToClipboard(const c8* text) const
        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
@@ -1947,7 +1796,7 @@ Bool PredicateIsEventType(Display *display, XEvent *event, XPointer arg)
 {\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
@@ -1980,11 +1829,49 @@ void CIrrDeviceLinux::initXAtoms()
 #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
@@ -2133,6 +2020,9 @@ CIrrDeviceLinux::CCursorControl::CCursorControl(CIrrDeviceLinux* dev, bool null)
        : 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
@@ -2140,6 +2030,20 @@ CIrrDeviceLinux::CCursorControl::CCursorControl(CIrrDeviceLinux* dev, bool null)
 #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