ecere: Initial Emscripten support
[sdk] / ecere / src / gui / drivers / XInterface.ec
index 29d4547..a920b26 100644 (file)
@@ -1,7 +1,8 @@
+#define _Noreturn
 namespace gui::drivers;
 
 import "instance"
-#if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D) && !defined(ECERE_NOGL)
+#if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D) && !defined(ECERE_NOGL) && !defined(__ODROID__)
 import "OpenGLDisplayDriver"
 #endif
 
@@ -22,6 +23,16 @@ default:
 #include <unistd.h>
 #include <sys/select.h>
 
+#if defined(__APPLE__)
+#define set _set
+#include <mach/mach.h>
+#include <mach/task.h>
+#include <mach/semaphore.h>
+#undef set
+#else
+#include <semaphore.h>
+#endif
+
 //#include <stdio.h>
 //#include <stdlib.h>
 //#include <string.h>
@@ -33,21 +44,34 @@ default:
 #define Time      X11Time
 #define KeyCode   X11KeyCode
 #define Picture   X11Picture
+#define Bool      X11Bool
+
+#define _XTYPEDEF_BOOL
+typedef int X11Bool;
 
 #include <X11/Xatom.h>
 #include <X11/Xlib.h>
+#if !defined(__EMSCRIPTEN__)
 #include <X11/Xresource.h>
+#endif
 #include <X11/Xutil.h>
 #include <X11/XKBlib.h>
 #include <X11/keysym.h>
 #include <X11/cursorfont.h>
 #include <fcntl.h>
-#if !defined(ECERE_NO3D) && !defined(ECERE_NOGL)
+#if !defined(ECERE_NO3D) && !defined(ECERE_NOGL) //&& !defined(__ODROID__)
+#if defined(__EMSCRIPTEN__)
+#include <GL/glfw.h>
+#else
 #include <GL/glx.h>
 #endif
+#endif
+#if !defined(__EMSCRIPTEN__)
 #include <X11/extensions/Xrender.h>
+#endif
 #include <X11/extensions/XShm.h>
 
+#undef Bool
 #undef Picture
 #undef Window
 #undef Cursor
@@ -90,11 +114,20 @@ static X11Cursor nullCursor;
 static X11Window capturedWindow = None;
 static Window restrictedWindow = null;
 static bool gotAnXEvent = false;
-static XEvent xEvent;
+//static XEvent xEvent;
 static int joystickFD[4];
 static X11Window activeWindow;
 static X11Cursor systemCursors[SystemCursor];
 
+static Window acquiredInputWindow;
+static Point acquireStart;
+static Point lastMouse;
+static MouseButtons buttonsState;
+
+static bool keyStates[KeyCode];
+
+static enum NETWMStateAction { remove = 0, add = 1, toggle = 2 };
+
 static enum AtomIdents
 {
    clipboard, multiple, targets, utf8_string, wm_delete_window, wm_hints, wm_name, wm_protocols, wm_state, wm_take_focus, wm_transient_for,
@@ -104,7 +137,8 @@ static enum AtomIdents
    _net_wm_window_type_desktop, _net_wm_window_type_dialog, _net_wm_window_type_dock, _net_wm_window_type_dropdown_menu,
    _net_wm_window_type_menu, _net_wm_window_type_normal, _net_wm_window_type_popup_menu, _net_wm_window_type_splash,
    _net_wm_window_type_toolbar, _net_wm_window_type_utility, _net_workarea, _net_frame_extents, _net_request_frame_extents,
-   _net_wm_state_maximized_vert, _net_wm_state_maximized_horz, _net_wm_state_modal, app_selection, _net_supported
+   _net_wm_state_maximized_vert, _net_wm_state_maximized_horz, _net_wm_state_modal, app_selection, _net_supported,
+   _net_wm_state_skip_taskbar, _net_wm_state_fullscreen, _net_wm_state_above, capsLock, numLock, scrollLock
 };
 
 static Atom atoms[AtomIdents];
@@ -151,20 +185,19 @@ static const char *atomNames[AtomIdents] = {
    "_NET_WM_STATE_MAXIMIZED_HORZ", // _net_wm_state_maximized_horz
    "_NET_WM_STATE_MODAL", // _net_wm_state_modal
    "APP_SELECTION",
-   "_NET_SUPPORTED"
+   "_NET_SUPPORTED",
+   "_NET_WM_STATE_SKIP_TASKBAR",
+   "_NET_WM_STATE_FULLSCREEN",
+   "_NET_WM_STATE_ABOVE",
+   "Caps Lock",
+   "Num Lock",
+   "Scroll Lock"
 };
 /*
 _NET_WM_STATE_STICKY, ATOM
-_NET_WM_STATE_MAXIMIZED_VERT, ATOM
-_NET_WM_STATE_MAXIMIZED_HORZ, ATOM
 _NET_WM_STATE_SHADED, ATOM
-_NET_WM_STATE_SKIP_TASKBAR, ATOM
 _NET_WM_STATE_SKIP_PAGER, ATOM
-_NET_WM_STATE_HIDDEN, ATOM
-_NET_WM_STATE_FULLSCREEN, ATOM
-_NET_WM_STATE_ABOVE, ATOM
 _NET_WM_STATE_BELOW, ATOM
-_NET_WM_STATE_DEMANDS_ATTENTION, ATOM
 */
 
 static bool autoRepeatDetectable;
@@ -174,7 +207,71 @@ PixelFormat xSystemPixelFormat;
 Visual * xSystemVisual;
 bool xSharedMemory;
 
-static Time timeStamp;
+static void SetNETWMState(X11Window windowHandle, bool throughRoot, NETWMStateAction action, Atom atom1, Atom atom2)
+{
+   if(atomsSupported[_net_wm_state])
+   {
+      int format;
+      unsigned long count, fill;
+      Atom type;
+      byte * data = null;
+      /*uint state = WithdrawnState;
+
+      if(XGetWindowProperty(xGlobalDisplay, windowHandle, atoms[wm_state], 0, 3, False,
+                 atoms[wm_state], &type, &format, &count, &fill, &data) == Success && count)
+      {
+         state = *(uint *)data;
+         XFree(data);
+      } */
+      if(!throughRoot) //state == WithdrawnState)
+      {
+         // We need to handle modifying these ourselves for withdrawn windows...
+         if(action == add)
+         {
+            Atom values[2] = { atom1, atom2 };
+            XChangeProperty(xGlobalDisplay, windowHandle, atoms[_net_wm_state], XA_ATOM,
+               32, PropModeAppend, (byte *)values, atom2 ? 2 : 1);
+         }
+         else if(XGetWindowProperty(xGlobalDisplay, windowHandle, atoms[_net_wm_state], 0, 32, False,
+             XA_ATOM, &type, &format, &count, &fill, &data) == Success)
+         {
+            Atom * values = (Atom *) data;
+            int i;
+            for (i = 0; i < count; i++)
+            {
+               if(values[i] == atom1 || (atom2 && values[i] == atom2))
+               {
+                  if(i < count - 1)
+                     memmove(values + i, values + i + 1, sizeof(Atom) * (count - i - 1));
+                  count--;
+                  i--;
+               }
+            }
+            XChangeProperty(xGlobalDisplay, windowHandle, atoms[_net_wm_state], XA_ATOM, 32, PropModeReplace, (byte *)values, (int)count);
+            XFree(data);
+         }
+      }
+      else
+      {
+         XClientMessageEvent event = { 0 };
+         event.type = ClientMessage;
+         event.message_type = atoms[_net_wm_state];
+         event.display = xGlobalDisplay;
+         event.serial = 0;
+         event.window = windowHandle;
+         event.send_event = 1;
+         event.format = 32;
+         event.data.l[0] = action;
+         event.data.l[1] = atom1;
+         event.data.l[2] = atom2;
+         XSendEvent(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), bool::false,
+            SubstructureRedirectMask | SubstructureNotifyMask, (union _XEvent *)&event);
+      }
+   }
+
+}
+
+static X11Time timeStamp;
 
 class XWindowData : struct
 {
@@ -185,6 +282,7 @@ public:
    // Decorations Size
    Box decor;
    bool gotFrameExtents;
+   bool currentlyVisible;
 };
 
 bool XGetBorderWidths(Window window, Box box)
@@ -238,7 +336,7 @@ static void RepositionDesktop(bool updateChildren)
    Screen * x_screen = XDefaultScreenOfDisplay(xGlobalDisplay);
    X11Window x_root;
    int current = 0;
-   char *data = null;
+   byte *data = null;
    int format;
    unsigned long len, fill;
    Atom type;
@@ -263,11 +361,12 @@ static void RepositionDesktop(bool updateChildren)
 
       if(data)
       {
+         /*
          int desktops = 0;
          desktops = (int)*(long *)data;
 
-         //printf("_NET_NUMBER_OF_DESKTOPS is %d\n", desktops);
-
+         printf("_NET_NUMBER_OF_DESKTOPS is %d\n", desktops);
+         */
          XFree(data);
          data = null;
       }
@@ -331,11 +430,39 @@ static void RepositionDesktop(bool updateChildren)
 
    if(desktopX != x || desktopY != y || desktopW != w || desktopH != h)
    {
-      guiApp.SetDesktopPosition(x, y, w, h, updateChildren);
-      desktopX = x;
-      desktopY = y;
-      desktopW = w;
-      desktopH = h;
+      bool skip = false;
+      // Don't change the desktop area if another fullscreen application is running
+      // (Attemps to solve the debugging IDE being re-activated while switching debugged app between fullscreen/windowed on Cinnamon)
+      if(XGetWindowProperty(xGlobalDisplay, x_root, atoms[_net_active_window], 0, 32,
+                            False, AnyPropertyType, &type, &format, &len,
+                            &fill, &data) == Success && data)
+      {
+         X11Window active = *(long *)data;
+         XFree(data);
+         if(XGetWindowProperty(xGlobalDisplay, active, atoms[_net_wm_state], 0, 32, False,
+             XA_ATOM, &type, &format, &len, &fill, &data) == Success)
+         {
+            Atom * values = (Atom *) data;
+            int i;
+            for (i = 0; i < len; i++)
+            {
+               if(values[i] == atoms[_net_wm_state_fullscreen])
+               {
+                  skip = true;
+                  break;
+               }
+            }
+            XFree(data);
+         }
+      }
+      if(w && h && !skip)
+      {
+         guiApp.SetDesktopPosition(x, y, w, h, updateChildren);
+         desktopX = x;
+         desktopY = y;
+         desktopW = w;
+         desktopH = h;
+      }
    }
 }
 
