+
+ return o->interactive;
+}
+
+static gboolean i_input_func(guint initial_state,
+ XEvent *e,
+ ObtIC *ic,
+ gpointer options,
+ gboolean *used)
+{
+ 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 (sym == XK_Escape)
+ return FALSE;
+
+ /* There were no modifiers and they pressed enter */
+ else if ((sym == XK_Return || sym == XK_KP_Enter) && !initial_mods)
+ return FALSE;
+ }
+ /* They released the modifiers */
+ else if (e->type == KeyRelease && initial_mods && !(mods & initial_mods))
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean i_pre_func(guint initial_state, gpointer options)
+{
+ guint initial_mods = obt_keyboard_only_modmasks(initial_state);
+ if (!initial_mods) {
+ Options *o = options;
+ o->interactive = FALSE;
+ return FALSE;
+ }
+ else {
+ screen_show_desktop_popup(screen_desktop, TRUE);
+ return TRUE;
+ }
+}
+
+static void i_post_func(gpointer options)
+{
+ screen_hide_desktop_popup();
+}
+
+/* 3.4-compatilibity */
+static gpointer setup_follow(xmlNodePtr node)
+{
+ xmlNodePtr n;
+ Options *o = g_slice_new0(Options);
+ o->send = TRUE;
+ o->follow = TRUE;
+ if ((n = obt_xml_find_node(node, "follow")))
+ o->follow = obt_xml_node_bool(n);
+ return o;
+}
+
+static gpointer setup_go_last_func(xmlNodePtr node)
+{
+ Options *o = g_slice_new0(Options);
+ o->type = LAST;
+ return o;
+}
+
+static gpointer setup_send_last_func(xmlNodePtr node)
+{
+ Options *o = setup_follow(node);
+ o->type = LAST;
+ return o;
+}
+
+static gpointer setup_go_abs_func(xmlNodePtr node)
+{
+ xmlNodePtr n;
+ Options *o = g_slice_new0(Options);
+ o->type = ABSOLUTE;
+ if ((n = obt_xml_find_node(node, "desktop")))
+ o->u.abs.desktop = obt_xml_node_int(n) - 1;
+ else
+ o->u.abs.desktop = screen_desktop;
+ return o;
+}
+
+static void setup_rel(Options *o, xmlNodePtr node, gboolean lin,
+ ObDirection dir,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsIPostFunc *post)
+{
+ xmlNodePtr n;
+
+ o->type = RELATIVE;
+ o->u.rel.linear = lin;
+ o->u.rel.dir = dir;
+ o->u.rel.wrap = TRUE;
+
+ if ((n = obt_xml_find_node(node, "wrap")))
+ o->u.rel.wrap = obt_xml_node_bool(n);
+
+ if (input) {
+ o->interactive = TRUE;
+ *pre = i_pre_func;
+ *input = i_input_func;
+ *post = i_post_func;
+ }
+}
+
+static gpointer setup_go_next_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o = g_slice_new0(Options);
+ setup_rel(o, node, TRUE, OB_DIRECTION_EAST, pre, input, post);
+ return o;
+}
+
+static gpointer setup_send_next_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o = setup_follow(node);
+ setup_rel(o, node, TRUE, OB_DIRECTION_EAST,
+ pre, (o->follow ? input : NULL), post);
+ return o;
+}
+
+static gpointer setup_go_prev_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o = g_slice_new0(Options);
+ setup_rel(o, node, TRUE, OB_DIRECTION_WEST, pre, input, post);
+ return o;
+}
+
+static gpointer setup_send_prev_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o = setup_follow(node);
+ setup_rel(o, node, TRUE, OB_DIRECTION_WEST,
+ pre, (o->follow ? input : NULL), post);
+ return o;
+}
+
+static gpointer setup_go_left_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o = g_slice_new0(Options);
+ setup_rel(o, node, FALSE, OB_DIRECTION_WEST, pre, input, post);
+ return o;
+}
+
+static gpointer setup_send_left_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o = setup_follow(node);
+ setup_rel(o, node, FALSE, OB_DIRECTION_WEST,
+ pre, (o->follow ? input : NULL), post);
+ return o;
+}
+
+static gpointer setup_go_right_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o = g_slice_new0(Options);
+ setup_rel(o, node, FALSE, OB_DIRECTION_EAST, pre, input, post);
+ return o;
+}
+
+static gpointer setup_send_right_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o = setup_follow(node);
+ setup_rel(o, node, FALSE, OB_DIRECTION_EAST,
+ pre, (o->follow ? input : NULL), post);
+ return o;
+}
+
+static gpointer setup_go_up_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o = g_slice_new0(Options);
+ setup_rel(o, node, FALSE, OB_DIRECTION_NORTH, pre, input, post);
+ return o;
+}
+
+static gpointer setup_send_up_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o = setup_follow(node);
+ setup_rel(o, node, FALSE, OB_DIRECTION_NORTH,
+ pre, (o->follow ? input : NULL), post);
+ return o;
+}
+
+static gpointer setup_go_down_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o = g_slice_new0(Options);
+ setup_rel(o, node, FALSE, OB_DIRECTION_SOUTH, pre, input, post);
+ return o;
+}
+
+static gpointer setup_send_down_func(xmlNodePtr node,
+ ObActionsIPreFunc *pre,
+ ObActionsIInputFunc *input,
+ ObActionsICancelFunc *cancel,
+ ObActionsIPostFunc *post)
+{
+ Options *o = setup_follow(node);
+ setup_rel(o, node, FALSE, OB_DIRECTION_SOUTH,
+ pre, (o->follow ? input : NULL), post);
+ return o;