Don't make desktop switching interactive when no mods used. (Fix bug #5203)
[mikachu/openbox.git] / openbox / actions / cyclewindows.c
index 6fba17f..a64d225 100644 (file)
 #include "openbox/focus_cycle.h"
 #include "openbox/openbox.h"
 #include "gettext.h"
+#include "obt/keyboard.h"
 
 typedef struct {
     gboolean linear;
-    gboolean dialog;
     gboolean dock_windows;
     gboolean desktop_windows;
+    gboolean only_hilite_windows;
     gboolean all_desktops;
     gboolean forward;
     gboolean bar;
     gboolean raise;
+    ObFocusCyclePopupMode dialog_mode;
     GSList *actions;
-} Options;
 
-static gboolean cycling = FALSE;
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
-static gpointer setup_forward_func(ObParseInst *i, xmlDocPtr doc,
-                                   xmlNodePtr node);
-static gpointer setup_backward_func(ObParseInst *i, xmlDocPtr doc,
-                                    xmlNodePtr node);
+    /* options for after we're done */
+    gboolean cancel; /* did the user cancel or not */
+    guint state;     /* keyboard state when finished */
+} Options;
+
+static gpointer setup_func(xmlNodePtr node,
+                           ObActionsIPreFunc *pre,
+                           ObActionsIInputFunc *in,
+                           ObActionsICancelFunc *c,
+                           ObActionsIPostFunc *post);
+static gpointer setup_forward_func(xmlNodePtr node,
+                                   ObActionsIPreFunc *pre,
+                                   ObActionsIInputFunc *in,
+                                   ObActionsICancelFunc *c,
+                                   ObActionsIPostFunc *post);
+static gpointer setup_backward_func(xmlNodePtr node,
+                                    ObActionsIPreFunc *pre,
+                                    ObActionsIInputFunc *in,
+                                    ObActionsICancelFunc *c,
+                                    ObActionsIPostFunc *post);
 static void     free_func(gpointer options);
 static gboolean run_func(ObActionsData *data, gpointer options);
 static gboolean i_input_func(guint initial_state,
                              XEvent *e,
+                             ObtIC *ic,
                              gpointer options,
                              gboolean *used);
 static void     i_cancel_func(gpointer options);
-
-static void     end_cycle(gboolean cancel, guint state, Options *o);
+static void     i_post_func(gpointer options);
 
 void action_cyclewindows_startup(void)
 {
-    actions_register("NextWindow", setup_forward_func, free_func,
-                     run_func, i_input_func, i_cancel_func);
-    actions_register("PreviousWindow", setup_backward_func, free_func,
-                     run_func, i_input_func, i_cancel_func);
+    actions_register_i("NextWindow", setup_forward_func, free_func, run_func);
+    actions_register_i("PreviousWindow", setup_backward_func, free_func,
+                       run_func);
 }
 