@@ -378,7 +505,6 @@ static bool ProcessKeyMessage(Window window, uint keyCode, int release, XKeyEven
    Key code;
    unichar ch = 0;
    KeySym keysym = NoSymbol;
-   Status status;
    int buflength = 0;
    static long bufsize = 16;
    static char *buf = NULL;
@@ -420,13 +546,21 @@ static bool ProcessKeyMessage(Window window, uint keyCode, int release, XKeyEven
 
    if(!buf)
       buf = malloc((uint)bufsize);
-   if(windowData && windowData.ic)
+
+   // TOCHECK: X*LookupString man page says we shouldn't invoke it for non KeyPress events
+   if(windowData && windowData.ic) // && event->type == KeyPress)
    {
-      buflength = XmbLookupString(windowData.ic, event, buf, (int)bufsize, &keysym, &status);
-      if (status == XBufferOverflow)
+      Status status;
+#ifdef X_HAVE_UTF8_STRING
+   #define LookupString Xutf8LookupString
+#else
+   #define LookupString XmbLookupString
+#endif
+      buflength = LookupString(windowData.ic, event, buf, (int)bufsize, &keysym, &status);
+      if(status == XBufferOverflow)
       {
          buf = realloc(buf, (uint)(bufsize = buflength));
-         buflength = XmbLookupString(windowData.ic, event, buf, (int)bufsize, &keysym, &status);
+         buflength = LookupString(windowData.ic, event, buf, (int)bufsize, &keysym, &status);
       }
       if(status != XLookupKeySym && status != XLookupBoth && release == 1)
          keysym = XLookupKeysym(event, 0);
@@ -701,7 +835,7 @@ static bool ProcessKeyMessage(Window window, uint keyCode, int release, XKeyEven
    }
    if(!windowData.ic)
    {
-      ch = (byte)Interface::TranslateKey(key, event->state & ShiftMask);
+      ch = (byte)Interface::TranslateKey(key, (event->state & ShiftMask) != 0);
       // 127 is delete, we don't treat that as a character (Use (SmartKey)key == del)
       if(ch == 128 || ch == 127) ch = 0;
    }
@@ -713,7 +847,18 @@ static bool ProcessKeyMessage(Window window, uint keyCode, int release, XKeyEven
    if(key != leftControl && key != rightControl && event->state & ControlMask)
       code.ctrl = true;
    if(key != leftAlt && key != rightAlt && event->state & Mod1Mask)
+   {
+      if(fullScreenMode && key == tab)
+      {
+         XUngrabKeyboard(xGlobalDisplay, CurrentTime);
+         guiApp.SetAppFocus(false);
+         SetNETWMState((X11Window)window.windowHandle, true, remove, atoms[_net_wm_state_fullscreen], 0);
+         XIconifyWindow(xGlobalDisplay, (X11Window)window.windowHandle, DefaultScreen(xGlobalDisplay));
+         if(acquiredInputWindow)
+            XInterface::SetMousePosition(guiApp.acquiredMouseX, guiApp.acquiredMouseY);
+      }
       code.alt = true;
+   }
 
 #ifdef __APPLE__
    if(key != leftAlt && key != rightAlt && event->state & (1<<13))
@@ -730,6 +875,9 @@ static bool ProcessKeyMessage(Window window, uint keyCode, int release, XKeyEven
    if(release == 1)
    {
       int numBytes;
+
+      if(key < KeyCode::enumSize)
+         keyStates[key] = false;
       if(windowData && windowData.ic) ch = buflength ? UTF8GetChar(buf, &numBytes) : 0;
       if(ch == 127) ch = 0;
       // printf("Release! %d %d %d\n", keysym, code, ch);
@@ -740,6 +888,9 @@ static bool ProcessKeyMessage(Window window, uint keyCode, int release, XKeyEven
       int c;
       if(release == 0)
       {
+         if(key < KeyCode::enumSize)
+            keyStates[key] = true;
+
          if(windowData.ic && buflength)
          {
             for(c = 0; c<buflength;)
@@ -796,16 +947,38 @@ static uint E_CALL XEventThread(void * data)
 }
 */
 
-static Bool EventChecker(void *display, XEvent *event, char * data)
+static X11Bool EventChecker(void *display, XEvent *event, char * data)
 {
-   return (!data || (event->type == (int) data)) && event->type != NoExpose && event->type != GraphicsExpose;
+   return (!data || (event->type == (int)(intptr_t) data)) && event->type != NoExpose && event->type != GraphicsExpose;
 }
 
-static Bool ConfigureNotifyChecker(void *display, XConfigureEvent *event, char * data)
+static X11Bool ConfigureNotifyChecker(void *display, XConfigureEvent *event, char * data)
 {
    return (!data || (event->window == (X11Window) data)) && event->type == ConfigureNotify;
 }
 
+static X11Bool FocusInChecker(void *display, XFocusChangeEvent *event, char * data)
+{
+   X11Bool result = False;
+   if(event->type == FocusIn)
+   {
+      Window window = null;
+      // --- This deadlocks and I think Xorg should fix this.
+      // XFindContext(xGlobalDisplay, event->window, windowContext, (XPointer *) &window);
+      if((X11Window)guiApp.desktop.windowHandle == event->window)
+         window = guiApp.desktop;
+      else
+      {
+         for(window = guiApp.desktop.firstChild; window; window = window.next)
+            if((X11Window)window.windowHandle == event->window)
+               break;
+      }
+      if(window)
+         result = True;
+   }
+   return result;
+}
+
 static enum FrameExtentSupport { unknown, working, broken };
 
 static FrameExtentSupport frameExtentSupported;
@@ -946,7 +1119,6 @@ static void WaitForViewableWindow(Window window)
    while(true)
    {
       XWindowAttributes attributes = { 0 };
-      int result;
       if(!XGetWindowAttributes(xGlobalDisplay, (X11Window)window.windowHandle, &attributes))
          break;
       if(attributes.map_state == IsViewable)
@@ -956,9 +1128,9 @@ static void WaitForViewableWindow(Window window)
    }
 }
 
-static bool RequestFrameExtents(Window window)
+static bool RequestFrameExtents(X11Window windowHandle)
 {
-   if(window.nativeDecorations && frameExtentSupported != broken)
+   if(frameExtentSupported != broken)
    {
       // Request decoration frame extents
       XClientMessageEvent event = { 0 };
@@ -966,20 +1138,21 @@ static bool RequestFrameExtents(Window window)
       event.message_type = atoms[_net_request_frame_extents];
       event.display = xGlobalDisplay;
       event.serial = 0;
-      event.window = (X11Window)window.windowHandle;
+      event.window = windowHandle;
       event.send_event = 1;
-      window.windowHandle = (void *)window.windowHandle;
       event.format = 32;
 
       if(frameExtentSupported == unknown && !frameExtentRequest)
       {
          frameExtentRequest = GetTime();
-         frameExtentWindow = (X11Window)window.windowHandle;
+         frameExtentWindow = windowHandle;
       }
 
       XSendEvent(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), bool::false,
          SubstructureRedirectMask | SubstructureNotifyMask, (union _XEvent *)&event);
+      return true;
    }
+   return false;
 }
 
 static bool GetFrameExtents(Window window, bool update)
@@ -989,7 +1162,7 @@ static bool GetFrameExtents(Window window, bool update)
    int format;
    unsigned long len, fill;
    Atom type;
-   char * data = null;
+   byte * data = null;
 
    if(XGetWindowProperty(xGlobalDisplay, (X11Window)window.windowHandle,
       atoms[_net_frame_extents], 0, 4,
@@ -1049,13 +1222,13 @@ static bool GetFrameExtents(Window window, bool update)
    return result;
 }
 
-static bool WaitForFrameExtents(Window window)
+static bool WaitForFrameExtents(Window window, bool update)
 {
    int attempts = 0;
    //XFlush(xGlobalDisplay);
-   while(attempts++ < 10)
+   while(attempts++ < 40)
    {
-      if(GetFrameExtents(window, false)) return true;
+      if(GetFrameExtents(window, update)) return true;
       Sleep(1.0 / RESOLUTION);
    }
    return false;
@@ -1125,7 +1298,7 @@ static void SigIntHandler(int value)
    }
    /*
    struct shmid_ds info;
-       int maxid = shmctl (0, SHM_INFO, &info);
+   int maxid = shmctl (0, SHM_INFO, &info);
    int pid = getpgrp();
    int thisPid = getpid();
    //if(thisPid == pid)
@@ -1134,11 +1307,11 @@ static void SigIntHandler(int value)
       if(maxid >= 0)
       {
          int id;
-             for(id = 0; id <= maxid; id++)
+         for(id = 0; id <= maxid; id++)
          {
-                struct shmid_ds shmseg;
+            struct shmid_ds shmseg;
             int shmid;
-                     if((shmid = shmctl(id, SHM_STAT, &shmseg)) >= 0)
+            if((shmid = shmctl(id, SHM_STAT, &shmseg)) >= 0)
             {
                if(shmseg.shm_cpid == pid || shmseg.shm_cpid == thisPid)
                {
@@ -1155,6 +1328,61 @@ static void SigIntHandler(int value)
       guiApp.desktop.Destroy(0);*/
 }
 
+static void X11UpdateState(Window window, bool * unmaximized)
+{
+   if(atomsSupported[_net_wm_state]) //window.nativeDecorations)
+   {
+      int format;
+      unsigned long len, fill;
+      Atom type;
+      byte * data = null;
+      if(XGetWindowProperty(xGlobalDisplay, (X11Window)window.systemHandle, atoms[_net_wm_state], 0, 32, False,
+             XA_ATOM, &type, &format, &len, &fill, &data) == Success)
+      {
+         bool maxVert = false, maxHorz = false, isMinimized = false;
+         Atom * hints = (Atom *)data;
+         int c;
+         for(c = 0; c < len && hints[c]; c++)
+         {
+            if(hints[c] == atoms[_net_wm_state_maximized_vert])
+               maxVert = true;
+            else if(hints[c] == atoms[_net_wm_state_maximized_horz])
+               maxHorz = true;
+            else if(hints[c] == atoms[_net_wm_state_hidden])
+               isMinimized = true;
+         }
+         XFree(data);
+
+         if(maxVert && maxHorz)
+         {
+            if(window.state != maximized)
+            {
+               *&window.state = maximized;
+               if(!window.nativeDecorations)
+                  window.CreateSystemChildren();
+            }
+         }
+         else if(isMinimized)
+         {
+            if(window.state != minimized)
+            {
+               *&window.state = minimized;
+               if(!window.nativeDecorations)
+                  window.CreateSystemChildren();
+            }
+         }
+         else if(window.state != normal)
+         {
+            if(unmaximized && window.state == maximized)
+               *unmaximized = true;
+            *&window.state = normal;
+            if(!window.nativeDecorations)
+               window.CreateSystemChildren();
+         }
+      }
+   }
+}
+
 class XInterface : Interface
 {
    class_property(name) = "X";
@@ -1173,26 +1401,34 @@ class XInterface : Interface
 #endif
       xTerminate = false;
       xGlobalDisplay = XOpenDisplay(null);
+
+#if (defined(__unix__) || defined(__APPLE__)) && !defined(__ANDROID__)
+      if(xGlobalDisplay)
+         XLockDisplay(xGlobalDisplay);
+#endif
+
+      // XSynchronize(xGlobalDisplay, True);
       frameExtentSupported = unknown;
 
-       joystickFD[0] = open("/dev/js0", O_RDONLY);
+      joystickFD[0] = open("/dev/js0", O_RDONLY);
       joystickFD[1] = open("/dev/js1", O_RDONLY);
       joystickFD[2] = open("/dev/js2", O_RDONLY);
       joystickFD[3] = open("/dev/js3", O_RDONLY);
 
-      systemCursors[iBeam]    = XCreateFontCursor(xGlobalDisplay, XC_xterm);
-      systemCursors[cross]    = XCreateFontCursor(xGlobalDisplay, XC_tcross);
-      systemCursors[moving]   = XCreateFontCursor(xGlobalDisplay, XC_fleur);
-      systemCursors[sizeNESW] = XCreateFontCursor(xGlobalDisplay, XC_bottom_left_corner);
-      systemCursors[sizeNS]   = XCreateFontCursor(xGlobalDisplay, XC_sb_v_double_arrow);
-      systemCursors[sizeNWSE] = XCreateFontCursor(xGlobalDisplay, XC_bottom_right_corner);
-      systemCursors[sizeWE]   = XCreateFontCursor(xGlobalDisplay, XC_sb_h_double_arrow);
-      systemCursors[hand]     = XCreateFontCursor(xGlobalDisplay, XC_hand2);
-      systemCursors[arrow]    = XCreateFontCursor(xGlobalDisplay, XC_left_ptr);
-
       if(xGlobalDisplay)
       {
          XWindowAttributes attributes = { 0 };
+
+         systemCursors[iBeam]    = XCreateFontCursor(xGlobalDisplay, XC_xterm);
+         systemCursors[cross]    = XCreateFontCursor(xGlobalDisplay, XC_tcross);
+         systemCursors[moving]   = XCreateFontCursor(xGlobalDisplay, XC_fleur);
+         systemCursors[sizeNESW] = XCreateFontCursor(xGlobalDisplay, XC_bottom_left_corner);
+         systemCursors[sizeNS]   = XCreateFontCursor(xGlobalDisplay, XC_sb_v_double_arrow);
+         systemCursors[sizeNWSE] = XCreateFontCursor(xGlobalDisplay, XC_bottom_right_corner);
+         systemCursors[sizeWE]   = XCreateFontCursor(xGlobalDisplay, XC_sb_h_double_arrow);
+         systemCursors[hand]     = XCreateFontCursor(xGlobalDisplay, XC_hand2);
+         systemCursors[arrow]    = XCreateFontCursor(xGlobalDisplay, XC_left_ptr);
+
          XGetWindowAttributes(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), &attributes);
          xSystemDepth = attributes.depth;
          xSystemVisual = attributes.visual;
@@ -1263,7 +1499,7 @@ class XInterface : Interface
             Pixmap mask = XCreatePixmap(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), 1, 1, 1);
             XSetWindowAttributes attributes = { 0 };
 
-            XkbSetDetectableAutoRepeat(xGlobalDisplay, True, &autoRepeatDetectable);
+            XkbSetDetectableAutoRepeat(xGlobalDisplay, True, (int *)&autoRepeatDetectable);
 
             XInternAtoms(xGlobalDisplay, (char**)atomNames, AtomIdents::enumSize, False, atoms);
 
@@ -1294,12 +1530,6 @@ class XInterface : Interface
                }
             }
 
-            {
-               Atom protocols[2] = { atoms[wm_delete_window], atoms[wm_take_focus] };
-
-               XSetWMProtocols(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), protocols, 2);
-            }
-
             /*
             if(atomsSupported[_net_workarea])
                printf("Warning: _NET_WORKAREA extension not supported\n");
@@ -1387,7 +1617,7 @@ class XInterface : Interface
 
    void Terminate()
    {
-      XEvent e = { 0 };
+      //XEvent e = { 0 };
       xTerminate = true;
 
       // WHY WAS THIS COMMENTED HERE?
@@ -1466,10 +1696,34 @@ class XInterface : Interface
                case KeyPress:
                {
                   XKeyEvent * event = (XKeyEvent *) thisEvent;
+                  incref window;
+                  timeStamp = event->time;
+                  if(!window.active)
+                  {
+                     Window modalRoot = window.FindModal();
+                     XWindowData windowData;
+
+                     activeWindow = (X11Window)window.windowHandle;
+
+                     if(!window.parent || window != window.parent.activeChild)
+                     {
+                        if(modalRoot)
+                           modalRoot.ExternalActivate(true, true, window, null);
+                        else
+                           window.ExternalActivate(true, true, window, null); // lastActive);
+                        windowData = modalRoot ? modalRoot.windowData : window.windowData;
+                        if(windowData && windowData.ic)
+                        {
+                           // XSetICValues(ic, XNClientWindow, window.windowHandle, XNFocusWindow, window.windowHandle, NULL);
+                           XSetICFocus(windowData.ic);
+                        }
+                     }
+                  }
                   //*XUnlockDisplay(xGlobalDisplay);
                   ProcessKeyMessage(window, event->keycode, (event->keycode == lastKeyCode) ? 2 : 0, event);
                   //*if(xGlobalDisplay) XLockDisplay(xGlobalDisplay);
                   lastKeyCode = event->keycode;
+                  delete window;
                   break;
                }
                case KeyRelease:
@@ -1477,6 +1731,7 @@ class XInterface : Interface
                   XKeyEvent * event = (XKeyEvent *) thisEvent;
                   XEvent nextEvent;
                   lastKeyCode = 0;
+                  timeStamp = event->time;
                   if(!autoRepeatDetectable && XCheckIfEvent(xGlobalDisplay, (XEvent *)&nextEvent, EventChecker, (void *)KeyPress))
                   {
                      if(im && XFilterEvent(&nextEvent, None))
@@ -1513,24 +1768,26 @@ class XInterface : Interface
                   static Point lastPos[3];
 
                   Modifiers keyFlags = 0;
-                  bool doubleClick;
-                  uint button, buttonDouble, whichButton;
-                  uint buttonMask;
+                  bool doubleClick = false;
+                  uint button = 0, buttonDouble = 0, whichButton;
+                  uint buttonMask = 0;
                   int x = event->x_root, y = event->y_root;
-
+                  timeStamp = event->time;
                   if(event->button == Button1)
                   {
                      // Force a raise on click here to deal with confused active state preventing to bring the window up
-                     if(!atomsSupported[_net_active_window] && !window.isRemote)
+                     if(!fullScreenMode)
                      {
-                        XRaiseWindow(xGlobalDisplay, (X11Window)window.windowHandle);
-                        XSetInputFocus(xGlobalDisplay, (X11Window)window.windowHandle, RevertToPointerRoot, CurrentTime);
+                        if(!atomsSupported[_net_active_window] && !window.isRemote)
+                           XRaiseWindow(xGlobalDisplay, (X11Window)window.windowHandle);
+                        XSetInputFocus(xGlobalDisplay, (X11Window)window.windowHandle, RevertToParent, CurrentTime);
                      }
                      button = __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown;
                      buttonDouble = __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick;
                      whichButton = 0;
                      buttonMask = Button1Mask;
                      keyFlags.left = true;
+                     buttonsState.left = true;
                   }
                   else if(event->button == Button3)
                   {
@@ -1539,26 +1796,31 @@ class XInterface : Interface
                      whichButton = 2;
                      buttonMask = Button3Mask;
                      keyFlags.right = true;
+                     buttonsState.right = true;
                   }
-                  else
+                  else if(event->button == Button2)
                   {
                      button = __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonDown;
                      buttonDouble = __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleDoubleClick;
                      whichButton = 1;
                      buttonMask = Button2Mask;
                      keyFlags.middle = true;
+                     buttonsState.middle = true;
                   }
                   if(event->state & buttonMask)
                      break;
 
-                  doubleClick = event->time - lastTime[whichButton] < DBLCLICK_DELAY &&
-                     window == lastWindow[whichButton] &&
-                     Abs(event->x_root - lastPos[whichButton].x) < DBLCLICK_DELTA &&
-                     Abs(event->y_root - lastPos[whichButton].y) < DBLCLICK_DELTA;
-                  lastTime[whichButton] = doubleClick ? 0 : event->time;
-                  lastWindow[whichButton] = window;
-                  lastPos[whichButton].x = event->x_root;
-                  lastPos[whichButton].y = event->y_root;
+                  if(buttonMask)
+                  {
+                     doubleClick = event->time - lastTime[whichButton] < DBLCLICK_DELAY &&
+                        window == lastWindow[whichButton] &&
+                        Abs(event->x_root - lastPos[whichButton].x) < DBLCLICK_DELTA &&
+                        Abs(event->y_root - lastPos[whichButton].y) < DBLCLICK_DELTA;
+                     lastTime[whichButton] = doubleClick ? 0 : event->time;
+                     lastWindow[whichButton] = window;
+                     lastPos[whichButton].x = event->x_root;
+                     lastPos[whichButton].y = event->y_root;
+                  }
 
                   if(event->state & ShiftMask)     keyFlags.shift = true;
                   if(event->state & ControlMask)   keyFlags.ctrl = true;
@@ -1571,9 +1833,9 @@ class XInterface : Interface
                   incref window;
                   if(event->button == Button4 || event->button == Button5)
                   {
-                     window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit, (event->button == Button4) ? wheelUp : wheelDown, 0);
+                     window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit, { modifiers = keyFlags, code = (event->button == Button4) ? wheelUp : wheelDown }, 0);
                   }
-                  else
+                  else if(button)
                   {
                      if(doubleClick)
                      {
@@ -1601,17 +1863,21 @@ class XInterface : Interface
                   {
                      button = __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonUp;
                      buttonMask = Button1Mask;
+                     buttonsState.left = false;
                   }
                   else if(event->button == Button3)
                   {
                      button = __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnRightButtonUp;
                      buttonMask = Button3Mask;
+                     buttonsState.right = false;
                   }
                   else
                   {
                      button = __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp;
                      buttonMask = Button2Mask;
+                     buttonsState.middle = false;
                   }
+                  timeStamp = event->time;
                   if(!(event->state & buttonMask)) break;
                   if(event->state & ShiftMask)     keyFlags.shift = true;
                   if(event->state & ControlMask)   keyFlags.ctrl = true;
@@ -1637,12 +1903,13 @@ class XInterface : Interface
                }
                case MotionNotify:
                {
-                  static uint lastTime = 0;
+                  //static uint lastTime = 0;
                   XMotionEvent * event = (XMotionEvent *) thisEvent;
                   while(XCheckIfEvent(xGlobalDisplay, (XEvent *)thisEvent, EventChecker, (void *)MotionNotify));
                   // if(event->time - lastTime > 15)
                   {
                      Modifiers keyFlags = 0;
+                     timeStamp = event->time;
                      // int x = event->x_root, y = event->y_root;
 
                      if(event->state & ShiftMask)     keyFlags.shift = true;
@@ -1653,11 +1920,16 @@ class XInterface : Interface
                      if(event->state & Button3Mask)   keyFlags.right = true;
                      //*XUnlockDisplay(xGlobalDisplay);
                      incref window;
+                     if(window == acquiredInputWindow)
+                     {
+                        lastMouse.x = event->x_root;
+                        lastMouse.y = event->y_root;
+                     }
                      window.MouseMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMouseMove,
                         event->x_root, event->y_root, &keyFlags, false, false);
                      delete window;
                      //*if(xGlobalDisplay) XLockDisplay(xGlobalDisplay);
-                     lastTime = (uint)event->time;
+                     //lastTime = (uint)event->time;
                   }
                   break;
                }
@@ -1665,23 +1937,18 @@ class XInterface : Interface
                {
                   XExposeEvent * event = (XExposeEvent *) thisEvent;
                   Box box;
-                  box.left = event->x - window.clientStart.x;
-                  box.top = event->y - window.clientStart.y;
+                  box.left = event->x;
+                  box.top = event->y;
                   box.right = box.left + event->width - 1;
                   box.bottom = box.top + event->height - 1;
-                  window.Update(box);
-                  box.left   += window.clientStart.x;
-                  box.top    += window.clientStart.y;
-                  box.right  += window.clientStart.x;
-                  box.bottom += window.clientStart.y;
                   window.UpdateDirty(box);
                   break;
                }
                case SelectionRequest:
                {
-                   XSelectionRequestEvent *req = (XSelectionRequestEvent *) thisEvent;
-                   XEvent respond;
-                        if(req->target == atoms[targets] && clipBoardData)
+                  XSelectionRequestEvent *req = (XSelectionRequestEvent *) thisEvent;
+                  XEvent respond;
+                  if(req->target == atoms[targets] && clipBoardData)
                   {
                      Atom * supportedTargets = new Atom[4];
                      supportedTargets[0] = atoms[targets];
@@ -1689,27 +1956,27 @@ class XInterface : Interface
                      supportedTargets[2] = XA_STRING;
                      supportedTargets[3] = atoms[utf8_string];
                      XChangeProperty(xGlobalDisplay,req->requestor, req->_property,
-                                        XA_ATOM,32,PropModeReplace, (byte *) supportedTargets, 4*sizeof(Atom));
+                        XA_ATOM,32,PropModeReplace, (byte *) supportedTargets, 4*sizeof(Atom));
                      respond.xselection._property = req->_property;
                      delete supportedTargets;
                   }
                   else if((req->target == XA_STRING || req->target == atoms[utf8_string]) && clipBoardData)
-                        {
+                  {
                      Atom _property = (req->_property == None) ? req->target : req->_property;
-                                XChangeProperty(xGlobalDisplay,req->requestor, _property,
-                                        req->target/*req->_property*/,8,PropModeReplace, (byte *) clipBoardData, strlen(clipBoardData));
-                                respond.xselection._property = _property;
-                        }
+                     XChangeProperty(xGlobalDisplay,req->requestor, _property,
+                        req->target/*req->_property*/,8,PropModeReplace, (byte *) clipBoardData, strlen(clipBoardData));
+                     respond.xselection._property = _property;
+                  }
                   else
