add directionaldesktop action
[mikachu/openbox.git] / openbox / actions / directionalcyclewindows.c
1 #include "openbox/actions.h"
2 #include "openbox/event.h"
3 #include "openbox/focus_cycle.h"
4 #include "openbox/openbox.h"
5 #include "openbox/misc.h"
6 #include "gettext.h"
7
8 typedef struct {
9     gboolean dialog;
10     gboolean dock_windows;
11     gboolean desktop_windows;
12     ObDirection direction;
13     GSList *actions;
14 } Options;
15
16 static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
17 static void     free_func(gpointer options);
18 static gboolean run_func(ObActionsData *data, gpointer options);
19 static gboolean i_input_func(guint initial_state,
20                              XEvent *e,
21                              gpointer options,
22                              gboolean *used);
23 static void     i_cancel_func(gpointer options);
24
25 static void     end_cycle(gboolean cancel, guint state, Options *o);
26
27 void action_directionalcyclewindows_startup()
28 {
29     actions_register("DirectionalCycleWindows",
30                      setup_func,
31                      free_func,
32                      run_func,
33                      i_input_func,
34                      i_cancel_func);
35 }
36
37 static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
38 {
39     xmlNodePtr n;
40     Options *o;
41
42     o = g_new0(Options, 1);
43     o->dialog = TRUE;
44
45     if ((n = parse_find_node("dialog", node)))
46         o->dialog = parse_bool(doc, n);
47     if ((n = parse_find_node("panels", node)))
48         o->dock_windows = parse_bool(doc, n);
49     if ((n = parse_find_node("desktop", node)))
50         o->desktop_windows = parse_bool(doc, n);
51     if ((n = parse_find_node("direction", node))) {
52         gchar *s = parse_string(doc, n);
53         if (!g_ascii_strcasecmp(s, "north") ||
54             !g_ascii_strcasecmp(s, "up"))
55             o->direction = OB_DIRECTION_NORTH;
56         else if (!g_ascii_strcasecmp(s, "northwest"))
57             o->direction = OB_DIRECTION_NORTHWEST;
58         else if (!g_ascii_strcasecmp(s, "northeast"))
59             o->direction = OB_DIRECTION_NORTHEAST;
60         else if (!g_ascii_strcasecmp(s, "west") ||
61                  !g_ascii_strcasecmp(s, "left"))
62             o->direction = OB_DIRECTION_WEST;
63         else if (!g_ascii_strcasecmp(s, "east") ||
64                  !g_ascii_strcasecmp(s, "right"))
65             o->direction = OB_DIRECTION_EAST;
66         else if (!g_ascii_strcasecmp(s, "south") ||
67                  !g_ascii_strcasecmp(s, "down"))
68             o->direction = OB_DIRECTION_NORTH;
69         else if (!g_ascii_strcasecmp(s, "southwest"))
70             o->direction = OB_DIRECTION_NORTHWEST;
71         else if (!g_ascii_strcasecmp(s, "southeast"))
72             o->direction = OB_DIRECTION_NORTHEAST;
73         g_free(s);
74     }
75
76     if ((n = parse_find_node("actions", node))) {
77         xmlNodePtr m;
78
79         m = parse_find_node("action", n->xmlChildrenNode);
80         while (m) {
81             ObActionsAct *action = actions_parse(i, doc, m);
82             if (action) o->actions = g_slist_prepend(o->actions, action);
83             m = parse_find_node("action", m->next);
84         }
85     }
86     return o;
87 }
88
89 static void free_func(gpointer options)
90 {
91     Options *o = options;
92
93     g_free(o);
94 }
95
96 static gboolean run_func(ObActionsData *data, gpointer options)
97 {
98     Options *o = options;
99
100     /* if using focus_delay, stop the timer now so that focus doesn't go moving
101        on us */
102     event_halt_focus_delay();
103     
104     focus_directional_cycle(o->direction,
105                             o->dock_windows,
106                             o->desktop_windows,
107                             TRUE,
108                             o->dialog,
109                             FALSE, FALSE);
110
111     return TRUE;
112 }
113
114 static gboolean i_input_func(guint initial_state,
115                              XEvent *e,
116                              gpointer options,
117                              gboolean *used)
118 {
119     if (e->type == KeyPress) {
120         /* Escape cancels no matter what */
121         if (e->xkey.keycode == ob_keycode(OB_KEY_ESCAPE)) {
122             end_cycle(TRUE, e->xkey.state, options);
123             return FALSE;
124         }
125
126         /* There were no modifiers and they pressed enter */
127         else if (e->xkey.keycode == ob_keycode(OB_KEY_RETURN) &&
128                  !initial_state)
129         {
130             end_cycle(FALSE, e->xkey.state, options);
131             return FALSE;
132         }
133     }
134     /* They released the modifiers */
135     else if (e->type == KeyRelease && initial_state &&
136              (e->xkey.state & initial_state) == 0)
137     {
138         end_cycle(FALSE, e->xkey.state, options);
139         return FALSE;
140     }
141
142     return TRUE;
143 }
144
145 static void i_cancel_func(gpointer options)
146 {
147     end_cycle(TRUE, 0, options);
148 }
149
150 static void end_cycle(gboolean cancel, guint state, Options *o)
151 {
152     struct _ObClient *ft;
153
154     ft = focus_directional_cycle(o->direction,
155                                  o->dock_windows,
156                                  o->desktop_windows,
157                                  TRUE,
158                                  o->dialog,
159                                  TRUE, cancel);
160
161     if (ft) {
162         actions_run_acts(o->actions, OB_USER_ACTION_KEYBOARD_KEY,
163                          state, -1, -1, 0, OB_FRAME_CONTEXT_NONE, ft);
164     }
165 }