ecere/gui/drivers/XInterface: Removed position and size flags when setting min/max...
[sdk] / ecere / src / gui / drivers / XInterface.ec
index 33a1b7b..3bb7145 100644 (file)
@@ -95,6 +95,8 @@ static int joystickFD[4];
 static X11Window activeWindow;
 static X11Cursor systemCursors[SystemCursor];
 
+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,
@@ -174,7 +176,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;
+      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 X11Time timeStamp;
 
 class XWindowData : struct
 {
@@ -956,6 +1022,33 @@ static void WaitForViewableWindow(Window window)
    }
 }
 
+static bool RequestFrameExtents(X11Window windowHandle)
+{
+   if(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 = windowHandle;
+      event.send_event = 1;
+      event.format = 32;
+
+      if(frameExtentSupported == unknown && !frameExtentRequest)
+      {
+         frameExtentRequest = GetTime();
+         frameExtentWindow = 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;
@@ -1016,13 +1109,25 @@ static bool GetFrameExtents(Window window, bool update)
                XInterface::UpdateRootWindow(window);
             }
          }
+         result = true;
       }
       XFree(data);
-      result = true;
    }
    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 /////////////
 ****************************************************************************/
@@ -1087,7 +1192,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)
@@ -1096,11 +1201,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)
                {
@@ -1135,9 +1240,10 @@ class XInterface : Interface
 #endif
       xTerminate = false;
       xGlobalDisplay = XOpenDisplay(null);
+      // 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);
@@ -1428,10 +1534,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, 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:
@@ -1439,6 +1569,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))
@@ -1479,15 +1610,13 @@ class XInterface : Interface
                   uint button, buttonDouble, whichButton;
                   uint buttonMask;
                   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)
-                     {
                         XRaiseWindow(xGlobalDisplay, (X11Window)window.windowHandle);
-                        XSetInputFocus(xGlobalDisplay, (X11Window)window.windowHandle, RevertToPointerRoot, CurrentTime);
-                     }
+                     XSetInputFocus(xGlobalDisplay, (X11Window)window.windowHandle, RevertToPointerRoot, CurrentTime);
                      button = __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftButtonDown;
                      buttonDouble = __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnLeftDoubleClick;
                      whichButton = 0;
@@ -1574,6 +1703,7 @@ class XInterface : Interface
                      button = __ecereVMethodID___ecereNameSpace__ecere__gui__Window_OnMiddleButtonUp;
                      buttonMask = Button2Mask;
                   }
+                  timeStamp = event->time;
                   if(!(event->state & buttonMask)) break;
                   if(event->state & ShiftMask)     keyFlags.shift = true;
                   if(event->state & ControlMask)   keyFlags.ctrl = true;
@@ -1605,6 +1735,7 @@ class XInterface : Interface
                   // 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;
@@ -1627,23 +1758,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];
@@ -1651,27 +1777,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:
@@ -1816,10 +1942,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)
 
-                  if(window.nativeDecorations)
+                  if(atomsSupported[_net_wm_state]) //window.nativeDecorations)
                   {
                      int format;
                      unsigned long len, fill;
@@ -1845,50 +1972,98 @@ 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 && window.nativeDecorations)
+                     {
+                        if(window.nativeDecorations && RequestFrameExtents((X11Window)window.windowHandle))
+                           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;
-                        int 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)
+                           {
+                              /*if(event->send_event)
+                                 offset = true;*/
+                              x = rootX;
+                              y = rootY;
+                           }
+                        }
+
+                        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 && window.state != maximized)
+                     // 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.Position(x, y, w, h, true, true, true, true, false, false);
                   }
                   break;
                }
@@ -1908,7 +2083,7 @@ class XInterface : Interface
                      bool laterFocus;
                      activeWindow = (X11Window)window.windowHandle;
 
-                     timeStamp = (int)event->data.l[1];
+                     timeStamp = (X11Time)event->data.l[1];
 
                      windowData = window.windowData;
                      laterFocus = windowData.laterFocus;
@@ -1965,10 +2140,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
@@ -1976,7 +2151,7 @@ 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, RevertToPointerRoot, timeStamp);
 
                                  //XFlush(xGlobalDisplay);
                                  //printf("Done.\n");