-                                respond.xselection._property = None;
+                     respond.xselection._property = None;
 
                   respond.xselection.type = SelectionNotify;
-                        respond.xselection.display = req->display;
-                        respond.xselection.requestor = req->requestor;
-                        respond.xselection.selection =req->selection;
-                        respond.xselection.target = req->target;
-                        respond.xselection.time = CurrentTime;
-                        XSendEvent(xGlobalDisplay, req->requestor,0,0,&respond);
+                  respond.xselection.display = req->display;
+                  respond.xselection.requestor = req->requestor;
+                  respond.xselection.selection =req->selection;
+                  respond.xselection.target = req->target;
+                  respond.xselection.time = CurrentTime;
+                  XSendEvent(xGlobalDisplay, req->requestor,0,0,&respond);
                   break;
                }
                case SelectionClear:
@@ -1719,9 +1986,30 @@ class XInterface : Interface
                }
                case FocusIn:
                {
+                  lastMouse = acquireStart;
+
+                  guiApp.SetAppFocus(true);
+
+                  X11UpdateState(window, null);
+
+                  if(fullScreenMode)
+                  {
+                     if(acquiredInputWindow)
+                     {
+                        GetMousePosition(&guiApp.acquiredMouseX, &guiApp.acquiredMouseY);
+                        lastMouse = { window.size.w/2, window.size.h/2 };
+                        SetMousePosition(lastMouse.x, lastMouse.y);
+                     }
+                     XRaiseWindow(xGlobalDisplay, (X11Window)window.windowHandle);
+                     SetNETWMState((X11Window)window.windowHandle, true, add, atoms[_net_wm_state_fullscreen], 0);
+                     XGrabKeyboard(xGlobalDisplay, (X11Window)window.windowHandle, False,  GrabModeAsync, GrabModeAsync, CurrentTime);
+                     XSetInputFocus(xGlobalDisplay, (X11Window)window.windowHandle, RevertToParent, timeStamp);
+                     XInterface::UpdateRootWindow(window);
+                     break;
+                  }
+
                   if(activeWindow != (X11Window)window.windowHandle)
                   {
-                     XFocusChangeEvent *event = (XFocusChangeEvent *) thisEvent;
                      Window modalRoot = window.FindModal();
                      XWindowData windowData;
 
@@ -1729,7 +2017,7 @@ class XInterface : Interface
 
                      if(window.parent && window == window.parent.activeChild) break;
                      incref window;
-                     //if(window.creationActivation == activate)
+                     //if(window.creationActivation == activate && guiApp.desktop.active)
                      {
                         if(modalRoot)
                            modalRoot.ExternalActivate(true, true, window, null); // lastActive);
@@ -1739,7 +2027,7 @@ class XInterface : Interface
                      windowData = modalRoot ? modalRoot.windowData : window.windowData;
                      if(windowData && windowData.ic)
                      {
-                        // XSetICValues(ic, XNClientWindow, window.windowHandle, XNFocusWindow, window.windowHandle, 0);
+                        // XSetICValues(ic, XNClientWindow, window.windowHandle, XNFocusWindow, window.windowHandle, NULL);
                         XSetICFocus(windowData.ic);
                      }
                      //delete lastActive;
@@ -1755,10 +2043,32 @@ class XInterface : Interface
                   //printf("Processing a FocusOut Event for %s (%x)\n", window._class.name, window);
 #endif
 
+                  /*
                   if(XCheckTypedWindowEvent(xGlobalDisplay, thisEvent->window, FocusIn, (XEvent *)thisEvent))
                   {
                      break;
                   }
+                  */
+
+                  if(XCheckIfEvent(xGlobalDisplay, (XEvent *)thisEvent, (void *)FocusInChecker, null))
+                  {
+                     if(!fullScreenMode)
+                        XPutBackEvent(xGlobalDisplay, (XEvent *)thisEvent);
+                     break;
+                  }
+
+
+                  if(fullScreenMode || (X11Window)window.windowHandle == activeWindow)
+                     guiApp.SetAppFocus(false);
+
+                  if(fullScreenMode)
+                  {
+                     //XUngrabKeyboard(xGlobalDisplay, CurrentTime);
+                     //SetNETWMState((X11Window)window.windowHandle, true, remove, atoms[_net_wm_state_fullscreen], 0);
+                     //XIconifyWindow(xGlobalDisplay, (X11Window)window.windowHandle, DefaultScreen(xGlobalDisplay));
+                     break;
+                  }
+
                   if(thisEvent->window == activeWindow)
                      activeWindow = (X11Window)null;
 #if 0
@@ -1829,8 +2139,7 @@ class XInterface : Interface
                   else
 #endif
                   {
-                     XFocusChangeEvent *event = (XFocusChangeEvent *) thisEvent;
-                     if(window != window.parent.activeChild && window != guiApp.interimWindow) break;
+                     if(window.parent && window != window.parent.activeChild && window != guiApp.interimWindow) break;
                      incref window;
 
 #ifdef _DEBUG
@@ -1855,68 +2164,21 @@ class XInterface : Interface
                {
                   XConfigureEvent * event = (XConfigureEvent *) thisEvent;
                   bool unmaximized = false;
+                  bool um = false;
+                  if(!window.visible || fullScreenMode) break;
                   while(XCheckIfEvent(xGlobalDisplay, (XEvent *)thisEvent, (void *)ConfigureNotifyChecker, (void *)window.windowHandle));
                   //if(event->x - desktopX != window.position.x || event->y - desktopY != window.position.y || event->width != window.size.w || event->height != window.size.h)
-
-                  if(window.nativeDecorations)
-                  {
-                     int format;
-                     unsigned long len, fill;
-                     Atom type;
-                     char * data = null;
-                     if(XGetWindowProperty(xGlobalDisplay, (X11Window)window.systemHandle, atoms[_net_wm_state], 0, 32, False,
-                            XA_ATOM, &type, &format, &len, &fill, &data) == Success)
-                     {
-                        bool maxVert = false, maxHorz = false, isMinimized = false;
-                        Atom * hints = (Atom *)data;
-                        int c;
-                        for(c = 0; c < len && hints[c]; c++)
-                        {
-                           if(hints[c] == atoms[_net_wm_state_maximized_vert])
-                              maxVert = true;
-                           else if(hints[c] == atoms[_net_wm_state_maximized_horz])
-                              maxHorz = true;
-                           else if(hints[c] == atoms[_net_wm_state_hidden])
-                              isMinimized = true;
-                        }
-                        XFree(data);
-
-                        if(maxVert && maxHorz)
-                        {
-                           if(window.state != maximized)
-                           {
-                              *&window.state = maximized;
-                              if(!window.nativeDecorations)
-                                 window.CreateSystemChildren();
-                           }
-                        }
-                        else if(isMinimized)
-                        {
-                           if(window.state != minimized)
-                           {
-                              *&window.state = minimized;
-                              if(!window.nativeDecorations)
-                                 window.CreateSystemChildren();
-                           }
-                        }
-                        else if(window.state != normal)
-                        {
-                           if(window.state == maximized)
-                              unmaximized = true;
-                           *&window.state = normal;
-                           if(!window.nativeDecorations)
-                              window.CreateSystemChildren();
-                        }
-                     }
-                  }
+                  X11UpdateState(window, &um);
+                  unmaximized = false;
                   {
+                     bool offset = false;
                      int x, y, w, h;
-                     if(unmaximized)
+                     if(unmaximized && window.nativeDecorations && ((BorderBits)window.borderStyle).fixed)
                      {
+                        if(window.nativeDecorations && RequestFrameExtents((X11Window)window.windowHandle))
+                           WaitForFrameExtents(window, false);
+
                         // Ensure we set the normal size anchor when un-maximizing
-                        if(window.nativeDecorations && RequestFrameExtents(window))
-                           WaitForFrameExtents(window);
-                        x = window.position.x, y = window.position.y, w = window.size.w, h = window.size.h;
                         window.ComputeAnchors(window.normalAnchor, window.normalSizeAnchor, &x, &y, &w, &h);
                      }
                      else
@@ -1932,45 +2194,44 @@ class XInterface : Interface
                            XTranslateCoordinates(xGlobalDisplay, event->window,
                               RootWindow(xGlobalDisplay, DefaultScreen(xGlobalDisplay)), 0, 0,
                               &rootX, &rootY, &rootChild);
-                           x = rootX;
-                           y = rootY;
+
+                           if(x != rootX || y != rootY)
+                           {
+                              if(!event->send_event)
+                              {
+                                 // offset = true;
+                                 x = rootX;
+                                 y = rootY;
+                              }
+                           }
                         }
 
                         x -= desktopX;
                         y -= desktopY;
 
-                        if(window.nativeDecorations && window.state != maximized)
+                        if(window.nativeDecorations && window.state != maximized && ((BorderBits)window.borderStyle).fixed)
                         {
                            x -= windowData.decor.left;
                            y -= windowData.decor.top;
                            w += windowData.decor.left + windowData.decor.right;
                            h += windowData.decor.top + windowData.decor.bottom;
-                           /*
-                           x -= window.clientStart.x;
-                           y -= window.clientStart.y - (window.hasMenuBar ? skinMenuHeight : 0);
-                           w += window.size.w - window.clientSize.w;
-                           h += window.size.h - window.clientSize.h;
-                           */
                         }
                      }
 
-                     // Break the anchors for moveable/resizable windows
-                     if(window.style.fixed && window.state == normal)
-                     {
-                        window.normalAnchor = Anchor { left = x, top = y };
-                        window.normalSizeAnchor = SizeAnchor { { w, h } };
-                        window.anchored = false;
-                     }
+                     window.Position(x, y, w, h, um, true, true, true, false, unmaximized);
 
                      // Break the anchors for moveable/resizable windows
-                     if(window.style.fixed && window.state == normal)
+                     // Avoid doing this if the translation wasn't in sync as it will cause the window to move around
+                     if(!unmaximized && !offset && window.style.fixed && window.state == normal)
                      {
-                        window.normalAnchor = Anchor { left = x, top = y };
-                        window.normalSizeAnchor = SizeAnchor { { w, h } };
-                        window.anchored = false;
+                        window.normalAnchor = Anchor
+                        {
+                           left = x + windowData.decor.left,
+                           top = y + windowData.decor.top
+                        };
+                        window.normalSizeAnchor =
+                           SizeAnchor { { window.clientSize.w, window.clientSize.h }, isClientW = true, isClientH = true };
                      }
-
-                     window.Position(x, y, w, h, true, true, true, true, false, unmaximized);
                   }
                   break;
                }
@@ -1988,9 +2249,19 @@ class XInterface : Interface
                      Window modalRoot;
                      XWindowData windowData;
                      bool laterFocus;
-                     activeWindow = (X11Window)window.windowHandle;
 
-                     timeStamp = (int)event->data.l[1];
+                     if(fullScreenMode)
+                     {
+                        XRaiseWindow(xGlobalDisplay, (X11Window)window.windowHandle);
+                        XSetInputFocus(xGlobalDisplay, (X11Window)window.windowHandle, RevertToParent, timeStamp);
+                        XGrabKeyboard(xGlobalDisplay, (X11Window)window.windowHandle, False,  GrabModeAsync, GrabModeAsync, CurrentTime);
+                        guiApp.SetAppFocus(true);
+                        break;
+                     }
+
+                     //activeWindow = (X11Window)window.windowHandle;
+
+                     timeStamp = (X11Time)event->data.l[1];
 
                      windowData = window.windowData;
                      laterFocus = windowData.laterFocus;
@@ -2011,7 +2282,7 @@ class XInterface : Interface
                            XFocusChangeEvent *event = (XFocusChangeEvent *) &checkEvent;
                            Window window;
                            XFindContext(xGlobalDisplay, event->window, windowContext, (XPointer *) &window);
-                           if(window != window.parent.activeChild) break;
+                           if(window.parent && window != window.parent.activeChild) break;
                            incref window;
 
       #ifdef _DEBUG
@@ -2027,6 +2298,7 @@ class XInterface : Interface
                         }
                      }
 
