|
|
1.1 root 1: /* $Id: gtk-keyboard.c,v 1.6 2003/10/16 02:48:23 fredette Exp $ */
2:
3: /* host/gtk/gtk-keyboard.c - GTK keyboard support: */
4:
5: /*
6: * Copyright (c) 2003 Matt Fredette
7: * All rights reserved.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. All advertising materials mentioning features or use of this software
18: * must display the following acknowledgement:
19: * This product includes software developed by Matt Fredette.
20: * 4. The name of the author may not be used to endorse or promote products
21: * derived from this software without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
27: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33: * POSSIBILITY OF SUCH DAMAGE.
34: */
35:
36: #include <tme/common.h>
37: _TME_RCSID("$Id: gtk-keyboard.c,v 1.6 2003/10/16 02:48:23 fredette Exp $");
38:
39: /* includes: */
40: #include "gtk-display.h"
41: #include <gdk/gdkkeysyms.h>
42:
43: /* macros: */
44:
45: /* types: */
46:
47: /* a GTK keysym: */
48: struct tme_gtk_keysym {
49:
50: /* the type of this keysym. this is either
51: TME_KEYBOARD_LOOKUP_FLAG_OK_DIRECT or
52: TME_KEYBOARD_LOOKUP_FLAG_OK_ALLOC, depending on whether or not
53: the keysym needed to be allocated: */
54: int tme_gtk_keysym_type;
55:
56: /* the keysym itself: */
57: tme_keyboard_keyval_t tme_gtk_keysym_keysym;
58: };
59:
60: /* if X11 support is present: */
61: #ifndef X_DISPLAY_MISSING
62:
63: /* includes: */
64: #include <gdk/gdkx.h>
65: #include <X11/Xlib.h>
66:
67: #if TME_KEYBOARD_EVENT_TIME_UNDEF != CurrentTime
68: #error "TME_KEYBOARD_EVENT_TIME_UNDEF and CurrentTime disagree"
69: #endif
70:
71: /* the X11 half of keyboard initialization: */
72: static void
73: _tme_gtk_keyboard_x11_new(struct tme_gtk_display *display)
74: {
75: struct tme_keyboard_buffer *buffer;
76: XModifierKeymap *modifier_keymap;
77: int x_modifier, modifier;
78: int keycode_to_modifier[(1 << (sizeof(KeyCode) * 8))];
79: tme_keyboard_keyval_t *modifier_keysyms[TME_KEYBOARD_MODIFIER_MAX + 1];
80: int modifier_keysyms_count[TME_KEYBOARD_MODIFIER_MAX + 1];
81: int keycode_min, keycode_max, keycode, keycode_i;
82: int keymap_width, keysym_i, keysym_j;
83: KeySym *keymap, keysym, keysym_cases[2];
84: const char *string;
85: struct tme_gtk_keysym *gtk_keysym;
86: int rc;
87:
88: /* get the keyboard buffer: */
89: buffer = display->tme_gtk_display_keyboard_buffer;
90:
91: /* note all keycodes that are attached to modifiers: */
92: for (keycode = 0;
93: keycode < (int) TME_ARRAY_ELS(keycode_to_modifier);
94: keycode++) {
95: keycode_to_modifier[keycode] = TME_KEYBOARD_MODIFIER_NONE;
96: }
97: modifier_keymap = XGetModifierMapping(GDK_DISPLAY());
98: for (x_modifier = 0;
99: x_modifier < 8;
100: x_modifier++) {
101:
102: /* turn this X modifier into a tme modifier: */
103: switch (x_modifier) {
104: case ShiftMapIndex: modifier = TME_KEYBOARD_MODIFIER_SHIFT ; break;
105: case LockMapIndex: modifier = TME_KEYBOARD_MODIFIER_LOCK ; break;
106: case ControlMapIndex: modifier = TME_KEYBOARD_MODIFIER_CONTROL ; break;
107: case Mod1MapIndex: modifier = TME_KEYBOARD_MODIFIER_MOD1 ; break;
108: case Mod2MapIndex: modifier = TME_KEYBOARD_MODIFIER_MOD2 ; break;
109: case Mod3MapIndex: modifier = TME_KEYBOARD_MODIFIER_MOD3 ; break;
110: case Mod4MapIndex: modifier = TME_KEYBOARD_MODIFIER_MOD4 ; break;
111: default: assert (FALSE);
112: case Mod5MapIndex: modifier = TME_KEYBOARD_MODIFIER_MOD5 ; break;
113: }
114:
115: /* note all keycodes that are attached to this modifier: */
116: for (keycode_i = 0;
117: keycode_i < modifier_keymap->max_keypermod;
118: keycode_i++) {
119: keycode = *(modifier_keymap->modifiermap
120: + (x_modifier * modifier_keymap->max_keypermod)
121: + keycode_i);
122: if (keycode != 0) {
123: keycode_to_modifier[keycode] = modifier;
124: }
125: }
126: }
127: XFreeModifiermap(modifier_keymap);
128:
129: /* get the keycode range: */
130: XDisplayKeycodes(GDK_DISPLAY(), &keycode_min, &keycode_max);
131:
132: /* get the keyboard mapping: */
133: keymap = XGetKeyboardMapping(GDK_DISPLAY(),
134: keycode_min,
135: (keycode_max - keycode_min) + 1,
136: &keymap_width);
137:
138: /* initialize the lists of modifiers to keysyms: */
139: memset (modifier_keysyms_count, 0, sizeof(modifier_keysyms_count));
140:
141: /* loop over the keycodes in the keyboard mapping: */
142: for (keycode = keycode_min;
143: keycode <= keycode_max;
144: keycode++) {
145:
146: /* if this keycode is attached to a modifier, we will take the
147: first keysym that this keycode maps to as the keysym attached
148: to the modifier: */
149: modifier = keycode_to_modifier[keycode];
150:
151: /* loop over the keysyms that this keycode can map to: */
152: for (keysym_i = 0;
153: keysym_i < keymap_width;
154: keysym_i++) {
155:
156: /* get this keysym: */
157: keysym = *(keymap
158: + ((keycode - keycode_min)
159: * keymap_width)
160: + keysym_i);
161:
162: /* ignore NoSymbol: */
163: if (keysym == NoSymbol) {
164: continue;
165: }
166:
167: /* get the upper- and lowercase versions of this keysym. if
168: this keysym has no case, this sets both keysym_cases[] values
169: to keysym: */
170: XConvertCase(keysym, &keysym_cases[0], &keysym_cases[1]);
171:
172: for (keysym_j = 0;
173: keysym_j < (int) TME_ARRAY_ELS(keysym_cases);
174: keysym_j++) {
175: keysym = keysym_cases[keysym_j];
176:
177: /* ignore any keysym that doesn't have a string
178: name that GDK knows as the same keysym: */
179: if ((string = XKeysymToString(keysym)) == NULL
180: || gdk_keyval_from_name(string) != keysym) {
181: continue;
182: }
183:
184: /* skip this keysym if it's already known: */
185: if (tme_hash_lookup(display->tme_gtk_display_keyboard_keysyms,
186: (tme_hash_data_t) string)
187: != (tme_hash_data_t) NULL) {
188:
189: /* if there is a keycode associated with this keysym,
190: remove it if it's different from this keycode: */
191: if (tme_hash_lookup(display->tme_gtk_display_keyboard_keysym_to_keycode,
192: (tme_hash_data_t) keysym)
193: != (tme_hash_data_t) keycode) {
194: tme_hash_remove(display->tme_gtk_display_keyboard_keysym_to_keycode,
195: (tme_hash_data_t) keysym);
196: }
197:
198: continue;
199: }
200:
201: /* if this keysym is attached to a modifier: */
202: if (modifier != TME_KEYBOARD_MODIFIER_NONE) {
203:
204: /* grow the modifier to keysyms list for this modifier.
205: this list always has an extra entry in it, for the
206: TME_KEYBOARD_KEYVAL_UNDEF that will terminate the list: */
207: if (modifier_keysyms_count[modifier] == 0) {
208: modifier_keysyms[modifier]
209: = tme_new(tme_keyboard_keyval_t, 2);
210: }
211: else {
212: modifier_keysyms[modifier]
213: = tme_renew(tme_keyboard_keyval_t,
214: modifier_keysyms[modifier],
215: modifier_keysyms_count[modifier] + 2);
216: }
217:
218: /* store this modifier keysym: */
219: modifier_keysyms[modifier][modifier_keysyms_count[modifier]]
220: = keysym;
221: modifier_keysyms_count[modifier]++;
222:
223: /* if this is a modifier that locks, tell the keyboard
224: buffer so that it can unlock it: */
225: /* XXX if this X server *doesn't* give these keysyms
226: locking behavior, we must *not* unlock them, because
227: inferring the extra transitions would be wrong: */
228: /* XXX we shouldn't attach them to the modifier either -
229: because the keyboard buffer input stage zero top half
230: assumes that keysyms attached to modifiers that it knows
231: about all have locking behavior. this is a feature bug
232: in the keyboard buffer: */
233: if (!strcmp(string, "Caps_Lock")
234: || !strcmp(string, "Shift_Lock")
235: || !strcmp(string, "Num_Lock")) {
236: rc = tme_keyboard_buffer_in_mode(buffer,
237: keysym,
238: TME_KEYBOARD_MODE_UNLOCK);
239: assert (rc == TME_OK);
240: }
241:
242: /* don't attach more than one keysym per keycode to
243: this modifier: */
244: modifier = TME_KEYBOARD_MODIFIER_NONE;
245: }
246:
247: /* remember that this keysym can be generated directly: */
248: gtk_keysym = tme_new0(struct tme_gtk_keysym, 1);
249: gtk_keysym->tme_gtk_keysym_type
250: = TME_KEYBOARD_LOOKUP_FLAG_OK_DIRECT;
251: gtk_keysym->tme_gtk_keysym_keysym
252: = keysym;
253: tme_hash_insert(display->tme_gtk_display_keyboard_keysyms,
254: (tme_hash_data_t) string,
255: (tme_hash_data_t) gtk_keysym);
256: tme_hash_insert(display->tme_gtk_display_keyboard_keysym_to_keycode,
257: (tme_hash_data_t) keysym,
258: (tme_hash_data_t) keycode);
259: }
260: }
261: }
262:
263: /* free the keyboard mapping: */
264: XFree(keymap);
265:
266: /* add in the modifiers information: */
267: for (modifier = 0;
268: modifier < TME_KEYBOARD_MODIFIER_MAX;
269: modifier++) {
270: if (modifier_keysyms_count[modifier] > 0) {
271: modifier_keysyms[modifier][modifier_keysyms_count[modifier]]
272: = TME_KEYBOARD_KEYVAL_UNDEF;
273: rc = tme_keyboard_buffer_in_modifier(buffer,
274: modifier,
275: modifier_keysyms[modifier]);
276: assert (rc == TME_OK);
277: tme_free(modifier_keysyms[modifier]);
278: }
279: }
280: }
281:
282: #endif /* !X_DISPLAY_MISSING */
283:
284: #if 1
285: /* this is used for debugging only: */
286: const char *_tme_gtk_keyboard_keyval_name _TME_P((tme_keyboard_keyval_t));
287: const char *
288: _tme_gtk_keyboard_keyval_name(tme_keyboard_keyval_t keyval)
289: {
290: return (gdk_keyval_name(keyval));
291: }
292: #endif
293:
294: /* this is a GTK callback for a key press or release event: */
295: static int
296: _tme_gtk_keyboard_key_event(GtkWidget *widget,
297: GdkEvent *gdk_event_raw,
298: struct tme_gtk_screen *screen)
299: {
300: struct tme_gtk_display *display;
301: GdkEventKey *gdk_event;
302: struct tme_keyboard_event tme_event;
303: int was_empty;
304: int new_callouts;
305: int rc;
306:
307: /* make a tme event from this gdk event: */
308: gdk_event = &gdk_event_raw->key;
309: tme_event.tme_keyboard_event_type
310: = (gdk_event->type == GDK_KEY_PRESS
311: ? TME_KEYBOARD_EVENT_PRESS
312: : TME_KEYBOARD_EVENT_RELEASE);
313: tme_event.tme_keyboard_event_modifiers
314: = gdk_event->state;
315: tme_event.tme_keyboard_event_keyval
316: = gdk_event->keyval;
317: tme_event.tme_keyboard_event_time
318: = gdk_event->time;
319:
320: /* assume that we won't need any new callouts: */
321: new_callouts = 0;
322:
323: /* recover our data structure: */
324: display = screen->tme_gtk_screen_display;
325:
326: /* lock the mutex: */
327: tme_mutex_lock(&display->tme_gtk_display_mutex);
328:
329: /* if this is a press of the mouse mode off key, turn mouse mode off
330: and return now: */
331: if (gdk_event->type == GDK_KEY_PRESS
332: && (gdk_event->keyval
333: == screen->tme_gtk_screen_mouse_keyval)) {
334: _tme_gtk_mouse_mode_off(screen,
335: gdk_event->time);
336:
337: /* unlock the mutex: */
338: tme_mutex_unlock(&display->tme_gtk_display_mutex);
339:
340: return (TRUE);
341: }
342:
343: /* get any keycode associated with this keysym: */
344: tme_event.tme_keyboard_event_keycode
345: = ((tme_keyboard_keyval_t)
346: tme_hash_lookup(display->tme_gtk_display_keyboard_keysym_to_keycode,
347: (tme_hash_data_t) tme_event.tme_keyboard_event_keyval));
348:
349: /* remember if the keyboard buffer was empty: */
350: was_empty
351: = tme_keyboard_buffer_is_empty(display->tme_gtk_display_keyboard_buffer);
352:
353: /* add this tme event to the keyboard buffer: */
354: rc = tme_keyboard_buffer_copyin(display->tme_gtk_display_keyboard_buffer,
355: &tme_event);
356: assert (rc == TME_OK);
357:
358: /* if the keyboard buffer was empty and now it isn't,
359: call out the keyboard controls: */
360: if (was_empty
361: && !tme_keyboard_buffer_is_empty(display->tme_gtk_display_keyboard_buffer)) {
362: new_callouts |= TME_GTK_DISPLAY_CALLOUT_KEYBOARD_CTRL;
363: }
364:
365: /* run any callouts: */
366: _tme_gtk_display_callout(display, new_callouts);
367:
368: /* unlock the mutex: */
369: tme_mutex_unlock(&display->tme_gtk_display_mutex);
370:
371: return (TRUE);
372: }
373:
374: /* this is called to look up a keysym: */
375: static tme_keyboard_keyval_t
376: _tme_gtk_keyboard_lookup(struct tme_keyboard_connection *conn_keyboard,
377: const struct tme_keyboard_lookup *lookup)
378: {
379: struct tme_gtk_display *display;
380: struct tme_gtk_keysym *keysym;
381: struct tme_gtk_keysym_bad **_keysym_bad, *keysym_bad;
382: char *string;
383: guint _keysym;
384:
385: /* recover our data structure: */
386: display = conn_keyboard
387: ->tme_keyboard_connection.tme_connection_element->tme_element_private;
388:
389: /* lock the mutex: */
390: tme_mutex_lock(&display->tme_gtk_display_mutex);
391:
392: /* if this is the "no more lookups" call, log complaints about all
393: keysyms that we were asked to look up, but have no way of
394: generating: */
395: if (lookup == NULL) {
396: for (; display->tme_gtk_display_keyboard_keysyms_bad != NULL; ) {
397: keysym_bad
398: = display->tme_gtk_display_keyboard_keysyms_bad;
399:
400: /* log the complaint: */
401: tme_log(&display->tme_gtk_display_element->tme_element_log_handle, 0, ENOENT,
402: (&display->tme_gtk_display_element->tme_element_log_handle,
403: _("cannot generate keysym '%s' directly%s"),
404: keysym_bad->tme_gtk_keysym_bad_string,
405: (keysym_bad->tme_keysym_bad_flags
406: != TME_KEYBOARD_LOOKUP_FLAG_OK_DIRECT
407: ? ""
408: : _(", or through a macro"))));
409:
410: /* free this record: */
411: display->tme_gtk_display_keyboard_keysyms_bad
412: = keysym_bad->tme_gtk_keysym_bad_next;
413: tme_free(keysym_bad->tme_gtk_keysym_bad_string);
414: tme_free(keysym_bad->tme_gtk_keysym_bad_context);
415: tme_free(keysym_bad);
416: }
417:
418: /* unlock the mutex: */
419: tme_mutex_unlock(&display->tme_gtk_display_mutex);
420:
421: return (TME_OK);
422: }
423:
424: /* if this lookup has context, find any existing bad keysym record
425: with the same context: */
426: _keysym_bad = NULL;
427: keysym_bad = NULL;
428: if (lookup->tme_keyboard_lookup_context_length > 0) {
429: for (_keysym_bad
430: = &display->tme_gtk_display_keyboard_keysyms_bad;
431: (keysym_bad = *_keysym_bad) != NULL;
432: _keysym_bad
433: = &keysym_bad->tme_gtk_keysym_bad_next) {
434:
435: /* stop if this bad keysym record has this context: */
436: if ((keysym_bad->tme_gtk_keysym_bad_context_length
437: == lookup->tme_keyboard_lookup_context_length)
438: && !memcmp(keysym_bad->tme_gtk_keysym_bad_context,
439: lookup->tme_keyboard_lookup_context,
440: lookup->tme_keyboard_lookup_context_length)) {
441: break;
442: }
443: }
444: }
445:
446: /* look up this keysym: */
447: keysym
448: = ((struct tme_gtk_keysym *)
449: tme_hash_lookup(display->tme_gtk_display_keyboard_keysyms,
450: (tme_hash_data_t) lookup->tme_keyboard_lookup_string));
451:
452: /* if the lookup failed and we're allowed to allocate this keysym: */
453: if (keysym == NULL
454: && (lookup->tme_keyboard_lookup_flags
455: & TME_KEYBOARD_LOOKUP_FLAG_OK_ALLOC_NOW)) {
456:
457: /* duplicate the lookup string: */
458: string = tme_strdup(lookup->tme_keyboard_lookup_string);
459:
460: /* create the new keysym: */
461: keysym = tme_new(struct tme_gtk_keysym, 1);
462: keysym->tme_gtk_keysym_type
463: = TME_KEYBOARD_LOOKUP_FLAG_OK_ALLOC;
464:
465: /* if GDK knows a keysym for this name: */
466: keysym->tme_gtk_keysym_keysym
467: = gdk_keyval_from_name(string);
468:
469: /* if GDK doesn't know a keysym for this name, else find an
470: unused keysym: */
471: if (keysym->tme_gtk_keysym_keysym
472: == GDK_VoidSymbol) {
473:
474: /* loop until we have an unused keysym that isn't also
475: TME_KEYBOARD_KEYVAL_UNDEF, or until we have exhausted the
476: GDK keysym space: */
477: for (_keysym = 0;; ) {
478: if (_keysym != TME_KEYBOARD_KEYVAL_UNDEF
479: && gdk_keyval_name(_keysym) == NULL) {
480: break;
481: }
482: if (++_keysym == 0) {
483: abort();
484: }
485: }
486:
487: /* use this new keysym: */
488: keysym->tme_gtk_keysym_keysym
489: = _keysym;
490: }
491:
492: /* add this newly allocated keysym: */
493: tme_hash_insert(display->tme_gtk_display_keyboard_keysyms,
494: (tme_hash_data_t) string,
495: (tme_hash_data_t) keysym);
496: }
497:
498: /* if the lookup failed or didn't give the right kind of keysym: */
499: if (keysym == NULL
500: || !(keysym->tme_gtk_keysym_type
501: & lookup->tme_keyboard_lookup_flags)) {
502:
503: /* if this lookup has context, and no bad keysym record
504: exists for this context, create a new one: */
505: if (lookup->tme_keyboard_lookup_context_length > 0
506: && keysym_bad == NULL) {
507:
508: /* create the new bad keysym record: */
509: keysym_bad = tme_new0(struct tme_gtk_keysym_bad, 1);
510: keysym_bad->tme_gtk_keysym_bad_next
511: = display->tme_gtk_display_keyboard_keysyms_bad;
512: keysym_bad->tme_gtk_keysym_bad_string
513: = tme_strdup(lookup->tme_keyboard_lookup_string);
514: keysym_bad->tme_keysym_bad_flags
515: = lookup->tme_keyboard_lookup_flags;
516: keysym_bad->tme_gtk_keysym_bad_context_length
517: = lookup->tme_keyboard_lookup_context_length;
518: keysym_bad->tme_gtk_keysym_bad_context
519: = tme_dup(tme_uint8_t,
520: lookup->tme_keyboard_lookup_context,
521: lookup->tme_keyboard_lookup_context_length);
522:
523: /* link in the new bad keysym record: */
524: display->tme_gtk_display_keyboard_keysyms_bad
525: = keysym_bad;
526: }
527:
528: /* unlock the mutex: */
529: tme_mutex_unlock(&display->tme_gtk_display_mutex);
530:
531: /* return failure: */
532: return (TME_KEYBOARD_KEYVAL_UNDEF);
533: }
534:
535: /* otherwise, this lookup succeeded. if a bad keysym record existed
536: for this context, forget it - this successful lookup forgives
537: that earlier failure: */
538: if (keysym_bad != NULL) {
539: *_keysym_bad = keysym_bad->tme_gtk_keysym_bad_next;
540: tme_free(keysym_bad->tme_gtk_keysym_bad_context);
541: tme_free(keysym_bad);
542: }
543:
544: /* unlock the mutex: */
545: tme_mutex_unlock(&display->tme_gtk_display_mutex);
546:
547: return (keysym->tme_gtk_keysym_keysym);
548: }
549:
550: /* this is called when the keyboard controls change: */
551: static int
552: _tme_gtk_keyboard_ctrl(struct tme_keyboard_connection *conn_keyboard,
553: unsigned int ctrl)
554: {
555: struct tme_gtk_display *display;
556:
557: /* recover our data structure: */
558: display = conn_keyboard
559: ->tme_keyboard_connection.tme_connection_element->tme_element_private;
560:
561: /* ring the bell: */
562: if (ctrl & TME_KEYBOARD_CTRL_BELL) {
563: gdk_beep();
564: }
565:
566: return (TME_OK);
567: }
568:
569: /* this is called to read the keyboard: */
570: static int
571: _tme_gtk_keyboard_read(struct tme_keyboard_connection *conn_keyboard,
572: struct tme_keyboard_event *event)
573: {
574: struct tme_gtk_display *display;
575: int rc;
576:
577: /* recover our data structure: */
578: display = conn_keyboard
579: ->tme_keyboard_connection.tme_connection_element->tme_element_private;
580:
581: /* lock the mutex: */
582: tme_mutex_lock(&display->tme_gtk_display_mutex);
583:
584: /* copy an event out of the keyboard buffer: */
585: rc = tme_keyboard_buffer_copyout(display->tme_gtk_display_keyboard_buffer,
586: event);
587:
588: /* unlock the mutex: */
589: tme_mutex_unlock(&display->tme_gtk_display_mutex);
590:
591: return (rc);
592: }
593:
594: /* this breaks a keyboard connection: */
595: static int
596: _tme_gtk_keyboard_connection_break(struct tme_connection *conn, unsigned int state)
597: {
598: abort();
599: }
600:
601: /* this makes a new keyboard connection: */
602: static int
603: _tme_gtk_keyboard_connection_make(struct tme_connection *conn,
604: unsigned int state)
605: {
606: struct tme_gtk_display *display;
607:
608: /* recover our data structure: */
609: display = conn->tme_connection_element->tme_element_private;
610:
611: /* both sides must be keyboard connections: */
612: assert(conn->tme_connection_type
613: == TME_CONNECTION_KEYBOARD);
614: assert(conn->tme_connection_other->tme_connection_type
615: == TME_CONNECTION_KEYBOARD);
616:
617: /* we are always set up to answer calls across the connection, so we
618: only have to do work when the connection has gone full, namely
619: taking the other side of the connection: */
620: if (state == TME_CONNECTION_FULL) {
621:
622: /* save our connection: */
623: tme_mutex_lock(&display->tme_gtk_display_mutex);
624: display->tme_gtk_display_keyboard_connection
625: = (struct tme_keyboard_connection *) conn->tme_connection_other;
626: tme_mutex_unlock(&display->tme_gtk_display_mutex);
627: }
628:
629: return (TME_OK);
630: }
631:
632: /* this scores a keyboard connection: */
633: static int
634: _tme_gtk_keyboard_connection_score(struct tme_connection *conn,
635: unsigned int *_score)
636: {
637: struct tme_keyboard_connection *conn_keyboard;
638:
639: /* both sides must be keyboard connections: */
640: assert(conn->tme_connection_type == TME_CONNECTION_KEYBOARD);
641: assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_KEYBOARD);
642:
643: /* the other side cannot be a real keyboard: */
644: conn_keyboard
645: = (struct tme_keyboard_connection *) conn->tme_connection_other;
646: *_score = (conn_keyboard->tme_keyboard_connection_read == NULL
647: && conn_keyboard->tme_keyboard_connection_lookup == NULL);
648: return (TME_OK);
649: }
650:
651: /* this makes a new connection side for a GTK keyboard: */
652: int
653: _tme_gtk_keyboard_connections_new(struct tme_gtk_display *display,
654: struct tme_connection **_conns)
655: {
656: struct tme_keyboard_connection *conn_keyboard;
657: struct tme_connection *conn;
658:
659: /* if we don't have a keyboard connection yet: */
660: if (display->tme_gtk_display_keyboard_connection == NULL) {
661:
662: /* create our side of a keyboard connection: */
663: conn_keyboard = tme_new0(struct tme_keyboard_connection, 1);
664: conn = &conn_keyboard->tme_keyboard_connection;
665:
666: /* fill in the generic connection: */
667: conn->tme_connection_next = *_conns;
668: conn->tme_connection_type = TME_CONNECTION_KEYBOARD;
669: conn->tme_connection_score = _tme_gtk_keyboard_connection_score;
670: conn->tme_connection_make = _tme_gtk_keyboard_connection_make;
671: conn->tme_connection_break = _tme_gtk_keyboard_connection_break;
672:
673: /* fill in the keyboard connection: */
674: conn_keyboard->tme_keyboard_connection_ctrl = _tme_gtk_keyboard_ctrl;
675: conn_keyboard->tme_keyboard_connection_read = _tme_gtk_keyboard_read;
676: conn_keyboard->tme_keyboard_connection_lookup = _tme_gtk_keyboard_lookup;
677:
678: /* return the connection side possibility: */
679: *_conns = conn;
680: }
681:
682: /* done: */
683: return (TME_OK);
684: }
685:
686: /* this attaches the GTK keyboard to a new screen: */
687: void
688: _tme_gtk_keyboard_attach(struct tme_gtk_screen *screen)
689: {
690:
691: /* make sure the event box for the framebuffer gets enter, key_press
692: and key_release events. we have to add these latter two events
693: to both the event box widget itself, and the top-level window,
694: since GTK 1.x appears to not select KeyRelease events at the
695: top-level: */
696: gtk_widget_add_events(screen->tme_gtk_screen_event_box,
697: GDK_ENTER_NOTIFY_MASK
698: | GDK_KEY_PRESS_MASK
699: | GDK_KEY_RELEASE_MASK);
700: gtk_widget_add_events (gtk_widget_get_toplevel(screen->tme_gtk_screen_event_box),
701: GDK_KEY_PRESS_MASK
702: | GDK_KEY_RELEASE_MASK);
703:
704: /* set a signal handler for these events: */
705: gtk_signal_connect(GTK_OBJECT(screen->tme_gtk_screen_event_box),
706: "enter_notify_event",
707: GTK_SIGNAL_FUNC(_tme_gtk_display_enter_focus),
708: NULL);
709: gtk_signal_connect(GTK_OBJECT(screen->tme_gtk_screen_event_box),
710: "key_press_event",
711: GTK_SIGNAL_FUNC(_tme_gtk_keyboard_key_event),
712: screen);
713: gtk_signal_connect(GTK_OBJECT(screen->tme_gtk_screen_event_box),
714: "key_release_event",
715: GTK_SIGNAL_FUNC(_tme_gtk_keyboard_key_event),
716: screen);
717:
718: /* the event box can focus, and have it grab the focus now: */
719: GTK_WIDGET_SET_FLAGS(screen->tme_gtk_screen_event_box, GTK_CAN_FOCUS);
720: gtk_widget_grab_focus(screen->tme_gtk_screen_event_box);
721: }
722:
723: /* this initializes keyboard part of the display: */
724: void
725: _tme_gtk_keyboard_new(struct tme_gtk_display *display)
726: {
727:
728: /* we have no keyboard connection: */
729: display->tme_gtk_display_keyboard_connection = NULL;
730:
731: /* allocate the keyboard buffer: */
732: display->tme_gtk_display_keyboard_buffer
733: = tme_keyboard_buffer_new(1024);
734: display->tme_gtk_display_keyboard_buffer->tme_keyboard_buffer_log_handle
735: = &display->tme_gtk_display_element->tme_element_log_handle;
736:
737: /* allocate the keysyms hash: */
738: display->tme_gtk_display_keyboard_keysyms
739: = tme_hash_new(tme_string_hash,
740: tme_string_compare,
741: (tme_hash_data_t) 0);
742:
743: /* allocate the keysym-to-keycode hash: */
744: display->tme_gtk_display_keyboard_keysym_to_keycode
745: = tme_hash_new(tme_direct_hash,
746: tme_direct_compare,
747: (tme_hash_data_t) TME_KEYBOARD_KEYVAL_UNDEF);
748:
749: /* there are no bad keysyms: */
750: display->tme_gtk_display_keyboard_keysyms_bad = NULL;
751:
752: /* initialize the input stages of the keyboard buffer. this needs
753: information that we can't get from GTK or GDK, like which keysyms
754: are attached to which modifiers, and which keysyms can be
755: generated by the keyboard: */
756: #ifndef X_DISPLAY_MISSING
757: if (TRUE) {
758: _tme_gtk_keyboard_x11_new(display);
759: }
760: #endif /* !X_DISPLAY_MISSING */
761: else {
762: abort();
763: }
764: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.