@@ -1984,7 +2159,7 @@ class XInterface : Interface
                            }
                            else
                            {
-                              XSetInputFocus(xGlobalDisplay, (X11Window)window.windowHandle, RevertToPointerRoot, (uint)timeStamp);
+                              XSetInputFocus(xGlobalDisplay, (X11Window)window.windowHandle, RevertToPointerRoot, timeStamp);
                               window.ExternalActivate(true, true, window, null); // lastActive);
                               if(windowData && windowData.ic)
                               {
@@ -2231,9 +2406,26 @@ class XInterface : Interface
          else
          {
             X11Window parentWindow = (X11Window)null;
-            int x = window.position.x, y = window.position.y;
+            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))
             {
@@ -2260,25 +2452,36 @@ 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)
+               {
+                  hints[0] = atoms[_net_wm_window_type_normal];
+
+                  // 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
                {
-                  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];
+                  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);
 
-                  XChangeProperty(xGlobalDisplay, windowHandle, atoms[_net_wm_window_type], XA_ATOM, 32,
-                     PropModeReplace, (unsigned char*)&hints, parentWindow ? 2 : 1);
                {
                   XWMHints xwmHints;
                   xwmHints.flags = InputHint;
@@ -2291,17 +2494,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;
@@ -2358,8 +2556,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);
@@ -2423,30 +2621,9 @@ class XInterface : Interface
          XUngrabPointer(xGlobalDisplay, CurrentTime);
       }
 
-      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)windowHandle;
-         event.send_event = 1;
-         window.windowHandle = (void *)windowHandle;
-         event.format = 32;
-
-         if(frameExtentSupported == unknown && !frameExtentRequest)
-         {
-            frameExtentRequest = GetTime();
-            frameExtentWindow = windowHandle;
-         }
-
-         XSendEvent(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), bool::false,
-            SubstructureRedirectMask | SubstructureNotifyMask, (union _XEvent *)&event);
-      }
-      else
+      if(!window.nativeDecorations || !RequestFrameExtents(windowHandle))
          ((XWindowData)window.windowData).gotFrameExtents = true;
+
       return (void *)windowHandle;
    }
 
@@ -2504,7 +2681,17 @@ class XInterface : Interface
             // 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) return;
+            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;
@@ -2513,26 +2700,36 @@ class XInterface : Interface
             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))
+            /*if(window.state == maximized && (desktopX + w > desktopW || desktopY + h > desktopH))
             {
                w -= 40;
                h -= 40;
-            }
+            }*/
          }
 
          x += desktopX;
          y += desktopY;
 
-         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);
-#if defined(__APPLE__)
-//         if(window.created && !visible)
-  //          XUnmapWindow(xGlobalDisplay, (X11Window)window.windowHandle);
-#endif
+         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;
+
+               XSetWMNormalHints(xGlobalDisplay, (X11Window)window.windowHandle, &hints);
+            }
+         }
       }
    }
 
@@ -2591,10 +2788,8 @@ class XInterface : Interface
             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);
@@ -2603,19 +2798,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;
@@ -2630,10 +2812,11 @@ class XInterface : Interface
             }
             else
             {
-               if(!atomsSupported[_net_wm_state] || !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!
+                  // 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;
@@ -2661,19 +2844,15 @@ 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);
+                  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);
+                  }
                }
             }
          }
@@ -2685,18 +2864,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)
@@ -2719,14 +2888,9 @@ 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;
+               event.data.l[1] = 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);
@@ -2784,7 +2948,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)
@@ -2848,8 +3012,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,
+            cursor == -1 ? (X11Cursor)0 : systemCursors[(SystemCursor)cursor]);
    }
 
    // --- Caret ---
@@ -2880,7 +3045,7 @@ class XInterface : Interface
       if(clipBoardData)
       {
          delete clipBoardData;
-       XSetSelectionOwner(xGlobalDisplay, atoms[clipboard], None, CurrentTime);
+         XSetSelectionOwner(xGlobalDisplay, atoms[clipboard], None, CurrentTime);
       }
       //*XUnlockDisplay(xGlobalDisplay);
    }
@@ -3068,8 +3233,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;
       }