+                     lastMouse = acquireStart;
                      modalRoot = window.FindModal();
                      windowData = modalRoot ? modalRoot.windowData : window.windowData;
                      if(windowData)
@@ -2047,10 +2319,10 @@ class XInterface : Interface
                                  event.window = (X11Window)modalRoot.windowHandle;
                                  event.send_event = 1;
                                  event.format = 32;
-                                 event.data.l[0] = 0;
+                                 event.data.l[0] = /*0*/ 1;
+                                 event.data.l[1] = timeStamp;
+                                 event.data.l[2] = activeWindow;
                                  /*
-                                 event.data.l[0] = 1;
-                                 event.data.l[1] = atoms[_net_wm_user_time];
                                  event.data.l[2] = activeWindow; //guiApp.desktop.activeChild.windowHandle;
                                  */
 #ifdef _DEBUG
@@ -2058,7 +2330,9 @@ class XInterface : Interface
 #endif
 
                                  XSendEvent(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), bool::false, SubstructureRedirectMask | SubstructureNotifyMask, (union _XEvent *)&event);
-                                 XSetInputFocus(xGlobalDisplay, (X11Window)modalRoot.windowHandle, RevertToPointerRoot, (uint)timeStamp);
+                                 XSetInputFocus(xGlobalDisplay, (X11Window)modalRoot.windowHandle, RevertToParent, timeStamp);
+                                 guiApp.SetAppFocus(true);
+                                 activeWindow = (X11Window)window.windowHandle;
 
                                  //XFlush(xGlobalDisplay);
                                  //printf("Done.\n");
