ecere/gui/XInterface: Reduced likelyhood of stealing focus
[sdk] / ecere / src / gui / drivers / XInterface.ec
index cd21877..ccfb10e 100644 (file)
@@ -22,6 +22,16 @@ default:
 #include <unistd.h>
 #include <sys/select.h>
 
+#if defined(__APPLE__)
+#define set _set
+#include <mach/mach.h>
+#include <mach/task.h>
+#include <mach/semaphore.h>
+#undef set
+#else
+#include <semaphore.h>
+#endif
+
 //#include <stdio.h>
 //#include <stdlib.h>
 //#include <string.h>
@@ -95,7 +105,7 @@ static X11Cursor nullCursor;
 static X11Window capturedWindow = None;
 static Window restrictedWindow = null;
 static bool gotAnXEvent = false;
-static XEvent xEvent;
+//static XEvent xEvent;
 static int joystickFD[4];
 static X11Window activeWindow;
 static X11Cursor systemCursors[SystemCursor];
@@ -172,7 +182,7 @@ static const char *atomNames[AtomIdents] = {
    "_NET_WM_STATE_ABOVE",
    "Caps Lock",
    "Num Lock",
-   "Scroll Lock",
+   "Scroll Lock"
 };
 /*
 _NET_WM_STATE_STICKY, ATOM
@@ -195,10 +205,10 @@ static void SetNETWMState(X11Window windowHandle, bool throughRoot, NETWMStateAc
       int format;
       unsigned long count, fill;
       Atom type;
-      char * data = null;
-      uint state = WithdrawnState;
+      byte * data = null;
+      /*uint state = WithdrawnState;
 
-      /*if(XGetWindowProperty(xGlobalDisplay, windowHandle, atoms[wm_state], 0, 3, False,
+      if(XGetWindowProperty(xGlobalDisplay, windowHandle, atoms[wm_state], 0, 3, False,
                  atoms[wm_state], &type, &format, &count, &fill, &data) == Success && count)
       {
          state = *(uint *)data;
@@ -317,7 +327,7 @@ static void RepositionDesktop(bool updateChildren)
    Screen * x_screen = XDefaultScreenOfDisplay(xGlobalDisplay);
    X11Window x_root;
    int current = 0;
-   char *data = null;
+   byte *data = null;
    int format;
    unsigned long len, fill;
    Atom type;
@@ -342,11 +352,12 @@ static void RepositionDesktop(bool updateChildren)
 
       if(data)
       {
+         /*
          int desktops = 0;
          desktops = (int)*(long *)data;
 
-         //printf("_NET_NUMBER_OF_DESKTOPS is %d\n", desktops);
-
+         printf("_NET_NUMBER_OF_DESKTOPS is %d\n", desktops);
+         */
          XFree(data);
          data = null;
       }
@@ -815,7 +826,7 @@ static bool ProcessKeyMessage(Window window, uint keyCode, int release, XKeyEven
    }
    if(!windowData.ic)
    {
-      ch = (byte)Interface::TranslateKey(key, event->state & ShiftMask);
+      ch = (byte)Interface::TranslateKey(key, (event->state & ShiftMask) != 0);
       // 127 is delete, we don't treat that as a character (Use (SmartKey)key == del)
       if(ch == 128 || ch == 127) ch = 0;
    }
