Annotation of tme/host/gtk/gtk-keyboard.c, revision 1.1.1.3

1.1.1.3 ! root        1: /* $Id: gtk-keyboard.c,v 1.10 2007/02/15 02:15:41 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.3 ! root       37: _TME_RCSID("$Id: gtk-keyboard.c,v 1.10 2007/02/15 02:15:41 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)
1.1.1.3 ! root      193:              != tme_keyboard_hash_data_from_keyval((tme_uint32_t) keycode)) {
1.1       root      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,
1.1.1.3 ! root      258:                        tme_keyboard_hash_data_from_keyval((tme_uint32_t) keycode));
1.1       root      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
1.1.1.3 ! root      345:     = tme_keyboard_hash_data_to_keyval(tme_hash_lookup(display->tme_gtk_display_keyboard_keysym_to_keycode,
        !           346:                                                       tme_keyboard_hash_data_from_keyval(tme_event.tme_keyboard_event_keyval)));
1.1       root      347: 
                    348:   /* remember if the keyboard buffer was empty: */
                    349:   was_empty
                    350:     = tme_keyboard_buffer_is_empty(display->tme_gtk_display_keyboard_buffer);
                    351: 
                    352:   /* add this tme event to the keyboard buffer: */
                    353:   rc = tme_keyboard_buffer_copyin(display->tme_gtk_display_keyboard_buffer,
                    354:                                  &tme_event);
                    355:   assert (rc == TME_OK);
                    356: 
                    357:   /* if the keyboard buffer was empty and now it isn't,
                    358:      call out the keyboard controls: */
                    359:   if (was_empty
                    360:       && !tme_keyboard_buffer_is_empty(display->tme_gtk_display_keyboard_buffer)) {
                    361:     new_callouts |= TME_GTK_DISPLAY_CALLOUT_KEYBOARD_CTRL;
                    362:   }
                    363: 
                    364:   /* run any callouts: */
                    365:   _tme_gtk_display_callout(display, new_callouts);
                    366: 
                    367:   /* unlock the mutex: */
                    368:   tme_mutex_unlock(&display->tme_gtk_display_mutex);
                    369: 
