]> icculus.org git repositories - dana/openbox.git/blob - openbox/actions/cyclewindows.c
Merge branch 'backport' into 3.4
[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 "openbox/client.h"
8 #include "gettext.h"
9
10 typedef struct {
11     gboolean linear;
12     gboolean dialog;
13     gboolean dock_windows;
14     gboolean desktop_windows;
15     gboolean all_desktops;
16     gboolean forward;
17     gboolean bar;
18     gboolean raise;
19     GSList *actions;
20 } Options;
21
22 static gboolean cycling = FALSE;
23
24 static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node);
25 static gpointer setup_forward_func(ObParseInst *i, xmlDocPtr doc,
26                                    xmlNodePtr node);
27 static gpointer setup_backward_func(ObParseInst *i, xmlDocPtr doc,
28                                     xmlNodePtr node);
29 static void     free_func(gpointer options);
30 static gboolean run_func(ObActionsData *data, gpointer options);
31 static gboolean i_input_func(guint initial_state,
32                              XEvent *e,
33                              gpointer options,
34                              gboolean *used);
35 static void     i_cancel_func(gpointer options);
36
37 static void     end_cycle(gboolean cancel, guint state, Options *o);
38
39 void action_cyclewindows_startup(void)
40 {
41     actions_register("NextWindow", setup_forward_func, free_func,
42                      run_func, i_input_func, i_cancel_func);
43     actions_register("PreviousWindow", setup_backward_func, free_func,
44                      run_func, i_input_func, i_cancel_func);
45 }
46
47 static gpointer setup_func(ObParseInst *i, xmlDocPtr doc, xmlNodePtr node)
48 {
49     xmlNodePtr n;
50     Options *o;
51
52     o = g_new0(Options, 1);
53     o->dialog = TRUE;
54     o->bar = TRUE;
55
56     if ((n = parse_find_node("linear", node)))
57         o->linear = parse_bool(doc, n);
58     if ((n = parse_find_node("dialog", node)))
59         o->dialog = parse_bool(doc, n);
60     if ((n = parse_find_node("bar", node)))
61         o->bar = parse_bool(doc, n);
62     if ((n = parse_find_node("raise", node)))
63         o->raise = parse_bool(doc, n);
64     if ((n = parse_find_node("panels", node)))
65         o->dock_windows = parse_bool(doc, n);
66     if ((n = parse_find_node("desktop", node)))
67         o->desktop_windows = parse_bool(doc, n);
68     if ((n = parse_find_node("allDesktops", node)))
69         o->all_desktops = parse_bool(doc, n);
70
71     if ((n = parse_find_node("finalactions", node))) {
72         xmlNodePtr m;
73
74         m = parse_find_node("action", n->xmlChildrenNode);
75         while (m) {
76             ObActionsAct *action = actions_parse(i, doc, m);
77             if (action) o->actions = g_slist_prepend(o->actions, action);
78             m = parse_find_node("action", m->next);
79         }
80     }
81     else {
82         o->actions = g_slist_prepend(o->actions,
83                                      actions_parse_string("Focus"));
84         o->actions = g_slist_prepend(o->actions,
85                                      actions_parse_string("Raise"));
86         o->actions = g_slist_prepend(o->actions,
87                                      actions_parse_string("Unshade"));
88     }
89
90     return o;
91 }
92
93 static gpointer setup_forward_func(ObParseInst *i, xmlDocPtr doc,
94                                    xmlNodePtr node)
95 {
96     Options *o = setup_func(i, doc, node);
97     o->forward = TRUE;
98     return o;
99 }
100
101 static gpointer setup_backward_func(ObParseInst *i, xmlDocPtr doc,
102                                     xmlNodePtr node)
103 {
104     Options *o = setup_func(i, doc, node);
105     o->forward = FALSE;
106     return o;
107 }
108
109 static void free_func(gpointer options)
110 {
111     Options *o = options;
112
113     while (o->actions) {
114         actions_act_unref(o->actions->data);
115         o->actions = g_slist_delete_link(o->actions, o->actions);
116     }
117
118     g_free(o);
119 }
120
121 static gboolean run_func(ObActionsData *data, gpointer options)
122 {
123     Options *o = options;
124     struct _ObClient *ft;
125
126     ft = focus_cycle(o->forward,
127                      o->all_desktops,
128                      o->dock_windows,
129                      o->desktop_windows,
130                      o->linear,
131                      TRUE,
132                      o->bar,
133                      o->dialog,
134                      FALSE, FALSE);
135     cycling = TRUE;
136
137     stacking_restore();
138     if (o->raise && ft) stacking_temp_raise(CLIENT_AS_WINDOW(ft));
139
140     return TRUE;
141 }
142
143 static gboolean i_input_func(guint initial_state,
144                              XEvent *e,
145                              gpointer options,
146                              gboolean *used)
147 {
148     if (e->type == KeyPress) {
149         /* Escape cancels no matter what */
150         if (e->xkey.keycode == ob_keycode(OB_KEY_ESCAPE)) {
151             end_cycle(TRUE, e->xkey.state, options);
152             return FALSE;
153         }
154
155         /* There were no modifiers and they pressed enter */
156         else if (e->xkey.keycode == ob_keycode(OB_KEY_RETURN) &&
157                  !initial_state)
158         {
159             end_cycle(FALSE, e->xkey.state, options);
160             return FALSE;
161         }
162     }
163     /* They released the modifiers */
164     else if (e->type == KeyRelease && initial_state &&
165              (e->xkey.state & initial_state) == 0)
166     {
167         end_cycle(FALSE, e->xkey.state, options);
168         return FALSE;
169     }
170
171     return TRUE;
172 }
173
174 static void i_cancel_func(gpointer options)
175 {
176     /* we get cancelled when we move focus, but we're not cycling anymore, so
177        just ignore that */
178     if (cycling)
179         end_cycle(TRUE, 0, options);
180 }
181
182 static void end_cycle(gboolean cancel, guint state, Options *o)
183 {
184     struct _ObClient *ft;
185
186     ft = focus_cycle(o->forward,
187                      o->all_desktops,
188                      o->dock_windows,
189                      o->desktop_windows,
190                      o->linear,
191                      TRUE,
192                      o->bar,
193                      o->dialog,
194                      TRUE, cancel);
195     cycling = FALSE;
196
197     if (ft)
198         actions_run_acts(o->actions, OB_USER_ACTION_KEYBOARD_KEY,
199                          state, -1, -1, 0, OB_FRAME_CONTEXT_NONE, ft);
200
201     stacking_restore();
202 }