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