@@ -856,7 +867,8 @@ static bool ProcessKeyMessage(Window window, uint keyCode, int release, XKeyEven
    {
       int numBytes;
 
-      if(code < KeyCode::enumSize) keyStates[code] = false;
+      if(key < KeyCode::enumSize)
+         keyStates[key] = false;
       if(windowData && windowData.ic) ch = buflength ? UTF8GetChar(buf, &numBytes) : 0;
       if(ch == 127) ch = 0;
       // printf("Release! %d %d %d\n", keysym, code, ch);
@@ -867,7 +879,8 @@ static bool ProcessKeyMessage(Window window, uint keyCode, int release, XKeyEven
       int c;
       if(release == 0)
       {
-         if(code < KeyCode::enumSize) keyStates[code] = true;
+         if(key < KeyCode::enumSize)
+            keyStates[key] = true;
 
          if(windowData.ic && buflength)
          {
@@ -927,7 +940,7 @@ static uint E_CALL XEventThread(void * data)
 
 static X11Bool EventChecker(void *display, XEvent *event, char * data)
 {
-   return (!data || (event->type == (int) data)) && event->type != NoExpose && event->type != GraphicsExpose;
+   return (!data || (event->type == (int)(intptr_t) data)) && event->type != NoExpose && event->type != GraphicsExpose;
 }
 
 static X11Bool ConfigureNotifyChecker(void *display, XConfigureEvent *event, char * data)
@@ -1097,7 +1110,6 @@ static void WaitForViewableWindow(Window window)
    while(true)
    {
       XWindowAttributes attributes = { 0 };
-      int result;
       if(!XGetWindowAttributes(xGlobalDisplay, (X11Window)window.windowHandle, &attributes))
          break;
       if(attributes.map_state == IsViewable)
@@ -1141,7 +1153,7 @@ static bool GetFrameExtents(Window window, bool update)
    int format;
    unsigned long len, fill;
    Atom type;
-   char * data = null;
+   byte * data = null;
 
    if(XGetWindowProperty(xGlobalDisplay, (X11Window)window.windowHandle,
       atoms[_net_frame_extents], 0, 4,
@@ -1314,7 +1326,7 @@ static void X11UpdateState(Window window, bool * unmaximized)
       int format;
       unsigned long len, fill;
       Atom type;
-      char * data = null;
+      byte * data = null;
       if(XGetWindowProperty(xGlobalDisplay, (X11Window)window.systemHandle, atoms[_net_wm_state], 0, 32, False,
              XA_ATOM, &type, &format, &len, &fill, &data) == Success)
       {
@@ -1478,7 +1490,7 @@ class XInterface : Interface
             Pixmap mask = XCreatePixmap(xGlobalDisplay, DefaultRootWindow(xGlobalDisplay), 1, 1, 1);
             XSetWindowAttributes attributes = { 0 };
 
-            XkbSetDetectableAutoRepeat(xGlobalDisplay, True, &autoRepeatDetectable);
+            XkbSetDetectableAutoRepeat(xGlobalDisplay, True, (int *)&autoRepeatDetectable);
 
             XInternAtoms(xGlobalDisplay, (char**)atomNames, AtomIdents::enumSize, False, atoms);
 
@@ -1596,7 +1608,7 @@ class XInterface : Interface
 
    void Terminate()
    {
-      XEvent e = { 0 };
+      //XEvent e = { 0 };
       xTerminate = true;
 
       // WHY WAS THIS COMMENTED HERE?
@@ -1693,7 +1705,7 @@ class XInterface : Interface
                         windowData = modalRoot ? modalRoot.windowData : window.windowData;
                         if(windowData && windowData.ic)
                         {
-                           // XSetICValues(ic, XNClientWindow, window.windowHandle, XNFocusWindow, window.windowHandle, 0);
+                           // XSetICValues(ic, XNClientWindow, window.windowHandle, XNFocusWindow, window.windowHandle, NULL);
                            XSetICFocus(windowData.ic);
                         }
                      }
@@ -1879,7 +1891,7 @@ class XInterface : Interface
                }
                case MotionNotify:
                {
-                  static uint lastTime = 0;
+                  //static uint lastTime = 0;
                   XMotionEvent * event = (XMotionEvent *) thisEvent;
                   while(XCheckIfEvent(xGlobalDisplay, (XEvent *)thisEvent, EventChecker, (void *)MotionNotify));
                   // if(event->time - lastTime > 15)
@@ -1905,7 +1917,7 @@ class XInterface : Interface
                         event->x_root, event->y_root, &keyFlags, false, false);
                      delete window;
                      //*if(xGlobalDisplay) XLockDisplay(xGlobalDisplay);
-                     lastTime = (uint)event->time;
+                     //lastTime = (uint)event->time;
                   }
                   break;
                }
@@ -1979,14 +1991,13 @@ class XInterface : Interface
                      XRaiseWindow(xGlobalDisplay, (X11Window)window.windowHandle);
                      SetNETWMState((X11Window)window.windowHandle, true, add, atoms[_net_wm_state_fullscreen], 0);
                      XGrabKeyboard(xGlobalDisplay, (X11Window)window.windowHandle, False,  GrabModeAsync, GrabModeAsync, CurrentTime);
-                        (xGlobalDisplay, (X11Window)window.windowHandle, RevertToParent, timeStamp);
+                     XSetInputFocus(xGlobalDisplay, (X11Window)window.windowHandle, RevertToParent, timeStamp);
                      XInterface::UpdateRootWindow(window);
                      break;
                   }
 
                   if(activeWindow != (X11Window)window.windowHandle)
                   {
-                     XFocusChangeEvent *event = (XFocusChangeEvent *) thisEvent;
                      Window modalRoot = window.FindModal();
                      XWindowData windowData;
 
@@ -1994,7 +2005,7 @@ class XInterface : Interface
 
                      if(window.parent && window == window.parent.activeChild) break;
                      incref window;
-                     //if(window.creationActivation == activate)
+                     //if(window.creationActivation == activate && guiApp.desktop.active)
                      {
                         if(modalRoot)
                            modalRoot.ExternalActivate(true, true, window, null); // lastActive);
@@ -2004,7 +2015,7 @@ class XInterface : Interface
                      windowData = modalRoot ? modalRoot.windowData : window.windowData;
                      if(windowData && windowData.ic)
                      {
-                        // XSetICValues(ic, XNClientWindow, window.windowHandle, XNFocusWindow, window.windowHandle, 0);
+                        // XSetICValues(ic, XNClientWindow, window.windowHandle, XNFocusWindow, window.windowHandle, NULL);
                         XSetICFocus(windowData.ic);
                      }
                      //delete lastActive;
@@ -2116,7 +2127,6 @@ class XInterface : Interface
                   else
 #endif
                   {
-                     XFocusChangeEvent *event = (XFocusChangeEvent *) thisEvent;
                      if(window.parent && window != window.parent.activeChild && window != guiApp.interimWindow) break;
                      incref window;
 
@@ -2324,7 +2334,7 @@ class XInterface : Interface
                               window.ExternalActivate(true, true, window, null); // lastActive);
                               if(windowData && windowData.ic)
                               {
-                                 // XSetICValues(ic, XNClientWindow, window.windowHandle, XNFocusWindow, window.windowHandle, 0);
+                                 // XSetICValues(ic, XNClientWindow, window.windowHandle, XNFocusWindow, window.windowHandle, NULL);
                                  //XSetICFocus(windowData.ic);
                               }
                            }
@@ -2380,11 +2390,11 @@ class XInterface : Interface
       //*XUnlockDisplay(xGlobalDisplay);
    }
 
-   char ** GraphicsDrivers(int * numDrivers)
+   const char ** GraphicsDrivers(int * numDrivers)
    {
-      static char *graphicsDrivers[] = { "X", "OpenGL" };
+      static const char *graphicsDrivers[] = { "X", "OpenGL" };
       *numDrivers = sizeof(graphicsDrivers) / sizeof(char *);
-      return (char **)graphicsDrivers;
+      return (const char **)graphicsDrivers;
    }
 
    void GetCurrentMode(bool * fullScreen, int * resolution, int * colorDepth, int * refreshRate)
@@ -2409,8 +2419,8 @@ class XInterface : Interface
       }
       else
       {
-         static bool firstTime = true;
-         firstTime = false;
+         //static bool firstTime = true;
+         //firstTime = false;
          desktopX = desktopY = desktopW = desktopH = 0;
 
          RepositionDesktop(false);
@@ -2734,7 +2744,7 @@ class XInterface : Interface
          int num_missing_charsets = 0;
          char *default_string;
          XFontSet fontset;
-         XRectangle area = { 0, 0,  400, 400 };
+         //XRectangle area = { 0, 0,  400, 400 };
          XVaNestedList argList;
 
          // sprintf(fontString, "-*-%s-*-r-*-*-*-%d-*-*-*-*-*-*", "Helvetica" /*window.font.faceName*/, (int)(window.font.size * 20));
@@ -2870,7 +2880,7 @@ class XInterface : Interface
 
    // -- Window manipulation ---
 
-   void SetRootWindowCaption(Window window, char * name)
+   void SetRootWindowCaption(Window window, const char * name)
    {
       if(window.windowHandle)
       {
@@ -2886,9 +2896,13 @@ class XInterface : Interface
       //Logf("Position root window %s\n", window.name);
       if(window.windowHandle && (!window.parent || !window.parent.display))
       {
-         bool visible = window.visible;
          if(window.visible && window.created)
+         {
+            long t = (window.creationActivation == activate && guiApp.desktop.active) ? (int)timeStamp : 0;
+            XChangeProperty(xGlobalDisplay, (X11Window)window.windowHandle, atoms[_net_wm_user_time],
+              XA_CARDINAL,32,PropModeReplace, (byte *)&t, 1);
             XMapWindow(xGlobalDisplay, (X11Window)window.windowHandle);
+         }
          if(window.state == minimized && atomsSupported[_net_wm_state]) return;
 
          if(window.nativeDecorations)
@@ -2927,7 +2941,7 @@ class XInterface : Interface
          x += desktopX;
          y += desktopY;
 
-         if(!fullScreenMode && (!atomsSupported[_net_wm_state] || window.state != maximized))
+         if(!fullScreenMode && (!atomsSupported[_net_wm_state] || (window.state != maximized || !window.visible)))
          {
             if(move && resize)
                XMoveResizeWindow(xGlobalDisplay, (X11Window)window.windowHandle, x, y, w, h);
@@ -2937,7 +2951,7 @@ class XInterface : Interface
                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)
+            if(window.style.fixed && !window.style.sizable && window.state != maximized)
             {
                XSizeHints hints = { 0 };
                long supplied;
@@ -2990,6 +3004,8 @@ class XInterface : Interface
 
    void SetRootWindowState(Window window, WindowState state, bool visible)
    {
+      WindowState curState = window.state;
+      *&window.state = state;
       // Old WM (e.g. TWM), use built-in decorations
       if(!atomsSupported[_net_wm_state])
          window.nativeDecorations = false;
@@ -3001,10 +3017,13 @@ class XInterface : Interface
          {
             if(!windowData.currentlyVisible)
             {
+               long t = (window.creationActivation == activate && guiApp.desktop.active) ? timeStamp : 0;
+               XChangeProperty(xGlobalDisplay, (X11Window)window.windowHandle, atoms[_net_wm_user_time],
+                 XA_CARDINAL,32,PropModeReplace, (byte *)&t, 1);
                XMapWindow(xGlobalDisplay, (X11Window)window.windowHandle);
                windowData.currentlyVisible = true;
                WaitForViewableWindow(window);
-               if(window.creationActivation == activate && state != minimized)
+               if(window.creationActivation == activate && guiApp.desktop.active && state != minimized)
                   ActivateRootWindow(window);
             }
 
@@ -3021,7 +3040,7 @@ class XInterface : Interface
 
             if(state == minimized && atomsSupported[_net_wm_state])
             {
-               uint iconic = IconicState;
+               //uint iconic = IconicState;
 
                // SetNETWMState(window.windowHandle, true, add, atoms[_net_wm_state_hidden], null);
                /*
@@ -3079,8 +3098,10 @@ class XInterface : Interface
                if(atomsSupported[_net_wm_state])
                {
                   // Maximize / Restore the window
-                  SetNETWMState((X11Window)window.windowHandle, true, state == maximized ? add : remove,
-                     atoms[_net_wm_state_maximized_vert], atoms[_net_wm_state_maximized_horz]);
+                  if(curState != state)
+                     SetNETWMState((X11Window)window.windowHandle, true, state == maximized ? add : remove,
+                        atoms[_net_wm_state_maximized_vert], atoms[_net_wm_state_maximized_horz]);
+
                   if(state == maximized)
                   {
                      // Prevent the code in ConfigureNotify to think the window has been unmaximized
@@ -3098,12 +3119,18 @@ class XInterface : Interface
          }
          //XFlush(xGlobalDisplay);
       }
+      *&window.state = curState;
    }
 
    void FlashRootWindow(Window window)
    {
+      void * hwnd = window.windowHandle;
+      Window master = window.master, rootWindow = (master && master != guiApp.desktop) ? master.rootWindow : null;
+      if(!window.style.showInTaskBar && rootWindow && (window._isModal || window.style.interim))
+         hwnd = rootWindow.windowHandle;
+
       // printf("Attempting to flash root window\n");
-      SetNETWMState((X11Window)window.windowHandle, true, add, atoms[_net_wm_state_demands_attention], 0);
+      SetNETWMState((X11Window)hwnd, true, add, atoms[_net_wm_state_demands_attention], 0);
    }
 
    void ActivateRootWindow(Window window)
@@ -3116,6 +3143,9 @@ class XInterface : Interface
             //printf("Activate root window %s\n", window._class.name);
             if(!windowData.currentlyVisible)
             {
+               long t = (window.creationActivation == activate && guiApp.desktop.active) ? timeStamp : 0;
+               XChangeProperty(xGlobalDisplay, (X11Window)window.windowHandle, atoms[_net_wm_user_time],
+                 XA_CARDINAL,32,PropModeReplace, (byte *)&t, 1);
                XMapWindow(xGlobalDisplay, (X11Window)window.windowHandle);
                WaitForViewableWindow(window);
                windowData.currentlyVisible = true;
@@ -3281,7 +3311,7 @@ class XInterface : Interface
                (short)(caretOwner.caretPos.y - caretOwner.scroll.y + caretOwner.absPosition.y - window.absPosition.y)
             };
             XVaNestedList argList = XVaCreateNestedList(0, XNSpotLocation, &cursor_location, NULL);
-            XSetICValues(windowData.ic, XNPreeditAttributes, argList, 0);
+            XSetICValues(windowData.ic, XNPreeditAttributes, argList, NULL);
          }
       }
    }
@@ -3385,7 +3415,7 @@ class XInterface : Interface
                               AnyPropertyType, &type,&format,&len, &dummy, &data) == Success)
                         {
                            clipBoard.text = new char[size+1];
-                           strncpy(clipBoard.text, data, size);
+                           strncpy(clipBoard.text, (char *)data, size);
                            clipBoard.text[size] = '\0';
                            XFree(data);
                            result = true;
@@ -3482,7 +3512,16 @@ class XInterface : Interface
          return (bool)state;
       }
       else
-         return keyStates[key.code];
+      {
+         if(key == alt)
+            return keyStates[leftAlt] || keyStates[rightAlt];
+         else if(key == shift)
+            return keyStates[leftShift] || keyStates[rightShift];
+         else if(key == control)
+            return keyStates[leftControl] || keyStates[rightControl];
+         else
+            return keyStates[key.code];
+      }
    }
 
    void SetTimerResolution(uint hertz)
@@ -3527,12 +3566,12 @@ class XInterface : Interface
    }
 }
 
-default dllexport void * __attribute__((stdcall)) IS_XGetDisplay()
+default dllexport void * IS_XGetDisplay()
 {
    return xGlobalDisplay;
 }
 
-default dllexport void * __attribute__((stdcall)) IS_XGetWindow(Window window)
+default dllexport void * IS_XGetWindow(Window window)
 {
    return window.windowHandle ? window.windowHandle : window.rootWindow.windowHandle;
 }