ecere/gui/drivers/XInterface: Fixed SetMouseRange confinement offset by desktopX/Y
[sdk] / ecere / src / gui / drivers / XInterface.ec
index c3abbb6..e7e9135 100644 (file)
@@ -1,7 +1,7 @@
 namespace gui::drivers;
 
 import "instance"
-#if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D)
+#if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D) && !defined(ECERE_NOGL)
 import "OpenGLDisplayDriver"
 #endif
 
@@ -18,12 +18,9 @@ default:
 #include <linux/joystick.h>
 #endif
 #include <sys/param.h>
-#ifdef BSD
 #include <stdlib.h>
-#else
-#include <malloc.h>
-#endif
 #include <unistd.h>
+#include <sys/select.h>
 
 //#include <stdio.h>
 //#include <stdlib.h>
@@ -43,8 +40,11 @@ default:
 #include <X11/Xutil.h>
 #include <X11/XKBlib.h>
 #include <X11/keysym.h>
-#include <sys/fcntl.h>
+#include <X11/cursorfont.h>
+#include <fcntl.h>
+#if !defined(ECERE_NO3D) && !defined(ECERE_NOGL)
 #include <GL/glx.h>
+#endif
 #include <X11/extensions/Xrender.h>
 #include <X11/extensions/XShm.h>
 
@@ -93,6 +93,9 @@ static bool gotAnXEvent = false;
 static XEvent xEvent;
 static int joystickFD[4];
 static X11Window activeWindow;
+static X11Cursor systemCursors[SystemCursor];
+
+static enum NETWMStateAction { remove = 0, add = 1, toggle = 2 };
 
 static enum AtomIdents
 {
@@ -103,10 +106,11 @@ 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, app_selection
+   _net_wm_state_maximized_vert, _net_wm_state_maximized_horz, _net_wm_state_modal, app_selection, _net_supported
 };
 
 static Atom atoms[AtomIdents];
+static bool atomsSupported[AtomIdents];
 
 static const char *atomNames[AtomIdents] = {
    "CLIPBOARD", //clipboard
@@ -147,8 +151,23 @@ static const char *atomNames[AtomIdents] = {
    "_NET_REQUEST_FRAME_EXTENTS", // _net_request_frame_extents
    "_NET_WM_STATE_MAXIMIZED_VERT", // _net_wm_state_maximized_vert
    "_NET_WM_STATE_MAXIMIZED_HORZ", // _net_wm_state_maximized_horz
-   "APP_SELECTION"
+   "_NET_WM_STATE_MODAL", // _net_wm_state_modal
+   "APP_SELECTION",
+   "_NET_SUPPORTED"
 };
+/*
+_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;
 static bool setICPosition;
@@ -157,6 +176,70 @@ PixelFormat xSystemPixelFormat;
 Visual * xSystemVisual;
 bool xSharedMemory;
 
+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;
+      char * 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 Time timeStamp;
 
 class XWindowData : struct
@@ -175,7 +258,10 @@ bool XGetBorderWidths(Window window, Box box)
    XWindowData windowData = window.windowData;
    if(windowData)
    {
-      box = windowData.decor;
+      if(window.state == maximized)
+         box = { 0, 0, 0, 0 };
+      else
+         box = windowData.decor;
       return true;
    }
    return false;
@@ -186,7 +272,7 @@ static Visual * FindFullColorVisual(X11Display *dpy, int * depth)
    XVisualInfo vinfo;
    XVisualInfo *vinfo_ret;
    int numitems;
-  
+
    vinfo._class = TrueColor;
    vinfo_ret = XGetVisualInfo(dpy, VisualClassMask, &vinfo, &numitems);
    if(numitems)
@@ -207,24 +293,9 @@ static Visual * FindFullColorVisual(X11Display *dpy, int * depth)
             return vinfo.visual;
          }
       }
-   } 
+   }
    return null;
 }
-/*
-_NET_WM_STATE_MODAL, ATOM
-_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 void RepositionDesktop(bool updateChildren)
 {
@@ -232,17 +303,22 @@ static void RepositionDesktop(bool updateChildren)
    int w, h;
    Screen * x_screen = XDefaultScreenOfDisplay(xGlobalDisplay);
    X11Window x_root;
-   int current = 0;   
+   int current = 0;
    char *data = null;
    int format;
    unsigned long len, fill;
    Atom type;
+   static double lastTime = 0, time;
+
+   time = GetTime();
+   if(desktopW && desktopH && time - lastTime < 1.5) return;
+   lastTime = time;
 
    w = XDisplayWidth(xGlobalDisplay, DefaultScreen(xGlobalDisplay));
    h = XDisplayHeight(xGlobalDisplay, DefaultScreen(xGlobalDisplay));
    x_root = XRootWindowOfScreen(x_screen);
-   
-   if(atoms[_net_number_of_desktops] != None)
+
+   if(atomsSupported[_net_number_of_desktops])
    {
       if(XGetWindowProperty(xGlobalDisplay, x_root, atoms[_net_number_of_desktops], 0, 1, False,
                             XA_CARDINAL, &type, &format, &len, &fill,
@@ -250,11 +326,11 @@ static void RepositionDesktop(bool updateChildren)
       {
          printf("cant get xa desktops property\n");
       }
-      
+
       if(data)
       {
          int desktops = 0;
-         desktops = *(long *)data;
+         desktops = (int)*(long *)data;
 
          //printf("_NET_NUMBER_OF_DESKTOPS is %d\n", desktops);
 
@@ -262,26 +338,26 @@ static void RepositionDesktop(bool updateChildren)
          data = null;
       }
    }
-   
-   if(atoms[_net_current_desktop] != None)
-   {   
+
+   if(atomsSupported[_net_current_desktop])
+   {
       if(XGetWindowProperty(xGlobalDisplay, x_root, atoms[_net_current_desktop], 0, 1, False,
                             XA_CARDINAL, &type, &format, &len, &fill,
                             &data) != Success)
       {
          printf("cant get xa current property\n");
       }
-      
+
       if(data)
       {
-         current = *(long *)data;
+         current = (int)*(long *)data;
          XFree(data);
          data = null;
 
          //printf("_NET_CURRENT_DESKTOP is %d\n", current);
       }
-   }   
-   if(atoms[_net_workarea] != None)
+   }
+   if(atomsSupported[_net_workarea])
    {
       long *workareas;
 
@@ -291,28 +367,30 @@ static void RepositionDesktop(bool updateChildren)
       {
          //printf("warning\n");
       }
-      
+
       /*
       if(type == None || format == 0)
          printf("warning\n");
 
       if(fill)
          printf("warning\n");
-      
+
       if(len % 4)
          printf("warning\n");
       */
-  
+
       if(data)
       {
          workareas = (long *)data;
-     
-         x = workareas[current * 4];
-         y = workareas[current * 4 + 1];
-         w = workareas[current * 4 + 2];
-         h = workareas[current * 4 + 3];   
+
+         x = (int)workareas[current * 4];
+         y = (int)workareas[current * 4 + 1];
+         w = (int)workareas[current * 4 + 2];
+         h = (int)workareas[current * 4 + 3];
 
          //printf("_NET_WORKAREA is x = %d, y = %d, w = %d, h = %d\n", x, y, w, h);
+         XFree(data);
+         data = null;
       }
       //   printf("Work Area width: %d, height %d\n", w, h);
    }
