]> icculus.org git repositories - mikachu/openbox.git/blob - openbox/actions/cyclewindows.c
Merge branch 'work' into wip/mikabox
[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 "openbox/client.h"
8 #include "gettext.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 } Options;
21
22 static gboolean cycling = FALSE;
23
24 static gpointer setup_func(xmlNodePtr node);
25 static gpointer setup_forward_func(xmlNodePtr node);
26 static gpointer setup_backward_func(xmlNodePtr node);
27 static void     free_func(gpointer options);
28 static gboolean run_func(ObActionsData *data, gpointer options);
29 static gboolean i_input_func(guint initial_state,
30                              XEvent *e,
31                              gpointer options,
32                              gboolean *used);
33 static void     i_cancel_func(gpointer options);
34
35 static void     end_cycle(gboolean cancel, guint state, Options *o);
36
37 void action_cyclewindows_startup(void)
38 {
39     actions_register("NextWindow", setup_forward_func, free_func,
40                      run_func, i_input_func, i_cancel_func);
41     actions_register("PreviousWindow", setup_backward_func, free_func,
42                      run_func, i_input_func, i_cancel_func);
43 }
44
45 static gpointer setup_func(xmlNodePtr node)
46 {
47     xmlNodePtr n;
48     Options *o;
49
50     o = g_new0(Options, 1);
51     o->bar = TRUE;
52     o->dialog_mode = OB_FOCUS_CYCLE_POPUP_MODE_LIST;
53
54     if ((n = obt_parse_find_node(node, "linear")))
55         o->linear = obt_parse_node_bool(n);
56     if ((n = obt_parse_find_node(node, "dialog"))) {
57         if (obt_parse_node_contains(n, "none"))
58             o->dialog_mode = OB_FOCUS_CYCLE_POPUP_MODE_NONE;
59         else if (obt_parse_node_contains(n, "icons"))
60             o->dialog_mode = OB_FOCUS_CYCLE_POPUP_MODE_ICONS;
61     }
62     if ((n = obt_parse_find_node(node, "bar")))
63         o->bar = obt_parse_node_bool(n);
64     if ((n = obt_parse_find_node(node, "raise")))
65         o->raise = obt_parse_node_bool(n);
66     if ((n = obt_parse_find_node(node, "panels")))
67         o->dock_windows = obt_parse_node_bool(n);
68     if ((n = obt_parse_find_node(node, "desktop")))
69         o->desktop_windows = obt_parse_node_bool(n);
70     if ((n = obt_parse_find_node(node, "allDesktops")))
71         o->all_desktops = obt_parse_node_bool(n);
72
73     if ((n = obt_parse_find_node(node, "finalactions"))) {
74         xmlNodePtr m;
75
76         m = obt_parse_find_node(n->children, "action");
77         while (m) {
78             ObActionsAct *action = actions_parse(m);
79             if (action) o->actions = g_slist_append(o->actions, action);
80             m = obt_parse_find_node(m->next, "action");
81         }
82     }
83     else {
84         o->actions = g_slist_prepend(o->actions,
85                                      actions_parse_string("Focus"));
86         o->actions = g_slist_prepend(o->actions,
87                                      actions_parse_string("Raise"));
88         o->actions = g_slist_prepend(o->actions,
89                                      actions_parse_string("Unshade"));
90     }
91
92     return o;
93 }
94
95 static gpointer setup_forward_func(xmlNodePtr node)
96 {
97     Options *o = setup_func(node);
98     o->forward = TRUE;
99     return o;
100 }
101
102 static gpointer setup_backward_func(xmlNodePtr node)
103 {
104     Options *o = setup_func(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_mode,
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_mode,
194                      TRUE, cancel);
195     cycling = FALSE;
196
197     if (g_list_find(client_list, 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 }