]> Dogcows Code - chaz/openbox/blobdiff - openbox/event.c
change in how things are ungrabbed to avoid grabwhilenotify. don't ungrab every key...
[chaz/openbox] / openbox / event.c
index 0add317a587c854aaa607dae2b4a74d5caff9c15..e7ef27fb3058b1ab7ca6942c3a582463cde39d32 100644 (file)
@@ -38,6 +38,7 @@
 #include "mainloop.h"
 #include "framerender.h"
 #include "focus.h"
+#include "focus_cycle.h"
 #include "moveresize.h"
 #include "group.h"
 #include "stacking.h"
@@ -318,6 +319,12 @@ static gboolean wanted_focusevent(XEvent *e, gboolean in_client_only)
             if (!w || !WINDOW_IS_CLIENT(w))
                 return FALSE;
         }
+        else {
+            /* This means focus reverted to parent from the client (this
+               happens often during iconify animation) */
+            if (detail == NotifyInferior)
+                return TRUE;
+        }
 
         /* This means focus moved from the root window to a client */
         if (detail == NotifyVirtual)
@@ -479,7 +486,8 @@ static void event_process(const XEvent *ec, gpointer data)
         {
             XEvent ce;
 
-            ob_debug_type(OB_DEBUG_FOCUS, "Focus went to pointer root/none\n");
+            ob_debug_type(OB_DEBUG_FOCUS, "Focus went to pointer root/none or"
+                          " the frame window\n");
 
             /* If another FocusIn is in the queue then don't fallback yet. This
                fixes the fun case of:
@@ -501,7 +509,7 @@ static void event_process(const XEvent *ec, gpointer data)
                 ob_debug_type(OB_DEBUG_FOCUS,
                               "  but another FocusIn is coming\n");
             } else {
-                /* Focus has been reverted to the root window or nothing.
+                /* Focus has been reverted.
 
                    FocusOut events come after UnmapNotify, so we don't need to
                    worry about focusing an invalid window
@@ -553,12 +561,8 @@ static void event_process(const XEvent *ec, gpointer data)
             xerror_set_ignore(FALSE);
             /* nothing is focused */
             focus_set_client(NULL);
-        } else if (ce.xany.window == e->xany.window) {
-            ob_debug_type(OB_DEBUG_FOCUS, "Focus didn't go anywhere\n");
-            /* If focus didn't actually move anywhere, there is nothing to do*/
-            nomove = TRUE;
         } else {
-            /* Focus did move, so process the FocusIn event */
+            /* Focus moved, so process the FocusIn event */
             ObEventData ed = { .ignored = FALSE };
             event_process(&ce, &ed);
             if (ed.ignored) {
@@ -571,10 +575,10 @@ static void event_process(const XEvent *ec, gpointer data)
             }
         }
 
-        if (client && !nomove) {
+        if (client && client != focus_client) {
             frame_adjust_focus(client->frame, FALSE);
-            if (client == focus_client)
-                focus_set_client(NULL);
+            /* focus_set_client(NULL) has already been called in this
+               section or by focus_fallback */
             client_calc_layer(client);
         }
     } else if (timewinclients)