@@ -381,7 +459,7 @@ static bool ProcessKeyMessage(Window window, uint keyCode, int release, XKeyEven
    /*
    key = key - 8;
    //Logf("Got 0x%x (%d)\n", key, key);
-   
+
    switch(key)
    {
       case KEYCODE_HOME: key = home; break;
@@ -396,7 +474,7 @@ static bool ProcessKeyMessage(Window window, uint keyCode, int release, XKeyEven
       case KEYCODE_DEL: key = del; break;
       case KEYCODE_SLASH: key = keyPadSlash; break;
    }
-  
+
    ch = (byte)Interface::TranslateKey(key, event->state & ShiftMask);
    */
 /*
@@ -407,14 +485,14 @@ static bool ProcessKeyMessage(Window window, uint keyCode, int release, XKeyEven
 */
 
    if(!buf)
-      buf = malloc(bufsize);
+      buf = malloc((uint)bufsize);
    if(windowData && windowData.ic)
-   { 
-      buflength = XmbLookupString(windowData.ic, event, buf, bufsize, &keysym, &status);
+   {
+      buflength = XmbLookupString(windowData.ic, event, buf, (int)bufsize, &keysym, &status);
       if (status == XBufferOverflow)
       {
-         buf = realloc(buf, (bufsize = buflength));
-         buflength = XmbLookupString(windowData.ic, event, buf, bufsize, &keysym, &status);
+         buf = realloc(buf, (uint)(bufsize = buflength));
+         buflength = XmbLookupString(windowData.ic, event, buf, (int)bufsize, &keysym, &status);
       }
       if(status != XLookupKeySym && status != XLookupBoth && release == 1)
          keysym = XLookupKeysym(event, 0);
@@ -454,7 +532,7 @@ static bool ProcessKeyMessage(Window window, uint keyCode, int release, XKeyEven
          // case XK_Begin:
 
          // case XK_Select:
-         // case XK_Print: 
+         // case XK_Print:
          // case XK_Execute:
          case XK_Insert:      key = insert; break;
          // case XK_Undo:
@@ -472,7 +550,7 @@ static bool ProcessKeyMessage(Window window, uint keyCode, int release, XKeyEven
          // case XK_script_switch:
          case XK_Num_Lock:    key = numLock; break;
 
-         // case XK_KP_Space: 
+         // case XK_KP_Space:
          // case XK_KP_Tab:
          case XK_KP_Enter:    key = keyPadEnter; break;
          // case XK_KP_F1:
@@ -497,7 +575,7 @@ static bool ProcessKeyMessage(Window window, uint keyCode, int release, XKeyEven
          case XK_KP_Add:      key = keyPadPlus; break;
          case XK_KP_Separator:key = keyPadDelete; break;
          case XK_KP_Subtract: key = keyPadMinus; break;
-         // case XK_KP_Decimal: 
+         // case XK_KP_Decimal:
          case XK_KP_Divide:   key = keyPadSlash; break;
 
          case XK_KP_0:  key = keyPad0; break;
@@ -578,7 +656,7 @@ static bool ProcessKeyMessage(Window window, uint keyCode, int release, XKeyEven
          case XK_Control_L: key = leftControl; break;
          case XK_Control_R: key = rightControl; break;
          case XK_Caps_Lock: key = capsLock; break;
-         // case XK_Shift_Lock: 
+         // case XK_Shift_Lock:
          // case XK_Meta_L:
          // case XK_Meta_R:
          case XK_Alt_L: key = leftAlt; break;
@@ -709,7 +787,7 @@ static bool ProcessKeyMessage(Window window, uint keyCode, int release, XKeyEven
       code.alt = true;
       /*buflength = 0;
       ch = 0;*/
-   } 
+   }
 #endif
 
    // Logf("Key Message: %s, keysym: 0x%x, key: %d state: %d, ch: %c\n", release ? ((release == 2) ? "REPEAT" : "KeyRelease") : "KeyPress", keysym, key, event->state, (byte)ch);
@@ -735,11 +813,11 @@ static bool ProcessKeyMessage(Window window, uint keyCode, int release, XKeyEven
                int numBytes;
                ch = UTF8GetChar(buf + c, &numBytes);
                if(ch == 127) ch = 0;
-               if(!numBytes) c = buflength;
-               result = window.KeyMessage((c == 0) ? 
+               result = window.KeyMessage((c == 0) ?
                   __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyDown : __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit,
                   (c == 0) ? code : 0, ch);
                c += numBytes;
+               if(!numBytes) c = buflength;
             }
          }
          else
@@ -753,16 +831,16 @@ static bool ProcessKeyMessage(Window window, uint keyCode, int release, XKeyEven
                int numBytes;
                ch = UTF8GetChar(buf + c, &numBytes);
                if(ch == 127) ch = 0;
-               if(!numBytes) c = buflength;
                result = window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit, code, ch);
                c += numBytes;
+               if(!numBytes) c = buflength;
             }
          else
             result = window.KeyMessage(__ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnKeyHit, code, ch);
-      } 
+      }
    }
    delete window;
-            
+
    return result;
 }
 /*
@@ -791,9 +869,15 @@ static Bool EventChecker(void *display, XEvent *event, char * data)
 
 static Bool ConfigureNotifyChecker(void *display, XConfigureEvent *event, char * data)
 {
-   return ((!data || (event->window == (int) data)) && event->type == ConfigureNotify;
+   return (!data || (event->window == (X11Window) data)) && event->type == ConfigureNotify;
 }
 
+static enum FrameExtentSupport { unknown, working, broken };
+
+static FrameExtentSupport frameExtentSupported;
+static Time frameExtentRequest;
+static X11Window frameExtentWindow;
+
 static uint timerDelay = MAXINT;
 #define RESOLUTION   (18.2 * 100)
 static uint XTimerThread(Thread thread)
@@ -809,7 +893,7 @@ static uint XTimerThread(Thread thread)
       //bool waitSemaphore = false;
       fd_set readSet, writeSet, exceptSet;
       struct timeval tv = { (timerDelay == MAXINT) ? 0 : (timerDelay / 1000000), (timerDelay == MAXINT) ? (int)(1000000 / 18.2) : (timerDelay % 1000000) };
-      
+
       if(xTerminate) break;
       FD_ZERO(&readSet);
       FD_ZERO(&writeSet);
@@ -822,8 +906,24 @@ static uint XTimerThread(Thread thread)
          if(FD_ISSET(s, &readSet))
             gotAnXEvent = true;
       }
+      if(frameExtentSupported == unknown && frameExtentRequest && GetTime() - frameExtentRequest > 1)
+      {
+         XPropertyEvent event = { 0 };
+         event.type = PropertyNotify;
+         event.state = PropertyNewValue;
+         event.atom = atoms[_net_frame_extents];
+         event.display = xGlobalDisplay;
+         event.serial = 0;
+         event.window = frameExtentWindow;
+         event.send_event = 1;
+
+         frameExtentSupported = broken;
+
+         XSendEvent(xGlobalDisplay, frameExtentWindow, bool::false,
+            PropertyChangeMask, (union _XEvent *)&event);
+      }
       xMutex.Release();
-      guiApp.SignalEvent();  
+      guiApp.SignalEvent();
       xSemaphore.Wait();
 
 #if 0
@@ -861,7 +961,9 @@ static int MyXErrorHandler(X11Display * display, XErrorEvent * event)
    char buffer[1024];
    if(xGlobalDisplay)
       XGetErrorText(xGlobalDisplay, event->error_code, buffer, sizeof(buffer));
+#ifdef _DEBUG
    Logf("X Error: %s\n", buffer);
+#endif
    return 0;
 }
 
@@ -906,7 +1008,7 @@ static void WaitForViewableWindow(Window window)
    //int attempts = 0;
    //Logf("Wait for viewable %s\n", window.name);
    XFlush(xGlobalDisplay);
-   //while(attempts++ < 40) 
+   //while(attempts++ < 40)
    while(true)
    {
       XWindowAttributes attributes = { 0 };
@@ -920,6 +1022,113 @@ static void WaitForViewableWindow(Window window)
    }
 }
 
+static bool RequestFrameExtents(Window window)
+{
+   if(window.nativeDecorations && frameExtentSupported != broken)
+   {
+      // Request decoration frame extents
+      XClientMessageEvent event = { 0 };
+      event.type = ClientMessage;
+      event.message_type = atoms[_net_request_frame_extents];
+      event.display = xGlobalDisplay;
+      event.serial = 0;
+      event.window = (X11Window)window.windowHandle;
+      event.send_event = 1;
+      window.windowHandle = (void *)window.windowHandle;
+      event.format = 32;
+
+      if(frameExtentSupported == unknown && !frameExtentRequest)
+      {
+         frameExtentRequest = GetTime();
+         frameExtentWindow = (X11Window)window.windowHandle;
+      }
+
+      XSendEvent(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), bool::false,
+         SubstructureRedirectMask | SubstructureNotifyMask, (union _XEvent *)&event);
+      return true;
+   }
+   return false;
+}
+
+static bool GetFrameExtents(Window window, bool update)
+{
+   XWindowData windowData = window.windowData;
+   bool result = false;
+   int format;
+   unsigned long len, fill;
+   Atom type;
+   char * data = null;
+
+   if(XGetWindowProperty(xGlobalDisplay, (X11Window)window.windowHandle,
+      atoms[_net_frame_extents], 0, 4,
+       False, XA_CARDINAL, &type, &format, &len,
+       &fill, &data) == Success && data)
+   {
+      long *extents = (long *)data;
+      bool change = extents[0] != windowData.decor.left ||
+                    extents[1] != windowData.decor.right ||
+                    extents[2] != windowData.decor.top ||
+                    extents[3] != windowData.decor.bottom;
+
+      bool hadFrameExtents = windowData.gotFrameExtents;
+      Box oldDecor = windowData.decor;
+
+      frameExtentSupported = working;
+      frameExtentWindow = 0;
+      frameExtentRequest = 0;
+
+      if(!hadFrameExtents || extents[0] || extents[1] || extents[2] || extents[3])
+      {
+         windowData.decor =
+         {
+            left = (int)extents[0], right  = (int)extents[1],
+            top  = (int)extents[2], bottom = (int)extents[3]
+         };
+         windowData.gotFrameExtents = true;
+         if(update && change && ((Window)window).clientSize.w > 0)
+         {
+            int x = window.position.x, y = window.position.y, w = window.size.w, h = window.size.h;
+            if(!hadFrameExtents && window.state != maximized)
+            {
+               window.ComputeAnchors(
+                  window.normalAnchor,
+                  window.normalSizeAnchor,
+                  &x, &y, &w, &h);
+            }
+            else
+            {
+               x += windowData.decor.left - oldDecor.left;
+               y += windowData.decor.top - oldDecor.top;
+
+               w += windowData.decor.left - oldDecor.left + windowData.decor.right - oldDecor.right;
+               h += windowData.decor.top - oldDecor.top   + windowData.decor.bottom - oldDecor.bottom;
+            }
+
+            if(window.state != maximized)
+            {
+               window.Position(x, y, w, h, true, true, true, true, false, !hadFrameExtents && window.state != maximized);
+               XInterface::UpdateRootWindow(window);
+            }
+         }
+         result = true;
+      }
+      XFree(data);
+   }
+   return result;
+}
+
+static bool WaitForFrameExtents(Window window)
+{
+   int attempts = 0;
+   //XFlush(xGlobalDisplay);
+   while(attempts++ < 10)
+   {
+      if(GetFrameExtents(window, false)) return true;
+      Sleep(1.0 / RESOLUTION);
+   }
+   return false;
+}
+
 /****************************************************************************
    /// DRIVER IMPLEMENTATION /////////////
 ****************************************************************************/
@@ -928,7 +1137,7 @@ static void WaitForViewableWindow(Window window)
 {
    bool terminate;
    uint delay;
-   
+
    void Stop()
    {
       if(started)
@@ -937,7 +1146,7 @@ static void WaitForViewableWindow(Window window)
          Wait();
       }
    }
-   
+
    uint Main()
    {
       while(!terminate)
@@ -958,7 +1167,7 @@ default:
 
 #include <sys/ipc.h>
 #include <sys/shm.h>
-#include <sys/signal.h>
+#include <signal.h>
 #include <locale.h>
 
 
@@ -984,7 +1193,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)
@@ -993,11 +1202,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)
                {
@@ -1032,12 +1241,23 @@ class XInterface : Interface
 #endif
       xTerminate = false;
       xGlobalDisplay = XOpenDisplay(null);
+      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 };
@@ -1052,8 +1272,8 @@ class XInterface : Interface
             {
                XVisualInfo vinfo;
                XVisualInfo *vinfo_ret;
-               long numitems;
-              
+               int numitems = 0;
+
                vinfo.visualid = XVisualIDFromVisual(xSystemVisual);
                vinfo_ret = XGetVisualInfo(xGlobalDisplay, VisualIDMask, &vinfo, &numitems);
                if(numitems)
@@ -1091,16 +1311,16 @@ class XInterface : Interface
                   else
                      printf("Could not get a 555 visual\n");
                   */
-               } 
+               }
                break;
             }
          }
          // printf("Got a depth of %d\n", xSystemDepth);
 
