|
|
1.1.1.2 ! root 1: /* $Id: gtk-keyboard.c,v 1.8 2005/05/14 18:04:22 fredette Exp $ */ 1.1 root 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> 1.1.1.2 ! root 37: _TME_RCSID("$Id: gtk-keyboard.c,v 1.8 2005/05/14 18:04:22 fredette Exp $"); 1.1 root 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: 1.1.1.2 ! root 371: /* don't process this event any further: */ 1.1 root 372: return (TRUE); 373: } 374: 375: /* this is called to look up a keysym: */ 376: static tme_keyboard_keyval_t 377: _tme_gtk_keyboard_lookup(struct tme_keyboard_connection *conn_keyboard, 378: const struct tme_keyboard_lookup *lookup) 379: { 380: struct tme_gtk_display *display; 381: struct tme_gtk_keysym *keysym; 382: struct tme_gtk_keysym_bad **_keysym_bad, *keysym_bad; 383: char *string; 384: guint _keysym; 385: 386: /* recover our data structure: */ 387: display = conn_keyboard 388: ->tme_keyboard_connection.tme_connection_element->tme_element_private; 389: 390: /* lock the mutex: */ 391: tme_mutex_lock(&display->tme_gtk_display_mutex); 392: 393: /* if this is the "no more lookups" call, log complaints about all 394: keysyms that we were asked to look up, but have no way of 395: generating: */ 396: if (lookup == NULL) { 397: for (; display->tme_gtk_display_keyboard_keysyms_bad != NULL; ) { 398: keysym_bad 399: = display->tme_gtk_display_keyboard_keysyms_bad; 400: 401: /* log the complaint: */ 402: tme_log(&display->tme_gtk_display_element->tme_element_log_handle, 0, ENOENT, 403: (&display->tme_gtk_display_element->tme_element_log_handle, 404: _("cannot generate keysym '%s' directly%s"), 405: keysym_bad->tme_gtk_keysym_bad_string, 406: (keysym_bad->tme_keysym_bad_flags 1.1.1.2 ! root 407: == TME_KEYBOARD_LOOKUP_FLAG_OK_DIRECT 1.1 root 408: ? "" 409: : _(", or through a macro")))); 410: 411: /* free this record: */ 412: display->tme_gtk_display_keyboard_keysyms_bad 413: = keysym_bad->tme_gtk_keysym_bad_next; 414: tme_free(keysym_bad->tme_gtk_keysym_bad_string); 415: tme_free(keysym_bad->tme_gtk_keysym_bad_context); 416: tme_free(keysym_bad); 417: } 418: 419: /* unlock the mutex: */ 420: tme_mutex_unlock(&display->tme_gtk_display_mutex); 421: 422: return (TME_OK); 423: } 424: 425: /* if this lookup has context, find any existing bad keysym record 426: with the same context: */ 427: _keysym_bad = NULL; 428: keysym_bad = NULL; 429: if (lookup->tme_keyboard_lookup_context_length > 0) { 430: for (_keysym_bad 431: = &display->tme_gtk_display_keyboard_keysyms_bad; 432: (keysym_bad = *_keysym_bad) != NULL; 433: _keysym_bad 434: = &keysym_bad->tme_gtk_keysym_bad_next) { 435: 436: /* stop if this bad keysym record has this context: */ 437: if ((keysym_bad->tme_gtk_keysym_bad_context_length 438: == lookup->tme_keyboard_lookup_context_length) 439: && !memcmp(keysym_bad->tme_gtk_keysym_bad_context, 440: lookup->tme_keyboard_lookup_context, 441: lookup->tme_keyboard_lookup_context_length)) { 442: break; 443: } 444: } 445: } 446: 447: /* look up this keysym: */ 448: keysym 449: = ((struct tme_gtk_keysym *) 450: tme_hash_lookup(display->tme_gtk_display_keyboard_keysyms, 451: (tme_hash_data_t) lookup->tme_keyboard_lookup_string)); 452: 453: /* if the lookup failed and we're allowed to allocate this keysym: */ 454: if (keysym == NULL 455: && (lookup->tme_keyboard_lookup_flags 456: & TME_KEYBOARD_LOOKUP_FLAG_OK_ALLOC_NOW)) { 457: 458: /* duplicate the lookup string: */ 459: string = tme_strdup(lookup->tme_keyboard_lookup_string); 460: 461: /* create the new keysym: */ 462: keysym = tme_new(struct tme_gtk_keysym, 1); 463: keysym->tme_gtk_keysym_type 464: = TME_KEYBOARD_LOOKUP_FLAG_OK_ALLOC; 465: 466: /* if GDK knows a keysym for this name: */ 467: keysym->tme_gtk_keysym_keysym 468: = gdk_keyval_from_name(string); 469: 470: /* if GDK doesn't know a keysym for this name, else find an 471: unused keysym: */ 472: if (keysym->tme_gtk_keysym_keysym 473: == GDK_VoidSymbol) { 474: 475: /* loop until we have an unused keysym that isn't also 476: TME_KEYBOARD_KEYVAL_UNDEF, or until we have exhausted the 477: GDK keysym space: */ 478: for (_keysym = 0;; ) { 479: if (_keysym != TME_KEYBOARD_KEYVAL_UNDEF 480: && gdk_keyval_name(_keysym) == NULL) { 481: break; 482: } 483: if (++_keysym == 0) { 484: abort(); 485: } 486: } 487: 488: /* use this new keysym: */ 489: keysym->tme_gtk_keysym_keysym 490: = _keysym; 491: } 492: 493: /* add this newly allocated keysym: */ 494: tme_hash_insert(display->tme_gtk_display_keyboard_keysyms, 495: (tme_hash_data_t) string, 496: (tme_hash_data_t) keysym); 497: } 498: 499: /* if the lookup failed or didn't give the right kind of keysym: */ 500: if (keysym == NULL 501: || !(keysym->tme_gtk_keysym_type 502: & lookup->tme_keyboard_lookup_flags)) { 503: 504: /* if this lookup has context, and no bad keysym record 505: exists for this context, create a new one: */ 506: if (lookup->tme_keyboard_lookup_context_length > 0 507: && keysym_bad == NULL) { 508: 509: /* create the new bad keysym record: */ 510: keysym_bad = tme_new0(struct tme_gtk_keysym_bad, 1); 511: keysym_bad->tme_gtk_keysym_bad_next 512: = display->tme_gtk_display_keyboard_keysyms_bad; 513: keysym_bad->tme_gtk_keysym_bad_string 514: = tme_strdup(lookup->tme_keyboard_lookup_string); 515: keysym_bad->tme_keysym_bad_flags 516: = lookup->tme_keyboard_lookup_flags; 517: keysym_bad->tme_gtk_keysym_bad_context_length 518: = lookup->tme_keyboard_lookup_context_length; 519: keysym_bad->tme_gtk_keysym_bad_context 520: = tme_dup(tme_uint8_t, 521: lookup->tme_keyboard_lookup_context, 522: lookup->tme_keyboard_lookup_context_length); 523: 524: /* link in the new bad keysym record: */ 525: display->tme_gtk_display_keyboard_keysyms_bad 526: = keysym_bad; 527: } 528: 529: /* unlock the mutex: */ 530: tme_mutex_unlock(&display->tme_gtk_display_mutex); 531: 532: /* return failure: */ 533: return (TME_KEYBOARD_KEYVAL_UNDEF); 534: } 535: 536: /* otherwise, this lookup succeeded. if a bad keysym record existed 537: for this context, forget it - this successful lookup forgives 538: that earlier failure: */ 539: if (keysym_bad != NULL) { 540: *_keysym_bad = keysym_bad->tme_gtk_keysym_bad_next; 541: tme_free(keysym_bad->tme_gtk_keysym_bad_context); 542: tme_free(keysym_bad); 543: } 544: 545: /* unlock the mutex: */ 546: tme_mutex_unlock(&display->tme_gtk_display_mutex); 547: 548: return (keysym->tme_gtk_keysym_keysym); 549: } 550: 551: /* this is called when the keyboard controls change: */ 552: static int 553: _tme_gtk_keyboard_ctrl(struct tme_keyboard_connection *conn_keyboard, 554: unsigned int ctrl) 555: { 556: struct tme_gtk_display *display; 557: 558: /* recover our data structure: */ 559: display = conn_keyboard 560: ->tme_keyboard_connection.tme_connection_element->tme_element_private; 561: 562: /* ring the bell: */ 563: if (ctrl & TME_KEYBOARD_CTRL_BELL) { 564: gdk_beep(); 565: } 566: 567: return (TME_OK); 568: } 569: 570: /* this is called to read the keyboard: */ 571: static int 572: _tme_gtk_keyboard_read(struct tme_keyboard_connection *conn_keyboard, 573: struct tme_keyboard_event *event) 574: { 575: struct tme_gtk_display *display; 576: int rc; 577: 578: /* recover our data structure: */ 579: display = conn_keyboard 580: ->tme_keyboard_connection.tme_connection_element->tme_element_private; 581: 582: /* lock the mutex: */ 583: tme_mutex_lock(&display->tme_gtk_display_mutex); 584: 585: /* copy an event out of the keyboard buffer: */ 586: rc = tme_keyboard_buffer_copyout(display->tme_gtk_display_keyboard_buffer, 587: event); 588: 589: /* unlock the mutex: */ 590: tme_mutex_unlock(&display->tme_gtk_display_mutex); 591: 592: return (rc); 593: } 594: 595: /* this breaks a keyboard connection: */ 596: static int 597: _tme_gtk_keyboard_connection_break(struct tme_connection *conn, unsigned int state) 598: { 599: abort(); 600: } 601: 602: /* this makes a new keyboard connection: */ 603: static int 604: _tme_gtk_keyboard_connection_make(struct tme_connection *conn, 605: unsigned int state) 606: { 607: struct tme_gtk_display *display; 608: 609: /* recover our data structure: */ 610: display = conn->tme_connection_element->tme_element_private; 611: 612: /* both sides must be keyboard connections: */ 613: assert(conn->tme_connection_type 614: == TME_CONNECTION_KEYBOARD); 615: assert(conn->tme_connection_other->tme_connection_type 616: == TME_CONNECTION_KEYBOARD); 617: 618: /* we are always set up to answer calls across the connection, so we 619: only have to do work when the connection has gone full, namely 620: taking the other side of the connection: */ 621: if (state == TME_CONNECTION_FULL) { 622: 623: /* save our connection: */ 624: tme_mutex_lock(&display->tme_gtk_display_mutex); 625: display->tme_gtk_display_keyboard_connection 626: = (struct tme_keyboard_connection *) conn->tme_connection_other; 627: tme_mutex_unlock(&display->tme_gtk_display_mutex); 628: } 629: 630: return (TME_OK); 631: } 632: 633: /* this scores a keyboard connection: */ 634: static int 635: _tme_gtk_keyboard_connection_score(struct tme_connection *conn, 636: unsigned int *_score) 637: { 638: struct tme_keyboard_connection *conn_keyboard; 639: 640: /* both sides must be keyboard connections: */ 641: assert(conn->tme_connection_type == TME_CONNECTION_KEYBOARD); 642: assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_KEYBOARD); 643: 644: /* the other side cannot be a real keyboard: */ 645: conn_keyboard 646: = (struct tme_keyboard_connection *) conn->tme_connection_other; 647: *_score = (conn_keyboard->tme_keyboard_connection_read == NULL 648: && conn_keyboard->tme_keyboard_connection_lookup == NULL); 649: return (TME_OK); 650: } 651: 652: /* this makes a new connection side for a GTK keyboard: */ 653: int 654: _tme_gtk_keyboard_connections_new(struct tme_gtk_display *display, 655: struct tme_connection **_conns) 656: { 657: struct tme_keyboard_connection *conn_keyboard; 658: struct tme_connection *conn; 659: 660: /* if we don't have a keyboard connection yet: */ 661: if (display->tme_gtk_display_keyboard_connection == NULL) { 662: 663: /* create our side of a keyboard connection: */ 664: conn_keyboard = tme_new0(struct tme_keyboard_connection, 1); 665: conn = &conn_keyboard->tme_keyboard_connection; 666: 667: /* fill in the generic connection: */ 668: conn->tme_connection_next = *_conns; 669: conn->tme_connection_type = TME_CONNECTION_KEYBOARD; 670: conn->tme_connection_score = _tme_gtk_keyboard_connection_score; 671: conn->tme_connection_make = _tme_gtk_keyboard_connection_make; 672: conn->tme_connection_break = _tme_gtk_keyboard_connection_break; 673: 674: /* fill in the keyboard connection: */ 675: conn_keyboard->tme_keyboard_connection_ctrl = _tme_gtk_keyboard_ctrl; 676: conn_keyboard->tme_keyboard_connection_read = _tme_gtk_keyboard_read; 677: conn_keyboard->tme_keyboard_connection_lookup = _tme_gtk_keyboard_lookup; 678: 679: /* return the connection side possibility: */ 680: *_conns = conn; 681: } 682: 683: /* done: */ 684: return (TME_OK); 685: } 686: 687: /* this attaches the GTK keyboard to a new screen: */ 688: void 689: _tme_gtk_keyboard_attach(struct tme_gtk_screen *screen) 690: { 691: 692: /* make sure the event box for the framebuffer gets enter, key_press 693: and key_release events. we have to add these latter two events 694: to both the event box widget itself, and the top-level window, 695: since GTK 1.x appears to not select KeyRelease events at the 696: top-level: */ 697: gtk_widget_add_events(screen->tme_gtk_screen_event_box, 698: GDK_ENTER_NOTIFY_MASK 699: | GDK_KEY_PRESS_MASK 700: | GDK_KEY_RELEASE_MASK); 701: gtk_widget_add_events (gtk_widget_get_toplevel(screen->tme_gtk_screen_event_box), 702: GDK_KEY_PRESS_MASK 703: | GDK_KEY_RELEASE_MASK); 704: 705: /* set a signal handler for these events: */ 706: gtk_signal_connect(GTK_OBJECT(screen->tme_gtk_screen_event_box), 707: "enter_notify_event", 708: GTK_SIGNAL_FUNC(_tme_gtk_display_enter_focus), 709: NULL); 1.1.1.2 ! root 710: gtk_signal_connect_after(GTK_OBJECT(screen->tme_gtk_screen_event_box), ! 711: "key_press_event", ! 712: GTK_SIGNAL_FUNC(_tme_gtk_keyboard_key_event), ! 713: screen); ! 714: gtk_signal_connect_after(GTK_OBJECT(screen->tme_gtk_screen_event_box), ! 715: "key_release_event", ! 716: GTK_SIGNAL_FUNC(_tme_gtk_keyboard_key_event), ! 717: screen); 1.1 root 718: 719: /* the event box can focus, and have it grab the focus now: */ 720: GTK_WIDGET_SET_FLAGS(screen->tme_gtk_screen_event_box, GTK_CAN_FOCUS); 721: gtk_widget_grab_focus(screen->tme_gtk_screen_event_box); 722: } 723: 724: /* this initializes keyboard part of the display: */ 725: void 726: _tme_gtk_keyboard_new(struct tme_gtk_display *display) 727: { 728: 729: /* we have no keyboard connection: */ 730: display->tme_gtk_display_keyboard_connection = NULL; 731: 732: /* allocate the keyboard buffer: */ 733: display->tme_gtk_display_keyboard_buffer 734: = tme_keyboard_buffer_new(1024); 735: display->tme_gtk_display_keyboard_buffer->tme_keyboard_buffer_log_handle 736: = &display->tme_gtk_display_element->tme_element_log_handle; 737: 738: /* allocate the keysyms hash: */ 739: display->tme_gtk_display_keyboard_keysyms 740: = tme_hash_new(tme_string_hash, 741: tme_string_compare, 742: (tme_hash_data_t) 0); 743: 744: /* allocate the keysym-to-keycode hash: */ 745: display->tme_gtk_display_keyboard_keysym_to_keycode 746: = tme_hash_new(tme_direct_hash, 747: tme_direct_compare, 748: (tme_hash_data_t) TME_KEYBOARD_KEYVAL_UNDEF); 749: 750: /* there are no bad keysyms: */ 751: display->tme_gtk_display_keyboard_keysyms_bad = NULL; 752: 753: /* initialize the input stages of the keyboard buffer. this needs 754: information that we can't get from GTK or GDK, like which keysyms 755: are attached to which modifiers, and which keysyms can be 756: generated by the keyboard: */ 757: #ifndef X_DISPLAY_MISSING 758: if (TRUE) { 759: _tme_gtk_keyboard_x11_new(display); 760: } 761: #endif /* !X_DISPLAY_MISSING */ 762: else { 763: abort(); 764: } 765: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.