]> Dogcows Code - chaz/openbox/blobdiff - openbox/event.c
change the "handle" context to "bottom". add a "top" context. make the top
[chaz/openbox] / openbox / event.c
index 0c594d6bcba135d02d133ee4806ced76e6d6f224..2ba9c4c7251ccb9f3e9e73cf67eb2fe04157d4a6 100644 (file)
@@ -98,6 +98,13 @@ Time event_curtime = CurrentTime;
 static guint ignore_enter_focus = 0;
 static gboolean menu_can_hide;
 static gboolean focus_left_screen = FALSE;
+/*! This variable is used for focus fallback. If we fallback to a window, we
+  set this to the window. And when focus goes somewhere after that, it will
+  be set to NULL. If between falling back to that window and something
+  getting focused, the window gets unmanaged, then if there are no incoming
+  FocusIn events, we fallback again because focus has just gotten itself lost.
+ */
+static ObClient *focus_tried = NULL;
 
 #ifdef USE_SM
 static void ice_handler(gint fd, gpointer conn)
@@ -498,7 +505,7 @@ static void event_process(const XEvent *ec, gpointer data)
                     focus_left_screen = FALSE;
 
                 if (!focus_left_screen)
-                    focus_fallback(TRUE);
+                    focus_tried = focus_fallback(TRUE);
             }
         } else if (client && client != focus_client) {
             focus_left_screen = FALSE;
@@ -506,6 +513,8 @@ static void event_process(const XEvent *ec, gpointer data)
             focus_set_client(client);
             client_calc_layer(client);
             client_bring_helper_windows(client);
+
+            focus_tried = NULL; /* focus isn't "trying" to go anywhere now */
         }
     } else if (e->type == FocusOut) {
         gboolean nomove = FALSE;
@@ -547,7 +556,7 @@ static void event_process(const XEvent *ec, gpointer data)
                 ob_debug_type(OB_DEBUG_FOCUS,
                               "Focus went to an unmanaged window 0x%x !\n",
                               ce.xfocus.window);
-                focus_fallback(TRUE);
+                focus_tried = focus_fallback(TRUE);
             }
         }
 
@@ -577,9 +586,6 @@ static void event_process(const XEvent *ec, gpointer data)
             ObClient *c = client_fake_manage(e->xclient.window);
             gulong vals[4];
 
-            /* adjust the decorations so we know the sizes */
-            frame_adjust_area(c->frame, FALSE, TRUE, TRUE);
-
             /* set the frame extents on the window */
             vals[0] = c->frame->size.left;
             vals[1] = c->frame->size.right;
@@ -593,7 +599,7 @@ static void event_process(const XEvent *ec, gpointer data)
         }
     }
     else if (e->type == ConfigureRequest) {
-        /* unhandled config5Aure requests must be used to configure the
+        /* unhandled configure requests must be used to configure the
            window directly */
         XWindowChanges xwc;
 
@@ -663,7 +669,7 @@ static void event_handle_root(XEvent *e)
             if (d > 0)
                 screen_set_num_desktops(d);
         } else if (msgtype == prop_atoms.net_showing_desktop) {
-            screen_show_desktop(e->xclient.data.l[0] != 0, TRUE);
+            screen_show_desktop(e->xclient.data.l[0] != 0, NULL);
         } else if (msgtype == prop_atoms.openbox_control) {
             if (e->xclient.data.l[0] == 1)
                 ob_reconfigure();
@@ -953,70 +959,33 @@ static void event_handle_client(ObClient *client, XEvent *e)
         break;
     }
     case ConfigureRequest:
+    {
         /* dont compress these unless you're going to watch for property
            notifies in between (these can change what the configure would
            do to the window).
            also you can't compress stacking events
         */
 
-        ob_debug("ConfigureRequest desktop %d wmstate %d vis %d\n",
-                 screen_desktop, client->wmstate, client->frame->visible);
+        gint x, y, w, h;
 
-        /* don't allow clients to move shaded windows (fvwm does this) */
-        if (client->shaded) {
-            e->xconfigurerequest.value_mask &= ~CWX;
-            e->xconfigurerequest.value_mask &= ~CWY;
-        }
+        /* if nothing is changed, then a configurenotify is needed */
+        gboolean config = TRUE;
 
-        /* resize, then move, as specified in the EWMH section 7.7 */
-        if (e->xconfigurerequest.value_mask & (CWWidth | CWHeight |
-                                               CWX | CWY |
-                                               CWBorderWidth)) {
-            gint x, y, w, h;
+        x = client->area.x;
+        y = client->area.y;
+        w = client->area.width;
+        h = client->area.height;
 
-            if (e->xconfigurerequest.value_mask & CWBorderWidth)
-                client->border_width = e->xconfigurerequest.border_width;
+        ob_debug("ConfigureRequest desktop %d wmstate %d visibile %d\n",
+                 screen_desktop, client->wmstate, client->frame->visible);
 
-            x = (e->xconfigurerequest.value_mask & CWX) ?
-                e->xconfigurerequest.x : client->area.x;
-            y = (e->xconfigurerequest.value_mask & CWY) ?
-                e->xconfigurerequest.y : client->area.y;
-            w = (e->xconfigurerequest.value_mask & CWWidth) ?
-                e->xconfigurerequest.width : client->area.width;
-            h = (e->xconfigurerequest.value_mask & CWHeight) ?
-                e->xconfigurerequest.height : client->area.height;
-
-            ob_debug("ConfigureRequest x %d %d y %d %d\n",
-                     e->xconfigurerequest.value_mask & CWX, x,
-                     e->xconfigurerequest.value_mask & CWY, y);
-
-            /* check for broken apps moving to their root position
-
-               XXX remove this some day...that would be nice. right now all
-               kde apps do this when they try activate themselves on another
-               desktop. eg. open amarok window on desktop 1, switch to desktop
-               2, click amarok tray icon. it will move by its decoration size.
-            */
-            if (x != client->area.x &&
-                x == (client->frame->area.x + client->frame->size.left -
-                      (gint)client->border_width) &&
-                y != client->area.y &&
-                y == (client->frame->area.y + client->frame->size.top -
-                      (gint)client->border_width))
-            {
-                ob_debug_type(OB_DEBUG_APP_BUGS,
-                              "Application %s is trying to move via "
-                              "ConfigureRequest to it's root window position "
-                              "but it is not using StaticGravity\n",
-                              client->title);
-                /* don't move it */
-                x = client->area.x;
-                y = client->area.y;
+        if (e->xconfigurerequest.value_mask & CWBorderWidth)
+            if (client->border_width != e->xconfigurerequest.border_width) {
+                client->border_width = e->xconfigurerequest.border_width;
+                /* if only the border width is changing, then it's not needed*/
+                config = FALSE;
             }
 
-            client_find_onscreen(client, &x, &y, w, h, FALSE);
-            client_configure_full(client, x, y, w, h, FALSE, TRUE, TRUE);
-        }
 
         if (e->xconfigurerequest.value_mask & CWStackMode) {
             ObClient *sibling = NULL;
@@ -1026,52 +995,85 @@ static void event_handle_client(ObClient *client, XEvent *e)
                 ObWindow *win;
                 win = g_hash_table_lookup(window_map,
                                           &e->xconfigurerequest.above);
-                if (WINDOW_IS_CLIENT(win))
+                if (WINDOW_IS_CLIENT(win) && WINDOW_AS_CLIENT(win) != client)
                     sibling = WINDOW_AS_CLIENT(win);
             }
 
-            switch (e->xconfigurerequest.detail) {
-            case Below:
-                ob_debug("ConfigureRequest Below for client %s sibling %s\n",
-                         client->title, sibling ? sibling->title : "(all)");
-                /* just lower it */
-                stacking_lower(CLIENT_AS_WINDOW(client));
-                break;
-            case BottomIf:
-                ob_debug("ConfigureRequest BottomIf for client %s sibling "
-                         "%s\n",
-                         client->title, sibling ? sibling->title : "(all)");
-                /* if this client occludes sibling (or anything if NULL), then
-                   lower it to the bottom */
-                if (stacking_occluded(sibling, client))
-                    stacking_lower(CLIENT_AS_WINDOW(client));
-                break;
-            case Above:
-                ob_debug("ConfigureRequest Above for client %s sibling %s\n",
-                         client->title, sibling ? sibling->title : "(all)");
-                /* activate it rather than just focus it */
-                client_activate(client, FALSE, FALSE);
-                break;
-            case TopIf:
-                ob_debug("ConfigureRequest TopIf for client %s sibling %s\n",
-                         client->title, sibling ? sibling->title : "(all)");
-                if (stacking_occluded(client, sibling))
-                    /* activate it rather than just focus it */
-                    client_activate(client, FALSE, FALSE);
-            case Opposite:
-                ob_debug("ConfigureRequest Opposite for client %s sibling "
-                         "%s\n",
-                         client->title, sibling ? sibling->title : "(all)");
-                if (stacking_occluded(client, sibling))
-                    /* activate it rather than just focus it */
-                    client_activate(client, FALSE, FALSE);
-                else if (stacking_occluded(sibling, client))
-                    stacking_lower(CLIENT_AS_WINDOW(client));
-            default:
-                break;
-            }
+            /* activate it rather than just focus it */
+            stacking_restack_request(client, sibling,
+                                     e->xconfigurerequest.detail, TRUE);
+
+            /* if a stacking change is requested then it is needed */
+            config = TRUE;
+        }
+
+        /* don't allow clients to move shaded windows (fvwm does this) */
+        if (client->shaded && (e->xconfigurerequest.value_mask & CWX ||
+                               e->xconfigurerequest.value_mask & CWY))
+        {
+            e->xconfigurerequest.value_mask &= ~CWX;
+            e->xconfigurerequest.value_mask &= ~CWY;
+
+            /* if the client tried to move and we aren't letting it then a
+               synthetic event is needed */
+            config = TRUE;
+        }
+
+        if (e->xconfigurerequest.value_mask & CWX ||
+            e->xconfigurerequest.value_mask & CWY ||
+            e->xconfigurerequest.value_mask & CWWidth ||
+            e->xconfigurerequest.value_mask & CWHeight)
+        {
+            if (e->xconfigurerequest.value_mask & CWX)
+                x = e->xconfigurerequest.x;
+            if (e->xconfigurerequest.value_mask & CWY)
+                y = e->xconfigurerequest.y;
+            if (e->xconfigurerequest.value_mask & CWWidth)
+                w = e->xconfigurerequest.width;
+            if (e->xconfigurerequest.value_mask & CWHeight)
+                h = e->xconfigurerequest.height;
+
+            /* if a new position or size is requested, then a configure is
+               needed */
+            config = TRUE;
+        }
+
+        ob_debug("ConfigureRequest x(%d) %d y(%d) %d w(%d) %d h(%d) %d\n",
+                 e->xconfigurerequest.value_mask & CWX, x,
+                 e->xconfigurerequest.value_mask & CWY, y,
+                 e->xconfigurerequest.value_mask & CWWidth, w,
+                 e->xconfigurerequest.value_mask & CWHeight, h);
+
+        /* check for broken apps moving to their root position
+
+           XXX remove this some day...that would be nice. right now all
+           kde apps do this when they try activate themselves on another
+           desktop. eg. open amarok window on desktop 1, switch to desktop
+           2, click amarok tray icon. it will move by its decoration size.
+        */
+        if (x != client->area.x &&
+            x == (client->frame->area.x + client->frame->size.left -
+                  (gint)client->border_width) &&
+            y != client->area.y &&
+            y == (client->frame->area.y + client->frame->size.top -
+                  (gint)client->border_width))
+        {
+            ob_debug_type(OB_DEBUG_APP_BUGS,
+                          "Application %s is trying to move via "
+                          "ConfigureRequest to it's root window position "
+                          "but it is not using StaticGravity\n",
+                          client->title);
+            /* don't move it */
+            x = client->area.x;
+            y = client->area.y;
+        }
+
+        if (config) {
+            client_find_onscreen(client, &x, &y, w, h, FALSE);
+            client_configure_full(client, x, y, w, h, FALSE, TRUE);
         }
         break;
+    }
     case UnmapNotify:
         if (client->ignore_unmaps) {
             client->ignore_unmaps--;
@@ -1082,10 +1084,40 @@ static void event_handle_client(ObClient *client, XEvent *e)
                  client->window, e->xunmap.event, e->xunmap.from_configure,
                  client->ignore_unmaps);
         client_unmanage(client);