-         {  
+         {
             int major, minor, pixmaps;
             xSharedMemory = XShmQueryExtension(xGlobalDisplay) && XShmQueryVersion(xGlobalDisplay, &major, &minor, &pixmaps) && pixmaps;
-         }  
+         }
 
          // printf("Opening IM\n");
          im = XOpenIM(xGlobalDisplay, null, null, null);
@@ -1114,7 +1334,34 @@ class XInterface : Interface
             XkbSetDetectableAutoRepeat(xGlobalDisplay, True, &autoRepeatDetectable);
 
             XInternAtoms(xGlobalDisplay, (char**)atomNames, AtomIdents::enumSize, False, atoms);
-            
+
+            // Check which atoms are supported by the WM
+            {
+               int format;
+               unsigned long count, fill;
+               Atom type;
+               Atom * data;
+
+               if(XGetWindowProperty(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), atoms[_net_supported],
+                  0, 10000, False, XA_ATOM, &type, &format, &count, &fill, (void *)&data) == Success)
+               {
+                  int i;
+                  for (i = 0; i < count; i++)
+                  {
+                     AtomIdents j;
+                     for(j = 0; j < AtomIdents::enumSize; j++)
+                     {
+                        if(atoms[j] == data[i])
+                        {
+                           atomsSupported[j] = true;
+                           break;
+                        }
+                     }
+                  }
+                  XFree(data);
+               }
+            }
+
             {
                Atom protocols[2] = { atoms[wm_delete_window], atoms[wm_take_focus] };
 
@@ -1122,7 +1369,7 @@ class XInterface : Interface
             }
 
             /*
-            if(atoms[_net_workarea] == None)
+            if(atomsSupported[_net_workarea])
                printf("Warning: _NET_WORKAREA extension not supported\n");
             */
 
