Merge branch 'master' into 3.4
authorDana Jansens <danakj@orodu.net>
Sat, 14 Jul 2007 13:09:14 +0000 (09:09 -0400)
committerDana Jansens <danakj@orodu.net>
Sat, 14 Jul 2007 13:09:14 +0000 (09:09 -0400)
1  2 
Makefile.am
openbox/actions/all.c
openbox/actions/all.h
openbox/actions/cyclewindows.c
openbox/actions/desktop.c
openbox/actions/directionalwindows.c
openbox/actions/layer.c
openbox/actions/maximize.c
openbox/config.c

diff --cc Makefile.am
Simple merge
Simple merge
Simple merge
index 21cab19a3e1c9fba8b754c81b17037a14b85e456,7b4bd11e29e58e3875206afcf2bde4ec2b323612..8a5fc4022b798316bbce6197bd5c92fb92983b9a
@@@ -182,11 -178,8 +179,7 @@@ static void end_cycle(gboolean cancel, 
                       TRUE, cancel);
      cycling = FALSE;
  
--    if (ft) {
-         if (o->actions)
-             actions_run_acts(o->actions, OB_USER_ACTION_KEYBOARD_KEY,
-                              state, -1, -1, 0, OB_FRAME_CONTEXT_NONE, ft);
-         else
-             client_activate(ft, FALSE, TRUE, TRUE, TRUE);
-     }
++    if (ft)
+         actions_run_acts(o->actions, OB_USER_ACTION_KEYBOARD_KEY,
+                          state, -1, -1, 0, OB_FRAME_CONTEXT_NONE, ft);
 -    }
  }
index abe48b74eede34636152be024ed204abd97a63f5,0e9ad7399d192fd0b8dce391e6a4be7dac6145e5..a25a22d9787233769be094f35a161ce4bfefc2db
@@@ -10,74 -26,95 +26,237 @@@ typedef struct 
      gboolean follow;
  } Options;
  
- static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
- static gpointer setup_send_func(ObParseInst *i, xmlDocPtr doc,xmlNodePtr node);
- static gpointer setup_last_func(ObParseInst *i, xmlDocPtr doc,xmlNodePtr node);
- static void     free_func(gpointer options);
 -static gpointer setup_go_func(ObParseInst *i, xmlDocPtr doc,
 -                                  xmlNodePtr node);
 -static gpointer setup_send_func(ObParseInst *i, xmlDocPtr doc,
 -                                xmlNodePtr node);