-static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
+static gpointer setup_func(xmlNodePtr node,
+                           ObActionsIPreFunc *pre,
+                           ObActionsIInputFunc *input,
+                           ObActionsICancelFunc *cancel,
+                           ObActionsIPostFunc *post)
 {
     xmlNodePtr n;
     Options *o;
 
-    o = g_new0(Options, 1);
-    o->dialog = TRUE;
+    o = g_slice_new0(Options);
     o->bar = TRUE;
-
-    if ((n = parse_find_node("linear", node)))
-        o->linear = parse_bool(doc, n);
-    if ((n = parse_find_node("dialog", node)))
-        o->dialog = parse_bool(doc, n);
-    if ((n = parse_find_node("bar", node)))
-        o->bar = parse_bool(doc, n);
-    if ((n = parse_find_node("raise", node)))
-        o->raise = parse_bool(doc, n);
-    if ((n = parse_find_node("panels", node)))
-        o->dock_windows = parse_bool(doc, n);
-    if ((n = parse_find_node("desktop", node)))
-        o->desktop_windows = parse_bool(doc, n);
-    if ((n = parse_find_node("allDesktops", node)))
-        o->all_desktops = parse_bool(doc, n);
-
-    if ((n = parse_find_node("finalactions", node))) {
+    o->dialog_mode = OB_FOCUS_CYCLE_POPUP_MODE_LIST;
+
+    if ((n = obt_xml_find_node(node, "linear")))
+        o->linear = obt_xml_node_bool(n);
+    if ((n = obt_xml_find_node(node, "dialog"))) {
+        if (obt_xml_node_contains(n, "none"))
+            o->dialog_mode = OB_FOCUS_CYCLE_POPUP_MODE_NONE;
+        else if (obt_xml_node_contains(n, "no"))
+            o->dialog_mode = OB_FOCUS_CYCLE_POPUP_MODE_NONE;
+        else if (obt_xml_node_contains(n, "icons"))
+            o->dialog_mode = OB_FOCUS_CYCLE_POPUP_MODE_ICONS;
+    }
+    if ((n = obt_xml_find_node(node, "bar")))
+        o->bar = obt_xml_node_bool(n);
+    if ((n = obt_xml_find_node(node, "raise")))
+        o->raise = obt_xml_node_bool(n);
+    if ((n = obt_xml_find_node(node, "panels")))
+        o->dock_windows = obt_xml_node_bool(n);
+    if ((n = obt_xml_find_node(node, "hilite")))
+        o->only_hilite_windows = obt_xml_node_bool(n);
+    if ((n = obt_xml_find_node(node, "desktop")))
+        o->desktop_windows = obt_xml_node_bool(n);
+    if ((n = obt_xml_find_node(node, "allDesktops")))
+        o->all_desktops = obt_xml_node_bool(n);
+
+    if ((n = obt_xml_find_node(node, "finalactions"))) {
         xmlNodePtr m;
 
-        m = parse_find_node("action", n->xmlChildrenNode);
+        m = obt_xml_find_node(n->children, "action");
         while (m) {
-            ObActionsAct *action = actions_parse(i, doc, m);
+            ObActionsAct *action = actions_parse(m);
             if (action) o->actions = g_slist_append(o->actions, action);
-            m = parse_find_node("action", m->next);
+            m = obt_xml_find_node(m->next, "action");
         }
     }
     else {
@@ -86,21 +112,30 @@ static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
                                      actions_parse_string("Unshade"));
     }
 
+    *input = i_input_func;
+    *cancel = i_cancel_func;
+    *post = i_post_func;
     return o;
 }
 
-static gpointer setup_forward_func(ObParseInst *i, xmlDocPtr doc,
-                                   xmlNodePtr node)
+static gpointer setup_forward_func(xmlNodePtr node,
+                                   ObActionsIPreFunc *pre,
+                                   ObActionsIInputFunc *input,
+                                   ObActionsICancelFunc *cancel,
+                                   ObActionsIPostFunc *post)
 {
-    Options *o = setup_func(i, doc, node);
+    Options *o = setup_func(node, pre, input, cancel, post);
     o->forward = TRUE;
     return o;
 }
 
-static gpointer setup_backward_func(ObParseInst *i, xmlDocPtr doc,
-                                    xmlNodePtr node)
+static gpointer setup_backward_func(xmlNodePtr node,
+                                    ObActionsIPreFunc *pre,
+                                    ObActionsIInputFunc *input,
+                                    ObActionsICancelFunc *cancel,
+                                    ObActionsIPostFunc *post)
 {
-    Options *o = setup_func(i, doc, node);
+    Options *o = setup_func(node, pre, input, cancel, post);
     o->forward = FALSE;
     return o;
 }
@@ -114,7 +149,7 @@ static void free_func(gpointer options)
         o->actions = g_slist_delete_link(o->actions, o->actions);
     }
 
-    g_free(o);
+    g_slice_free(Options, o);
 }
 
 static gboolean run_func(ObActionsData *data, gpointer options)