@@ -1147,7 +1394,7 @@ class XInterface : Interface
 
                /*
                XIMStyles *IMcando;
-               XIMStyle  clientCanDo; 
+               XIMStyle  clientCanDo;
                XIMStyle  styleWeWillUse = null;
                int i;
                XVaNestedList arglist;
@@ -1160,7 +1407,7 @@ class XInterface : Interface
                   XIMPreeditPosition | XIMStatusArea |
                   XIMPreeditArea | XIMStatusArea |
                   XIMPreeditNothing | XIMStatusNothing;
-               
+
                for(i=0; i<IMcando->count_styles; i++)
                {
                    XIMStyle tmpStyle;
@@ -1193,7 +1440,7 @@ class XInterface : Interface
                XSetICFocus(ic);
                */
             }
-            
+
             xMutex.Wait();
             timerThread = Thread { };
             incref timerThread;
@@ -1201,7 +1448,7 @@ class XInterface : Interface
             timerThread.Create();
 
             return true;
-         }   
+         }
       }
       return false;
    }
@@ -1222,6 +1469,16 @@ class XInterface : Interface
       delete timerThread;
       hiResTimer.Stop();
 
+      XFreeCursor(xGlobalDisplay, systemCursors[iBeam]);
+      XFreeCursor(xGlobalDisplay, systemCursors[cross]);
+      XFreeCursor(xGlobalDisplay, systemCursors[moving]);
+      XFreeCursor(xGlobalDisplay, systemCursors[sizeNESW]);
+      XFreeCursor(xGlobalDisplay, systemCursors[sizeNS]);
+      XFreeCursor(xGlobalDisplay, systemCursors[sizeNWSE]);
+      XFreeCursor(xGlobalDisplay, systemCursors[sizeWE]);
+      XFreeCursor(xGlobalDisplay, systemCursors[hand]);
+      XFreeCursor(xGlobalDisplay, systemCursors[arrow]);
+
       //XPutBackEvent(xGlobalDisplay, &e);
       // xThread.Wait();
       // delete xThread;
@@ -1277,10 +1534,33 @@ class XInterface : Interface
                case KeyPress:
                {
                   XKeyEvent * event = (XKeyEvent *) thisEvent;
+                  incref window;
+                  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, 0);
+                           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:
@@ -1331,6 +1611,12 @@ class XInterface : Interface
 
                   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)
+                     {
+                        XRaiseWindow(xGlobalDisplay, (X11Window)window.windowHandle);
+                        XSetInputFocus(xGlobalDisplay, (X11Window)window.windowHandle, RevertToPointerRoot, CurrentTime);
+                     }
                      button = __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown;
                      buttonDouble = __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick;
                      whichButton = 0;
@@ -1441,7 +1727,7 @@ class XInterface : Interface
                   break;
                }
                case MotionNotify:
-               { 
+               {
                   static uint lastTime = 0;
                   XMotionEvent * event = (XMotionEvent *) thisEvent;
                   while(XCheckIfEvent(xGlobalDisplay, (XEvent *)thisEvent, EventChecker, (void *)MotionNotify));
@@ -1462,7 +1748,7 @@ class XInterface : Interface
                         event->x_root, event->y_root, &keyFlags, false, false);
                      delete window;
                      //*if(xGlobalDisplay) XLockDisplay(xGlobalDisplay);
-                     lastTime = event->time;
+                     lastTime = (uint)event->time;
                   }
                   break;
                }
@@ -1484,9 +1770,9 @@ class XInterface : Interface
                }
                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];
@@ -1494,27 +1780,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:
@@ -1524,30 +1810,34 @@ class XInterface : Interface
                }
                case FocusIn:
                {
-                  XFocusChangeEvent *event = (XFocusChangeEvent *) thisEvent;
-                  Window modalRoot = window.FindModal();
-                  XWindowData windowData;
-                  activeWindow = (X11Window)window.windowHandle;
-
-                  if(window.parent && window == window.parent.activeChild) break;
-                  incref window;
-                  //if(window.creationActivation == activate)
+                  if(activeWindow != (X11Window)window.windowHandle)
                   {
-                     if(modalRoot)
-                        modalRoot.ExternalActivate(true, true, window, null); // lastActive);
-                     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, 0);
-                     XSetICFocus(windowData.ic);
+                     XFocusChangeEvent *event = (XFocusChangeEvent *) thisEvent;
+                     Window modalRoot = window.FindModal();
+                     XWindowData windowData;
+
+                     activeWindow = (X11Window)window.windowHandle;
+
+                     if(window.parent && window == window.parent.activeChild) break;
+                     incref window;
+                     //if(window.creationActivation == activate)
+                     {
+                        if(modalRoot)
+                           modalRoot.ExternalActivate(true, true, window, null); // lastActive);
+                        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, 0);
+                        XSetICFocus(windowData.ic);
+                     }
+                     //delete lastActive;
+                     //lastActive = window;
+                     //incref lastActive;
+                     delete window;
                   }
-                  //delete lastActive;
-                  //lastActive = window;
-                  //incref lastActive;
-                  delete window;
                   break;
                }
                case FocusOut:
