]> Dogcows Code - chaz/openbox/blob - openbox/keyboard.c
42eea890b2fea4add7c442baf05b55324ea8c5a5
[chaz/openbox] / openbox / keyboard.c
1 #include "focus.h"
2 #include "screen.h"
3 #include "frame.h"
4 #include "openbox.h"
5 #include "event.h"
6 #include "grab.h"
7 #include "client.h"
8 #include "action.h"
9 #include "prop.h"
10 #include "timer.h"
11 #include "config.h"
12 #include "keytree.h"
13 #include "keyboard.h"
14 #include "translate.h"
15
16 #include <glib.h>
17
18 KeyBindingTree *keyboard_firstnode;
19
20 typedef struct {
21 guint state;
22 ObClient *client;
23 ObAction *action;
24 ObFrameContext context;
25 } ObInteractiveState;
26
27 static GSList *interactive_states;
28
29 static KeyBindingTree *curpos;
30 static ObTimer *chain_timer;
31
32 static void grab_for_window(Window win, gboolean grab)
33 {
34 KeyBindingTree *p;
35
36 ungrab_all_keys(win);
37
38 if (grab) {
39 p = curpos ? curpos->first_child : keyboard_firstnode;
40 while (p) {
41 grab_key(p->key, p->state, win, GrabModeAsync);
42 p = p->next_sibling;
43 }
44 if (curpos)
45 grab_key(config_keyboard_reset_keycode,
46 config_keyboard_reset_state,
47 win, GrabModeAsync);
48 }
49 }
50
51 void keyboard_grab_for_client(ObClient *c, gboolean grab)
52 {
53 grab_for_window(c->window, grab);
54 }
55
56 static void grab_keys(gboolean grab)
57 {
58 GList *it;
59
60 grab_for_window(screen_support_win, grab);
61 for (it = client_list; it; it = g_list_next(it))
62 grab_for_window(((ObClient*)it->data)->frame->window, grab);
63 }
64
65 void keyboard_reset_chains()
66 {
67 if (chain_timer) {
68 timer_stop(chain_timer);
69 chain_timer = NULL;
70 }
71 if (curpos) {
72 curpos = NULL;
73 grab_keys(TRUE);
74 }
75 }
76
77 static void chain_timeout(ObTimer *t, void *data)
78 {
79 keyboard_reset_chains();
80 }
81
82 gboolean keyboard_bind(GList *keylist, ObAction *action)
83 {
84 KeyBindingTree *tree, *t;
85 gboolean conflict;
86
87 g_assert(keylist != NULL);
88 g_assert(action != NULL);
89
90 if (!(tree = tree_build(keylist)))
91 return FALSE;
92
93 if ((t = tree_find(tree, &conflict)) != NULL) {
94 /* already bound to something, use the existing tree */
95 tree_destroy(tree);
96 tree = NULL;
97 } else
98 t = tree;
99 while (t->first_child) t = t->first_child;
100
101 if (conflict) {
102 g_warning("conflict with binding");
103 tree_destroy(tree);
104 return FALSE;
105 }
106
107 /* set the action */
108 t->actions = g_slist_append(t->actions, action);
109 /* assimilate this built tree into the main tree. assimilation
110 destroys/uses the tree */
111 if (tree) tree_assimilate(tree);
112
113 return TRUE;
114 }
115
116 void keyboard_interactive_grab(guint state, ObClient *client,
117 ObFrameContext context, ObAction *action)
118 {
119 ObInteractiveState *s;
120
121 if (!interactive_states) {
122 if (!grab_keyboard(TRUE))
123 return;
124 if (!grab_pointer(TRUE, None)) {
125 grab_keyboard(FALSE);
126 return;
127 }
128 }
129
130 s = g_new(ObInteractiveState, 1);
131
132 s->state = state;
133 s->client = client;
134 s->action = action;
135 s->context = context;
136
137 interactive_states = g_slist_append(interactive_states, s);
138 }
139
140 gboolean keyboard_process_interactive_grab(const XEvent *e,
141 ObClient **client,
142 ObFrameContext *context)
143 {
144 GSList *it, *next;
145 gboolean handled = FALSE;
146 gboolean done = FALSE;
147 gboolean cancel = FALSE;
148
149 for (it = interactive_states; it; it = next) {
150 ObInteractiveState *s = it->data;
151
152 next = g_slist_next(it);
153
154 *client = s->client;
155 *context = s->context;
156
157 if ((e->type == KeyRelease &&
158 !(s->state & e->xkey.state)))
159 done = TRUE;
160 else if (e->type == KeyPress) {
161 if (e->xkey.keycode == ob_keycode(OB_KEY_RETURN))
162 done = TRUE;
163 else if (e->xkey.keycode == ob_keycode(OB_KEY_ESCAPE))
164 cancel = done = TRUE;
165 }
166 if (done) {
167 if (s->action->func == action_cycle_windows) {
168 s->action->data.cycle.cancel = cancel;
169 s->action->data.cycle.final = TRUE;
170 }
171 if (s->action->func == action_desktop_dir) {
172 s->action->data.desktopdir.cancel = cancel;
173 s->action->data.desktopdir.final = TRUE;
174 }
175 if (s->action->func == action_send_to_desktop_dir) {
176 s->action->data.sendtodir.cancel = cancel;
177 s->action->data.sendtodir.final = TRUE;
178 }
179
180 s->action->func(&s->action->data);
181
182 grab_keyboard(FALSE);
183 grab_pointer(FALSE, None);
184 keyboard_reset_chains();
185
186 g_free(s);
187 interactive_states = g_slist_delete_link(interactive_states, it);
188 handled = TRUE;
189 }
190 }
191
192 return handled;
193 }
194
195 void keyboard_event(ObClient *client, const XEvent *e)
196 {
197 KeyBindingTree *p;
198
199 g_assert(e->type == KeyPress);
200
201 if (e->xkey.keycode == config_keyboard_reset_keycode &&
202 e->xkey.state == config_keyboard_reset_state)
203 {
204 keyboard_reset_chains();
205 return;
206 }
207
208 if (curpos == NULL)
209 p = keyboard_firstnode;
210 else
211 p = curpos->first_child;
212 while (p) {
213 if (p->key == e->xkey.keycode &&
214 p->state == e->xkey.state) {
215 if (p->first_child != NULL) { /* part of a chain */
216 if (chain_timer) timer_stop(chain_timer);
217 /* 5 second timeout for chains */
218 chain_timer = timer_start(5000*1000, chain_timeout,
219 NULL);
220 curpos = p;
221 grab_keys(TRUE);
222 } else {
223 GSList *it;
224 for (it = p->actions; it; it = it->next) {
225 ObAction *act = it->data;
226 if (act->func != NULL) {
227 act->data.any.c = client;
228
229 if (act->func == action_cycle_windows)
230 {
231 act->data.cycle.final = FALSE;
232 act->data.cycle.cancel = FALSE;
233 }
234 if (act->func == action_desktop_dir)
235 {
236 act->data.desktopdir.final = FALSE;
237 act->data.desktopdir.cancel = FALSE;
238 }
239 if (act->func == action_send_to_desktop_dir)
240 {
241 act->data.sendtodir.final = FALSE;
242 act->data.sendtodir.cancel = FALSE;
243 }
244
245 if (act->func == action_moveresize)
246 {
247 screen_pointer_pos(&act->data.moveresize.x,
248 &act->data.moveresize.y);
249 }
250
251 if ((act->func == action_cycle_windows ||
252 act->func == action_desktop_dir ||
253 act->func == action_send_to_desktop_dir))
254 {
255 keyboard_interactive_grab(e->xkey.state, client,
256 0, act);
257 }
258
259 if (act->func == action_showmenu)
260 {
261 act->data.showmenu.x = e->xkey.x_root;
262 act->data.showmenu.y = e->xkey.y_root;
263 }
264
265 act->data.any.c = client;
266 act->func(&act->data);
267 }
268 }
269
270 keyboard_reset_chains();
271 }
272 break;
273 }
274 p = p->next_sibling;
275 }
276 }
277
278 void keyboard_startup()
279 {
280 grab_keys(TRUE);
281 }
282
283 void keyboard_shutdown()
284 {
285 tree_destroy(keyboard_firstnode);
286 keyboard_firstnode = NULL;
287 grab_keys(FALSE);
288 }
289
This page took 0.0427689999999999 seconds and 3 git commands to generate.