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