get the modifier mask for a modifier key that is pressed/released more accurately...
[mikachu/openbox.git] / openbox / actions / cyclewindows.c
1 #include "openbox/actions.h"
2 #include "openbox/stacking.h"
3 #include "openbox/window.h"
4 #include "openbox/event.h"
5 #include "openbox/focus_cycle.h"
6 #include "openbox/openbox.h"
7 #include "gettext.h"
8 #include "obt/keyboard.h"
9
10 typedef struct {
11     gboolean linear;
12     gboolean dock_windows;
13     gboolean desktop_windows;
14     gboolean all_desktops;
15     gboolean forward;
16     gboolean bar;
17     gboolean raise;
18     ObFocusCyclePopupMode dialog_mode;
19     GSList *actions;
20
21
22     /* options for after we're done */
23     gboolean cancel; /* did the user cancel or not */
24     guint state;     /* keyboard state when finished */
25 } Options;
26
27 static gpointer setup_func(xmlNodePtr node,
28                            ObActionsIPreFunc *pre,
29                            ObActionsIInputFunc *in,
30                            ObActionsICancelFunc *c,
31                            ObActionsIPostFunc *post);
32 static gpointer setup_forward_func(xmlNodePtr node,
33                                    ObActionsIPreFunc *pre,
34                                    ObActionsIInputFunc *in,
35                                    ObActionsICancelFunc *c,
36                                    ObActionsIPostFunc *post);
37 static gpointer setup_backward_func(xmlNodePtr node,
38                                     ObActionsIPreFunc *pre,
39                                     ObActionsIInputFunc *in,
40                                     ObActionsICancelFunc *c,
41                                     ObActionsIPostFunc *post);
42 static void     free_func(gpointer options);
43 static gboolean run_func(ObActionsData *data, gpointer options);
44 static gboolean i_input_func(guint initial_state,
45                              XEvent *e,
46                              ObtIC *ic,
47                              gpointer options,
48                              gboolean *used);
49 static void     i_cancel_func(gpointer options);
50 static void     i_post_func(gpointer options);
51
52 void action_cyclewindows_startup(void)
53 {
54     actions_register_i("NextWindow", setup_forward_func, free_func, run_func);
55     actions_register_i("PreviousWindow", setup_backward_func, free_func,
56                        run_func);
57 }
58
59 static gpointer setup_func(xmlNodePtr node,
60                            ObActionsIPreFunc *pre,
61                            ObActionsIInputFunc *input,
62                            ObActionsICancelFunc *cancel,
63                            ObActionsIPostFunc *post)
64 {
65     xmlNodePtr n;
66     Options *o;
67
68     o = g_slice_new0(Options);
69     o->bar = TRUE;
70     o->dialog_mode = OB_FOCUS_CYCLE_POPUP_MODE_LIST;
71
72     if ((n = obt_xml_find_node(node, "linear")))
73         o->linear = obt_xml_node_bool(n);
74     if ((n = obt_xml_find_node(node, "dialog"))) {
75         if (obt_xml_node_contains(n, "none"))
76             o->dialog_mode = OB_FOCUS_CYCLE_POPUP_MODE_NONE;
77         else if (obt_xml_node_contains(n, "icons"))
78             o->dialog_mode = OB_FOCUS_CYCLE_POPUP_MODE_ICONS;
79     }
80     if ((n = obt_xml_find_node(node, "bar")))
81         o->bar = obt_xml_node_bool(n);
82     if ((n = obt_xml_find_node(node, "raise")))
83         o->raise = obt_xml_node_bool(n);
84     if ((n = obt_xml_find_node(node, "panels")))
85         o->dock_windows = obt_xml_node_bool(n);
86     if ((n = obt_xml_find_node(node, "desktop")))
87         o->desktop_windows = obt_xml_node_bool(n);
88     if ((n = obt_xml_find_node(node, "allDesktops")))
89         o->all_desktops = obt_xml_node_bool(n);
90
91     if ((n = obt_xml_find_node(node, "finalactions"))) {
92         xmlNodePtr m;
93
94         m = obt_xml_find_node(n->children, "action");
95         while (m) {
96             ObActionsAct *action = actions_parse(m);
97             if (action) o->actions = g_slist_append(o->actions, action);
98             m = obt_xml_find_node(m->next, "action");
99         }
100     }
101     else {
102         o->actions = g_slist_prepend(o->actions,
103                                      actions_parse_string("Focus"));
104         o->actions = g_slist_prepend(o->actions,
105                                      actions_parse_string("Raise"));
106         o->actions = g_slist_prepend(o->actions,
107                                      actions_parse_string("Unshade"));
108     }
109
110     *input = i_input_func;
111     *cancel = i_cancel_func;
112     *post = i_post_func;
113     return o;
114 }
115
116 static gpointer setup_forward_func(xmlNodePtr node,
117                                    ObActionsIPreFunc *pre,
118                                    ObActionsIInputFunc *input,
119                                    ObActionsICancelFunc *cancel,
120                                    ObActionsIPostFunc *post)
121 {
122     Options *o = setup_func(node, pre, input, cancel, post);
123     o->forward = TRUE;
124     return o;
125 }
126
127 static gpointer setup_backward_func(xmlNodePtr node,
128                                     ObActionsIPreFunc *pre,
129                                     ObActionsIInputFunc *input,
130                                     ObActionsICancelFunc *cancel,
131                                     ObActionsIPostFunc *post)
132 {
133     Options *o = setup_func(node, pre, input, cancel, post);
134     o->forward = FALSE;
135     return o;
136 }
137
138 static void free_func(gpointer options)
139 {
140     Options *o = options;
141
142     while (o->actions) {
143         actions_act_unref(o->actions->data);
144         o->actions = g_slist_delete_link(o->actions, o->actions);
145     }
146
147     g_slice_free(Options, o);
148 }
149
150 static gboolean run_func(ObActionsData *data, gpointer options)
151 {
152     Options *o = options;
153     struct _ObClient *ft;
154
155     ft = focus_cycle(o->forward,
156                      o->all_desktops,
157                      o->dock_windows,
158                      o->desktop_windows,
159                      o->linear,
160                      TRUE,
161                      o->bar,
162                      o->dialog_mode,
163                      FALSE, FALSE);
164
165     stacking_restore();
166     if (o->raise && ft) stacking_temp_raise(CLIENT_AS_WINDOW(ft));
167
168     return TRUE;
169 }
170
171 static gboolean i_input_func(guint initial_state,
172                              XEvent *e,
173                              ObtIC *ic,
174                              gpointer options,
175                              gboolean *used)
176 {
177     Options *o = options;
178     guint mods;
179
180     mods = obt_keyboard_only_modmasks(e->xkey.state);
181     if (e->type == KeyRelease) {
182         /* remove from the state the mask of the modifier key being
183            released, if it is a modifier key being released that is */
184         mods &= ~obt_keyboard_keyevent_to_modmask(e);
185     }
186
187     if (e->type == KeyPress) {
188         KeySym sym = obt_keyboard_keypress_to_keysym(e);
189
190         /* Escape cancels no matter what */
191         if (sym == XK_Escape) {
192             o->cancel = TRUE;
193             o->state = e->xkey.state;
194             return FALSE;
195         }
196
197         /* There were no modifiers and they pressed enter */
198         else if (sym == XK_Return && !initial_state) {
199             o->cancel = FALSE;
200             o->state = e->xkey.state;
201             return FALSE;
202         }
203     }
204     /* They released the modifiers */
205     else if (e->type == KeyRelease && initial_state && !(mods & initial_state))
206     {
207         o->cancel = FALSE;
208         o->state = e->xkey.state;
209         return FALSE;
210     }
211
212     return TRUE;
213 }
214
215 static void i_cancel_func(gpointer options)
216 {
217     Options *o = options;
218     o->cancel = TRUE;
219     o->state = 0;
220 }
221
222 static void i_post_func(gpointer options)
223 {
224     Options *o = options;
225     struct _ObClient *ft;
226
227     ft = focus_cycle(o->forward,
228                      o->all_desktops,
229                      o->dock_windows,
230                      o->desktop_windows,
231                      o->linear,
232                      TRUE,
233                      o->bar,
234                      o->dialog_mode,
235                      TRUE, o->cancel);
236
237     if (ft)
238         actions_run_acts(o->actions, OB_USER_ACTION_KEYBOARD_KEY,
239                          o->state, -1, -1, 0, OB_FRAME_CONTEXT_NONE, ft);
240
241     stacking_restore();
242 }