++static gpointer setup_go_last_func(ObParseInst *i, xmlDocPtr doc,
++                                   xmlNodePtr node);
++static gpointer setup_send_last_func(ObParseInst *i, xmlDocPtr doc,
++                                     xmlNodePtr node);
++static gpointer setup_go_abs_func(ObParseInst *i, xmlDocPtr doc,
++                                   xmlNodePtr node);
++static gpointer setup_send_abs_func(ObParseInst *i, xmlDocPtr doc,
++                                     xmlNodePtr node);
++static gpointer setup_go_next_func(ObParseInst *i, xmlDocPtr doc,
++                                   xmlNodePtr node);
++static gpointer setup_send_next_func(ObParseInst *i, xmlDocPtr doc,
++                                     xmlNodePtr node);
++static gpointer setup_go_prev_func(ObParseInst *i, xmlDocPtr doc,
++                                   xmlNodePtr node);
++static gpointer setup_send_prev_func(ObParseInst *i, xmlDocPtr doc,
++                                     xmlNodePtr node);
++static gpointer setup_go_left_func(ObParseInst *i, xmlDocPtr doc,
++                                   xmlNodePtr node);
++static gpointer setup_send_left_func(ObParseInst *i, xmlDocPtr doc,
++                                     xmlNodePtr node);
++static gpointer setup_go_right_func(ObParseInst *i, xmlDocPtr doc,
++                                   xmlNodePtr node);
++static gpointer setup_send_right_func(ObParseInst *i, xmlDocPtr doc,
++                                     xmlNodePtr node);
++static gpointer setup_go_up_func(ObParseInst *i, xmlDocPtr doc,
++                                   xmlNodePtr node);
++static gpointer setup_send_up_func(ObParseInst *i, xmlDocPtr doc,
++                                     xmlNodePtr node);
++static gpointer setup_go_down_func(ObParseInst *i, xmlDocPtr doc,
++                                   xmlNodePtr node);
++static gpointer setup_send_down_func(ObParseInst *i, xmlDocPtr doc,
++                                     xmlNodePtr node);
  static gboolean run_func(ObActionsData *data, gpointer options);
  
  void action_desktop_startup()
  {
-     actions_register("Desktop",
-                      setup_func,
-                      free_func,
-                      run_func,
-                      NULL, NULL);
-     actions_register("DesktopLast",
-                      setup_last_func,
-                      free_func,
-                      run_func,
 -    actions_register("GoToDesktop", setup_go_func, g_free, run_func,
--                     NULL, NULL);
-     actions_register("SendToDesktop",
-                      setup_send_func,
-                      free_func,
-                      run_func,
 -    actions_register("SendToDesktop", setup_send_func, g_free, run_func,
--                     NULL, NULL);
- }
- static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
++    actions_register("DesktopLast", setup_go_last_func, g_free,
++                     run_func, NULL, NULL);
++    actions_register("SendToDesktopLast", setup_send_last_func, g_free,
++                     run_func, NULL, NULL);
++    actions_register("Desktop", setup_go_abs_func, g_free,
++                     run_func, NULL, NULL);
++    actions_register("SendToDesktop", setup_send_abs_func, g_free,
++                     run_func, NULL, NULL);
++    actions_register("DesktopNext", setup_go_next_func, g_free,
++                     run_func, NULL, NULL);
++    actions_register("SendToDesktopNext", setup_send_next_func, g_free,
++                     run_func, NULL, NULL);
++    actions_register("DesktopPrevious", setup_go_prev_func, g_free,
++                     run_func, NULL, NULL);
++    actions_register("SendToDesktopPrevious", setup_send_prev_func, g_free,
++                     run_func, NULL, NULL);
++    actions_register("DesktopLeft", setup_go_left_func, g_free,
++                     run_func, NULL, NULL);
++    actions_register("SendToDesktopLeft", setup_send_left_func, g_free,
++                     run_func, NULL, NULL);
++    actions_register("DesktopRight", setup_go_right_func, g_free,
++                     run_func, NULL, NULL);
++    actions_register("SendToDesktopRight", setup_send_right_func, g_free,
++                     run_func, NULL, NULL);
++    actions_register("DesktopUp", setup_go_up_func, g_free,
++                     run_func, NULL, NULL);
++    actions_register("SendToDesktopUp", setup_send_up_func, g_free,
++                     run_func, NULL, NULL);
++    actions_register("DesktopDown", setup_go_down_func, g_free,
++                     run_func, NULL, NULL);
++    actions_register("SendToDesktopDown", setup_send_down_func, g_free,
++                     run_func, NULL, NULL);
+ }
 -static gpointer setup_go_func(ObParseInst *i, xmlDocPtr doc,
 -                                  xmlNodePtr node)
++static gpointer setup_follow(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
  {
      xmlNodePtr n;
--    Options *o;
-     o = g_new0(Options, 1);
++    Options *o = g_new0(Options, 1);
++    o->send = TRUE;
 +    o->follow = TRUE;
-     if ((n = parse_find_node("desktop", node))) {
-         gchar *s = parse_string(doc, n);
-         if (!g_ascii_strcasecmp(s, "last"))
-             o->last = TRUE;
-         else
-             o->desktop = parse_int(doc, n) - 1;
-         g_free(s);
-     }
-     if ((n = parse_find_node("send", node)))
-         o->send = parse_bool(doc, n);
 +    if ((n = parse_find_node("follow", node)))
 +        o->follow = parse_bool(doc, n);
++    return o;
++}
  
 -    o = g_new0(Options, 1);
 -    /* don't go anywhere if theres no options given */
++static gpointer setup_go_last_func(ObParseInst *i, xmlDocPtr doc,
++                                   xmlNodePtr node)
++{
++    Options *o = g_new0(Options, 1);
++    o->type = LAST;
 +    return o;
 +}
 +
- static gpointer setup_send_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
++static gpointer setup_send_last_func(ObParseInst *i, xmlDocPtr doc,
++                                     xmlNodePtr node)
 +{
-     Options *o = setup_func(i, doc, node);
-     o->send = TRUE;
++    Options *o = setup_follow(i, doc, node);
++    o->type = LAST;
 +    return o;
 +}
 +
- static gpointer setup_last_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
++static gpointer setup_go_abs_func(ObParseInst *i, xmlDocPtr doc,
++                                   xmlNodePtr node)
 +{
-     Options *o = setup_func(i, doc, node);
-     o->last = TRUE;
++    xmlNodePtr n;
++    Options *o = g_new0(Options, 1);
+     o->type = ABSOLUTE;
 -    o->abs.desktop = screen_desktop;
 -    /* wrap by default - it's handy! */
 -    o->rel.wrap = TRUE;
++    if ((n = parse_find_node("desktop", node)))
++        o->abs.desktop = parse_int(doc, n) - 1;
++    else
++        o->abs.desktop = screen_desktop;
 +    return o;
 +}
  
- static void free_func(gpointer options)
 -    if ((n = parse_find_node("to", node))) {
 -        gchar *s = parse_string(doc, n);
 -        if (!g_ascii_strcasecmp(s, "last") ||
 -            !g_ascii_strcasecmp(s, "previous"))
 -            o->type = LAST;
 -        else if (!g_ascii_strcasecmp(s, "next")) {
 -            o->type = RELATIVE;
 -            o->rel.linear = TRUE;
 -            o->rel.dir = OB_DIRECTION_EAST;
 -        }
 -        else if (!g_ascii_strcasecmp(s, "previous")) {
 -            o->type = RELATIVE;
 -            o->rel.linear = TRUE;
 -            o->rel.dir = OB_DIRECTION_WEST;
 -        }
 -        else if (!g_ascii_strcasecmp(s, "north") ||
 -                 !g_ascii_strcasecmp(s, "up")) {
 -            o->type = RELATIVE;
 -            o->rel.dir = OB_DIRECTION_NORTH;
 -        }
 -        else if (!g_ascii_strcasecmp(s, "south") ||
 -                 !g_ascii_strcasecmp(s, "down")) {
 -            o->type = RELATIVE;
 -            o->rel.dir = OB_DIRECTION_SOUTH;
 -        }
 -        else if (!g_ascii_strcasecmp(s, "west") ||
 -                 !g_ascii_strcasecmp(s, "left")) {
 -            o->type = RELATIVE;
 -            o->rel.dir = OB_DIRECTION_WEST;
 -        }
 -        else if (!g_ascii_strcasecmp(s, "east") ||
 -                 !g_ascii_strcasecmp(s, "right")) {
 -            o->type = RELATIVE;
 -            o->rel.dir = OB_DIRECTION_EAST;
 -        }
 -        else {
 -            o->type = ABSOLUTE;
 -            o->abs.desktop = parse_int(doc, n) - 1;
 -        }
 -        g_free(s);
 -    }
++static gpointer setup_send_abs_func(ObParseInst *i, xmlDocPtr doc,
++                                     xmlNodePtr node)
 +{
-     Options *o = options;
++    xmlNodePtr n;
++    Options *o = setup_follow(i, doc, node);
++    o->type = ABSOLUTE;
++    if ((n = parse_find_node("desktop", node)))
++        o->abs.desktop = parse_int(doc, n) - 1;
++    else
++        o->abs.desktop = screen_desktop;
++    return o;
++}
++
++static void setup_rel(Options *o, ObParseInst *i, xmlDocPtr doc,
++                      xmlNodePtr node, gboolean lin, ObDirection dir)
++{
++    xmlNodePtr n;
++
++    o->type = RELATIVE;
++    o->rel.linear = lin;
++    o->rel.dir = dir;
++    o->rel.wrap = TRUE;
+     if ((n = parse_find_node("wrap", node)))
+         o->rel.wrap = parse_bool(doc, n);
++}
++static gpointer setup_go_next_func(ObParseInst *i, xmlDocPtr doc,
++                                   xmlNodePtr node)
++{
++    Options *o = g_new0(Options, 1);
++    setup_rel(o, i, doc, node, TRUE, OB_DIRECTION_EAST);
+     return o;
+ }
 -static gpointer setup_send_func(ObParseInst *i, xmlDocPtr doc,
 -                                xmlNodePtr node)
++static gpointer setup_send_next_func(ObParseInst *i, xmlDocPtr doc,
++                                     xmlNodePtr node)
+ {
 -    xmlNodePtr n;
 -    Options *o;
++    Options *o = setup_follow(i, doc, node);
++    setup_rel(o, i, doc, node, TRUE, OB_DIRECTION_EAST);
++    return o;
++}
 -    o = setup_go_func(i, doc, node);
 -    o->send = TRUE;
 -    o->follow = TRUE;
++static gpointer setup_go_prev_func(ObParseInst *i, xmlDocPtr doc,
++                                   xmlNodePtr node)
++{
++    Options *o = g_new0(Options, 1);
++    setup_rel(o, i, doc, node, TRUE, OB_DIRECTION_WEST);
++    return o;
++}
 -    if ((n = parse_find_node("follow", node)))
 -        o->follow = parse_bool(doc, n);
++static gpointer setup_send_prev_func(ObParseInst *i, xmlDocPtr doc,
++                                     xmlNodePtr node)
++{
++    Options *o = setup_follow(i, doc, node);
++    setup_rel(o, i, doc, node, TRUE, OB_DIRECTION_WEST);
++    return o;
++}
++
++static gpointer setup_go_left_func(ObParseInst *i, xmlDocPtr doc,
++                                   xmlNodePtr node)
++{
++    Options *o = g_new0(Options, 1);
++    setup_rel(o, i, doc, node, FALSE, OB_DIRECTION_WEST);
++    return o;
++}
++
++static gpointer setup_send_left_func(ObParseInst *i, xmlDocPtr doc,
++                                     xmlNodePtr node)
++{
++    Options *o = setup_follow(i, doc, node);
++    setup_rel(o, i, doc, node, FALSE, OB_DIRECTION_WEST);
++    return o;
++}
++
++static gpointer setup_go_right_func(ObParseInst *i, xmlDocPtr doc,
++                                    xmlNodePtr node)
++{
++    Options *o = g_new0(Options, 1);
++    setup_rel(o, i, doc, node, FALSE, OB_DIRECTION_EAST);
++    return o;
++}
++
++static gpointer setup_send_right_func(ObParseInst *i, xmlDocPtr doc,
++                                      xmlNodePtr node)
++{
++    Options *o = setup_follow(i, doc, node);
++    setup_rel(o, i, doc, node, FALSE, OB_DIRECTION_EAST);
++    return o;
++}
 +
-     g_free(o);
++static gpointer setup_go_up_func(ObParseInst *i, xmlDocPtr doc,
++                                 xmlNodePtr node)
++{
++    Options *o = g_new0(Options, 1);
++    setup_rel(o, i, doc, node, FALSE, OB_DIRECTION_NORTH);
++    return o;
++}
++
++static gpointer setup_send_up_func(ObParseInst *i, xmlDocPtr doc,
++                                   xmlNodePtr node)
++{
++    Options *o = setup_follow(i, doc, node);
++    setup_rel(o, i, doc, node, FALSE, OB_DIRECTION_NORTH);
++    return o;
++}
++static gpointer setup_go_down_func(ObParseInst *i, xmlDocPtr doc,
++                                   xmlNodePtr node)
++{
++    Options *o = g_new0(Options, 1);
++    setup_rel(o, i, doc, node, FALSE, OB_DIRECTION_SOUTH);
++    return o;
++}
++
++static gpointer setup_send_down_func(ObParseInst *i, xmlDocPtr doc,
++                                     xmlNodePtr node)
++{
++    Options *o = setup_follow(i, doc, node);
++    setup_rel(o, i, doc, node, FALSE, OB_DIRECTION_SOUTH);
+     return o;
  }
  
  /* Always return FALSE because its not interactive */
index 0000000000000000000000000000000000000000,884ebcb65274567308819cb7cbc0e59b8859fc26..fa8757ae09f9a14b13035921a29b2b0bbcd781f7
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,205 +1,365 @@@
 -static gpointer setup_cycle_func(ObParseInst *i, xmlDocPtr doc,
 -                                 xmlNodePtr node);
 -static gpointer setup_target_func(ObParseInst *i, xmlDocPtr doc,
 -                                  xmlNodePtr node);
+ #include "openbox/actions.h"
+ #include "openbox/event.h"
+ #include "openbox/focus_cycle.h"
+ #include "openbox/openbox.h"
++#include "openbox/client.h"
+ #include "openbox/misc.h"
+ #include "gettext.h"
+ typedef struct {
+     gboolean interactive;
+     gboolean dialog;
+     gboolean dock_windows;
+     gboolean desktop_windows;
+     ObDirection direction;
+     GSList *actions;
+ } Options;
+ static gboolean cycling = FALSE;
+ static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
 -    actions_register("DirectionalCycleWindows", setup_cycle_func, free_func,
 -                     run_func, i_input_func, i_cancel_func);
 -    actions_register("DirectionalTargetWindow", setup_target_func, free_func,
 -                     run_func, NULL, NULL);
++static gpointer setup_north_cycle_func(ObParseInst *i,
++                                       xmlDocPtr doc, xmlNodePtr node);
++static gpointer setup_south_cycle_func(ObParseInst *i,
++                                       xmlDocPtr doc, xmlNodePtr node);
++static gpointer setup_east_cycle_func(ObParseInst *i,
++                                      xmlDocPtr doc, xmlNodePtr node);
++static gpointer setup_west_cycle_func(ObParseInst *i,
++                                      xmlDocPtr doc, xmlNodePtr node);
++static gpointer setup_northwest_cycle_func(ObParseInst *i,
++                                           xmlDocPtr doc, xmlNodePtr node);
++static gpointer setup_northeast_cycle_func(ObParseInst *i,
++                                           xmlDocPtr doc, xmlNodePtr node);
++static gpointer setup_southwest_cycle_func(ObParseInst *i,
++                                           xmlDocPtr doc, xmlNodePtr node);
++static gpointer setup_southeast_cycle_func(ObParseInst *i,
++                                           xmlDocPtr doc, xmlNodePtr node);
++static gpointer setup_north_target_func(ObParseInst *i,
++                                        xmlDocPtr doc, xmlNodePtr node);
++static gpointer setup_south_target_func(ObParseInst *i,
++                                        xmlDocPtr doc, xmlNodePtr node);
++static gpointer setup_east_target_func(ObParseInst *i,
++                                       xmlDocPtr doc, xmlNodePtr node);
++static gpointer setup_west_target_func(ObParseInst *i,
++                                       xmlDocPtr doc, xmlNodePtr node);
++static gpointer setup_northwest_target_func(ObParseInst *i,
++                                            xmlDocPtr doc, xmlNodePtr node);
++static gpointer setup_northeast_target_func(ObParseInst *i,
++                                            xmlDocPtr doc, xmlNodePtr node);
++static gpointer setup_southwest_target_func(ObParseInst *i,
++                                            xmlDocPtr doc, xmlNodePtr node);
++static gpointer setup_southeast_target_func(ObParseInst *i,
++                                            xmlDocPtr doc, xmlNodePtr node);
+ static void     free_func(gpointer options);
+ static gboolean run_func(ObActionsData *data, gpointer options);
+ static gboolean i_input_func(guint initial_state,
+                              XEvent *e,
+                              gpointer options,
+                              gboolean *used);
+ static void     i_cancel_func(gpointer options);
+ static void     end_cycle(gboolean cancel, guint state, Options *o);
+ void action_directionalwindows_startup()
+ {
 -    if ((n = parse_find_node("direction", node))) {
 -        gchar *s = parse_string(doc, n);
 -        if (!g_ascii_strcasecmp(s, "north") ||
 -            !g_ascii_strcasecmp(s, "up"))
 -            o->direction = OB_DIRECTION_NORTH;
 -        else if (!g_ascii_strcasecmp(s, "northwest"))
 -            o->direction = OB_DIRECTION_NORTHWEST;
 -        else if (!g_ascii_strcasecmp(s, "northeast"))
 -            o->direction = OB_DIRECTION_NORTHEAST;
 -        else if (!g_ascii_strcasecmp(s, "west") ||
 -                 !g_ascii_strcasecmp(s, "left"))
 -            o->direction = OB_DIRECTION_WEST;
 -        else if (!g_ascii_strcasecmp(s, "east") ||
 -                 !g_ascii_strcasecmp(s, "right"))
 -            o->direction = OB_DIRECTION_EAST;
 -        else if (!g_ascii_strcasecmp(s, "south") ||
 -                 !g_ascii_strcasecmp(s, "down"))
 -            o->direction = OB_DIRECTION_SOUTH;
 -        else if (!g_ascii_strcasecmp(s, "southwest"))
 -            o->direction = OB_DIRECTION_SOUTHWEST;
 -        else if (!g_ascii_strcasecmp(s, "southeast"))
 -            o->direction = OB_DIRECTION_SOUTHEAST;
 -        g_free(s);
 -    }
++    actions_register("DirectionalFocusNorth", setup_north_cycle_func,
++                     free_func, run_func, i_input_func, i_cancel_func);
++    actions_register("DirectionalFocusSouth", setup_south_cycle_func,
++                     free_func, run_func, i_input_func, i_cancel_func);
++    actions_register("DirectionalFocusWest", setup_west_cycle_func,
++                     free_func, run_func, i_input_func, i_cancel_func);
++    actions_register("DirectionalFocusEast", setup_east_cycle_func,
++                     free_func, run_func, i_input_func, i_cancel_func);
++    actions_register("DirectionalFocusNorthWest", setup_northwest_cycle_func,
++                     free_func, run_func, i_input_func, i_cancel_func);
++    actions_register("DirectionalFocusNorthEast", setup_northeast_cycle_func,
++                     free_func, run_func, i_input_func, i_cancel_func);
++    actions_register("DirectionalFocusSouthWest", setup_southwest_cycle_func,
++                     free_func, run_func, i_input_func, i_cancel_func);
++    actions_register("DirectionalFocusSouthEast", setup_southeast_cycle_func,
++                     free_func, run_func, i_input_func, i_cancel_func);
++    actions_register("DirectionalTargetNorth", setup_north_target_func,
++                     free_func, run_func, i_input_func, i_cancel_func);
++    actions_register("DirectionalTargetSouth", setup_south_target_func,
++                     free_func, run_func, i_input_func, i_cancel_func);
++    actions_register("DirectionalTargetWest", setup_west_target_func,
++                     free_func, run_func, i_input_func, i_cancel_func);
++    actions_register("DirectionalTargetEast", setup_east_target_func,
++                     free_func, run_func, i_input_func, i_cancel_func);
++    actions_register("DirectionalTargetNorthWest", setup_northwest_target_func,
++                     free_func, run_func, i_input_func, i_cancel_func);
++    actions_register("DirectionalTargetNorthEast", setup_northeast_target_func,
++                     free_func, run_func, i_input_func, i_cancel_func);
++    actions_register("DirectionalTargetSouthWest", setup_southwest_target_func,
++                     free_func, run_func, i_input_func, i_cancel_func);
++    actions_register("DirectionalTargetSouthEast", setup_southeast_target_func,
++                     free_func, run_func, i_input_func, i_cancel_func);
+ }
+ static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
+ {
+     xmlNodePtr n;
+     Options *o;
+     o = g_new0(Options, 1);
+     o->dialog = TRUE;
+     if ((n = parse_find_node("dialog", node)))
+         o->dialog = 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);
 -static gpointer setup_cycle_func(ObParseInst *i, xmlDocPtr doc,
 -                                 xmlNodePtr node)
+     if ((n = parse_find_node("finalactions", node))) {
+         xmlNodePtr m;
+         m = parse_find_node("action", n->xmlChildrenNode);
+         while (m) {
+             ObActionsAct *action = actions_parse(i, doc, m);
+             if (action) o->actions = g_slist_prepend(o->actions, action);
+             m = parse_find_node("action", m->next);
+         }
+     }
+     else {
+         o->actions = g_slist_prepend(o->actions,
+                                      actions_parse_string("Focus"));
+         o->actions = g_slist_prepend(o->actions,
+                                      actions_parse_string("Raise"));
+         o->actions = g_slist_prepend(o->actions,
+                                      actions_parse_string("Unshade"));
+     }
+     return o;
+ }
 -static gpointer setup_target_func(ObParseInst *i, xmlDocPtr doc,
 -                                  xmlNodePtr node)
++static gpointer setup_north_cycle_func(ObParseInst *i,
++                                       xmlDocPtr doc, xmlNodePtr node)
++{
++    Options *o = setup_func(i, doc, node);
++    o->interactive = TRUE;
++    o->direction = OB_DIRECTION_NORTH;
++    return o;
++}
++
++static gpointer setup_south_cycle_func(ObParseInst *i,
++                                       xmlDocPtr doc, xmlNodePtr node)
++{
++    Options *o = setup_func(i, doc, node);
++    o->interactive = TRUE;
++    o->direction = OB_DIRECTION_SOUTH;
++    return o;
++}
++
++static gpointer setup_east_cycle_func(ObParseInst *i,
++                                      xmlDocPtr doc, xmlNodePtr node)
++{
++    Options *o = setup_func(i, doc, node);
++    o->interactive = TRUE;
++    o->direction = OB_DIRECTION_EAST;
++    return o;
++}
++
++static gpointer setup_west_cycle_func(ObParseInst *i,
++                                      xmlDocPtr doc, xmlNodePtr node)
++{
++    Options *o = setup_func(i, doc, node);
++    o->interactive = TRUE;
++    o->direction = OB_DIRECTION_WEST;
++    return o;
++}
++
++static gpointer setup_northwest_cycle_func(ObParseInst *i,
++                                           xmlDocPtr doc, xmlNodePtr node)
++{
++    Options *o = setup_func(i, doc, node);
++    o->interactive = TRUE;
++    o->direction = OB_DIRECTION_NORTHWEST;
++    return o;
++}
++
++static gpointer setup_northeast_cycle_func(ObParseInst *i,
++                                           xmlDocPtr doc, xmlNodePtr node)
++{
++    Options *o = setup_func(i, doc, node);
++    o->interactive = TRUE;
++    o->direction = OB_DIRECTION_EAST;
++    return o;
++}
++
++static gpointer setup_southwest_cycle_func(ObParseInst *i,
++                                           xmlDocPtr doc, xmlNodePtr node)
++{
++    Options *o = setup_func(i, doc, node);
++    o->interactive = TRUE;
++    o->direction = OB_DIRECTION_SOUTHWEST;
++    return o;
++}
++
++static gpointer setup_southeast_cycle_func(ObParseInst *i,
++                                           xmlDocPtr doc, xmlNodePtr node)
+ {
+     Options *o = setup_func(i, doc, node);
+     o->interactive = TRUE;
++    o->direction = OB_DIRECTION_SOUTHEAST;
+     return o;
+ }
 -    if (ft) {
++static gpointer setup_north_target_func(ObParseInst *i,
++                                        xmlDocPtr doc, xmlNodePtr node)
+ {
+     Options *o = setup_func(i, doc, node);
+     o->interactive = FALSE;
++    o->direction = OB_DIRECTION_NORTH;
++    return o;
++}
++
++static gpointer setup_south_target_func(ObParseInst *i,
++                                        xmlDocPtr doc, xmlNodePtr node)
++{
++    Options *o = setup_func(i, doc, node);
++    o->interactive = FALSE;
++    o->direction = OB_DIRECTION_SOUTH;
++    return o;
++}
++
++static gpointer setup_east_target_func(ObParseInst *i,
++                                       xmlDocPtr doc, xmlNodePtr node)
++{
++    Options *o = setup_func(i, doc, node);
++    o->interactive = FALSE;
++    o->direction = OB_DIRECTION_EAST;
++    return o;
++}
++
++static gpointer setup_west_target_func(ObParseInst *i,
++                                       xmlDocPtr doc, xmlNodePtr node)
++{
++    Options *o = setup_func(i, doc, node);
++    o->interactive = FALSE;
++    o->direction = OB_DIRECTION_WEST;
++    return o;
++}
++
++static gpointer setup_northwest_target_func(ObParseInst *i,
++                                            xmlDocPtr doc, xmlNodePtr node)
++{
++    Options *o = setup_func(i, doc, node);
++    o->interactive = FALSE;
++    o->direction = OB_DIRECTION_NORTHWEST;
++    return o;
++}
++
++static gpointer setup_northeast_target_func(ObParseInst *i,
++                                            xmlDocPtr doc, xmlNodePtr node)
++{
++    Options *o = setup_func(i, doc, node);
++    o->interactive = FALSE;
++    o->direction = OB_DIRECTION_NORTHEAST;
++    return o;
++}
++
++static gpointer setup_southwest_target_func(ObParseInst *i,
++                                            xmlDocPtr doc, xmlNodePtr node)
++{
++    Options *o = setup_func(i, doc, node);
++    o->interactive = FALSE;
++    o->direction = OB_DIRECTION_SOUTHWEST;
++    return o;
++}
++
++static gpointer setup_southeast_target_func(ObParseInst *i,
++                                            xmlDocPtr doc, xmlNodePtr node)
++{
++    Options *o = setup_func(i, doc, node);
++    o->interactive = FALSE;
++    o->direction = OB_DIRECTION_SOUTHEAST;
+     return o;
+ }
+ static void free_func(gpointer options)
+ {
+     Options *o = options;
+     while (o->actions) {
+         actions_act_unref(o->actions->data);
+         o->actions = g_slist_delete_link(o->actions, o->actions);
+     }
+     g_free(o);
+ }
+ static gboolean run_func(ObActionsData *data, gpointer options)
+ {
+     Options *o = options;
+     if (!o->interactive)
+         end_cycle(FALSE, data->state, o);
+     else {
+         focus_directional_cycle(o->direction,
+                                 o->dock_windows,
+                                 o->desktop_windows,
+                                 TRUE,
+                                 o->dialog,
+                                 FALSE, FALSE);
+         cycling = TRUE;
+     }
+     return o->interactive;
+ }
+ static gboolean i_input_func(guint initial_state,
+                              XEvent *e,
+                              gpointer options,
+                              gboolean *used)
+ {
+     if (e->type == KeyPress) {
+         /* Escape cancels no matter what */
+         if (e->xkey.keycode == ob_keycode(OB_KEY_ESCAPE)) {
+             end_cycle(TRUE, e->xkey.state, options);
+             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);
+             return FALSE;
+         }
+     }
+     /* They released the modifiers */
+     else if (e->type == KeyRelease && initial_state &&
+              (e->xkey.state & initial_state) == 0)
+     {
+         end_cycle(FALSE, e->xkey.state, options);
+         return FALSE;
+     }
+     return TRUE;
+ }
+ 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);
+ }
+ static void end_cycle(gboolean cancel, guint state, Options *o)
+ {
+     struct _ObClient *ft;
+     ft = focus_directional_cycle(o->direction,
+                                  o->dock_windows,
+                                  o->desktop_windows,
+                                  o->interactive,
+                                  o->dialog,
+                                  TRUE, cancel);
+     cycling = FALSE;
 -    }
