]> icculus.org git repositories - dana/openbox.git/blob - plugins/keyboard/keyboard.c
grab the keyboard not the server!
[dana/openbox.git] / plugins / keyboard / keyboard.c
1 #include "../../kernel/focus.h"
2 #include "../../kernel/dispatch.h"
3 #include "../../kernel/openbox.h"
4 #include "../../kernel/grab.h"
5 #include "../../kernel/action.h"
6 #include "tree.h"
7 #include "keyboard.h"
8 #include "keyaction.h"
9 #include <glib.h>
10
11 KeyBindingTree *firstnode;
12
13 static KeyBindingTree *curpos;
14 static guint reset_key, reset_state;
15 static gboolean grabbed;
16
17 static void grab_keys(gboolean grab)
18 {
19     if (!grab) {
20         XUngrabKey(ob_display, AnyKey, AnyModifier, ob_root);
21     } else {
22         KeyBindingTree *p = firstnode;
23         while (p) {
24             XGrabKey(ob_display, p->key, p->state, ob_root, FALSE,
25                      GrabModeAsync, GrabModeSync);
26             p = p->next_sibling;
27         }
28     }
29 }
30
31 static void reset_chains()
32 {
33     /* XXX kill timer */
34     curpos = NULL;
35     if (grabbed) {
36         grabbed = FALSE;
37         grab_keyboard(FALSE);
38     }
39 }
40
41 static void clearall()
42 {
43     grab_keys(FALSE);
44     tree_destroy(firstnode);
45     firstnode = NULL;
46     grab_keys(TRUE);
47 }
48
49 static gboolean bind(GList *keylist, KeyAction *action)
50 {
51     KeyBindingTree *tree, *t;
52     gboolean conflict;
53
54     if (!(tree = tree_build(keylist))) {
55         g_warning("invalid binding");
56         return FALSE;
57     }
58
59     t = tree_find(tree, &conflict);
60     if (conflict) {
61         g_warning("conflict with binding");
62         tree_destroy(tree);
63         return FALSE;
64     }
65     if (t != NULL) {
66         /* already bound to something */
67         g_warning("keychain is already bound");
68         tree_destroy(tree);
69         return FALSE;
70     }
71
72     /* grab the server here to make sure no key pressed go missed */
73     grab_server(TRUE);
74
75     grab_keys(FALSE);
76
77     /* set the function */
78     t = tree;
79     while (t->first_child) t = t->first_child;
80     t->action.action = action->action;
81     t->action.type[0] = action->type[0];
82     t->action.type[1] = action->type[1];
83     t->action.data[0] = action->data[0];
84     t->action.data[1] = action->data[1];
85
86     /* assimilate this built tree into the main tree */
87     tree_assimilate(tree); /* assimilation destroys/uses the tree */
88
89     grab_keys(TRUE); 
90
91     grab_server(FALSE);
92
93     return TRUE;
94 }
95
96 static void press(ObEvent *e, void *foo)
97 {
98     if (e->data.x.e->xkey.keycode == reset_key &&
99         e->data.x.e->xkey.state == reset_state) {
100         reset_chains();
101         XAllowEvents(ob_display, AsyncKeyboard, CurrentTime);
102     } else {
103         KeyBindingTree *p;
104         if (curpos == NULL)
105             p = firstnode;
106         else
107             p = curpos->first_child;
108         while (p) {
109             if (p->key == e->data.x.e->xkey.keycode &&
110                 p->state == e->data.x.e->xkey.state) {
111                 if (p->first_child != NULL) { /* part of a chain */
112                     /* XXX TIMER */
113                     if (!grabbed) {
114                         grab_keyboard(TRUE);
115                         grabbed = TRUE;
116                         XAllowEvents(ob_display, AsyncKeyboard, CurrentTime);
117                     }
118                     curpos = p;
119                 } else {
120                     keyaction_do(&p->action, focus_client);
121
122                     XAllowEvents(ob_display, AsyncKeyboard, CurrentTime);
123                     reset_chains();
124                 }
125                 break;
126             }
127             p = p->next_sibling;
128         }
129     }
130 }
131
132 static void binddef()
133 {
134     GList *list = g_list_append(NULL, NULL);
135     KeyAction a;
136
137     list->data = "C-Right";
138     a.action = Action_NextDesktop;
139     keyaction_set_bool(&a, 0, TRUE);
140     keyaction_set_none(&a, 1);
141     bind(list, &a);
142
143     list->data = "C-Left";
144     a.action = Action_PreviousDesktop;
145     keyaction_set_bool(&a, 0, TRUE);
146     keyaction_set_none(&a, 1);
147     bind(list, &a);
148
149     list->data = "C-1";
150     a.action = Action_Desktop;
151     keyaction_set_uint(&a, 0, 0);
152     keyaction_set_none(&a, 1);
153     bind(list, &a);
154
155     list->data = "C-2";
156     a.action = Action_Desktop;
157     keyaction_set_uint(&a, 0, 1);
158     keyaction_set_none(&a, 1);
159     bind(list, &a);
160
161     list->data = "C-3";
162     a.action = Action_Desktop;
163     keyaction_set_uint(&a, 0, 2);
164     keyaction_set_none(&a, 1);
165     bind(list, &a);
166
167     list->data = "C-4";
168     a.action = Action_Desktop;
169     keyaction_set_uint(&a, 0, 3);
170     keyaction_set_none(&a, 1);
171     bind(list, &a);
172
173     list->data = "C-space";
174     a.action = Action_Execute;
175     keyaction_set_string(&a, 0, "xterm");
176     keyaction_set_none(&a, 1);
177     bind(list, &a);
178 }
179
180 void plugin_startup()
181 {
182     dispatch_register(Event_X_KeyPress, (EventHandler)press, NULL);
183
184     /* XXX parse config file! */
185     binddef();
186 }
187
188 void plugin_shutdown()
189 {
190     dispatch_register(0, (EventHandler)press, NULL);
191     clearall();
192 }
193