@@ -678,7 +682,7 @@ static void event_handle_root(XEvent *e)
             }
         } else if (msgtype == prop_atoms.net_number_of_desktops) {
             guint d = e->xclient.data.l[0];
-            if (d > 0)
+            if (d > 0 && d <= 1000)
                 screen_set_num_desktops(d);
         } else if (msgtype == prop_atoms.net_showing_desktop) {
             screen_show_desktop(e->xclient.data.l[0] != 0, NULL);
@@ -771,7 +775,8 @@ static void event_handle_client(ObClient *client, XEvent *e)
         {
             /* use where the press occured */
             con = frame_context(client, e->xbutton.window, px, py);
-            con = mouse_button_frame_context(con, e->xbutton.button);
+            con = mouse_button_frame_context(con, e->xbutton.button,
+                                             e->xbutton.state);
 
             if (e->type == ButtonRelease && e->xbutton.button == pb)
                 pb = 0, px = py = -1;
@@ -808,6 +813,8 @@ static void event_handle_client(ObClient *client, XEvent *e)
                             e->xmotion.x, e->xmotion.y);
         switch (con) {
         case OB_FRAME_CONTEXT_TITLEBAR:
+        case OB_FRAME_CONTEXT_TLCORNER:
+        case OB_FRAME_CONTEXT_TRCORNER:
             /* we've left the button area inside the titlebar */
             if (client->frame->max_hover || client->frame->desk_hover ||
                 client->frame->shade_hover || client->frame->iconify_hover ||
@@ -859,6 +866,22 @@ static void event_handle_client(ObClient *client, XEvent *e)
         con = frame_context(client, e->xcrossing.window,
                             e->xcrossing.x, e->xcrossing.y);
         switch (con) {
+        case OB_FRAME_CONTEXT_TITLEBAR:
+        case OB_FRAME_CONTEXT_TLCORNER:
+        case OB_FRAME_CONTEXT_TRCORNER:
+            /* we've left the button area inside the titlebar */
+            if (client->frame->max_hover || client->frame->desk_hover ||
+                client->frame->shade_hover || client->frame->iconify_hover ||
+                client->frame->close_hover)
+            {
+                client->frame->max_hover = FALSE;
+                client->frame->desk_hover = FALSE;
+                client->frame->shade_hover = FALSE;
+                client->frame->iconify_hover = FALSE;
+                client->frame->close_hover = FALSE;
+                frame_adjust_state(client->frame);
+            }
+            break;
         case OB_FRAME_CONTEXT_MAXIMIZE:
             client->frame->max_hover = FALSE;
             frame_adjust_state(client->frame);
@@ -884,7 +907,7 @@ static void event_handle_client(ObClient *client, XEvent *e)
                corresponding enter events. Pretend like the animating window
                doesn't even exist..! */
             if (frame_iconify_animating(client->frame))
-                event_ignore_enters_leaving_window(client);
+                event_ignore_all_queued_enters();
 
             ob_debug_type(OB_DEBUG_FOCUS,
                           "%sNotify mode %d detail %d on %lx\n",
@@ -973,14 +996,11 @@ static void event_handle_client(ObClient *client, XEvent *e)
         */
 
         gint x, y, w, h;
+        gboolean move = FALSE;
+        gboolean resize = FALSE;
 
-        /* if nothing is changed, then a configurenotify is needed */
-        gboolean config = TRUE;
-
-        x = client->area.x;
-        y = client->area.y;
-        w = client->area.width;
-        h = client->area.height;
+        /* get the current area */
+        RECT_TO_DIMS(client->area, x, y, w, h);
 
         ob_debug("ConfigureRequest desktop %d wmstate %d visibile %d\n",
                  screen_desktop, client->wmstate, client->frame->visible);
@@ -988,8 +1008,13 @@ static void event_handle_client(ObClient *client, XEvent *e)
         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;
+
+                /* if the border width is changing then that is the same
+                   as requesting a resize, but we don't actually change
+                   the client's border, so it will change their root
+                   coordiantes (since they include the border width) and
+                   we need to a notify then */
+                move = TRUE;
             }
 
 
@@ -1009,20 +1034,8 @@ static void event_handle_client(ObClient *client, XEvent *e)
             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 a stacking change moves the window without resizing */
+            move = TRUE;
         }
 
         if (e->xconfigurerequest.value_mask & CWX ||
@@ -1030,25 +1043,48 @@ static void event_handle_client(ObClient *client, XEvent *e)
             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)
+            if (e->xconfigurerequest.value_mask & CWX) {
+                /* don't allow clients to move shaded windows (fvwm does this)
+                 */
+                if (!client->shaded)
+                    x = e->xconfigurerequest.x;
+                move = TRUE;
+            }
+            if (e->xconfigurerequest.value_mask & CWY) {
+                /* don't allow clients to move shaded windows (fvwm does this)
+                 */
+                if (!client->shaded)
+                    y = e->xconfigurerequest.y;
+                move = TRUE;
+            }
+
+            if (e->xconfigurerequest.value_mask & CWWidth) {
                 w = e->xconfigurerequest.width;
-            if (e->xconfigurerequest.value_mask & CWHeight)
+                resize = TRUE;
+
+                /* if x was not given, then use gravity to figure out the new
+                   x.  the reference point should not be moved */
+                if (!(e->xconfigurerequest.value_mask & CWX))
+                    client_gravity_resize_w(client, &x, client->area.width, w);
+            }
+            if (e->xconfigurerequest.value_mask & CWHeight) {
                 h = e->xconfigurerequest.height;
+                resize = TRUE;
 
-            /* if a new position or size is requested, then a configure is
-               needed */
-            config = TRUE;
+                /* if y was not given, then use gravity to figure out the new
+                   y.  the reference point should not be moved */
+                if (!(e->xconfigurerequest.value_mask & CWY))
+                    client_gravity_resize_h(client, &y, client->area.height,h);
+            }
         }
 
-        ob_debug("ConfigureRequest x(%d) %d y(%d) %d w(%d) %d h(%d) %d\n",
+        ob_debug("ConfigureRequest x(%d) %d y(%d) %d w(%d) %d h(%d) %d "
+                 "move %d resize %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);
+                 e->xconfigurerequest.value_mask & CWHeight, h,
+                 move, resize);
 
         /* check for broken apps moving to their root position
 
@@ -1057,7 +1093,8 @@ static void event_handle_client(ObClient *client, XEvent *e)
            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 &&
+        if (move && !resize &&
+            x != client->area.x &&
             x == (client->frame->area.x + client->frame->size.left -
                   (gint)client->border_width) &&
             y != client->area.y &&
@@ -1072,14 +1109,26 @@ static void event_handle_client(ObClient *client, XEvent *e)
             /* don't move it */
             x = client->area.x;
             y = client->area.y;
+
+            /* they still requested a move, so don't change whether a
+               notify is sent or not */
         }
 
-        if (config) {
+        if (move || resize) {
+            gint lw,lh;
+
             client_find_onscreen(client, &x, &y, w, h, FALSE);
-            client_configure(client, x, y, w, h, FALSE, TRUE);
+            client_try_configure(client, &x, &y, &w, &h, &lw, &lh, FALSE);
+            /* if they requested something that moves the window, or if
+               the window is actually being changed then configure it and
+               send a configure notify to them */
+            if (move || !RECT_EQUAL_DIMS(client->area, x, y, w, h)) {
+                ob_debug("Doing configure\n");
+                client_configure(client, x, y, w, h, FALSE, TRUE);
+            }
 
             /* ignore enter events caused by these like ob actions do */
-            event_ignore_enters_leaving_window(client);
+            event_ignore_all_queued_enters();
         }
         break;
     }
@@ -1175,7 +1224,7 @@ static void event_handle_client(ObClient *client, XEvent *e)
                              e->xclient.data.l[1], e->xclient.data.l[2]);
 
             /* ignore enter events caused by these like ob actions do */
-            event_ignore_enters_leaving_window(client);
+            event_ignore_all_queued_enters();
         } else if (msgtype == prop_atoms.net_close_window) {
             ob_debug("net_close_window for 0x%lx\n", client->window);
             client_close(client);
@@ -1186,11 +1235,16 @@ static void event_handle_client(ObClient *client, XEvent *e)
                       (e->xclient.data.l[0] == 1 ? "application" :
                        (e->xclient.data.l[0] == 2 ? "user" : "INVALID"))));
             /* XXX make use of data.l[2] !? */
