s/xmlChildrenNode/children/
[manmower/openbox.git] / openbox / actions / directionalwindows.c
1 #include "openbox/actions.h"
2 #include "openbox/event.h"
3 #include "openbox/stacking.h"
4 #include "openbox/window.h"
5 #include "openbox/focus_cycle.h"
6 #include "openbox/openbox.h"
7 #include "openbox/misc.h"
8 #include "gettext.h"
9
10 typedef struct {
11     gboolean interactive;
12     gboolean dialog;
13     gboolean dock_windows;
14     gboolean desktop_windows;
15     ObDirection direction;
16     gboolean bar;
17     gboolean raise;
18     GSList *actions;
19 } Options;
20
21 static gboolean cycling = FALSE;
22
23 static gpointer setup_func(xmlNodePtr node);
24 static gpointer setup_cycle_func(xmlNodePtr node);
25 static gpointer setup_target_func(xmlNodePtr node);
26 static void     free_func(gpointer options);
27 static gboolean run_func(ObActionsData *data, gpointer options);
28 static gboolean i_input_func(guint initial_state,
29                              XEvent *e,
30                              gpointer options,
31                              gboolean *used);
32 static void     i_cancel_func(gpointer options);
33
34 static void     end_cycle(gboolean cancel, guint state, Options *o);
35
36 void action_directionalwindows_startup(void)
37 {
38     actions_register("DirectionalCycleWindows", setup_cycle_func, free_func,
39                      run_func, i_input_func, i_cancel_func);
40     actions_register("DirectionalTargetWindow", setup_target_func, free_func,
41                      run_func, NULL, NULL);
42 }
43
44 static gpointer setup_func(xmlNodePtr node)
45 {
46     xmlNodePtr n;
47     Options *o;
48
49     o = g_new0(Options, 1);
50     o->dialog = TRUE;
51     o->bar = TRUE;
52
53     if ((n = obt_parse_find_node(node, "dialog")))
54         o->dialog = obt_parse_node_bool(n);
55     if ((n = obt_parse_find_node(node, "bar")))
56         o->bar = obt_parse_node_bool(n);
57     if ((n = obt_parse_find_node(node, "raise")))
58         o->raise = obt_parse_node_bool(n);
59     if ((n = obt_parse_find_node(node, "panels")))
60         o->dock_windows = obt_parse_node_bool(n);
61     if ((n = obt_parse_find_node(node, "desktop")))
62         o->desktop_windows = obt_parse_node_bool(n);
63     if ((n = obt_parse_find_node(node, "direction"))) {
64         gchar *s = obt_parse_node_string(n);
65         if (!g_ascii_strcasecmp(s, "north") ||
66             !g_ascii_strcasecmp(s, "up"))
67             o->direction = OB_DIRECTION_NORTH;
68         else if (!g_ascii_strcasecmp(s, "northwest"))
69             o->direction = OB_DIRECTION_NORTHWEST;
70         else if (!g_ascii_strcasecmp(s, "northeast"))
71             o->direction = OB_DIRECTION_NORTHEAST;
72         else if (!g_ascii_strcasecmp(s, "west") ||
73                  !g_ascii_strcasecmp(s, "left"))
74             o->direction = OB_DIRECTION_WEST;
75         else if (!g_ascii_strcasecmp(s, "east") ||
76                  !g_ascii_strcasecmp(s, "right"))
77             o->direction = OB_DIRECTION_EAST;
78         else if (!g_ascii_strcasecmp(s, "south") ||
79                  !g_ascii_strcasecmp(s, "down"))
80             o->direction = OB_DIRECTION_SOUTH;
81         else if (!g_ascii_strcasecmp(s, "southwest"))
82             o->direction = OB_DIRECTION_SOUTHWEST;
83         else if (!g_ascii_strcasecmp(s, "southeast"))
84             o->direction = OB_DIRECTION_SOUTHEAST;
85         g_free(s);
86     }
87
88     if ((n = obt_parse_find_node(node, "finalactions"))) {
89         xmlNodePtr m;
90
91         m = obt_parse_find_node(n->children, "action");
92         while (m) {
93             ObActionsAct *action = actions_parse(m);
94             if (action) o->actions = g_slist_prepend(o->actions, action);
95             m = obt_parse_find_node(m->next, "action");
96         }
97     }
98     else {
99         o->actions = g_slist_prepend(o->actions,
100                                      actions_parse_string("Focus"));
101         o->actions = g_slist_prepend(o->actions,
102                                      actions_parse_string("Raise"));
103         o->actions = g_slist_prepend(o->actions,
104                                      actions_parse_string("Unshade"));
105     }
106
107     return o;
108 }
109
110 static gpointer setup_cycle_func(xmlNodePtr node)
111 {
112     Options *o = setup_func(node);
113     o->interactive = TRUE;
114     return o;
115 }
116
117 static gpointer setup_target_func(xmlNodePtr node)
118 {
119     Options *o = setup_func(node);
120     o->interactive = FALSE;
121     return o;
122 }
123
124 static void free_func(gpointer options)
125 {
126     Options *o = options;
127
128     while (o->actions) {
129         actions_act_unref(o->actions->data);
130         o->actions = g_slist_delete_link(o->actions, o->actions);
131     }
132
133     g_free(o);
134 }
135
136 static gboolean run_func(ObActionsData *data, gpointer options)
137 {
138     Options *o = options;
139
140     if (!o->interactive)
141         end_cycle(FALSE, data->state, o);
142     else {
143         struct _ObClient *ft;
144
145         ft = focus_directional_cycle(o->direction,
146                                      o->dock_windows,
147                                      o->desktop_windows,
148                                      TRUE,
149                                      o->bar,
150                                      o->dialog,
151                                      FALSE, FALSE);
152         cycling = TRUE;
153
154         stacking_restore();
155         if (o->raise) stacking_temp_raise(CLIENT_AS_WINDOW(ft));
156     }
157
158     return o->interactive;
159 }
160
161 static gboolean i_input_func(guint initial_state,
162                              XEvent *e,
163                              gpointer options,
164                              gboolean *used)
165 {
166     if (e->type == KeyPress) {
167         /* Escape cancels no matter what */
168         if (e->xkey.keycode == ob_keycode(OB_KEY_ESCAPE)) {
169             end_cycle(TRUE, e->xkey.state, options);
170             return FALSE;
171         }
172
173         /* There were no modifiers and they pressed enter */
174         else if (e->xkey.keycode == ob_keycode(OB_KEY_RETURN) &&
175                  !initial_state)
176         {
177             end_cycle(FALSE, e->xkey.state, options);
178             return FALSE;
179         }
180     }
181     /* They released the modifiers */
182     else if (e->type == KeyRelease && initial_state &&
183              (e->xkey.state & initial_state) == 0)
184     {
185         end_cycle(FALSE, e->xkey.state, options);
186         return FALSE;
187     }
188
189     return TRUE;
190 }
191
192 static void i_cancel_func(gpointer options)
193 {
194     /* we get cancelled when we move focus, but we're not cycling anymore, so
195        just ignore that */
196     if (cycling)
197         end_cycle(TRUE, 0, options);
198 }
199
200 static void end_cycle(gboolean cancel, guint state, Options *o)
201 {
202     struct _ObClient *ft;
203
204     ft = focus_directional_cycle(o->direction,
205                                  o->dock_windows,
206                                  o->desktop_windows,
207                                  o->interactive,
208                                  o->bar,
209                                  o->dialog,
210                                  TRUE, cancel);
211     cycling = FALSE;
212
213     if (ft)
214         actions_run_acts(o->actions, OB_USER_ACTION_KEYBOARD_KEY,
215                          state, -1, -1, 0, OB_FRAME_CONTEXT_NONE, ft);
216
217     stacking_restore();
218 }