@@ -2066,11 +2340,13 @@ class XInterface : Interface
                            }
                            else
                            {
-                              XSetInputFocus(xGlobalDisplay, (X11Window)window.windowHandle, RevertToPointerRoot, (uint)timeStamp);
+                              XSetInputFocus(xGlobalDisplay, (X11Window)window.windowHandle, RevertToParent, timeStamp);
+                              guiApp.SetAppFocus(true);
+                              activeWindow = (X11Window)window.windowHandle;
                               window.ExternalActivate(true, true, window, null); // lastActive);
                               if(windowData && windowData.ic)
                               {
-                                 // XSetICValues(ic, XNClientWindow, window.windowHandle, XNFocusWindow, window.windowHandle, 0);
+                                 // XSetICValues(ic, XNClientWindow, window.windowHandle, XNFocusWindow, window.windowHandle, NULL);
                                  //XSetICFocus(windowData.ic);
                               }
                            }
@@ -2088,7 +2364,7 @@ class XInterface : Interface
                {
                   XWindowData windowData = window.windowData;
                   XPropertyEvent * event = (XPropertyEvent *) thisEvent;
-                  if(event->atom == atoms[_net_frame_extents] &&
+                  if(!fullScreenMode && event->atom == atoms[_net_frame_extents] &&
                     event->state == PropertyNewValue && windowData)
                   {
                      if(!GetFrameExtents(window, true))
@@ -2126,11 +2402,11 @@ class XInterface : Interface
       //*XUnlockDisplay(xGlobalDisplay);
    }
 
-   char ** GraphicsDrivers(int * numDrivers)
+   const char ** GraphicsDrivers(int * numDrivers)
    {
-      static char *graphicsDrivers[] = { "X", "OpenGL" };
+      static const char *graphicsDrivers[] = { "X", "OpenGL" };
       *numDrivers = sizeof(graphicsDrivers) / sizeof(char *);
-      return (char **)graphicsDrivers;
+      return (const char **)graphicsDrivers;
    }
 
    void GetCurrentMode(bool * fullScreen, int * resolution, int * colorDepth, int * refreshRate)
@@ -2155,8 +2431,8 @@ class XInterface : Interface
       }
       else
       {
-         static bool firstTime = true;
-         firstTime = false;
+         //static bool firstTime = true;
+         //firstTime = false;
          desktopX = desktopY = desktopW = desktopH = 0;
 
          RepositionDesktop(false);
@@ -2181,7 +2457,7 @@ class XInterface : Interface
       attributes.override_redirect = (window.interim || (!atomsSupported[_net_wm_state] && !window.nativeDecorations)) ? True : False;
       attributes.event_mask = EVENT_MASK;
       //printf("%s\n", guiApp.defaultDisplayDriver);
-#if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D) && !defined(ECERE_NOGL)
+#if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D) && !defined(ECERE_NOGL) && !defined(__ODROID__)
       if(window.dispDriver == class(OpenGLDisplayDriver) || !strcmp(guiApp.defaultDisplayDriver, "OpenGL"))
       {
          int samples;
@@ -2280,6 +2556,20 @@ class XInterface : Interface
          };
          visualInfo = glXChooseVisual(xGlobalDisplay, DefaultScreen(xGlobalDisplay), attrList);
       }
+#elif defined(__ODROID__)
+      if(!visualInfo)
+      {
+         // System visual not working on ODROID?
+         int attrList[] =
+         {
+            GLX_USE_GL, GLX_DEPTH_SIZE, 1,
+            GLX_RGBA,
+            GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1,
+            GLX_DOUBLEBUFFER,
+            None
+         };
+         visualInfo = glXChooseVisual(xGlobalDisplay, DefaultScreen(xGlobalDisplay), attrList);
+      }
 #endif
       depth = visualInfo ? visualInfo->depth : (window.alphaBlend ? 32 : xSystemDepth);
       visual = visualInfo ? visualInfo->visual : (window.alphaBlend ? FindFullColorVisual (xGlobalDisplay, &depth) : xSystemVisual);
@@ -2295,9 +2585,50 @@ class XInterface : Interface
 
       if(fullScreenMode)
       {
-         windowHandle = XCreateWindow(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay),
-            0,0,guiApp.desktop.size.w,guiApp.desktop.size.h,0, depth, InputOutput, visual ? visual : CopyFromParent,
-            CWEventMask | (visual ? (CWColormap | CWBorderPixel) : 0)/*| CWOverrideRedirect*/, &attributes);
+         windowHandle = XCreateWindow(xGlobalDisplay,
+               DefaultRootWindow(xGlobalDisplay),
+               0,0,
+               XDisplayWidth(xGlobalDisplay, DefaultScreen(xGlobalDisplay)),
+               XDisplayHeight(xGlobalDisplay, DefaultScreen(xGlobalDisplay)),
+               0, depth, InputOutput, visual ? visual : CopyFromParent,
+               CWEventMask | (visual ? (CWColormap | CWBorderPixel) : 0) | CWOverrideRedirect,
+               &attributes);
+
+         {
+            XSizeHints hints = { 0 };
+            XSetWMNormalHints(xGlobalDisplay, windowHandle, &hints);
+         }
+
+         {
+            String caption = window.caption;
+            XChangeProperty(xGlobalDisplay, windowHandle, atoms[_net_wm_name],
+               atoms[utf8_string], 8, PropModeReplace, (byte *)window.caption, caption ? strlen(caption) : 0);
+            XChangeProperty(xGlobalDisplay, windowHandle, atoms[wm_name],
+               atoms[utf8_string], 8, PropModeReplace, (byte *)window.caption, caption ? strlen(caption) : 0);
+         }
+
+         SetNETWMState((X11Window)windowHandle, false, add, atoms[_net_wm_state_fullscreen], 0);
+         //SetNETWMState((X11Window)windowHandle, false, add, atoms[_net_wm_state_above], 0);
+         {
+            Atom hints[4];
+            int count;
+
+            hints[0] = atoms[_net_wm_window_type_normal];
+            count = 1;
+            XChangeProperty(xGlobalDisplay, windowHandle, atoms[_net_wm_window_type], XA_ATOM, 32,
+               PropModeReplace, (unsigned char*)&hints, count);
+         }
+
+         {
+            XWMHints xwmHints;
+            xwmHints.flags = InputHint;
+            xwmHints.input = 0;
+            XSetWMHints(xGlobalDisplay, windowHandle, &xwmHints);
+         }
+         {
+            Atom protocols[2] = { atoms[wm_delete_window], atoms[wm_take_focus] };
+            XSetWMProtocols(xGlobalDisplay, windowHandle, protocols, 2);
+         }
       }
       /*
          Unsupported for now...
@@ -2316,6 +2647,18 @@ class XInterface : Interface
             int x = window.position.x + desktopX, y = window.position.y + desktopY;
             int w = window.state == normal ? Max(1, window.size.w) : Max(1, window.normalSizeAnchor.size.w);
             int h = window.state == normal ? Max(1, window.size.h) : Max(1, window.normalSizeAnchor.size.h);
+            MinMaxValue smw = 0, smh = 0;
+            MinMaxValue minW = window.minSize.w, minH = window.minSize.h;
+            window.OnResizing((int *)&minW, (int *)&minH);
+
+            // To fix jumping message boxes on Cinnamon:
+            if(window.state == normal && (minW > window.minSize.w || minH > window.minSize.w))
+               window.ComputeAnchors(window.normalAnchor, window.normalSizeAnchor, &x, &y, &w, &h);
+
+            window.SetWindowMinimum(&smw, &smh);
+            minW = Max(minW, smw);
+            minH = Max(minH, smh);
+
             if(!window.nativeDecorations && window.state != normal)
             {
                w += window.size.w - window.clientSize.w;
@@ -2347,25 +2690,40 @@ class XInterface : Interface
                //printf("Done.\n");
                //XChangeProperty(xGlobalDisplay, windowHandle, atoms[wm_transient_for], XA_WINDOW, 32, PropModeReplace, (unsigned char*)&parentWindow, 1);
                if(window.isModal)
-               {
-                  Atom hints[1] = { atoms[_net_wm_state_modal] };
-                  XChangeProperty(xGlobalDisplay, windowHandle, atoms[_net_wm_state], XA_ATOM, 32, PropModeReplace, (unsigned char*)&hints, 1);
-               }
+                  SetNETWMState(windowHandle, false, add, atoms[_net_wm_state_modal], 0);
             }
 
             {
-               Atom hints[2] =
+               Atom hints[4];
+               int count;
+               if(parentWindow && window.interim)
+               {
+                  hints[0] = atoms[_net_wm_window_type_dropdown_menu];
+                  hints[1] = atoms[_net_wm_window_type_popup_menu];
+                  hints[2] = atoms[_net_wm_window_type_menu];
+                  count = 3;
+               }
+               else if(parentWindow)
                {
-                  parentWindow ? atoms[_net_wm_window_type_menu] : atoms[_net_wm_window_type_normal],
-                  parentWindow ? atoms[_net_wm_window_type_popup_menu] : 0
+                  hints[0] = atoms[_net_wm_window_type_normal];
+                  SetNETWMState(windowHandle, false, add, atoms[_net_wm_state_skip_taskbar], 0);
+
+                  // Some WMs won't show a close button if dialog is set
+                  // Additionally, this casues jumping of all dialog windows on Cinnamon
+                  //hints[0] = atoms[_net_wm_window_type_dialog];
+                  count = 1;
+               }
+               else
+               {
+                  hints[0] = atoms[_net_wm_window_type_normal];
+                  count = 1;
                };
-#if defined(__APPLE__) || defined(__FreeBSD__)
-               // Don't set this on non-interim windows for OS X...
-               if(parentWindow && window.interim)
-#endif
+               XChangeProperty(xGlobalDisplay, windowHandle, atoms[_net_wm_window_type], XA_ATOM, 32,
+                  PropModeReplace, (unsigned char*)&hints, count);
+
+               if(window.stayOnTop)
+                  SetNETWMState((X11Window)windowHandle, false, add, atoms[_net_wm_state_above], 0);
 
-                  XChangeProperty(xGlobalDisplay, windowHandle, atoms[_net_wm_window_type], XA_ATOM, 32,
-                     PropModeReplace, (unsigned char*)&hints, parentWindow ? 2 : 1);
                {
                   XWMHints xwmHints;
                   xwmHints.flags = InputHint;
@@ -2378,17 +2736,12 @@ class XInterface : Interface
                }
 
                // Set Normal hints for minimum/maximum size
-               if(true) //window.minSize.w || window.minSize.h || window.maxSize.w < MAXINT || window.maxSize.h < MAXINT)
                {
                   XSizeHints hints = { 0 };
-                  MinMaxValue mw, mh;
-                  window.SetWindowMinimum(&mw, &mh);
-                  if(window.minSize.w || window.minSize.h)
-                  {
-                     hints.min_width = Max(window.minSize.w, mw);
-                     hints.min_height = Max(window.minSize.h, mh);
-                     hints.flags |= PMinSize;
-                  }
+                  hints.min_width = minW;
+                  hints.min_height = minH;
+                  hints.flags |= PMinSize;
+
                   if(window.maxSize.w < MAXINT || window.minSize.h < MAXINT)
                   {
                      hints.max_width = window.maxSize.w;
@@ -2417,7 +2770,7 @@ class XInterface : Interface
          int num_missing_charsets = 0;
          char *default_string;
          XFontSet fontset;
-         XRectangle area = { 0, 0,  400, 400 };
+         //XRectangle area = { 0, 0,  400, 400 };
          XVaNestedList argList;
 
          // sprintf(fontString, "-*-%s-*-r-*-*-*-%d-*-*-*-*-*-*", "Helvetica" /*window.font.faceName*/, (int)(window.font.size * 20));