@@ -1568,7 +1858,7 @@ class XInterface : Interface
                      if(XCheckTypedWindowEvent(xGlobalDisplay, thisEvent->window, FocusOut, (XEvent *)thisEvent))
                      {
                         XFocusChangeEvent *event = (XFocusChangeEvent *) thisEvent;
-                        
+
                         XFindContext(xGlobalDisplay, thisEvent->window, windowContext, (XPointer *) &window);
                         if(window)
                         {
@@ -1601,7 +1891,7 @@ class XInterface : Interface
                      {
                         XWindowData windowData;
                         XFindContext(xGlobalDisplay, thisEvent->window, windowContext, (XPointer *) &window);
-                        
+
                         if(window)
                         {
                            XFocusChangeEvent *event = (XFocusChangeEvent *) thisEvent;
@@ -1642,7 +1932,7 @@ class XInterface : Interface
                      {
                         XCheckTypedEvent(xGlobalDisplay, /*thisEvent->window, */ButtonPress, (XEvent *)thisEvent);
                      }
-                     
+
                      //delete lastActive;
                      /*
                      lastActive = window;
@@ -1655,11 +1945,11 @@ class XInterface : Interface
                case ConfigureNotify:
                {
                   XConfigureEvent * event = (XConfigureEvent *) thisEvent;
+                  bool unmaximized = false;
                   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)
 
-                  // TODO: Support _NET_REQUEST_FRAME_EXTENTS message / _NET_FRAME_EXTENTS property for decoration size awareness
-                  if(window.nativeDecorations)
+                  if(atomsSupported[_net_wm_state]) //window.nativeDecorations)
                   {
                      int format;
                      unsigned long len, fill;
@@ -1685,50 +1975,96 @@ class XInterface : Interface
                         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();
+                        }
                      }
                   }
                   {
-                     int x = event->x;
-                     int y = event->y;
-                     int w = event->width, h = event->height;
+                     bool offset = false;
+                     int x, y, w, h;
+                     if(unmaximized)
+                     {
+                        if(window.nativeDecorations && RequestFrameExtents(window))
+                           WaitForFrameExtents(window);
 
-                     //if(event->send_event)
+                        // Ensure we set the normal size anchor when un-maximizing
+                        window.ComputeAnchors(window.normalAnchor, window.normalSizeAnchor, &x, &y, &w, &h);
+                     }
+                     else
                      {
-                        X11Window rootChild;
-                        long rootX, rootY;
-                        XTranslateCoordinates(xGlobalDisplay, event->window,
-                           RootWindow(xGlobalDisplay, DefaultScreen(xGlobalDisplay)), 0, 0, 
-                           &rootX, &rootY, &rootChild);
-                        x = rootX;
-                        y = rootY;
+                        x = event->x;
+                        y = event->y;
+                        w = event->width, h = event->height;
+
+                        //if(event->send_event)
+                        {
+                           X11Window rootChild;
+                           int rootX, rootY;
+                           XTranslateCoordinates(xGlobalDisplay, event->window,
+                              RootWindow(xGlobalDisplay, DefaultScreen(xGlobalDisplay)), 0, 0,
+                              &rootX, &rootY, &rootChild);
+                           if(x != rootX || y != rootY)
+                           {
+                              x = rootX;
+                              y = rootY;
+                              offset = true;
+                           }
+                        }
+
+                        x -= desktopX;
+                        y -= desktopY;
+
+                        if(window.nativeDecorations && window.state != maximized)
+                        {
+                           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;
+                           */
+                        }
                      }
 
-                     x -= desktopX;
-                     y -= desktopY;
+                     window.Position(x, y, w, h, true, true, true, true, false, unmaximized);
 
-                     if(window.nativeDecorations)
+                     // Break the anchors for moveable/resizable windows
+                     // 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)
                      {
-                        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;
-                        */
+                        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.ExternalPosition(x, y, w, h);
                   }
                   break;
                }
@@ -1748,8 +2084,8 @@ class XInterface : Interface
                      bool laterFocus;
                      activeWindow = (X11Window)window.windowHandle;
 
-                     timeStamp = event->data.l[1];
-                     
+                     timeStamp = (int)event->data.l[1];
+
                      windowData = window.windowData;
                      laterFocus = windowData.laterFocus;
                      windowData.laterFocus = true;
@@ -1760,7 +2096,7 @@ class XInterface : Interface
                      if(guiApp.interimWindow && guiApp.interimWindow.created && window != guiApp.interimWindow) break; //window == window.parent.activeChild) break;
                      // if(window == window.parent.activeChild) break;
                      incref window;
-   
+
                      {
                         XEvent checkEvent;
                         //XFlush(xGlobalDisplay);
@@ -1795,7 +2131,7 @@ class XInterface : Interface
                            {
                               XRaiseWindow(xGlobalDisplay, (X11Window)modalRoot.windowHandle);
                               WaitForViewableWindow(modalRoot);
-                              if(atoms[_net_active_window])
+                              if(atomsSupported[_net_active_window])
                               {
                                  XClientMessageEvent event = { 0 };
                                  event.type = ClientMessage;
@@ -1825,7 +2161,7 @@ class XInterface : Interface
                            else
                            {
                               XSetInputFocus(xGlobalDisplay, (X11Window)window.windowHandle, RevertToPointerRoot, (uint)timeStamp);
-                              window.ExternalActivate(true, true, window, null); // lastActive); 
+                              window.ExternalActivate(true, true, window, null); // lastActive);
                               if(windowData && windowData.ic)
                               {
                                  // XSetICValues(ic, XNClientWindow, window.windowHandle, XNFocusWindow, window.windowHandle, 0);
@@ -1849,41 +2185,7 @@ class XInterface : Interface
                   if(event->atom == atoms[_net_frame_extents] &&
                     event->state == PropertyNewValue && windowData)
                   {
-                     int format;
-                     unsigned long len, fill;
-                     Atom type;
-                     char * data = null;
-
-                     if(XGetWindowProperty(xGlobalDisplay, (X11Window)window.windowHandle,
-                        atoms[_net_frame_extents], 0, 4,
-                         False, XA_CARDINAL, &type, &format, &len,
-                         &fill, &data) == Success && data)
-                     {
-                        long *extents = (long *)data;
-                        bool hadFrameExtents = windowData.gotFrameExtents;
-                        windowData.decor =
-                        {
-                           left = extents[0], right  = extents[1],
-                           top  = extents[2], bottom = extents[3]
-                        };
-                        windowData.gotFrameExtents = true;
-                        {
-                           int x, y, w, h;
-                           window.ComputeAnchors(
-                              window.normalAnchor,
-                              window.normalSizeAnchor,
-                              &x, &y, &w, &h);
-                           if(!hadFrameExtents) // || window.state == normal)
-                           {
-                              bool isMaximized = window.state == maximized;
-                              window.Position(x, y, w, h, true, true, true, true, false, true);
-                              UpdateRootWindow(window);
-                           }
-                        }
-
-                        XFree(data);
-                     }
-                     else
+                     if(!GetFrameExtents(window, true))
                         windowData.gotFrameExtents = true; // Unsupported?
                   }
                   break;
@@ -1967,10 +2269,13 @@ class XInterface : Interface
       XIC ic = null;
       unsigned long mask = EVENT_MASK;
 
-      attributes.override_redirect = window.interim ? True : False;
+      // Old WM (e.g. TWM), use built-in decorations
+      if(!atomsSupported[_net_wm_state])
+         window.nativeDecorations = false;
+      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)
+#if !defined(ECERE_VANILLA) && !defined(ECERE_NO3D) && !defined(ECERE_NOGL)
       if(window.dispDriver == class(OpenGLDisplayDriver) || !strcmp(guiApp.defaultDisplayDriver, "OpenGL"))
       {
          int samples;
@@ -1989,7 +2294,7 @@ class XInterface : Interface
                GLX_BLUE_SIZE, 1
             };
             int numAttribs = 14;
-            
+
             GLXFBConfig *fbconfigs = null, fbconfig;
             int numfbconfigs;
             int i;
@@ -2059,12 +2364,12 @@ class XInterface : Interface
       }
       if(!visualInfo)
       {
-         int attrList[] = 
+         int attrList[] =
          {
             GLX_USE_GL, GLX_DEPTH_SIZE, 1,
-            GLX_RGBA, 
+            GLX_RGBA,
             GLX_RED_SIZE, 1, GLX_GREEN_SIZE, 1, GLX_BLUE_SIZE, 1,
-            GLX_DOUBLEBUFFER, 
+            GLX_DOUBLEBUFFER,
             None
          };
          visualInfo = glXChooseVisual(xGlobalDisplay, DefaultScreen(xGlobalDisplay), attrList);
@@ -2085,7 +2390,7 @@ 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, 
+            0,0,guiApp.desktop.size.w,guiApp.desktop.size.h,0, depth, InputOutput, visual ? visual : CopyFromParent,
             CWEventMask | (visual ? (CWColormap | CWBorderPixel) : 0)/*| CWOverrideRedirect*/, &attributes);
       }
       /*
@@ -2102,6 +2407,26 @@ class XInterface : Interface
          else
          {
             X11Window parentWindow = (X11Window)null;
+            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;
+               h += window.size.h - window.clientSize.h;
+            }
 
             if(window.master.rootWindow && window.master.rootWindow != guiApp.desktop && (window._isModal || window.style.interim))
             {
@@ -2115,17 +2440,20 @@ class XInterface : Interface
             if(window.style.showInTaskBar)
                parentWindow = (X11Window)null;
 
-            windowHandle = XCreateWindow(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), 
-               0,0,1,1,0, depth, InputOutput, visual ? visual : CopyFromParent, 
+            windowHandle = XCreateWindow(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay),
+               x, y, w, h,
+               0, depth, InputOutput, visual ? visual : CopyFromParent,
                CWEventMask | CWOverrideRedirect | (visual ? (CWColormap | CWBorderPixel) : 0), &attributes);
 
-            if(parentWindow && window.interim)
+            if(parentWindow && (window.interim || window.isModal))
             {
                //printf("Setting WM_TRANSIENT_FOR of %s to %s\n", window._class.name, window.master.rootWindow._class.name);
                XSetTransientForHint(xGlobalDisplay, windowHandle, parentWindow);
                //XFlush(xGlobalDisplay);
                //printf("Done.\n");
                //XChangeProperty(xGlobalDisplay, windowHandle, atoms[wm_transient_for], XA_WINDOW, 32, PropModeReplace, (unsigned char*)&parentWindow, 1);
+               if(window.isModal)
+                  SetNETWMState(windowHandle, false, add, atoms[_net_wm_state_modal], 0);
             }
 
             {
@@ -2151,6 +2479,31 @@ class XInterface : Interface
                   Atom protocols[2] = { atoms[wm_delete_window], atoms[wm_take_focus] };
                   XSetWMProtocols(xGlobalDisplay, windowHandle, protocols, 2);
                }
+
+               // Set Normal hints for minimum/maximum size
+               if(true)
+               {
+                  XSizeHints hints = { 0 };
+                  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;
+                     hints.max_height = window.maxSize.h;
+                     hints.flags |= PMaxSize;
+                  }
+                  hints.x = x;
+                  hints.y = y;
+                  hints.flags |= PPosition;
+
+                  hints.width = w;
+                  hints.height = h;
+                  hints.flags |= PSize;
+
+                  XSetWMNormalHints(xGlobalDisplay, windowHandle, &hints);
+               }
             }
          }
       }
@@ -2163,13 +2516,13 @@ 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));
          fontset = XCreateFontSet(xGlobalDisplay, fontString, &missing_charsets, &num_missing_charsets, &default_string);
          argList = XVaCreateNestedList(0,
-                                       XNSpotLocation, &cursor_location, 
+                                       XNSpotLocation, &cursor_location,
                                        //XNArea, &area,
                                        XNFontSet, fontset,/*
                                        XNForeground,
@@ -2191,8 +2544,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);
@@ -2206,7 +2559,7 @@ class XInterface : Interface
       */
 
       {
-         if ( atoms[_motif_wm_hints] != None ) 
+         if ( atoms[_motif_wm_hints] != None )
          {
             MWM_Hints hints
             {
@@ -2221,19 +2574,21 @@ class XInterface : Interface
             XChangeProperty(xGlobalDisplay, windowHandle, atoms[_motif_wm_hints], atoms[_motif_wm_hints], 32,
                PropModeReplace, (unsigned char*)&hints, 5);
          }
-         if(atoms[_net_wm_pid] != None)
+
+         // *** We set this for ourselves, so don't check atomsSupported !!! ***
+         if(atoms[_net_wm_pid])
          {
             int pid = getpid();
-            // printf("Setting _NET_WM_PID to %d\n", pid); 
+            // printf("Setting _NET_WM_PID to %d\n", pid);
             XChangeProperty(xGlobalDisplay, windowHandle, atoms[_net_wm_pid], XA_CARDINAL, 32,
-               PropModeReplace, (unsigned char*)&pid, 1);            
+               PropModeReplace, (unsigned char*)&pid, 1);
          }
       }
-      
+
       /*
       {
          Atom protocolsAtom = XInternAtom(xGlobalDisplay, "WM_PROTOCOLS", False);
-         if ( protocolsAtom != None ) 
+         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,
@@ -2242,7 +2597,7 @@ class XInterface : Interface
       }*/
       // XFlush(xGlobalDisplay);
       window.windowData = XWindowData { visualInfo, ic };
-      
+
       XSaveContext(xGlobalDisplay, windowHandle, windowContext, (XPointer)window);
 
       XSelectInput(xGlobalDisplay, windowHandle, mask);
@@ -2254,21 +2609,8 @@ class XInterface : Interface
          XUngrabPointer(xGlobalDisplay, CurrentTime);
       }
 
-      if(window.nativeDecorations)
-      {
-         // Maximize / Restore the window
-         XClientMessageEvent event = { 0 };
-         event.type = ClientMessage;
-         event.message_type = atoms[_net_request_frame_extents];
-         event.display = xGlobalDisplay;
-         event.serial = 0;
-         event.window = (X11Window)windowHandle;
-         event.send_event = 1;
-         window.windowHandle = (void *)windowHandle;
-         event.format = 32;
-         XSendEvent(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), bool::false,
-            SubstructureRedirectMask | SubstructureNotifyMask, (union _XEvent *)&event);
-      }
+      if(!window.nativeDecorations || !RequestFrameExtents(window))
+         ((XWindowData)window.windowData).gotFrameExtents = true;
       return (void *)windowHandle;
    }
 
