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

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: }

unix.superglobalmegacorp.com

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