@@ -2445,8 +2798,8 @@ class XInterface : Interface
       }
       if(ic)
       {
-             XGetICValues(ic, XNFilterEvents, &mask, NULL);
-             mask |= EVENT_MASK;
+         XGetICValues(ic, XNFilterEvents, &mask, NULL);
+         mask |= EVENT_MASK;
       }
       /*
       XSelectInput(xGlobalDisplay, windowHandle, mask);
@@ -2462,14 +2815,16 @@ class XInterface : Interface
       {
          if ( atoms[_motif_wm_hints] != None )
          {
+            BorderBits borderBits = (BorderBits)window.borderStyle;
+            bool hasTitleBar = borderBits.fixed;
             MWM_Hints hints
             {
-               (window.nativeDecorations ? 0 : MWM_HINTS_DECORATIONS)|MWM_HINTS_FUNCTIONS,
+               ((window.nativeDecorations && hasTitleBar) ? 0 : MWM_HINTS_DECORATIONS)|MWM_HINTS_FUNCTIONS,
                (window.hasClose ? MWM_FUNC_CLOSE : 0) |
-               (window.hasMaximize ? MWM_FUNC_MAXIMIZE : 0) |
-               (window.hasMinimize ? MWM_FUNC_MINIMIZE : 0) |
-               ((window.moveable || ((BorderBits)window.borderStyle).fixed) ? MWM_FUNC_MOVE : 0) |
-               (((BorderBits)window.borderStyle).sizable ? MWM_FUNC_RESIZE : 0),
+               (fullScreenMode || window.hasMaximize ? MWM_FUNC_MAXIMIZE : 0) |
+               (fullScreenMode || window.hasMinimize ? MWM_FUNC_MINIMIZE : 0) |
+               ((fullScreenMode || window.moveable || hasTitleBar) ? MWM_FUNC_MOVE : 0) |
+               (fullScreenMode || borderBits.sizable ? MWM_FUNC_RESIZE : 0),
                 0, 0, 0
             };
             XChangeProperty(xGlobalDisplay, windowHandle, atoms[_motif_wm_hints], atoms[_motif_wm_hints], 32,
@@ -2486,16 +2841,12 @@ class XInterface : Interface
          }
       }
 
-      /*
       {
-         Atom protocolsAtom = XInternAtom(xGlobalDisplay, "WM_PROTOCOLS", False);
-         if ( protocolsAtom != None )
-         {
-            MWM_Hints hints = { MWM_HINTS_DECORATIONS|MWM_HINTS_FUNCTIONS, 0, 0, 0, 0 };
-            XChangeProperty(xGlobalDisplay, windowHandle, atoms[_motif_wm_hints], atoms[_motif_wm_hints], 32,
-               PropModeReplace, (unsigned char*)&hints, sizeof(hints)/4);
-         }
-      }*/
+         XWMHints wmHints = { 0 };
+         wmHints.input = True;
+         XSetWMHints(xGlobalDisplay, windowHandle, &wmHints);
+      }
+
       // XFlush(xGlobalDisplay);
       window.windowData = XWindowData { visualInfo, ic };
 