@@ -2276,7 +2618,7 @@ class XInterface : Interface
    {
       XEvent event;
 
-      XDeleteContext(xGlobalDisplay, (XID)window, windowContext); 
+      XDeleteContext(xGlobalDisplay, (XID)window, windowContext);
       XSaveContext(xGlobalDisplay, (X11Window)window.windowHandle, windowContext, null);
       XDestroyWindow(xGlobalDisplay, (X11Window)window.windowHandle);
       XSync(xGlobalDisplay, 0);
@@ -2306,7 +2648,7 @@ class XInterface : Interface
             atoms[utf8_string], 8, PropModeReplace, (byte *)name, name ? strlen(name) : 0);
          XChangeProperty(xGlobalDisplay, (X11Window)window.windowHandle, atoms[wm_name],
             atoms[utf8_string], 8, PropModeReplace, (byte *)name, name ? strlen(name) : 0);
-      }   
+      }
    }
 
    void PositionRootWindow(Window window, int x, int y, int w, int h, bool move, bool resize)
@@ -2314,32 +2656,66 @@ class XInterface : Interface
       //Logf("Position root window %s\n", window.name);
       if(window.windowHandle && (!window.parent || !window.parent.display))
       {
-#if defined(__APPLE__) || defined(__FreeBSD__)
          bool visible = window.visible;
-         if(window.visible)
-         {
+         if(window.visible && window.created)
             XMapWindow(xGlobalDisplay, (X11Window)window.windowHandle);
-            WaitForViewableWindow(window);
-         }
-#endif
-         if(window.state == minimized) return;
+         if(window.state == minimized && atomsSupported[_net_wm_state]) return;
 
          if(window.nativeDecorations)
          {
             XWindowData windowData = window.windowData;
-#if !defined(__APPLE__) && !defined(__FreeBSD__)
-            // TODO: How to handle frame extents not supported?
-            if(!windowData.gotFrameExtents || window.state == maximized) return;
-#endif
-            w -= window.size.w - window.clientSize.w;
-            h -= window.size.h - window.clientSize.h;
+
+            // Was commenting this out was part of #700/#795 fix, but this causes jumping of e.g. About box after getting frame extents PropertyNotify
+
+               // && window.state != maximized -- required for Cinnamon on Mint 14/15
+            if(!windowData.gotFrameExtents && window.state != maximized)
+            {
+               if(WaitForFrameExtents(window))
+               {
+                  x += windowData.decor.left;
+                  y += windowData.decor.top ;
+
+                  w += windowData.decor.left + windowData.decor.right;
+                  h += windowData.decor.top  + windowData.decor.bottom;
+               }
+            }
+
+            x -= windowData.decor.left;
+            y -= windowData.decor.top;
+
+            w -= windowData.decor.left + windowData.decor.right;
+            h -= windowData.decor.top + windowData.decor.bottom;
+
+            // Tweak for first unmaximize on Unity on Ubuntu 11.10
+            /*if(window.state == maximized && (desktopX + w > desktopW || desktopY + h > desktopH))
+            {
+               w -= 40;
+               h -= 40;
+            }*/
+         }
+
+         x += desktopX;
+         y += desktopY;
+
+         if(!atomsSupported[_net_wm_state] || window.state != maximized)
+         {
+            if(move && resize)
+               XMoveResizeWindow(xGlobalDisplay, (X11Window)window.windowHandle, x, y, w, h);
+            else if(move)
+               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)
+            {
+               XSizeHints hints = { 0 };
+               hints.min_width = hints.max_width = w;
+               hints.min_height = hints.max_height = h;
+               hints.flags |= PMinSize|PMaxSize|PPosition|PSize;
+               XSetWMNormalHints(xGlobalDisplay, (X11Window)window.windowHandle, &hints);
+            }
          }
