Annotation of tme/host/gtk/gtk-keyboard.c, revision 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.