-            event_curtime = e->xclient.data.l[1];
-            if (event_curtime == 0)
+            if (e->xclient.data.l[0] == 1 || e->xclient.data.l[0] == 2) {
+                event_curtime = e->xclient.data.l[1];
+                if (event_curtime == 0)
+                    ob_debug_type(OB_DEBUG_APP_BUGS,
+                                  "_NET_ACTIVE_WINDOW message for window %s is"
+                                  " missing a timestamp\n", client->title);
+            } else
                 ob_debug_type(OB_DEBUG_APP_BUGS,
                               "_NET_ACTIVE_WINDOW message for window %s is "
-                              "missing a timestamp\n", client->title);
+                              "missing source indication\n");
             client_activate(client, FALSE,
                             (e->xclient.data.l[0] == 0 ||
                              e->xclient.data.l[0] == 2));
@@ -1230,12 +1284,12 @@ static void event_handle_client(ObClient *client, XEvent *e)
                      prop_atoms.net_wm_moveresize_cancel)
                 moveresize_end(TRUE);
         } else if (msgtype == prop_atoms.net_moveresize_window) {
-            gint grav, x, y, w, h;
+            gint ograv, x, y, w, h;
+
+            ograv = client->gravity;
 
             if (e->xclient.data.l[0] & 0xff)
-                grav = e->xclient.data.l[0] & 0xff;
-            else 
-                grav = client->gravity;
+                client->gravity = e->xclient.data.l[0] & 0xff;
 
             if (e->xclient.data.l[0] & 1 << 8)
                 x = e->xclient.data.l[1];
@@ -1245,25 +1299,42 @@ static void event_handle_client(ObClient *client, XEvent *e)
                 y = e->xclient.data.l[2];
             else
                 y = client->area.y;
-            if (e->xclient.data.l[0] & 1 << 10)
+
+            if (e->xclient.data.l[0] & 1 << 10) {
                 w = e->xclient.data.l[3];
+
+                /* if x was not given, then use gravity to figure out the new
+                   x.  the reference point should not be moved */
+                if (!(e->xclient.data.l[0] & 1 << 8))
+                    client_gravity_resize_w(client, &x, client->area.width, w);
+            }
             else
                 w = client->area.width;
-            if (e->xclient.data.l[0] & 1 << 11)
+
+            if (e->xclient.data.l[0] & 1 << 11) {
                 h = e->xclient.data.l[4];
+
+                /* if y was not given, then use gravity to figure out the new
+                   y.  the reference point should not be moved */
+                if (!(e->xclient.data.l[0] & 1 << 9))
+                    client_gravity_resize_h(client, &y, client->area.height,h);
+            }
             else
                 h = client->area.height;
 
-            ob_debug("MOVERESIZE x %d %d y %d %d\n",
+            ob_debug("MOVERESIZE x %d %d y %d %d (gravity %d)\n",
                      e->xclient.data.l[0] & 1 << 8, x,
-                     e->xclient.data.l[0] & 1 << 9, y);
-            client_convert_gravity(client, grav, &x, &y, w, h);
+                     e->xclient.data.l[0] & 1 << 9, y,
+                     client->gravity);
+
             client_find_onscreen(client, &x, &y, w, h, FALSE);
 
             client_configure(client, x, y, w, h, FALSE, TRUE);
 
+            client->gravity = ograv;
+
             /* ignore enter events caused by these like ob actions do */
-            event_ignore_enters_leaving_window(client);
+            event_ignore_all_queued_enters();
         } else if (msgtype == prop_atoms.net_restack_window) {
             if (e->xclient.data.l[0] != 2) {
                 ob_debug_type(OB_DEBUG_APP_BUGS,
@@ -1273,8 +1344,8 @@ static void event_handle_client(ObClient *client, XEvent *e)
             } else {
                 ObClient *sibling = NULL;
                 if (e->xclient.data.l[1]) {
-                    ObWindow *win = g_hash_table_lookup(window_map,
-                                                        &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)
                     {
@@ -1481,8 +1552,11 @@ static gboolean event_handle_menu_keyboard(XEvent *ev)
         ret = FALSE;
 
     else if (keycode == ob_keycode(OB_KEY_ESCAPE) && state == 0) {
-        /* Escape closes the active menu */
-        menu_frame_hide(frame);
+        /* Escape goes to the parent menu or closes the last one */
+        if (frame->parent)
+            menu_frame_select(frame, NULL, TRUE);
+        else
+            menu_frame_hide_all();
     }
 
     else if (keycode == ob_keycode(OB_KEY_RETURN) && (state == 0 ||
@@ -1514,8 +1588,8 @@ static gboolean event_handle_menu_keyboard(XEvent *ev)
         menu_frame_select_next(frame);
     }
 
-    /* keyboard accelerator shortcuts. */
-    else if (ev->xkey.state == 0 &&
+    /* keyboard accelerator shortcuts. (allow controlmask) */
+    else if ((ev->xkey.state & ~ControlMask) == 0 &&
              /* was it a valid key? */
              unikey != 0 &&
              /* don't bother if the menu is empty. */
@@ -1606,6 +1680,10 @@ static gboolean event_handle_menu(XEvent *ev)
         }
         break;
     case LeaveNotify:
+        /*ignore leaves when we're already in the window */
+        if (ev->xcrossing.detail == NotifyInferior)
+            break;
+
         if ((e = g_hash_table_lookup(menu_frame_map, &ev->xcrossing.window)) &&
             (f = find_active_menu()) && f->selected == e &&
             e->entry->type != OB_MENU_ENTRY_TYPE_SUBMENU)
@@ -1716,10 +1794,9 @@ static Bool event_look_for_enters(Display *d, XEvent *e, XPointer arg)
 {
     if (e->type == EnterNotify &&
         /* these types aren't used for focusing */
-        (e->xcrossing.mode == NotifyGrab ||
-         e->xcrossing.mode == NotifyUngrab ||
-         /*ignore enters when we're already in the window */
-         e->xcrossing.detail == NotifyInferior))
+        !(e->xcrossing.mode == NotifyGrab ||
+          e->xcrossing.mode == NotifyUngrab ||
+          e->xcrossing.detail == NotifyInferior))
     {
         ObWindow *win;
 
@@ -1733,19 +1810,11 @@ static Bool event_look_for_enters(Display *d, XEvent *e, XPointer arg)
 }
 
 void event_ignore_all_queued_enters()
-{
-    event_ignore_enters_leaving_window(NULL);
-}
-
-void event_ignore_enters_leaving_window(ObClient *c)
 {
     XEvent e;
 
     XSync(ob_display, FALSE);
 
-    ob_debug_type(OB_DEBUG_FOCUS, "want to ignore enters leaving window "
-                  "%s\n", c?c->title:"(all)");
-
     /* count the events without disrupting them */
     ignore_enter_focus = 0;
     XCheckIfEvent(ob_display, &e, event_look_for_enters, NULL);
@@ -1753,7 +1822,10 @@ void event_ignore_enters_leaving_window(ObClient *c)
 
 static gboolean is_enter_focus_event_ignored(XEvent *e)
 {
-    g_assert(e->type == EnterNotify);
+    g_assert(e->type == EnterNotify &&
+             !(e->xcrossing.mode == NotifyGrab ||
+               e->xcrossing.mode == NotifyUngrab ||
+               e->xcrossing.detail == NotifyInferior));
 
     ob_debug_type(OB_DEBUG_FOCUS, "# enters ignored: %d\n",
                   ignore_enter_focus);
@@ -1765,6 +1837,25 @@ static gboolean is_enter_focus_event_ignored(XEvent *e)
     return FALSE;
 }
 
+void event_cancel_all_key_grabs()
+{
+    if (keyboard_interactively_grabbed())
+        keyboard_interactive_cancel();
+    else if (menu_frame_visible)
+        menu_frame_hide_all();
+    else if (grab_on_keyboard())
+        ungrab_keyboard();
+    else
+        /* If we don't have the keyboard grabbed, then ungrab it with
+           XUngrabKeyboard, so that there is not a passive grab left
+           on from the KeyPress. If the grab is left on, and focus
+           moves during that time, it will be NotifyWhileGrabbed, and
+           applications like to ignore those! */
+        if (!keyboard_interactively_grabbed())
+            XUngrabKeyboard(ob_display, CurrentTime);
+
+}
+
 gboolean event_time_after(Time t1, Time t2)
 {
     g_assert(t1 != CurrentTime);
This page took 0.032457 seconds and 4 git commands to generate.