-         if(move && resize)
-            XMoveResizeWindow(xGlobalDisplay, (X11Window)window.windowHandle, x + desktopX, y + desktopY, w, h);
-         else if(move)
-            XMoveWindow(xGlobalDisplay, (X11Window)window.windowHandle, x + desktopX, y + desktopY);
-         else if(resize)
-            XResizeWindow(xGlobalDisplay, (X11Window)window.windowHandle, w, h);
 #if defined(__APPLE__)
 //         if(window.created && !visible)
   //          XUnmapWindow(xGlobalDisplay, (X11Window)window.windowHandle);
@@ -2384,46 +2760,31 @@ class XInterface : Interface
       }
    }
 
-
    void SetRootWindowState(Window window, WindowState state, bool visible)
    {
+      // Old WM (e.g. TWM), use built-in decorations
+      if(!atomsSupported[_net_wm_state])
+         window.nativeDecorations = false;
       if(!window.parent || !window.parent.display)
       {
          //Logf("Set root window state %d %s\n", state, window.name);
          if(visible)
          {
             XMapWindow(xGlobalDisplay, (X11Window)window.windowHandle);
-#if defined(__APPLE__) || defined(__FreeBSD__)
             WaitForViewableWindow(window);
-#endif
             if(window.creationActivation == activate && state != minimized)
                ActivateRootWindow(window);
-            
-            if(state == minimized)
+
+            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);
-               */
+
+               // SetNETWMState(window.windowHandle, true, add, atoms[_net_wm_state_hidden], null);
                /*
                XChangeProperty(xGlobalDisplay, window.windowHandle, atoms[wm_state], XA_CARDINAL, 32,
                   PropModeReplace, &iconic, 1);
                */
-               
-               /*
-               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;
@@ -2441,34 +2802,47 @@ class XInterface : Interface
             }
             else
             {
-               if(!window.nativeDecorations || (!((XWindowData)window.windowData).gotFrameExtents && window.state == maximized)) //((XWindowData)window.windowData).gotFrameExtents && (!window.nativeDecorations || window.state == state))
+               //((XWindowData)window.windowData).gotFrameExtents && (!window.nativeDecorations || window.state == state))
+               if(!atomsSupported[_net_wm_state] || (!((XWindowData)window.windowData).gotFrameExtents && window.state == maximized))
                {
-                  // With native decorations, we do it the first time
-                  // or the WM (Gnome) is sticking it to the top/right!
-                  XMoveResizeWindow(xGlobalDisplay, 
-                     (X11Window)window.windowHandle,
-                     window.position.x + desktopX,
-                     window.position.y + desktopY,
-                     window.nativeDecorations ? window.clientSize.w : window.size.w,
-                     window.nativeDecorations ? window.clientSize.h : window.size.h);
+                  // Running this block avoids the initial IDE maximized->unmaximized flicker
+                  //if(window.state != maximized || !atomsSupported[_net_wm_state] || window.nativeDecorations)
+                  {
+                     int x = window.position.x;
+                     int y = window.position.y;
+                     int w = window.size.w;
+                     int h = window.size.h;
+
+                     if(window.nativeDecorations)
+                     {
+                        XWindowData windowData = window.windowData;
+                        x -= windowData.decor.left;
+                        y -= windowData.decor.top;
+
+                        w -= windowData.decor.left + windowData.decor.right;
+                        h -= windowData.decor.top + windowData.decor.bottom;
+                     }
+                     x += desktopX;
+                     y += desktopY;
+
+                     XMoveResizeWindow(xGlobalDisplay,
+                        (X11Window)window.windowHandle,
+                        x, y, w, h);
+                  }
                   UpdateRootWindow(window);
                }
-               if(window.nativeDecorations)
+               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);
+                  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
+                     // if the Window Manager hasn't set the hints yet.
+                     XFlush(xGlobalDisplay);
+                     Sleep(0.01);
+                  }
                }
             }
          }
@@ -2480,18 +2854,8 @@ class XInterface : Interface
 
    void FlashRootWindow(Window window)
    {
-      XClientMessageEvent event = { 0 };
       // 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)window.windowHandle, true, add, atoms[_net_wm_state_demands_attention], 0);
    }
 
    void ActivateRootWindow(Window window)
@@ -2504,7 +2868,7 @@ class XInterface : Interface
             XRaiseWindow(xGlobalDisplay, (X11Window)window.windowHandle);
             XMapWindow(xGlobalDisplay, (X11Window)window.windowHandle);
             WaitForViewableWindow(window);
-            if(atoms[_net_active_window])
+            if(atomsSupported[_net_active_window])
             {
                XClientMessageEvent event = { 0 };
                event.type = ClientMessage;
@@ -2515,18 +2879,18 @@ class XInterface : Interface
                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;
-               
+
 #ifdef _DEBUG
                //printf("(ActivateRootWindow) Setting _NET_ACTIVE_WINDOW for %s (%x)\n", window._class.name, window);
 #endif
-               
+
                XSendEvent(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), bool::false, SubstructureRedirectMask | SubstructureNotifyMask, (union _XEvent *)&event);
 //#if defined(__APPLE__)
                XSetInputFocus(xGlobalDisplay, (X11Window)window.windowHandle, RevertToPointerRoot, CurrentTime);
@@ -2559,7 +2923,7 @@ class XInterface : Interface
       unsigned int state;
       ((GuiApplication)__thisModule.application).Lock();
       //XLockDisplay(xGlobalDisplay);
-      XQueryPointer(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), &childWindow, 
+      XQueryPointer(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), &childWindow,
          &rootWindow, x, y, &mx, &my, &state);
       //XUnlockDisplay(xGlobalDisplay);
       ((GuiApplication)__thisModule.application).Unlock();
@@ -2574,14 +2938,14 @@ class XInterface : Interface
    {
       ((GuiApplication)__thisModule.application).Lock();
       //XLockDisplay(xGlobalDisplay);
-      if(box && box.left > 0 && box.top > 0 && 
+      if(box && box.left > 0 && box.top > 0 &&
          box.right < guiApp.desktop.clientSize.w - 1 && box.bottom < guiApp.desktop.clientSize.h - 1)
       {
          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)
                XMapWindow(xGlobalDisplay, confineWindow);
 
@@ -2602,7 +2966,7 @@ class XInterface : Interface
          }
          else
             XUngrabPointer(xGlobalDisplay, CurrentTime);
-         
+
          if(restrictedWindow)
             XUnmapWindow(xGlobalDisplay, confineWindow);
 
@@ -2629,7 +2993,7 @@ class XInterface : Interface
       else if(capturedWindow != None)
       {
          if(restrictedWindow)
-            XGrabPointer(xGlobalDisplay, (X11Window) restrictedWindow.rootWindow.windowHandle, False, 
+            XGrabPointer(xGlobalDisplay, (X11Window) restrictedWindow.rootWindow.windowHandle, False,
                ButtonPressMask | ButtonReleaseMask | PointerMotionMask, GrabModeAsync,
                GrabModeAsync, confineWindow, fullScreenMode ? nullCursor : None, CurrentTime);
          else
@@ -2641,14 +3005,11 @@ class XInterface : Interface
 
    // -- Mouse cursor ---
 
-   void SetMouseCursor(int cursor)
+   void SetMouseCursor(Window window, int cursor)
    {
-      //*XLockDisplay(xGlobalDisplay);
-      if(cursor == -1)
-      {
-         XDefineCursor(xGlobalDisplay, (X11Window) guiApp.desktop.windowHandle, nullCursor);
-      }
-      //*XUnlockDisplay(xGlobalDisplay);
+      if(window.rootWindow.windowHandle)
+         XDefineCursor(xGlobalDisplay, (X11Window) window.rootWindow.windowHandle,
+            cursor == -1 ? (X11Cursor)0 : systemCursors[(SystemCursor)cursor]);
    }
 
    // --- Caret ---
@@ -2671,7 +3032,7 @@ class XInterface : Interface
             XSetICValues(windowData.ic, XNPreeditAttributes, argList, 0);
          }
       }
-   }  
+   }
 
    void ClearClipboard()
    {
@@ -2679,7 +3040,7 @@ class XInterface : Interface
       if(clipBoardData)
       {
          delete clipBoardData;
-       XSetSelectionOwner(xGlobalDisplay, atoms[clipboard], None, CurrentTime);
+         XSetSelectionOwner(xGlobalDisplay, atoms[clipboard], None, CurrentTime);
       }
       //*XUnlockDisplay(xGlobalDisplay);
    }
@@ -2688,7 +3049,7 @@ class XInterface : Interface
    {
       bool result = false;
       if((clipBoard.text = new0 byte[size]))
-         result = true;   
+         result = true;
       return result;
    }
 
@@ -2699,16 +3060,16 @@ class XInterface : Interface
       if(clipBoard.text)
       {
          Window rootWindow = guiApp.desktop;
-         if(!fullScreenMode) 
+         if(!fullScreenMode)
          {
-            for(rootWindow = rootWindow.children.first; 
-               rootWindow && !rootWindow.windowHandle; 
+            for(rootWindow = rootWindow.children.first;
+               rootWindow && !rootWindow.windowHandle;
                rootWindow = rootWindow.next);
          }
          if(clipBoardData)
             delete clipBoardData;
          else if(rootWindow)
-          XSetSelectionOwner(xGlobalDisplay, atoms[clipboard], 
+            XSetSelectionOwner(xGlobalDisplay, atoms[clipboard],
                (X11Window) rootWindow.windowHandle, CurrentTime);
          clipBoardData = clipBoard.text;
          clipBoard.text = null;
@@ -2736,8 +3097,8 @@ class XInterface : Interface
          Window rootWindow = guiApp.desktop;
          if(!fullScreenMode)
          {
-            for(rootWindow = rootWindow.children.first; 
-               rootWindow && !rootWindow.windowHandle; 
+            for(rootWindow = rootWindow.children.first;
+               rootWindow && !rootWindow.windowHandle;
                rootWindow = rootWindow.next);
          }
          if(rootWindow)
@@ -2756,11 +3117,16 @@ class XInterface : Interface
                   {
                      XSelectionEvent * selection = (XSelectionEvent *) &e;
                      //printf("Got a SelectionNotify with %d (%s)\n", selection->_property, XGetAtomName(xGlobalDisplay, selection->_property));
-                     byte *data;
+                     byte *data = null;
                      unsigned long len, size = 0, dummy;
                      Atom type;
                      int format;
                      XGetWindowProperty(xGlobalDisplay, (X11Window) rootWindow.windowHandle, selection->_property ? selection->_property : atom, 0, 0, False, AnyPropertyType, &type, &format, &len, &size, &data);
+                     if(data)
+                     {
+                        XFree(data);
+                        data = null;
+                     }
                      if(size > 0)
                      {
                         if(XGetWindowProperty(xGlobalDisplay, (X11Window) rootWindow.windowHandle, selection->_property ? selection->_property : atom, 0, size, False,
@@ -2806,7 +3172,7 @@ class XInterface : Interface
    bool GetJoystickState(int device, Joystick joystick)
    {
       bool result = false;
-   #if defined(__linux__)   
+   #if defined(__linux__)
       if(joystick && device < 4)
       {
          struct JS_DATA_TYPE js = { 0 };
@@ -2819,7 +3185,7 @@ class XInterface : Interface
             result = true;
          }
       }
-   #endif   
+   #endif
       return result;
    }
 
@@ -2840,7 +3206,7 @@ class XInterface : Interface
          hiResTimer.Create();
       }
       */
-   }  
+   }
 
    bool SetIcon(Window window, BitmapResource resource)
    {
@@ -2862,8 +3228,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;
       }