@@ -2510,14 +2861,28 @@ class XInterface : Interface
          XUngrabPointer(xGlobalDisplay, CurrentTime);
       }
 
-      if(!window.nativeDecorations || !RequestFrameExtents(window))
+      if(fullScreenMode || !window.nativeDecorations ||  !((BorderBits)window.borderStyle).fixed || !RequestFrameExtents(windowHandle))
          ((XWindowData)window.windowData).gotFrameExtents = true;
+
+      window.windowHandle = (void *)windowHandle;
+      if(window.state != maximized)
+         WaitForFrameExtents(window, true);
+
+      //GetFrameExtents(window, true);
+
+      if(fullScreenMode)
+      {
+         XMapWindow(xGlobalDisplay, windowHandle);
+         XGrabKeyboard(xGlobalDisplay, windowHandle, False,  GrabModeAsync, GrabModeAsync, CurrentTime);
+      }
       return (void *)windowHandle;
    }
 
    void DestroyRootWindow(Window window)
    {
       XEvent event;
+      if(window == acquiredInputWindow)
+         delete acquiredInputWindow;
 
       XDeleteContext(xGlobalDisplay, (XID)window, windowContext);
       XSaveContext(xGlobalDisplay, (X11Window)window.windowHandle, windowContext, null);
@@ -2541,7 +2906,7 @@ class XInterface : Interface
 
    // -- Window manipulation ---
 
-   void SetRootWindowCaption(Window window, char * name)
+   void SetRootWindowCaption(Window window, const char * name)
    {
       if(window.windowHandle)
       {
@@ -2557,9 +2922,13 @@ class XInterface : Interface
       //Logf("Position root window %s\n", window.name);
       if(window.windowHandle && (!window.parent || !window.parent.display))
       {
-         bool visible = window.visible;
          if(window.visible && window.created)
+         {
+            long t = (window.creationActivation == activate && guiApp.desktop.active) ? (int)timeStamp : 0;
+            XChangeProperty(xGlobalDisplay, (X11Window)window.windowHandle, atoms[_net_wm_user_time],
+              XA_CARDINAL,32,PropModeReplace, (byte *)&t, 1);
             XMapWindow(xGlobalDisplay, (X11Window)window.windowHandle);
+         }
          if(window.state == minimized && atomsSupported[_net_wm_state]) return;
 
          if(window.nativeDecorations)
@@ -2571,7 +2940,7 @@ class XInterface : Interface
                // && window.state != maximized -- required for Cinnamon on Mint 14/15
             if(!windowData.gotFrameExtents && window.state != maximized)
             {
-               if(WaitForFrameExtents(window))
+               if(WaitForFrameExtents(window, false))
                {
                   x += windowData.decor.left;
                   y += windowData.decor.top ;
@@ -2598,7 +2967,7 @@ class XInterface : Interface
          x += desktopX;
          y += desktopY;
 
-         if(!atomsSupported[_net_wm_state] || window.state != maximized)
+         if(!fullScreenMode && (!atomsSupported[_net_wm_state] || (window.state != maximized || !window.visible)))
          {
             if(move && resize)
                XMoveResizeWindow(xGlobalDisplay, (X11Window)window.windowHandle, x, y, w, h);
@@ -2606,17 +2975,25 @@ class XInterface : Interface
                XMoveWindow(xGlobalDisplay, (X11Window)window.windowHandle, x, y);
             else if(resize)
                XResizeWindow(xGlobalDisplay, (X11Window)window.windowHandle, w, h);
+
+            // Reset min/max for fixed size windows on WMs not looking at MWM_FUNC_RESIZE (e.g. Cinnamon)
+            if(window.style.fixed && !window.style.sizable && window.state != maximized)
+            {
+               XSizeHints hints = { 0 };
+               long supplied;
+               XGetWMNormalHints(xGlobalDisplay, (X11Window)window.windowHandle, &hints, &supplied);
+               hints.min_width = hints.max_width = w;
+               hints.min_height = hints.max_height = h;
+               hints.flags |= PMinSize|PMaxSize;
+               XSetWMNormalHints(xGlobalDisplay, (X11Window)window.windowHandle, &hints);
+            }
          }
-#if defined(__APPLE__)
-//         if(window.created && !visible)
-  //          XUnmapWindow(xGlobalDisplay, (X11Window)window.windowHandle);
-#endif
       }
    }
 
    void OrderRootWindow(Window window, bool topMost)
    {
-
+      SetNETWMState((X11Window)window.windowHandle, false, topMost ? add : remove, atoms[_net_wm_state_above], 0);
    }
 
    void SetRootWindowColor(Window window)
@@ -2653,26 +3030,45 @@ class XInterface : Interface
 
    void SetRootWindowState(Window window, WindowState state, bool visible)
    {
+      WindowState curState = window.state;
+      *&window.state = state;
       // Old WM (e.g. TWM), use built-in decorations
       if(!atomsSupported[_net_wm_state])
          window.nativeDecorations = false;
       if(!window.parent || !window.parent.display)
       {
+         XWindowData windowData = window.windowData;
          //Logf("Set root window state %d %s\n", state, window.name);
          if(visible)
          {
-            XMapWindow(xGlobalDisplay, (X11Window)window.windowHandle);
-            WaitForViewableWindow(window);
-            if(window.creationActivation == activate && state != minimized)
-               ActivateRootWindow(window);
+            if(!windowData.currentlyVisible)
+            {
+               long t = (window.creationActivation == activate && guiApp.desktop.active) ? timeStamp : 0;
+               XChangeProperty(xGlobalDisplay, (X11Window)window.windowHandle, atoms[_net_wm_user_time],
+                 XA_CARDINAL,32,PropModeReplace, (byte *)&t, 1);
+               XMapWindow(xGlobalDisplay, (X11Window)window.windowHandle);
+               windowData.currentlyVisible = true;
+               WaitForViewableWindow(window);
+               if(window.creationActivation == activate && guiApp.desktop.active && state != minimized)
+                  ActivateRootWindow(window);
+            }
+
+            if(fullScreenMode && state != minimized)
+            {
+               int w = XDisplayWidth(xGlobalDisplay, DefaultScreen(xGlobalDisplay));
+               int h = XDisplayHeight(xGlobalDisplay, DefaultScreen(xGlobalDisplay));
+               SetNETWMState((X11Window)window.windowHandle, true, add, atoms[_net_wm_state_fullscreen], 0);
+               XMoveResizeWindow(xGlobalDisplay, (X11Window)window.windowHandle, 0, 0, w, h);
+
+               guiApp.SetDesktopPosition(0, 0, w, h, true);
+               window.Position(0, 0, w, h, true, true, true, true, false, false);
+            }
 
             if(state == minimized && atomsSupported[_net_wm_state])
             {
-               uint iconic = IconicState;
-               /*
-               XChangeProperty(xGlobalDisplay, window.windowHandle, atoms[_net_wm_state], XA_ATOM, 32,
-                  PropModeReplace, (unsigned char*)&atoms[_net_wm_state_hidden], 1);
-               */
+               //uint iconic = IconicState;
+
+               // SetNETWMState(window.windowHandle, true, add, atoms[_net_wm_state_hidden], null);
                /*
                XChangeProperty(xGlobalDisplay, window.windowHandle, atoms[wm_state], XA_CARDINAL, 32,
                   PropModeReplace, &iconic, 1);
@@ -2681,19 +3077,6 @@ class XInterface : Interface
                /*
                XClientMessageEvent event = { 0 };
                event.type = ClientMessage;
-               event.message_type = atoms[_net_wm_state];
-               event.display = xGlobalDisplay;
-               event.serial = 0;
-               event.window = window.windowHandle;
-               event.send_event = 1;
-               event.format = 32;
-               event.data.l[0] = 2; // 1;
-               event.data.l[1] = atoms[_net_wm_state_hidden];
-               XSendEvent(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), bool::false, SubstructureRedirectMask | SubstructureNotifyMask, &event);
-               */
-               /*
-               XClientMessageEvent event = { 0 };
-               event.type = ClientMessage;
                event.message_type = atoms[wm_state];
                event.display = xGlobalDisplay;
                event.window = window.windowHandle;
@@ -2704,9 +3087,10 @@ class XInterface : Interface
                */
 
                // printf("Attempting to minimize %s\n", window._class.name);
-               XIconifyWindow(xGlobalDisplay, (X11Window)window.windowHandle, DefaultScreen(xGlobalDisplay));
+               if(!fullScreenMode)
+                  XIconifyWindow(xGlobalDisplay, (X11Window)window.windowHandle, DefaultScreen(xGlobalDisplay));
             }
-            else
+            else if(!fullScreenMode)
             {
                //((XWindowData)window.windowData).gotFrameExtents && (!window.nativeDecorations || window.state == state))
                if(!atomsSupported[_net_wm_state] || (!((XWindowData)window.windowData).gotFrameExtents && window.state == maximized))
@@ -2740,19 +3124,10 @@ class XInterface : Interface
                if(atomsSupported[_net_wm_state])
                {
                   // Maximize / Restore the window
-                  XClientMessageEvent event = { 0 };
-                  event.type = ClientMessage;
-                  event.message_type = atoms[_net_wm_state];
-                  event.display = xGlobalDisplay;
-                  event.serial = 0;
-                  event.window = (X11Window)window.windowHandle;
-                  event.send_event = 1;
-                  event.format = 32;
-                  event.data.l[0] = (state == maximized) ? 1 : 0;
-                  event.data.l[1] = atoms[_net_wm_state_maximized_vert];
-                  event.data.l[2] = atoms[_net_wm_state_maximized_horz];
-                  XSendEvent(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), bool::false,
-                     SubstructureRedirectMask | SubstructureNotifyMask, (union _XEvent *)&event);
+                  if(curState != state)
+                     SetNETWMState((X11Window)window.windowHandle, true, state == maximized ? add : remove,
+                        atoms[_net_wm_state_maximized_vert], atoms[_net_wm_state_maximized_horz]);
+
                   if(state == maximized)
                   {
                      // Prevent the code in ConfigureNotify to think the window has been unmaximized
@@ -2764,25 +3139,24 @@ class XInterface : Interface
             }
          }
          else
+         {
             XUnmapWindow(xGlobalDisplay, (X11Window)window.windowHandle);
+            windowData.currentlyVisible = false;
+         }
          //XFlush(xGlobalDisplay);
       }
+      *&window.state = curState;
    }
 
    void FlashRootWindow(Window window)
    {
-      XClientMessageEvent event = { 0 };
+      void * hwnd = window.windowHandle;
+      Window master = window.master, rootWindow = (master && master != guiApp.desktop) ? master.rootWindow : null;
+      if(!window.style.showInTaskBar && rootWindow && (window._isModal || window.style.interim))
+         hwnd = rootWindow.windowHandle;
+
       // printf("Attempting to flash root window\n");
-      event.type = ClientMessage;
-      event.message_type = atoms[_net_wm_state];
-      event.display = xGlobalDisplay;
-      event.serial = 0;
-      event.window = (X11Window)window.windowHandle;
-      event.send_event = 1;
-      event.format = 32;
-      event.data.l[0] = 1;
-      event.data.l[1] = atoms[_net_wm_state_demands_attention];
-      XSendEvent(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), bool::false, SubstructureRedirectMask | SubstructureNotifyMask, (union _XEvent *)&event);
+      SetNETWMState((X11Window)hwnd, true, add, atoms[_net_wm_state_demands_attention], 0);
    }
 
    void ActivateRootWindow(Window window)
@@ -2791,10 +3165,18 @@ class XInterface : Interface
       {
          if(!window.style.hidden && window.created)
          {
+            XWindowData windowData = window.windowData;
             //printf("Activate root window %s\n", window._class.name);
+            if(!windowData.currentlyVisible)
+            {
+               long t = (window.creationActivation == activate && guiApp.desktop.active) ? timeStamp : 0;
+               XChangeProperty(xGlobalDisplay, (X11Window)window.windowHandle, atoms[_net_wm_user_time],
+                 XA_CARDINAL,32,PropModeReplace, (byte *)&t, 1);
+               XMapWindow(xGlobalDisplay, (X11Window)window.windowHandle);
+               WaitForViewableWindow(window);
+               windowData.currentlyVisible = true;
+            }
             XRaiseWindow(xGlobalDisplay, (X11Window)window.windowHandle);
-            XMapWindow(xGlobalDisplay, (X11Window)window.windowHandle);
-            WaitForViewableWindow(window);
             if(atomsSupported[_net_active_window])
             {
                XClientMessageEvent event = { 0 };
@@ -2805,14 +3187,12 @@ class XInterface : Interface
                event.window = (X11Window)window.windowHandle;
                event.send_event = 1;
                event.format = 32;
-               event.data.l[0] = 0;
-
-               //event.data.l[0] = 2;
-               //event.data.l[1] = timeStamp;
-
-
-               //event.data.l[1] = atoms[_net_wm_user_time];
-               //event.data.l[2] = activeWindow; //guiApp.desktop.activeChild.windowHandle;
+               event.data.l[0] = /*0*/ 1;
+               // WMs will complain about using CurrentTime here, but when ActivateRootWindow() is called we really need to take over,
+               // otherwise a debugged application stays on top of the IDE when we hit a breakpoint (there was no user interaction with the IDE,
+               // but it really should be activated)
+               event.data.l[1] = CurrentTime; //timeStamp;
+               event.data.l[2] = activeWindow; //guiApp.desktop.activeChild.windowHandle;
 
 #ifdef _DEBUG
                //printf("(ActivateRootWindow) Setting _NET_ACTIVE_WINDOW for %s (%x)\n", window._class.name, window);
@@ -2820,11 +3200,11 @@ class XInterface : Interface
 
                XSendEvent(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), bool::false, SubstructureRedirectMask | SubstructureNotifyMask, (union _XEvent *)&event);
 //#if defined(__APPLE__)
-               XSetInputFocus(xGlobalDisplay, (X11Window)window.windowHandle, RevertToPointerRoot, CurrentTime);
+               XSetInputFocus(xGlobalDisplay, (X11Window)window.windowHandle, RevertToParent, CurrentTime);
 //#endif
             }
             else
-               XSetInputFocus(xGlobalDisplay, (X11Window)window.windowHandle, RevertToPointerRoot, CurrentTime);
+               XSetInputFocus(xGlobalDisplay, (X11Window)window.windowHandle, RevertToParent, CurrentTime);
          }
       }
    }
@@ -2858,7 +3238,8 @@ class XInterface : Interface
 
    void SetMousePosition(int x, int y)
    {
-
+      XWarpPointer(xGlobalDisplay, None, DefaultRootWindow(xGlobalDisplay), 0, 0, 0, 0, x, y);
+      XFlush(xGlobalDisplay);
    }
 
    void SetMouseRange(Window window, Box box)
@@ -2870,7 +3251,7 @@ class XInterface : Interface
       {
          if(!window.parent || !window.parent.display)
          {
-            XMoveResizeWindow(xGlobalDisplay, confineWindow, box.left + desktopX, box.top + desktopY,
+            XMoveResizeWindow(xGlobalDisplay, confineWindow, box.left /*+ desktopX*/, box.top /*+ desktopY*/,
                box.right - box.left + 1, box.bottom - box.top + 1);
 
             if(!restrictedWindow)
@@ -2934,8 +3315,9 @@ class XInterface : Interface
 
    void SetMouseCursor(Window window, int cursor)
    {
-      XDefineCursor(xGlobalDisplay, (X11Window) window.rootWindow.windowHandle,
-         cursor == -1 ? (X11Cursor)0 : systemCursors[(SystemCursor)cursor]);
+      if(window.rootWindow.windowHandle)
+         XDefineCursor(xGlobalDisplay, (X11Window) window.rootWindow.windowHandle,
+            (acquiredInputWindow || cursor == -1) ? nullCursor : systemCursors[(SystemCursor)cursor]);
    }
 
    // --- Caret ---
@@ -2955,7 +3337,7 @@ class XInterface : Interface
                (short)(caretOwner.caretPos.y - caretOwner.scroll.y + caretOwner.absPosition.y - window.absPosition.y)
             };
             XVaNestedList argList = XVaCreateNestedList(0, XNSpotLocation, &cursor_location, NULL);
-            XSetICValues(windowData.ic, XNPreeditAttributes, argList, 0);
+            XSetICValues(windowData.ic, XNPreeditAttributes, argList, NULL);
          }
       }
    }
@@ -2966,7 +3348,7 @@ class XInterface : Interface
       if(clipBoardData)
       {
          delete clipBoardData;
-       XSetSelectionOwner(xGlobalDisplay, atoms[clipboard], None, CurrentTime);
+         XSetSelectionOwner(xGlobalDisplay, atoms[clipboard], None, CurrentTime);
       }
       //*XUnlockDisplay(xGlobalDisplay);
    }
