]> Dogcows Code - chaz/openbox/blob - plugins/keyboard/keyboard.c
45b93ac434d6082f21d0009a2dc546e7aa36a83a
[chaz/openbox] / plugins / keyboard / keyboard.c
1 #include "kernel/focus.h"
2 #include "kernel/frame.h"
3 #include "kernel/dispatch.h"
4 #include "kernel/openbox.h"
5 #include "kernel/event.h"
6 #include "kernel/grab.h"
7 #include "kernel/action.h"
8 #include "kernel/prop.h"
9 #include "kernel/timer.h"
10 #include "parser/parse.h"
11 #include "tree.h"
12 #include "keyboard.h"
13 #include "translate.h"
14 #include <glib.h>
15
16 /*
17
18 <keybind key="C-x">
19 <action name="ChangeDesktop">
20 <desktop>3</desktop>
21 </action>
22 </keybind>
23
24 */
25
26 static void parse_key(xmlDocPtr doc, xmlNodePtr node, GList *keylist)
27 {
28 char *key;
29 Action *action;
30 xmlNodePtr n, nact;
31 GList *it;
32
33 n = parse_find_node("keybind", node);
34 while (n) {
35 if (parse_attr_string("key", n, &key)) {
36 keylist = g_list_append(keylist, key);
37
38 parse_key(doc, n->xmlChildrenNode, keylist);
39
40 it = g_list_last(keylist);
41 g_free(it->data);
42 keylist = g_list_delete_link(keylist, it);
43 }
44 n = parse_find_node("keybind", n->next);
45 }
46 if (keylist) {
47 nact = parse_find_node("action", node);
48 while (nact) {
49 if ((action = action_parse(doc, nact))) {
50 /* validate that its okay for a key binding */
51 if (action->func == action_moveresize &&
52 action->data.moveresize.corner !=
53 prop_atoms.net_wm_moveresize_move_keyboard &&
54 action->data.moveresize.corner !=
55 prop_atoms.net_wm_moveresize_size_keyboard) {
56 action_free(action);
57 action = NULL;
58 }
59
60 if (action)
61 kbind(keylist, action);
62 }
63 nact = parse_find_node("action", nact->next);
64 }
65 }
66 }
67
68 static void parse_xml(xmlDocPtr doc, xmlNodePtr node, void *d)
69 {
70 parse_key(doc, node, NULL);
71 }
72
73 void plugin_setup_config()
74 {
75 parse_register("keyboard", parse_xml, NULL);
76 }
77
78 KeyBindingTree *firstnode = NULL;
79
80 static KeyBindingTree *curpos;
81 static guint reset_key, reset_state;
82 static Timer *chain_timer;
83
84 static void grab_for_window(Window win, gboolean grab)
85 {
86 KeyBindingTree *p;
87
88 ungrab_all_keys(win);
89
90 if (grab) {
91 p = curpos ? curpos->first_child : firstnode;
92 while (p) {
93 grab_key(p->key, p->state, win, GrabModeAsync);
94 p = p->next_sibling;
95 }
96 if (curpos)
97 grab_key(reset_key, reset_state, win, GrabModeAsync);
98 }
99 }
100
101 static void grab_keys(gboolean grab)
102 {
103 GList *it;
104
105 grab_for_window(focus_backup, grab);
106 for (it = client_list; it; it = g_list_next(it))
107 grab_for_window(((Client*)it->data)->frame->window, grab);
108 }
109
110 static void reset_chains()
111 {
112 if (chain_timer) {
113 timer_stop(chain_timer);
114 chain_timer = NULL;
115 }
116 if (curpos) {
117 curpos = NULL;
118 grab_keys(TRUE);
119 }
120 }
121
122 static void chain_timeout(void *data)
123 {
124 reset_chains();
125 }
126
127 gboolean kbind(GList *keylist, Action *action)
128 {
129 KeyBindingTree *tree, *t;
130 gboolean conflict;
131
132 g_assert(keylist != NULL);
133 g_assert(action != NULL);
134
135 if (!(tree = tree_build(keylist)))
136 return FALSE;
137
138 if ((t = tree_find(tree, &conflict)) != NULL) {
139 /* already bound to something, use the existing tree */
140 tree_destroy(tree);
141 tree = NULL;
142 } else
143 t = tree;
144 while (t->first_child) t = t->first_child;
145
146 if (conflict) {
147 g_message("conflict with binding");
148 tree_destroy(tree);
149 return FALSE;
150 }
151
152 /* set the action */
153 t->actions = g_slist_append(t->actions, action);
154 /* assimilate this built tree into the main tree. assimilation
155 destroys/uses the tree */
156 if (tree) tree_assimilate(tree);
157
158 return TRUE;
159 }
160
161 static void event(ObEvent *e, void *foo)
162 {
163 static KeyBindingTree *grabbed_key = NULL;
164
165 if (e->type == Event_Client_Mapped) {
166 grab_for_window(e->data.c.client->window, TRUE);
167 return;
168 } else if (e->type == Event_Client_Destroy) {
169 grab_for_window(e->data.c.client->window, FALSE);
170 return;
171 }
172
173 if (grabbed_key) {
174 gboolean done = FALSE;
175
176 if ((e->type == Event_X_KeyRelease &&
177 !(grabbed_key->state & e->data.x.e->xkey.state)))
178 done = TRUE;
179 else if (e->type == Event_X_KeyPress) {
180 if (e->data.x.e->xkey.keycode == ob_keycode(OB_KEY_RETURN))
181 done = TRUE;
182 else if (e->data.x.e->xkey.keycode == ob_keycode(OB_KEY_ESCAPE)) {
183 GSList *it;
184 for (it = grabbed_key->actions; it; it = it->next) {
185 Action *act = it->data;
186 act->data.cycle.cancel = TRUE;
187 }
188 done = TRUE;
189 }
190 }
191 if (done) {
192 GSList *it;
193 for (it = grabbed_key->actions; it; it = it->next) {
194 Action *act = it->data;
195 act->data.cycle.final = TRUE;
196 act->func(&act->data);
197 }
198 grabbed_key = NULL;
199 grab_keyboard(FALSE);
200 reset_chains();
201 return;
202 }
203 }
204 if (e->type == Event_X_KeyRelease)
205 return;
206
207 g_assert(e->type == Event_X_KeyPress);
208
209 if (e->data.x.e->xkey.keycode == reset_key &&
210 e->data.x.e->xkey.state == reset_state) {
211 reset_chains();
212 } else {
213 KeyBindingTree *p;
214 if (curpos == NULL)
215 p = firstnode;
216 else
217 p = curpos->first_child;
218 while (p) {
219 if (p->key == e->data.x.e->xkey.keycode &&
220 p->state == e->data.x.e->xkey.state) {
221 if (p->first_child != NULL) { /* part of a chain */
222 if (chain_timer) timer_stop(chain_timer);
223 /* 5 second timeout for chains */
224 chain_timer = timer_start(5000*1000, chain_timeout,
225 NULL);
226 curpos = p;
227 grab_keys(TRUE);
228 } else {
229 GSList *it;
230 for (it = p->actions; it; it = it->next) {
231 Action *act = it->data;
232 if (act->func != NULL) {
233 act->data.any.c = focus_client;
234
235 if (act->func == action_cycle_windows) {
236 act->data.cycle.final = FALSE;
237 act->data.cycle.cancel = FALSE;
238 }
239
240 if (act->func == action_cycle_windows &&
241 !grabbed_key && grab_keyboard(TRUE)) {
242 grabbed_key = p;
243 }
244
245 act->data.any.c = focus_client;
246 act->func(&act->data);
247 }
248 }
249
250 reset_chains();
251 }
252 break;
253 }
254 p = p->next_sibling;
255 }
256 }
257 }
258
259 void plugin_startup()
260 {
261 curpos = NULL;
262 chain_timer = NULL;
263
264 dispatch_register(Event_Client_Mapped | Event_Client_Destroy |
265 Event_X_KeyPress | Event_X_KeyRelease,
266 (EventHandler)event, NULL);
267
268 translate_key("C-g", &reset_state, &reset_key);
269
270 grab_keys(TRUE);
271 }
272
273 void plugin_shutdown()
274 {
275 dispatch_register(0, (EventHandler)event, NULL);
276
277 tree_destroy(firstnode);
278 firstnode = NULL;
279 grab_keys(FALSE);
280 }
281
This page took 0.042678 seconds and 3 git commands to generate.