Add support for the zoomed state to managed windows.
[gwm.git] / keyboard.c
blob29a7983de094dde039d050a64ebd2bfde1048dec
1 /*
2 * keyboard.c
4 * Part of gwm, the Gratuitous Window Manager,
5 * by Gary Wong, <gtw@gnu.org>.
7 * Copyright (C) 2009 Gary Wong
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of version 3 of the GNU General Public License as
11 * published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 * $Id$
24 #include <config.h>
26 #include <assert.h>
27 #include <stdlib.h>
28 #include <xcb/xcb.h>
30 #include "gwm.h"
32 #include "actions.h"
33 #include "keyboard.h"
35 enum _keysym {
36 /* See X Window System Protocol (version 11, release 6.7), Appendix A. */
37 KEYSYM_TAB = 0xFF09,
38 KEYSYM_MENU = 0xFF67,
39 KEYSYM_NUM_LOCK = 0xFF7F,
40 KEYSYM_F1 = 0xFFBE,
41 KEYSYM_F2 = 0xFFBF,
42 KEYSYM_F3 = 0xFFC0,
43 KEYSYM_F4 = 0xFFC1,
44 KEYSYM_F5 = 0xFFC2,
45 KEYSYM_F6 = 0xFFC3,
46 KEYSYM_F7 = 0xFFC4,
47 KEYSYM_F8 = 0xFFC5,
48 KEYSYM_F9 = 0xFFC6,
49 KEYSYM_F10 = 0xFFC7,
50 KEYSYM_F11 = 0xFFC8,
51 KEYSYM_F12 = 0xFFC9,
52 KEYSYM_SHIFT_L = 0xFFE1,
53 KEYSYM_SHIFT_R = 0xFFE2,
54 KEYSYM_CONTROL_L = 0xFFE3,
55 KEYSYM_CONTROL_R = 0xFFE4,
56 KEYSYM_CAPS_LOCK = 0xFFE5,
57 KEYSYM_SHIFT_LOCK = 0xFFE6,
58 KEYSYM_META_L = 0xFFE7,
59 KEYSYM_META_R = 0xFFE8,
60 KEYSYM_ALT_L = 0xFFE9,
61 KEYSYM_ALT_R = 0xFFEA
64 /* Map of keysyms: first index is keycode, second index is group/modifier. */
65 xcb_keysym_t keyboard_map[ 0x100 ][ 4 ];
66 /* Map of modifiers, indexed by xcb_map_index_t. */
67 xcb_keycode_t *modifier_map[ 8 ];
69 const struct key_action key_actions[] = {
70 /* FIXME This table should be configurable, of course. */
71 { KEYSYM_TAB, XCB_MOD_MASK_1, action_raise_lowest },
72 { KEYSYM_F1, XCB_MOD_MASK_1, action_iconify_window },
73 { KEYSYM_F5, XCB_MOD_MASK_1, action_stack_opposite },
74 { KEYSYM_F10, XCB_MOD_MASK_1, action_max_window }
76 const int num_key_actions = sizeof key_actions / sizeof *key_actions;
78 static void establish_grabs( void ) {
80 int populated, i, j, screen, lock, num_lock;
82 populated = FALSE;
83 lock = num_lock = -1;
84 for( i = 0; i < 8; i++ )
85 if( modifier_map[ i ] ) {
86 populated = TRUE;
88 for( j = 0; modifier_map[ i ][ j ]; j++ )
89 if( keyboard_map[ modifier_map[ i ][ j ] ][ 0 ] ==
90 KEYSYM_CAPS_LOCK ||
91 keyboard_map[ modifier_map[ i ][ j ] ][ 0 ] ==
92 KEYSYM_SHIFT_LOCK )
93 lock = i;
94 else if( keyboard_map[ modifier_map[ i ][ j ] ][ 0 ] ==
95 KEYSYM_NUM_LOCK )
96 num_lock = i;
99 if( !populated )
100 /* The modifier map is unpopulated: there's nothing we can do yet,
101 and we'll be invoked again later once there is. */
102 return;
104 for( screen = 0; screen < num_screens; screen++ ) {
105 /* Undo any previous grabs. */
106 xcb_ungrab_key( c, XCB_GRAB_ANY, screens[ screen ]->root,
107 XCB_GRAB_ANY );
109 for( i = 0; i < num_key_actions; i++ ) {
110 for( j = 0; j < 0x100 &&
111 keyboard_map[ j ][ 0 ] != key_actions[ i ].keysym; j++ )
114 if( j >= 0x100 )
115 /* No key is currently bound to keysym; omit this action. */
116 continue;
118 xcb_grab_key( c, FALSE, screens[ screen ]->root,
119 key_actions[ i ].modifiers, j, XCB_GRAB_MODE_ASYNC,
120 XCB_GRAB_MODE_ASYNC );
122 if( lock >= 0 )
123 xcb_grab_key( c, FALSE, screens[ screen ]->root,
124 key_actions[ i ].modifiers | ( 1 << lock ),
125 j, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC );
127 if( num_lock >= 0 )
128 xcb_grab_key( c, FALSE, screens[ screen ]->root,
129 key_actions[ i ].modifiers | ( 1 << num_lock ),
130 j, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC );
132 if( lock >= 0 && num_lock >= 0 )
133 xcb_grab_key( c, FALSE, screens[ screen ]->root,
134 key_actions[ i ].modifiers | ( 1 << lock ) |
135 ( 1 << num_lock ), j, XCB_GRAB_MODE_ASYNC,
136 XCB_GRAB_MODE_ASYNC );
141 static void handle_get_keyboard_mapping( unsigned int sequence, void *reply,
142 xcb_generic_error_t *error,
143 union callback_param cp ) {
145 if( error ) {
146 show_error( error );
148 free( error );
151 if( reply ) {
152 xcb_get_keyboard_mapping_reply_t *r = reply;
153 xcb_keysym_t *in, *out;
154 int i, j, syms_used, count = r->length / r->keysyms_per_keycode;
156 syms_used = r->keysyms_per_keycode < 4 ? r->keysyms_per_keycode : 4;
158 in = xcb_get_keyboard_mapping_keysyms( r );
159 out = keyboard_map[ cp.l ];
161 for( i = 0; i < count; i++ ) {
162 for( j = 0; j < syms_used; j++ )
163 *out++ = *in++;
164 for( ; j < 4; j++ )
165 *out++ = XCB_NONE;
166 if( r->keysyms_per_keycode > 4 )
167 in += r->keysyms_per_keycode - 4;
170 free( reply );
172 establish_grabs();
176 extern void get_keyboard_mapping( int first, int count ) {
178 union callback_param cp;
180 cp.l = first;
181 handle_async_reply( xcb_get_keyboard_mapping( c, first, count ).sequence,
182 handle_get_keyboard_mapping, cp );
185 static void handle_get_modifier_mapping( unsigned int sequence, void *reply,
186 xcb_generic_error_t *error,
187 union callback_param cp ) {
189 xcb_keycode_t *in, *out;
190 xcb_get_modifier_mapping_reply_t *r;
191 int i, j, codes_used;
193 assert( !error ); /* the protocol defines no error conditions... */
194 assert( reply ); /* ...so we should always get a valid response */
196 r = reply;
198 codes_used = r->keycodes_per_modifier < 8 ? r->keycodes_per_modifier : 8;
200 in = xcb_get_modifier_mapping_keycodes( r );
202 for( i = 0; i < 8; i++, in += r->keycodes_per_modifier ) {
203 if( modifier_map[ i ] )
204 free( modifier_map[ i ] );
206 for( codes_used = 0, j = 0; j < r->keycodes_per_modifier; j++ )
207 if( in[ j ] )
208 codes_used++;
210 if( codes_used ) {
211 modifier_map[ i ] = out = xmalloc( ( codes_used + 1 ) *
212 sizeof *out );
214 for( j = 0; j < r->keycodes_per_modifier; j++ )
215 if( in[ j ] )
216 *out++ = in[ j ];
218 *out = 0;
219 } else
220 modifier_map[ i ] = NULL;
223 free( reply );
225 establish_grabs();
228 extern void get_modifier_mapping( void ) {
230 union callback_param cp;
232 cp.l = 0;
233 handle_async_reply( xcb_get_modifier_mapping( c ).sequence,
234 handle_get_modifier_mapping, cp );
237 #if DEBUG
238 extern void cleanup_keyboard( void ) {
240 int i;
242 for( i = 0; i < 8; i++ )
243 if( modifier_map[ i ] )
244 free( modifier_map[ i ] );
246 #endif