@@ -124,14 +159,14 @@ static gboolean run_func(ObActionsData *data, gpointer options)
 
     ft = focus_cycle(o->forward,
                      o->all_desktops,
+                     !o->only_hilite_windows,
                      o->dock_windows,
                      o->desktop_windows,
                      o->linear,
                      TRUE,
                      o->bar,
-                     o->dialog,
+                     o->dialog_mode,
                      FALSE, FALSE);
-    cycling = TRUE;
 
     stacking_restore();
     if (o->raise && ft) stacking_temp_raise(CLIENT_AS_WINDOW(ft));
@@ -141,29 +176,43 @@ static gboolean run_func(ObActionsData *data, gpointer options)
 
 static gboolean i_input_func(guint initial_state,
                              XEvent *e,
+                             ObtIC *ic,
                              gpointer options,
                              gboolean *used)
 {
+    Options *o = options;
+    guint mods, initial_mods;
+
+    initial_mods = obt_keyboard_only_modmasks(initial_state);
+    mods = obt_keyboard_only_modmasks(e->xkey.state);
+    if (e->type == KeyRelease) {
+        /* remove from the state the mask of the modifier key being
+           released, if it is a modifier key being released that is */
+        mods &= ~obt_keyboard_keyevent_to_modmask(e);
+    }
+
     if (e->type == KeyPress) {
+        KeySym sym = obt_keyboard_keypress_to_keysym(e);
+
         /* Escape cancels no matter what */
-        if (e->xkey.keycode == ob_keycode(OB_KEY_ESCAPE)) {
-            end_cycle(TRUE, e->xkey.state, options);
+        if (sym == XK_Escape) {
+            o->cancel = TRUE;
+            o->state = e->xkey.state;
             return FALSE;
         }
 
         /* There were no modifiers and they pressed enter */
-        else if (e->xkey.keycode == ob_keycode(OB_KEY_RETURN) &&
-                 !initial_state)
-        {
-            end_cycle(FALSE, e->xkey.state, options);
+        else if ((sym == XK_Return || sym == XK_KP_Enter) && !initial_mods) {
+            o->cancel = FALSE;
+            o->state = e->xkey.state;
             return FALSE;
         }
     }
     /* They released the modifiers */
-    else if (e->type == KeyRelease && initial_state &&
-             (e->xkey.state & initial_state) == 0)
+    else if (e->type == KeyRelease && initial_mods && !(mods & initial_mods))
     {
-        end_cycle(FALSE, e->xkey.state, options);
+        o->cancel = FALSE;
+        o->state = e->xkey.state;
         return FALSE;
     }
 
@@ -172,30 +221,30 @@ static gboolean i_input_func(guint initial_state,
 
 static void i_cancel_func(gpointer options)
 {
-    /* we get cancelled when we move focus, but we're not cycling anymore, so
-       just ignore that */
-    if (cycling)
-        end_cycle(TRUE, 0, options);
+    Options *o = options;
+    o->cancel = TRUE;
+    o->state = 0;
 }
 
-static void end_cycle(gboolean cancel, guint state, Options *o)
+static void i_post_func(gpointer options)
 {
+    Options *o = options;
     struct _ObClient *ft;
 
     ft = focus_cycle(o->forward,
                      o->all_desktops,
+                     !o->only_hilite_windows,
                      o->dock_windows,
                      o->desktop_windows,
                      o->linear,
                      TRUE,
                      o->bar,
-                     o->dialog,
-                     TRUE, cancel);
-    cycling = FALSE;
+                     o->dialog_mode,
+                     TRUE, o->cancel);
 
     if (ft)
         actions_run_acts(o->actions, OB_USER_ACTION_KEYBOARD_KEY,
-                         state, -1, -1, 0, OB_FRAME_CONTEXT_NONE, ft);
+                         o->state, -1, -1, 0, OB_FRAME_CONTEXT_NONE, ft);
 
     stacking_restore();
 }