1.1.1.2   root      370:   /* don't process this event any further: */
1.1       root      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;
1.1.1.3 ! root      383:   const char *string_other;
1.1       root      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:     
1.1.1.3 ! root      470:     /* if GDK doesn't know a keysym for this name, or if the string
        !           471:        for this keysym isn't the same name, find an unused keysym: */
        !           472:     if (keysym->tme_gtk_keysym_keysym == GDK_VoidSymbol
        !           473:        || (string_other = gdk_keyval_name(keysym->tme_gtk_keysym_keysym)) == NULL
        !           474:        || strcmp(string, string_other)) {
1.1       root      475:       
                    476:       /* loop until we have an unused keysym that isn't also
                    477:         TME_KEYBOARD_KEYVAL_UNDEF, or until we have exhausted the
                    478:         GDK keysym space: */
1.1.1.3 ! root      479:       for (_keysym = display->tme_gtk_display_keyboard_keysym_alloc_next;;) {
        !           480:        if ((_keysym + 1) == 0) {
        !           481:          abort();
        !           482:        }
1.1       root      483:        if (_keysym != TME_KEYBOARD_KEYVAL_UNDEF
1.1.1.3 ! root      484:            && _keysym != GDK_VoidSymbol
1.1       root      485:            && gdk_keyval_name(_keysym) == NULL) {
                    486:          break;
                    487:        }
1.1.1.3 ! root      488:        _keysym++;
1.1       root      489:       }
1.1.1.3 ! root      490:       display->tme_gtk_display_keyboard_keysym_alloc_next = _keysym + 1;
1.1       root      491:       
                    492:       /* use this new keysym: */
                    493:       keysym->tme_gtk_keysym_keysym
                    494:        = _keysym;
                    495:     }
                    496:     
                    497:     /* add this newly allocated keysym: */
                    498:     tme_hash_insert(display->tme_gtk_display_keyboard_keysyms,
                    499:                    (tme_hash_data_t) string,
                    500:                    (tme_hash_data_t) keysym);
                    501:   }
                    502: 
                    503:   /* if the lookup failed or didn't give the right kind of keysym: */
                    504:   if (keysym == NULL
                    505:       || !(keysym->tme_gtk_keysym_type
                    506:           & lookup->tme_keyboard_lookup_flags)) {
                    507: 
                    508:     /* if this lookup has context, and no bad keysym record
                    509:        exists for this context, create a new one: */
                    510:     if (lookup->tme_keyboard_lookup_context_length > 0
                    511:        && keysym_bad == NULL) {
                    512: 
                    513:       /* create the new bad keysym record: */
                    514:       keysym_bad = tme_new0(struct tme_gtk_keysym_bad, 1);
                    515:       keysym_bad->tme_gtk_keysym_bad_next
                    516:        = display->tme_gtk_display_keyboard_keysyms_bad;
                    517:       keysym_bad->tme_gtk_keysym_bad_string
                    518:        = tme_strdup(lookup->tme_keyboard_lookup_string);
                    519:       keysym_bad->tme_keysym_bad_flags
                    520:        = lookup->tme_keyboard_lookup_flags;
                    521:       keysym_bad->tme_gtk_keysym_bad_context_length
                    522:        = lookup->tme_keyboard_lookup_context_length;
                    523:       keysym_bad->tme_gtk_keysym_bad_context
                    524:        = tme_dup(tme_uint8_t,
                    525:                  lookup->tme_keyboard_lookup_context,
                    526:                  lookup->tme_keyboard_lookup_context_length);
                    527: 
                    528:       /* link in the new bad keysym record: */
                    529:       display->tme_gtk_display_keyboard_keysyms_bad
                    530:        = keysym_bad;
                    531:     }
                    532: 
                    533:     /* unlock the mutex: */
                    534:     tme_mutex_unlock(&display->tme_gtk_display_mutex);
                    535: 
                    536:     /* return failure: */
                    537:     return (TME_KEYBOARD_KEYVAL_UNDEF);
                    538:   }
                    539: 
                    540:   /* otherwise, this lookup succeeded.  if a bad keysym record existed
                    541:      for this context, forget it - this successful lookup forgives
                    542:      that earlier failure: */
                    543:   if (keysym_bad != NULL) {
                    544:     *_keysym_bad = keysym_bad->tme_gtk_keysym_bad_next;
                    545:     tme_free(keysym_bad->tme_gtk_keysym_bad_context);
                    546:     tme_free(keysym_bad);
                    547:   }
                    548: 
                    549:   /* unlock the mutex: */
                    550:   tme_mutex_unlock(&display->tme_gtk_display_mutex);
                    551: 
                    552:   return (keysym->tme_gtk_keysym_keysym);
                    553: }
                    554: 
                    555: /* this is called when the keyboard controls change: */
                    556: static int
                    557: _tme_gtk_keyboard_ctrl(struct tme_keyboard_connection *conn_keyboard, 
                    558:                       unsigned int ctrl)
                    559: {
                    560:   struct tme_gtk_display *display;
                    561: 
                    562:   /* recover our data structure: */
                    563:   display = conn_keyboard
                    564:     ->tme_keyboard_connection.tme_connection_element->tme_element_private;
                    565: 
                    566:   /* ring the bell: */
                    567:   if (ctrl & TME_KEYBOARD_CTRL_BELL) {
                    568:     gdk_beep();
                    569:   }
                    570: 
                    571:   return (TME_OK);
                    572: }
                    573: 
                    574: /* this is called to read the keyboard: */
                    575: static int
                    576: _tme_gtk_keyboard_read(struct tme_keyboard_connection *conn_keyboard, 
                    577:                       struct tme_keyboard_event *event)
                    578: {
                    579:   struct tme_gtk_display *display;
                    580:   int rc;
                    581: 
                    582:   /* recover our data structure: */
                    583:   display = conn_keyboard
                    584:     ->tme_keyboard_connection.tme_connection_element->tme_element_private;
                    585: 
                    586:   /* lock the mutex: */
                    587:   tme_mutex_lock(&display->tme_gtk_display_mutex);
                    588: 
                    589:   /* copy an event out of the keyboard buffer: */
                    590:   rc = tme_keyboard_buffer_copyout(display->tme_gtk_display_keyboard_buffer,
                    591:                                   event);
                    592: 
                    593:   /* unlock the mutex: */
                    594:   tme_mutex_unlock(&display->tme_gtk_display_mutex);
                    595: 
                    596:   return (rc);
                    597: }
                    598: 
                    599: /* this breaks a keyboard connection: */
                    600: static int
                    601: _tme_gtk_keyboard_connection_break(struct tme_connection *conn, unsigned int state)
                    602: {
                    603:   abort();
                    604: }
                    605: 
                    606: /* this makes a new keyboard connection: */
                    607: static int
                    608: _tme_gtk_keyboard_connection_make(struct tme_connection *conn,
                    609:                                  unsigned int state)
                    610: {
                    611:   struct tme_gtk_display *display;
                    612: 
                    613:   /* recover our data structure: */
                    614:   display = conn->tme_connection_element->tme_element_private;
                    615: 
                    616:   /* both sides must be keyboard connections: */
                    617:   assert(conn->tme_connection_type
                    618:         == TME_CONNECTION_KEYBOARD);
                    619:   assert(conn->tme_connection_other->tme_connection_type
                    620:         == TME_CONNECTION_KEYBOARD);
                    621: 
                    622:   /* we are always set up to answer calls across the connection, so we
                    623:      only have to do work when the connection has gone full, namely
                    624:      taking the other side of the connection: */
                    625:   if (state == TME_CONNECTION_FULL) {
                    626: 
                    627:     /* save our connection: */
                    628:     tme_mutex_lock(&display->tme_gtk_display_mutex);
                    629:     display->tme_gtk_display_keyboard_connection
                    630:       = (struct tme_keyboard_connection *) conn->tme_connection_other;
                    631:     tme_mutex_unlock(&display->tme_gtk_display_mutex);
                    632:   }
                    633: 
                    634:   return (TME_OK);
                    635: }
                    636: 
                    637: /* this scores a keyboard connection: */
                    638: static int
                    639: _tme_gtk_keyboard_connection_score(struct tme_connection *conn,
                    640:                                   unsigned int *_score)
                    641: {
                    642:   struct tme_keyboard_connection *conn_keyboard;
                    643: 
                    644:   /* both sides must be keyboard connections: */
                    645:   assert(conn->tme_connection_type == TME_CONNECTION_KEYBOARD);
                    646:   assert(conn->tme_connection_other->tme_connection_type == TME_CONNECTION_KEYBOARD);
                    647: 
                    648:   /* the other side cannot be a real keyboard: */
                    649:   conn_keyboard
                    650:     = (struct tme_keyboard_connection *) conn->tme_connection_other;
                    651:   *_score = (conn_keyboard->tme_keyboard_connection_read == NULL
                    652:             && conn_keyboard->tme_keyboard_connection_lookup == NULL);
                    653:   return (TME_OK);
                    654: }
                    655: 
                    656: /* this makes a new connection side for a GTK keyboard: */
                    657: int
                    658: _tme_gtk_keyboard_connections_new(struct tme_gtk_display *display, 
                    659:                                  struct tme_connection **_conns)
                    660: {
                    661:   struct tme_keyboard_connection *conn_keyboard;
                    662:   struct tme_connection *conn;
                    663: 
                    664:   /* if we don't have a keyboard connection yet: */
                    665:   if (display->tme_gtk_display_keyboard_connection == NULL) {
                    666: 
                    667:     /* create our side of a keyboard connection: */
                    668:     conn_keyboard = tme_new0(struct tme_keyboard_connection, 1);
                    669:     conn = &conn_keyboard->tme_keyboard_connection;
                    670: 
                    671:     /* fill in the generic connection: */
                    672:     conn->tme_connection_next = *_conns;
                    673:     conn->tme_connection_type = TME_CONNECTION_KEYBOARD;
                    674:     conn->tme_connection_score = _tme_gtk_keyboard_connection_score;
                    675:     conn->tme_connection_make = _tme_gtk_keyboard_connection_make;
                    676:     conn->tme_connection_break = _tme_gtk_keyboard_connection_break;
                    677: 
                    678:     /* fill in the keyboard connection: */
                    679:     conn_keyboard->tme_keyboard_connection_ctrl = _tme_gtk_keyboard_ctrl;
                    680:     conn_keyboard->tme_keyboard_connection_read = _tme_gtk_keyboard_read;
                    681:     conn_keyboard->tme_keyboard_connection_lookup = _tme_gtk_keyboard_lookup;
                    682: 
                    683:     /* return the connection side possibility: */
                    684:     *_conns = conn;
                    685:   }
                    686: 
                    687:   /* done: */
                    688:   return (TME_OK);
                    689: }
                    690: 
                    691: /* this attaches the GTK keyboard to a new screen: */
                    692: void
                    693: _tme_gtk_keyboard_attach(struct tme_gtk_screen *screen)
                    694: {
                    695: 
                    696:   /* make sure the event box for the framebuffer gets enter, key_press
                    697:      and key_release events.  we have to add these latter two events
                    698:      to both the event box widget itself, and the top-level window,
                    699:      since GTK 1.x appears to not select KeyRelease events at the
                    700:      top-level: */
                    701:   gtk_widget_add_events(screen->tme_gtk_screen_event_box,
                    702:                        GDK_ENTER_NOTIFY_MASK
                    703:                        | GDK_KEY_PRESS_MASK
                    704:                        | GDK_KEY_RELEASE_MASK);
                    705:   gtk_widget_add_events (gtk_widget_get_toplevel(screen->tme_gtk_screen_event_box),
                    706:                         GDK_KEY_PRESS_MASK
                    707:                         | GDK_KEY_RELEASE_MASK);
                    708: 
                    709:   /* set a signal handler for these events: */
                    710:   gtk_signal_connect(GTK_OBJECT(screen->tme_gtk_screen_event_box),
                    711:                     "enter_notify_event",
                    712:                     GTK_SIGNAL_FUNC(_tme_gtk_display_enter_focus),
                    713:                     NULL);
1.1.1.2   root      714:   gtk_signal_connect_after(GTK_OBJECT(screen->tme_gtk_screen_event_box),
                    715:                           "key_press_event",
                    716:                           GTK_SIGNAL_FUNC(_tme_gtk_keyboard_key_event), 
                    717:                           screen);
                    718:   gtk_signal_connect_after(GTK_OBJECT(screen->tme_gtk_screen_event_box),
                    719:                           "key_release_event",
                    720:                           GTK_SIGNAL_FUNC(_tme_gtk_keyboard_key_event), 
                    721:                           screen);
1.1       root      722: 
                    723:   /* the event box can focus, and have it grab the focus now: */
                    724:   GTK_WIDGET_SET_FLAGS(screen->tme_gtk_screen_event_box, GTK_CAN_FOCUS);
                    725:   gtk_widget_grab_focus(screen->tme_gtk_screen_event_box);
                    726: }
                    727: 
                    728: /* this initializes keyboard part of the display: */
                    729: void
                    730: _tme_gtk_keyboard_new(struct tme_gtk_display *display)
                    731: {
                    732: 
                    733:   /* we have no keyboard connection: */
                    734:   display->tme_gtk_display_keyboard_connection = NULL;
                    735:   
                    736:   /* allocate the keyboard buffer: */
                    737:   display->tme_gtk_display_keyboard_buffer
                    738:     = tme_keyboard_buffer_new(1024);
                    739:   display->tme_gtk_display_keyboard_buffer->tme_keyboard_buffer_log_handle
                    740:     = &display->tme_gtk_display_element->tme_element_log_handle;
                    741: 
                    742:   /* allocate the keysyms hash: */
                    743:   display->tme_gtk_display_keyboard_keysyms
                    744:     = tme_hash_new(tme_string_hash,
                    745:                   tme_string_compare,
                    746:                   (tme_hash_data_t) 0);
                    747: 
                    748:   /* allocate the keysym-to-keycode hash: */
                    749:   display->tme_gtk_display_keyboard_keysym_to_keycode
                    750:     = tme_hash_new(tme_direct_hash,
                    751:                   tme_direct_compare,
                    752:                   (tme_hash_data_t) TME_KEYBOARD_KEYVAL_UNDEF);
                    753: 
                    754:   /* there are no bad keysyms: */
                    755:   display->tme_gtk_display_keyboard_keysyms_bad = NULL;
                    756: 
                    757:   /* initialize the input stages of the keyboard buffer.  this needs
                    758:      information that we can't get from GTK or GDK, like which keysyms
                    759:      are attached to which modifiers, and which keysyms can be
                    760:      generated by the keyboard: */
                    761: #ifndef X_DISPLAY_MISSING
                    762:   if (TRUE) {
                    763:     _tme_gtk_keyboard_x11_new(display);
                    764:   }
                    765: #endif /* !X_DISPLAY_MISSING */
                    766:   else {
                    767:     abort();
                    768:   }
                    769: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.