Fix focus stealing for changing desktops/Use timestamp for user input events
[dana/openbox.git] / openbox / event.c
index 0d67fce..ba156da 100644 (file)
@@ -273,7 +273,7 @@ static void event_set_curtime(XEvent *e)
        which can happen if the clock goes backwards, we erase the last
        specified user_time */
     if (t && event_last_user_time && event_time_after(event_last_user_time, t))
-        event_last_user_time = CurrentTime;
+        event_reset_user_time();
 
     event_sourcetime = CurrentTime;
     event_curtime = t;
@@ -700,6 +700,8 @@ static void event_process(const XEvent *ec, gpointer data)
         static guint pressed = 0;
         static Window pressed_win = None;
 
+        event_sourcetime = event_curtime;
+
         /* If the button press was on some non-root window, or was physically
            on the root window... */
         if (window != obt_root(ob_screen) ||
@@ -726,6 +728,8 @@ static void event_process(const XEvent *ec, gpointer data)
     else if (e->type == KeyPress || e->type == KeyRelease ||
              e->type == MotionNotify)
     {
+        event_sourcetime = event_curtime;
+
         used = event_handle_user_input(client, e);
 
         if (prompt && !used)
@@ -1103,7 +1107,9 @@ static void event_handle_client(ObClient *client, XEvent *e)
             if (grab_on_keyboard())
                 break;
             if (e->xcrossing.mode == NotifyGrab ||
-                e->xcrossing.mode == NotifyUngrab ||
+                (e->xcrossing.mode == NotifyUngrab &&
+                 /* ungrab enters are used when _under_ mouse is being used */
+                 !(config_focus_follow && config_focus_under_mouse)) ||
                 /*ignore enters when we're already in the window */
                 e->xcrossing.detail == NotifyInferior)
             {
@@ -1443,9 +1449,15 @@ static void event_handle_client(ObClient *client, XEvent *e)
                 ob_debug_type(OB_DEBUG_APP_BUGS,
                               "_NET_ACTIVE_WINDOW message for window %s is "
                               "missing source indication", client->title);
-            client_activate(client, FALSE, FALSE, TRUE, TRUE,
-                            (e->xclient.data.l[0] == 0 ||
-                             e->xclient.data.l[0] == 2));
+            /* TODO(danakj) This should use
+               (e->xclient.data.l[0] == 0 ||
+                e->xclient.data.l[0] == 2)
+               to determine if a user requested the activation, however GTK+
+               applications seem unable to make this distinction ever
+               (including panels such as xfce4-panel and gnome-panel).
+               So we are left just assuming all activations are from the user.
+            */
+            client_activate(client, FALSE, FALSE, TRUE, TRUE, TRUE);
         } else if (msgtype == OBT_PROP_ATOM(NET_WM_MOVERESIZE)) {
             ob_debug("net_wm_moveresize for 0x%lx direction %d",
                      client->window, e->xclient.data.l[2]);
@@ -1695,10 +1707,12 @@ static void event_handle_client(ObClient *client, XEvent *e)
                         client->shaped = ((XShapeEvent*)e)->shaped;
                         kind = ShapeBounding;
                         break;
+#ifdef ShapeInput
                     case ShapeInput:
                         client->shaped_input = ((XShapeEvent*)e)->shaped;
                         kind = ShapeInput;
                         break;
+#endif
                     default:
                         g_assert_not_reached();
                 }
@@ -1849,14 +1863,23 @@ static gboolean event_handle_menu_input(XEvent *ev)
                 ret = TRUE;
             }
 
-            else if (sym == XK_Right) {
-                /* Right goes to the selected submenu */
-                if (frame->selected &&
-                    frame->selected->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU)
-                {
-                    /* make sure it is visible */
-                    menu_frame_select(frame, frame->selected, TRUE);
-                    menu_frame_select_next(frame->child);
+            else if (sym == XK_Right || sym == XK_Return || sym == XK_KP_Enter)
+            {
+                /* Right and enter goes to the selected submenu.
+                   Enter executes instead if it's not on a submenu. */
+
+                if (frame->selected) {
+                    const ObMenuEntryType t = frame->selected->entry->type;
+
+                    if (t == OB_MENU_ENTRY_TYPE_SUBMENU) {
+                        /* make sure it is visible */
+                        menu_frame_select(frame, frame->selected, TRUE);
+                        /* move focus to the child menu */
+                        menu_frame_select_next(frame->child);
+                    }
+                    else if (sym != XK_Right) {
+                        frame->press_doexec = TRUE;
+                    }
                 }
                 ret = TRUE;
             }
@@ -1881,11 +1904,6 @@ static gboolean event_handle_menu_input(XEvent *ev)
                 ret = TRUE;
             }
 
-            else if (sym == XK_Return || sym == XK_KP_Enter) {
-                frame->press_doexec = TRUE;
-                ret = TRUE;
-            }
-
             /* keyboard accelerator shortcuts. (if it was a valid key) */
             else if (frame->entries &&
                      (unikey =
@@ -1931,8 +1949,15 @@ static gboolean event_handle_menu_input(XEvent *ev)
                 if (found) {
                     menu_frame_select(frame, found, TRUE);
 
-                    if (num_found == 1)
-                        frame->press_doexec = TRUE;
+                    if (num_found == 1) {
+                        if (found->entry->type == OB_MENU_ENTRY_TYPE_SUBMENU) {
+                            /* move focus to the child menu */
+                            menu_frame_select_next(frame->child);
+                        }
+                        else {
+                            frame->press_doexec = TRUE;
+                        }
+                    }
                     ret = TRUE;
                 }
             }
@@ -1947,9 +1972,7 @@ static gboolean event_handle_menu_input(XEvent *ev)
                 frame->got_press &&
                 frame->press_doexec)
             {
-                if (frame->child)
-                    menu_frame_select_next(frame->child);
-                else if (frame->selected)
+                if (frame->selected)
                     menu_entry_frame_execute(frame->selected, ev->xkey.state);
             }
         }
@@ -2202,7 +2225,7 @@ gboolean event_time_after(guint32 t1, guint32 t2)
 gboolean find_timestamp(XEvent *e, gpointer data)
 {
     const Time t = event_get_timestamp(e);
-    if (t >= event_curtime) {
+    if (t && t >= event_curtime) {
         event_curtime = t;
         return TRUE;
     }
@@ -2246,3 +2269,13 @@ void event_reset_time(void)
 {
     next_time();
 }
+
+void event_update_user_time(void)
+{
+    event_last_user_time = event_time();
+}
+
+void event_reset_user_time(void)
+{
+    event_last_user_time = CurrentTime;
+}