+
+        /* we were trying to focus this window but it's gone */
+        if (client == focus_tried) {
+            ob_debug_type(OB_DEBUG_FOCUS, "Tried to focus window 0x%x and it "
+                          "is being unmanaged:\n");
+            if (XCheckIfEvent(ob_display, &ce, look_for_focusin_client, NULL)){
+                XPutBackEvent(ob_display, &ce);
+                ob_debug_type(OB_DEBUG_FOCUS,
+                              "  but another FocusIn is coming\n");
+            } else {
+                ob_debug_type(OB_DEBUG_FOCUS,
+                              "  so falling back focus again.\n");
+                focus_tried = focus_fallback(TRUE);
+            }
+        }
         break;
     case DestroyNotify:
         ob_debug("DestroyNotify for window 0x%x\n", client->window);
         client_unmanage(client);
+
+        /* we were trying to focus this window but it's gone */
+        if (client == focus_tried) {
+            ob_debug_type(OB_DEBUG_FOCUS, "Tried to focus window 0x%x and it "
+                          "is being unmanaged:\n");
+            if (XCheckIfEvent(ob_display, &ce, look_for_focusin_client, NULL)){
+                XPutBackEvent(ob_display, &ce);
+                ob_debug_type(OB_DEBUG_FOCUS,
+                              "  but another FocusIn is coming\n");
+            } else {
+                ob_debug_type(OB_DEBUG_FOCUS,
+                              "  so falling back focus again.\n");
+                focus_tried = focus_fallback(TRUE);
+            }
+        }
         break;
     case ReparentNotify:
         /* this is when the client is first taken captive in the frame */