++    if (ft)
+         actions_run_acts(o->actions, OB_USER_ACTION_KEYBOARD_KEY,
+                          state, -1, -1, 0, OB_FRAME_CONTEXT_NONE, ft);
+ }
index 87df62006bd7fc1e1316e25f870add0e48171e33,5f0d6ce63aec8c55702e3111b5d1ae79088114c0..28a69d833c5a83c4647e1878410951b6deb60893
@@@ -4,96 -4,30 +4,38 @@@
  typedef struct {
      gint layer; /*!< -1 for below, 0 for normal, and 1 for above */
      gboolean toggle;
-     gboolean on;
  } Options;
  
- static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
- static gpointer setup_toggletop_func(ObParseInst *i,
-                                      xmlDocPtr doc, xmlNodePtr node);
- static gpointer setup_togglebottom_func(ObParseInst *i,
-                                         xmlDocPtr doc, xmlNodePtr node);
+ static gpointer setup_func_top(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
+ static gpointer setup_func_bottom(ObParseInst *i, xmlDocPtr doc,
+                                   xmlNodePtr node);
 -static gpointer setup_func_send(ObParseInst *i, xmlDocPtr doc,
 -                                xmlNodePtr node);
 +static gpointer setup_sendtop_func(ObParseInst *i,
 +                                     xmlDocPtr doc, xmlNodePtr node);
 +static gpointer setup_sendbottom_func(ObParseInst *i,
 +                                        xmlDocPtr doc, xmlNodePtr node);
 +static gpointer setup_sendnormal_func(ObParseInst *i,
 +                                      xmlDocPtr doc, xmlNodePtr node);
- static void     free_func(gpointer options);
  static gboolean run_func(ObActionsData *data, gpointer options);
  
  void action_layer_startup()
  {
-     actions_register("Layer",
-                      setup_func,
-                      free_func,
-                      run_func,
-                      NULL, NULL);
-     actions_register("ToggleAlwaysOnTop",
-                      setup_toggletop_func,
-                      free_func,
-                      run_func,
-                      NULL, NULL);
-     actions_register("ToggleAlwaysOnBottom",
-                      setup_togglebottom_func,
-                      free_func,
-                      run_func,
-                      NULL, NULL);
-     actions_register("SendToTopLayer",
-                      setup_sendtop_func,
-                      free_func,
-                      run_func,
-                      NULL, NULL);
-     actions_register("SendToBottomLayer",
-                      setup_sendbottom_func,
-                      free_func,
-                      run_func,
-                      NULL, NULL);
-     actions_register("SendToNormalLayer",
-                      setup_sendnormal_func,
-                      free_func,
-                      run_func,
-                      NULL, NULL);
+     actions_register("ToggleAlwaysOnTop", setup_func_top, g_free,
+                      run_func, NULL, NULL);
+     actions_register("ToggleAlwaysOnBottom", setup_func_bottom, g_free,
+                      run_func, NULL, NULL);
 -    actions_register("SendToLayer", setup_func_send, g_free,
++    actions_register("SendToTopLayer", setup_sendtop_func, g_free,
++                     run_func, NULL, NULL);
++    actions_register("SendToBottomLayer", setup_sendbottom_func, g_free,
++                     run_func, NULL, NULL);
++    actions_register("SendToNormalLayer", setup_sendnormal_func, g_free,
+                      run_func, NULL, NULL);
  }
  
- static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
- {
-     xmlNodePtr n;
-     Options *o;
-     o = g_new0(Options, 1);
-     o->toggle = TRUE;
-     if ((n = parse_find_node("layer", node))) {
-         gchar *s = parse_string(doc, n);
-         if (!g_ascii_strcasecmp(s, "above") ||
-             !g_ascii_strcasecmp(s, "top"))
-             o->layer = 1;
-         else if (!g_ascii_strcasecmp(s, "below") ||
-                  !g_ascii_strcasecmp(s, "bottom"))
-             o->layer = -1;
-         else if (!g_ascii_strcasecmp(s, "normal") ||
-                  !g_ascii_strcasecmp(s, "middle"))
-             o->layer = 0;
-         g_free(s);
-     }
-     if ((n = parse_find_node("state", node))) {
-         gchar *s = parse_string(doc, n);
-         if (g_ascii_strcasecmp(s, "toggle")) {
-             o->toggle = FALSE;
-             o->on = parse_bool(doc, n);
-         }
-         g_free(s);
-     }
-     return o;
- }
- static gpointer setup_toggletop_func(ObParseInst *i,
-                                      xmlDocPtr doc, xmlNodePtr node)
+ static gpointer setup_func_top(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
  {
      Options *o = g_new0(Options, 1);
-     o->toggle = TRUE;
      o->layer = 1;
+     o->toggle = TRUE;
      return o;
  }
  
@@@ -106,30 -40,28 +48,30 @@@ static gpointer setup_func_bottom(ObPar
      return o;
  }
  
 -static gpointer setup_func_send(ObParseInst *i, xmlDocPtr doc,
 -                                xmlNodePtr node)
 +static gpointer setup_sendtop_func(ObParseInst *i,
 +                                     xmlDocPtr doc, xmlNodePtr node)
  {
 -    xmlNodePtr n;
 -    Options *o;
 -
 -    o = g_new0(Options, 1);
 +    Options *o = g_new0(Options, 1);
-     o->on = TRUE;
 +    o->layer = 1;
++    o->toggle = FALSE;
 +    return o;
 +}
  
 -    if ((n = parse_find_node("layer", node))) {
 -        gchar *s = parse_string(doc, n);
 -        if (!g_ascii_strcasecmp(s, "above") ||
 -            !g_ascii_strcasecmp(s, "top"))
 -            o->layer = 1;
 -        else if (!g_ascii_strcasecmp(s, "below") ||
 -                 !g_ascii_strcasecmp(s, "bottom"))
 -            o->layer = -1;
 -        else if (!g_ascii_strcasecmp(s, "normal") ||
 -                 !g_ascii_strcasecmp(s, "middle"))
 -            o->layer = 0;
 -        g_free(s);
 -    }
 +static gpointer setup_sendbottom_func(ObParseInst *i,
 +                                        xmlDocPtr doc, xmlNodePtr node)
 +{
 +    Options *o = g_new0(Options, 1);
-     o->on = TRUE;
 +    o->layer = -1;
++    o->toggle = FALSE;
 +    return o;
 +}
  
-     o->on = TRUE;
 +static gpointer setup_sendnormal_func(ObParseInst *i,
 +                                      xmlDocPtr doc, xmlNodePtr node)
 +{
 +    Options *o = g_new0(Options, 1);
 +    o->layer = 0;
++    o->toggle = FALSE;
      return o;
  }
  
index 3af1eb02bf25e0bdc7affb299f8fea9d46af219c,8bb0cc953e355b52a9595b659edd885b05cd04d9..4ab6dd7f6c4e5bb54b83e53f62faaeea833848b4
@@@ -1,74 -1,51 +1,67 @@@
  #include "openbox/actions.h"
  #include "openbox/client.h"
  
+ /* These match the values for client_maximize */
+ typedef enum {
+     BOTH = 0,
+     HORZ = 1,
+     VERT = 2
+ } MaxDirection;
  typedef struct {
-     gboolean toggle;
-     gboolean on;
+     MaxDirection dir;
  } Options;
  
--static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
- static gpointer setup_on_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
- static gpointer setup_off_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
- static gpointer setup_toggle_func(ObParseInst *i,
++static gpointer setup_both_func(ObParseInst *i, xmlDocPtr doc,
++                              xmlNodePtr node);
++static gpointer setup_horz_func(ObParseInst *i, xmlDocPtr doc,
++                               xmlNodePtr node);
++static gpointer setup_vert_func(ObParseInst *i,
 +                                  xmlDocPtr doc, xmlNodePtr node);
- static void     free_func(gpointer options);
- static gboolean run_func(ObActionsData *data, gpointer options);
+ static gboolean run_func_on(ObActionsData *data, gpointer options);
+ static gboolean run_func_off(ObActionsData *data, gpointer options);
+ static gboolean run_func_toggle(ObActionsData *data, gpointer options);
  
  void action_maximize_startup()
  {
-     actions_register("Maximize",
-                      setup_func,
-                      free_func,
-                      run_func,
-                      NULL, NULL);
-     actions_register("MaximizeFull",
-                      setup_on_func,
-                      free_func,
-                      run_func,
 -    actions_register("Maximize", setup_func, g_free, run_func_on,
--                     NULL, NULL);
-     actions_register("UnmaximizeFull",
-                      setup_off_func,
-                      free_func,
-                      run_func,
 -    actions_register("Unmaximize", setup_func, g_free, run_func_off,
--                     NULL, NULL);
-     actions_register("ToggleMaximizeFull",
-                      setup_toggle_func,
-                      free_func,
-                      run_func,
 -    actions_register("ToggleMaximize", setup_func, g_free, run_func_toggle,
--                     NULL, NULL);
++    actions_register("MaximizeFull", setup_both_func, g_free,
++                     run_func_on, NULL, NULL);
++    actions_register("UnmaximizeFull", setup_both_func, g_free,
++                     run_func_off, NULL, NULL);
++    actions_register("ToggleMaximizeFull", setup_both_func, g_free,
++                     run_func_toggle, NULL, NULL);
++    actions_register("MaximizeHorz", setup_horz_func, g_free,
++                     run_func_on, NULL, NULL);
++    actions_register("UnmaximizeHorz", setup_horz_func, g_free,
++                     run_func_off, NULL, NULL);
++    actions_register("ToggleMaximizeHorz", setup_horz_func, g_free,
++                     run_func_toggle, NULL, NULL);
++    actions_register("MaximizeVert", setup_vert_func, g_free,
++                     run_func_on, NULL, NULL);
++    actions_register("UnmaximizeVert", setup_vert_func, g_free,
++                     run_func_off, NULL, NULL);
++    actions_register("ToggleMaximizeVert", setup_vert_func, g_free,
++                     run_func_toggle, NULL, NULL);
  }
  
--static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
++static gpointer setup_both_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
  {
--    xmlNodePtr n;
--    Options *o;
--
--    o = g_new0(Options, 1);
-     o->toggle = TRUE;
-     if ((n = parse_find_node("state", node))) {
-         gchar *s = parse_string(doc, n);
-         if (g_ascii_strcasecmp(s, "toggle")) {
-             o->toggle = FALSE;
-             o->on = parse_bool(doc, n);
-         }
-         g_free(s);
-     }
++    Options *o = g_new0(Options, 1);
+     o->dir = BOTH;
 +    return o;
 +}
  
- static gpointer setup_on_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
 -    if ((n = parse_find_node("direction", node))) {
 -        gchar *s = parse_string(doc, n);
 -        if (!g_ascii_strcasecmp(s, "vertical") ||
 -            !g_ascii_strcasecmp(s, "vert"))
 -            o->dir = VERT;
 -        else if (!g_ascii_strcasecmp(s, "horizontal") ||
 -                 !g_ascii_strcasecmp(s, "horz"))
 -            o->dir = HORZ;
 -        g_free(s);
 -    }
++static gpointer setup_horz_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
 +{
 +    Options *o = g_new0(Options, 1);
-     o->on = TRUE;
++    o->dir = HORZ;
 +    return o;
 +}
  
- static gpointer setup_off_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
++static gpointer setup_vert_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
 +{
 +    Options *o = g_new0(Options, 1);
-     o->on = FALSE;
++    o->dir = VERT;
      return o;
  }
  
Simple merge