load keybindings from keysrc
[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 <glib.h>
10
11 void plugin_setup_config()
12 {
13 }
14
15 KeyBindingTree *firstnode;
16
17 static KeyBindingTree *curpos;
18 static guint reset_key, reset_state;
19 static gboolean grabbed;
20
21 static void grab_keys(gboolean grab)
22 {
23     if (!grab) {
24         ungrab_all_keys();
25     } else {
26         KeyBindingTree *p = firstnode;
27         while (p) {
28             grab_key(p->key, p->state, GrabModeSync);
29             p = p->next_sibling;
30         }
31     }
32 }
33
34 static void reset_chains()
35 {
36     /* XXX kill timer */
37     curpos = NULL;
38     if (grabbed) {
39         grabbed = FALSE;
40         grab_keyboard(FALSE);
41     }
42 }
43
44 gboolean kbind(GList *keylist, Action *action)
45 {
46     KeyBindingTree *tree, *t;
47     gboolean conflict;
48
49     g_assert(keylist != NULL);
50     g_assert(action != NULL);
51
52     if (!(tree = tree_build(keylist))) {
53         g_warning("invalid binding");
54         return FALSE;
55     }
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                     }
106                     curpos = p;
107                 } else {
108                     if (p->action->func != NULL) {
109                         p->action->data.any.c = focus_client;
110
111                         g_assert(!(p->action->func == action_move ||
112                                    p->action->func == action_resize));
113
114                         p->action->func(&p->action->data);
115                     }
116
117                     reset_chains();
118                 }
119                 break;
120             }
121             p = p->next_sibling;
122         }
123     }
124     XAllowEvents(ob_display, AsyncKeyboard, e->data.x.e->xkey.time);
125 }
126
127 void plugin_startup()
128 {
129     dispatch_register(Event_X_KeyPress, (EventHandler)press, NULL);
130
131     keysrc_parse();
132 }
133
134 void plugin_shutdown()
135 {
136     dispatch_register(0, (EventHandler)press, NULL);
137
138     grab_keys(FALSE);
139     tree_destroy(firstnode);
140     firstnode = NULL;
141     grab_keys(TRUE);
142 }
143