@@ -1104,6 +1136,21 @@ static void event_handle_client(ObClient *client, XEvent *e)
      
         ob_debug("ReparentNotify for window 0x%x\n", client->window);
         client_unmanage(client);
+
+        /* we were trying to focus this window but it's gone */
+        if (client == focus_tried) {
+            ob_debug_type(OB_DEBUG_FOCUS, "Tried to focus window 0x%x and it "
+                          "is being unmanaged:\n");
+            if (XCheckIfEvent(ob_display, &ce, look_for_focusin_client, NULL)){
+                XPutBackEvent(ob_display, &ce);
+                ob_debug_type(OB_DEBUG_FOCUS,
+                              "  but another FocusIn is coming\n");
+            } else {
+                ob_debug_type(OB_DEBUG_FOCUS,
+                              "  so falling back focus again.\n");
+                focus_tried = focus_fallback(TRUE);
+            }
+        }
         break;
     case MapRequest:
         ob_debug("MapRequest for 0x%lx\n", client->window);
@@ -1246,6 +1293,50 @@ static void event_handle_client(ObClient *client, XEvent *e)
             client_convert_gravity(client, grav, &x, &y, w, h);
             client_find_onscreen(client, &x, &y, w, h, FALSE);
             client_configure(client, x, y, w, h, FALSE, TRUE);
+        } else if (msgtype == prop_atoms.net_restack_window) {
+            if (e->xclient.data.l[0] != 2) {
+                ob_debug_type(OB_DEBUG_APP_BUGS,
+                              "_NET_RESTACK_WINDOW sent for window %s with "
+                              "invalid source indication %ld\n",
+                              client->title, e->xclient.data.l[0]);
+            } else {
+                ObClient *sibling = NULL;
+                if (e->xclient.data.l[1]) {
+                    ObWindow *win = g_hash_table_lookup(window_map,
+                                                        &e->xclient.data.l[1]);
+                    if (WINDOW_IS_CLIENT(win) &&
+                        WINDOW_AS_CLIENT(win) != client)
+                    {
+                        sibling = WINDOW_AS_CLIENT(win);
+                    }
+                    if (sibling == NULL)
+                        ob_debug_type(OB_DEBUG_APP_BUGS,
+                                      "_NET_RESTACK_WINDOW sent for window %s "
+                                      "with invalid sibling 0x%x\n",
+                                 client->title, e->xclient.data.l[1]);
+                }
+                if (e->xclient.data.l[2] == Below ||
+                    e->xclient.data.l[2] == BottomIf ||
+                    e->xclient.data.l[2] == Above ||
+                    e->xclient.data.l[2] == TopIf ||
+                    e->xclient.data.l[2] == Opposite)
+                {
+                    /* just raise, don't activate */
+                    stacking_restack_request(client, sibling,
+                                             e->xclient.data.l[2], FALSE);
+                    /* send a synthetic ConfigureNotify, cuz this is supposed
+                       to be like a ConfigureRequest. */
+                    client_configure_full(client, client->area.x,
+                                          client->area.y,
+                                          client->area.width,
+                                          client->area.height,
+                                          FALSE, TRUE);
+                } else
+                    ob_debug_type(OB_DEBUG_APP_BUGS,
+                                  "_NET_RESTACK_WINDOW sent for window %s "
+                                  "with invalid detail %d\n",
+                                  client->title, e->xclient.data.l[2]);
+            }
         }
         break;
     case PropertyNotify:
This page took 0.032043 seconds and 4 git commands to generate.