use CurrentTime again?
[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 "keysrc.h"
9 #include "translate.h"
10 #include <glib.h>
11
12 void plugin_setup_config()
13 {
14 }
15
16 KeyBindingTree *firstnode;
17
18 static KeyBindingTree *curpos;
19 static guint reset_key, reset_state;
20 static gboolean grabbed;
21
22 static void grab_keys(gboolean grab)
23 {
24     if (!grab) {
25         ungrab_all_keys();
26     } else {
27         KeyBindingTree *p = firstnode;
28         while (p) {
29             grab_key(p->key, p->state, GrabModeSync);
30             p = p->next_sibling;
31         }
32     }
33 }
34
35 static void reset_chains()
36 {
37     /* XXX kill timer */
38     curpos = NULL;
39     if (grabbed) {
40         grabbed = FALSE;
41         grab_keyboard(FALSE);
42     } else
43         XAllowEvents(ob_display, AsyncKeyboard, CurrentTime);
44 }
45
46 gboolean kbind(GList *keylist, Action *action)
47 {
48     KeyBindingTree *tree, *t;
49     gboolean conflict;
50
51     g_assert(keylist != NULL);
52     g_assert(action != NULL);
53
54     if (!(tree = tree_build(keylist)))
55         return FALSE;
56     if ((t = tree_find(tree, &conflict)) != NULL) {
57         /* already bound to something */
58         g_warning("keychain is already bound");
59         tree_destroy(tree);
60         return FALSE;
61     }
62     if (conflict) {
63         g_warning("conflict with binding");
64         tree_destroy(tree);
65         return FALSE;
66     }
67
68     /* grab the server here to make sure no key presses go missed */
69     grab_server(TRUE);
70     grab_keys(FALSE);
71
72     /* set the action */
73     t = tree;
74     while (t->first_child) t = t->first_child;
75     t->action = action;
76     /* assimilate this built tree into the main tree. assimilation
77        destroys/uses the tree */
78     tree_assimilate(tree);
79
80     grab_keys(TRUE); 
81     grab_server(FALSE);
82
83     return TRUE;
84 }
85
86 static void press(ObEvent *e, void *foo)
87 {
88     if (e->data.x.e->xkey.keycode == reset_key &&
89         e->data.x.e->xkey.state == reset_state) {
90         reset_chains();
91     } else {
92         KeyBindingTree *p;
93         if (curpos == NULL)
94             p = firstnode;
95         else
96             p = curpos->first_child;
97         while (p) {
98             if (p->key == e->data.x.e->xkey.keycode &&
99                 p->state == e->data.x.e->xkey.state) {
100                 if (p->first_child != NULL) { /* part of a chain */
101                     /* XXX TIMER */
102                     if (!grabbed) {
103                         grab_keyboard(TRUE);
104                         grabbed = TRUE;
105                         XAllowEvents(ob_display, AsyncKeyboard, CurrentTime);
106                     }
107                     curpos = p;
108                 } else {
109                     if (p->action->func != NULL) {
110                         p->action->data.any.c = focus_client;
111
112                         g_assert(!(p->action->func == action_move ||
113                                    p->action->func == action_resize));
114
115                         p->action->func(&p->action->data);
116                     }
117
118                     reset_chains();
119                 }
120                 break;
121             }
122             p = p->next_sibling;
123         }
124     }
125 }
126
127 void plugin_startup()
128 {
129     dispatch_register(Event_X_KeyPress, (EventHandler)press, NULL);
130
131     translate_key("C-g", &reset_state, &reset_key);
132
133     keysrc_parse();
134 }
135
136 void plugin_shutdown()
137 {
138     dispatch_register(0, (EventHandler)press, NULL);
139
140     grab_keys(FALSE);
141     tree_destroy(firstnode);
142     firstnode = NULL;
143     grab_keys(TRUE);
144 }
145