@@ -3059,7 +3441,7 @@ class XInterface : Interface
                               AnyPropertyType, &type,&format,&len, &dummy, &data) == Success)
                         {
                            clipBoard.text = new char[size+1];
-                           strncpy(clipBoard.text, data, size);
+                           strncpy(clipBoard.text, (char *)data, size);
                            clipBoard.text[size] = '\0';
                            XFree(data);
                            result = true;
@@ -3084,14 +3466,36 @@ class XInterface : Interface
 
    bool AcquireInput(Window window, bool state)
    {
-      return false;
+      if(state && window)
+      {
+         GetMousePosition(&acquireStart.x, &acquireStart.y);
+         lastMouse = acquireStart;
+         acquiredInputWindow = window;
+         incref acquiredInputWindow;
+      }
+      else if(acquiredInputWindow)
+         delete acquiredInputWindow;
+      return true;
    }
 
    bool GetMouseState(MouseButtons * buttons, int * x, int * y)
    {
       bool result = false;
-      if(x) *x = 0;
-      if(y) *y = 0;
+      if(acquiredInputWindow && guiApp.desktop.active)
+      {
+         if(x) *x = lastMouse.x - acquireStart.x;
+         if(y) *y = lastMouse.y - acquireStart.y;
+         *buttons = buttonsState;
+         SetMousePosition(acquireStart.x, acquireStart.y);
+         lastMouse = acquireStart;
+         result = true;
+      }
+      else
+      {
+         if(x) *x = 0;
+         if(y) *y = 0;
+         if(buttons) *buttons = 0;
+      }
       return result;
    }
 
@@ -3117,8 +3521,33 @@ class XInterface : Interface
 
    bool GetKeyState(Key key)
    {
-      int keyState = 0;
-      return keyState;
+      if(key == capsState || key == numState || key == scrollState)
+      {
+         Atom atom = None;
+         X11Bool state = 0;
+         int idx = 0;
+         switch(key)
+         {
+            case capsState:    atom = atoms[capsLock];   idx = 0; break;
+            case numState:     atom = atoms[numLock];    idx = 1; break;
+            case scrollState:  atom = atoms[scrollLock]; idx = 2; break;
+         }
+         /*XkbGetIndicatorState(xGlobalDisplay, XkbUseCoreKbd, &state);
+         state = (state & (1 << idx)) ? 1 : 0;*/
+         XkbGetNamedIndicator(xGlobalDisplay, /*XkbUseCoreKbd,*/ atom, &idx, &state, NULL, NULL);
+         return (bool)state;
+      }
+      else
+      {
+         if(key == alt)
+            return keyStates[leftAlt] || keyStates[rightAlt];
+         else if(key == shift)
+            return keyStates[leftShift] || keyStates[rightShift];
+         else if(key == control)
+            return keyStates[leftControl] || keyStates[rightControl];
+         else
+            return keyStates[key.code];
+      }
    }
 
    void SetTimerResolution(uint hertz)
@@ -3154,8 +3583,8 @@ class XInterface : Interface
             else
                memcpy(icon + 2, bitmap.picture, bitmap.width * bitmap.height * sizeof(uint32));
             XChangeProperty(xGlobalDisplay, (X11Window)window.windowHandle, atoms[_net_wm_icon],
-                         XA_CARDINAL,32,PropModeReplace, (byte *)icon, 2+bitmap.width*bitmap.height);
-           delete icon;
+              XA_CARDINAL,32,PropModeReplace, (byte *)icon, 2+bitmap.width*bitmap.height);
+            delete icon;
          }
          delete bitmap;
       }
@@ -3163,12 +3592,12 @@ class XInterface : Interface
    }
 }
 
-default dllexport void * __attribute__((stdcall)) IS_XGetDisplay()
+default dllexport void * IS_XGetDisplay()
 {
    return xGlobalDisplay;
 }
 
-default dllexport void * __attribute__((stdcall)) IS_XGetWindow(Window window)
+default dllexport void * IS_XGetWindow(Window window)
 {
    return window.windowHandle ? window.windowHandle : window.rootWindow.windowHandle;
 }