gdkkeys-x11.c 44.7 KB
Newer Older
Havoc Pennington's avatar
Havoc Pennington committed
1 2 3 4 5 6 7 8 9 10
/* GDK - The GIMP Drawing Kit
 * Copyright (C) 2000 Red Hat, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Havoc Pennington's avatar
Havoc Pennington committed
12 13 14
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
Javier Jardón's avatar
Javier Jardón committed
15
 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
Havoc Pennington's avatar
Havoc Pennington committed
16 17 18 19 20 21 22 23 24
 */

/*
 * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
 */

25
#include "config.h"
26

27
#include "gdkx11keys.h"
28 29
#include "gdkkeysprivate.h"
#include "gdkkeysyms.h"
30 31 32
#include "gdkprivate-x11.h"
#include "gdkdisplay-x11.h"

Havoc Pennington's avatar
Havoc Pennington committed
33 34 35 36 37 38 39
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <limits.h>
#include <errno.h>

40 41
#ifdef HAVE_XKB
#include <X11/XKBlib.h>
42 43 44 45 46

/* OSF-4.0 is apparently missing this macro
 */
#  ifndef XkbKeySymEntry
#    define XkbKeySymEntry(d,k,sl,g) \
47
        (XkbKeySym(d,k,((XkbKeyGroupsWidth(d,k)*(g))+(sl))))
48 49
#  endif
#endif /* HAVE_XKB */
50

51 52 53 54 55 56 57 58 59
typedef struct _DirectionCacheEntry DirectionCacheEntry;

struct _DirectionCacheEntry
{
  guint serial;
  Atom group_atom;
  PangoDirection direction;
};

60
struct _GdkX11Keymap
61 62
{
  GdkKeymap     parent_instance;
63

64 65 66 67 68
  gint min_keycode;
  gint max_keycode;
  KeySym* keymap;
  gint keysyms_per_keycode;
  XModifierKeymap* mod_keymap;
69
  guint lock_keysym;
70
  GdkModifierType group_switch_mask;
71
  GdkModifierType num_lock_mask;
72
  GdkModifierType modmap[8];
73
  PangoDirection current_direction;
74
  guint have_direction  : 1;
75
  guint have_lock_state : 1;
76
  guint caps_lock_state : 1;
77 78
  guint num_lock_state  : 1;
  guint modifier_state;
79
  guint current_serial;
80

81 82
#ifdef HAVE_XKB
  XkbDescPtr xkb_desc;
83 84 85 86 87 88 89 90 91
  /* We cache the directions */
  Atom current_group_atom;
  guint current_cache_serial;
  /* A cache of size four should be more than enough, people usually
   * have two groups around, and the xkb limit is four.  It still
   * works correct for more than four groups.  It's just the
   * cache.
   */
  DirectionCacheEntry group_direction_cache[4];
92 93 94
#endif
};

95
struct _GdkX11KeymapClass
96
{
97 98
  GdkKeymapClass parent_class;
};
99

100 101
#define KEYMAP_USE_XKB(keymap) GDK_X11_DISPLAY ((keymap)->display)->use_xkb
#define KEYMAP_XDISPLAY(keymap) GDK_DISPLAY_XDISPLAY ((keymap)->display)
102

103
G_DEFINE_TYPE (GdkX11Keymap, gdk_x11_keymap, GDK_TYPE_KEYMAP)
104 105

static void
106
gdk_x11_keymap_init (GdkX11Keymap *keymap)
107 108 109 110 111 112 113
{
  keymap->min_keycode = 0;
  keymap->max_keycode = 0;

  keymap->keymap = NULL;
  keymap->keysyms_per_keycode = 0;
  keymap->mod_keymap = NULL;
114

115
  keymap->num_lock_mask = 0;
116
  keymap->group_switch_mask = 0;
117
  keymap->lock_keysym = GDK_KEY_Caps_Lock;
118
  keymap->have_direction = FALSE;
119
  keymap->have_lock_state = FALSE;
120 121
  keymap->current_serial = 0;

122
#ifdef HAVE_XKB
123
  keymap->xkb_desc = NULL;
124 125
  keymap->current_group_atom = 0;
  keymap->current_cache_serial = 0;
126
#endif
Havoc Pennington's avatar
Havoc Pennington committed
127

128
}
Havoc Pennington's avatar
Havoc Pennington committed
129

130
static void
131
gdk_x11_keymap_finalize (GObject *object)
132
{
133
  GdkX11Keymap *keymap_x11 = GDK_X11_KEYMAP (object);
134 135 136 137 138 139 140 141 142

  if (keymap_x11->keymap)
    XFree (keymap_x11->keymap);

  if (keymap_x11->mod_keymap)
    XFreeModifiermap (keymap_x11->mod_keymap);

#ifdef HAVE_XKB
  if (keymap_x11->xkb_desc)
143
    XkbFreeKeyboard (keymap_x11->xkb_desc, XkbAllComponentsMask, True);
144 145
#endif

146
  G_OBJECT_CLASS (gdk_x11_keymap_parent_class)->finalize (object);
147 148
}

Havoc Pennington's avatar
Havoc Pennington committed
149
static inline void
150
update_keyrange (GdkX11Keymap *keymap_x11)
Havoc Pennington's avatar
Havoc Pennington committed
151
{
152 153
  if (keymap_x11->max_keycode == 0)
    XDisplayKeycodes (KEYMAP_XDISPLAY (GDK_KEYMAP (keymap_x11)),
154
                      &keymap_x11->min_keycode, &keymap_x11->max_keycode);
Havoc Pennington's avatar
Havoc Pennington committed
155 156 157 158
}

#ifdef HAVE_XKB

159 160
static void
update_modmap (Display      *display,
161
               GdkX11Keymap *keymap_x11)
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
{
  static struct {
    const gchar *name;
    Atom atom;
    GdkModifierType mask;
  } vmods[] = {
    { "Meta", 0, GDK_META_MASK },
    { "Super", 0, GDK_SUPER_MASK },
    { "Hyper", 0, GDK_HYPER_MASK },
    { NULL, 0, 0 }
  };

  gint i, j, k;

  if (!vmods[0].atom)
    for (i = 0; vmods[i].name; i++)
      vmods[i].atom = XInternAtom (display, vmods[i].name, FALSE);

180 181 182
  for (i = 0; i < 8; i++)
    keymap_x11->modmap[i] = 1 << i;

183 184 185
  for (i = 0; i < XkbNumVirtualMods; i++)
    {
      for (j = 0; vmods[j].atom; j++)
186 187 188 189 190 191 192 193 194 195
        {
          if (keymap_x11->xkb_desc->names->vmods[i] == vmods[j].atom)
            {
              for (k = 0; k < 8; k++)
                {
                  if (keymap_x11->xkb_desc->server->vmods[i] & (1 << k))
                    keymap_x11->modmap[k] |= vmods[j].mask;
                }
            }
        }
196 197 198
    }
}

Havoc Pennington's avatar
Havoc Pennington committed
199
static XkbDescPtr
200
get_xkb (GdkX11Keymap *keymap_x11)
Havoc Pennington's avatar
Havoc Pennington committed
201
{
202
  GdkX11Display *display_x11 = GDK_X11_DISPLAY (GDK_KEYMAP (keymap_x11)->display);
203
  Display *xdisplay = display_x11->xdisplay;
204

205
  update_keyrange (keymap_x11);
206

207
  if (keymap_x11->xkb_desc == NULL)
Havoc Pennington's avatar
Havoc Pennington committed
208
    {
209
      keymap_x11->xkb_desc = XkbGetMap (xdisplay, XkbKeySymsMask | XkbKeyTypesMask | XkbModifierMapMask | XkbVirtualModsMask, XkbUseCoreKbd);
210
      if (keymap_x11->xkb_desc == NULL)
Matthias Clasen's avatar
Matthias Clasen committed
211
        {
212
          g_error ("Failed to get keymap");
Matthias Clasen's avatar
Matthias Clasen committed
213 214
          return NULL;
        }
215

216 217 218
      XkbGetNames (xdisplay, XkbGroupNamesMask | XkbVirtualModNamesMask, keymap_x11->xkb_desc);

      update_modmap (xdisplay, keymap_x11);
Havoc Pennington's avatar
Havoc Pennington committed
219
    }
220
  else if (keymap_x11->current_serial != display_x11->keymap_serial)
Havoc Pennington's avatar
Havoc Pennington committed
221
    {
222
      XkbGetUpdatedMap (xdisplay, XkbKeySymsMask | XkbKeyTypesMask | XkbModifierMapMask | XkbVirtualModsMask,
223
                        keymap_x11->xkb_desc);
224 225 226
      XkbGetNames (xdisplay, XkbGroupNamesMask | XkbVirtualModNamesMask, keymap_x11->xkb_desc);

      update_modmap (xdisplay, keymap_x11);
Havoc Pennington's avatar
Havoc Pennington committed
227 228
    }

229
  keymap_x11->current_serial = display_x11->keymap_serial;
Havoc Pennington's avatar
Havoc Pennington committed
230

231
  if (keymap_x11->num_lock_mask == 0)
232
    keymap_x11->num_lock_mask = XkbKeysymToModifiers (KEYMAP_XDISPLAY (GDK_KEYMAP (keymap_x11)), GDK_KEY_Num_Lock);
233

234
  return keymap_x11->xkb_desc;
Havoc Pennington's avatar
Havoc Pennington committed
235 236 237
}
#endif /* HAVE_XKB */

238
/* Whether we were able to turn on detectable-autorepeat using
239
 * XkbSetDetectableAutorepeat. If FALSE, we’ll fall back
240 241 242
 * to checking the next event with XPending().
 */

243
/* Find the index of the group/level pair within the keysyms for a key.
244 245
 * We round up the number of keysyms per keycode to the next even number,
 * otherwise we lose a whole group of keys
246
 */
247
#define KEYSYM_INDEX(keymap_impl, group, level) \
248
  (2 * ((group) % (gint)((keymap_impl->keysyms_per_keycode + 1) / 2)) + (level))
249 250
#define KEYSYM_IS_KEYPAD(s) (((s) >= 0xff80 && (s) <= 0xffbd) || \
                             ((s) >= 0x11000000 && (s) <= 0x1100ffff))
251

252 253
static gint
get_symbol (const KeySym *syms,
254 255 256
            GdkX11Keymap *keymap_x11,
            gint          group,
            gint          level)
257
{
258
  gint index;
259 260

  index = KEYSYM_INDEX(keymap_x11, group, level);
261
  if (index >= keymap_x11->keysyms_per_keycode)
262 263 264 265 266
      return NoSymbol;

  return syms[index];
}

267
static void
268
set_symbol (KeySym       *syms,
269
            GdkX11Keymap *keymap_x11,
270 271 272
            gint          group,
            gint          level,
            KeySym        sym)
273 274 275 276 277 278 279 280 281 282
{
  gint index;

  index = KEYSYM_INDEX(keymap_x11, group, level);
  if (index >= keymap_x11->keysyms_per_keycode)
      return;

  syms[index] = sym;
}

Havoc Pennington's avatar
Havoc Pennington committed
283
static void
284
update_keymaps (GdkX11Keymap *keymap_x11)
Havoc Pennington's avatar
Havoc Pennington committed
285
{
286
  GdkX11Display *display_x11 = GDK_X11_DISPLAY (GDK_KEYMAP (keymap_x11)->display);
287
  Display *xdisplay = display_x11->xdisplay;
288

Havoc Pennington's avatar
Havoc Pennington committed
289
#ifdef HAVE_XKB
290
  g_assert (!KEYMAP_USE_XKB (GDK_KEYMAP (keymap_x11)));
Havoc Pennington's avatar
Havoc Pennington committed
291
#endif
292

293 294
  if (keymap_x11->keymap == NULL ||
      keymap_x11->current_serial != display_x11->keymap_serial)
Havoc Pennington's avatar
Havoc Pennington committed
295 296 297
    {
      gint i;
      gint map_size;
298
      gint keycode;
299

300
      keymap_x11->current_serial = display_x11->keymap_serial;
301

302
      update_keyrange (keymap_x11);
303

304 305
      if (keymap_x11->keymap)
        XFree (keymap_x11->keymap);
Havoc Pennington's avatar
Havoc Pennington committed
306

307 308
      if (keymap_x11->mod_keymap)
        XFreeModifiermap (keymap_x11->mod_keymap);
309

310
      keymap_x11->keymap = XGetKeyboardMapping (xdisplay, keymap_x11->min_keycode,
311 312
                                                keymap_x11->max_keycode - keymap_x11->min_keycode + 1,
                                                &keymap_x11->keysyms_per_keycode);
Havoc Pennington's avatar
Havoc Pennington committed
313

314

315
      /* GDK_KEY_ISO_Left_Tab, as usually configured through XKB, really messes
316
       * up the whole idea of "consumed modifiers" because shift is consumed.
317
       * However, <shift>Tab is not usually GDK_KEY_ISO_Left_Tab without XKB,
318 319
       * we we fudge the map here.
       */
320
      keycode = keymap_x11->min_keycode;
321
      while (keycode <= keymap_x11->max_keycode)
322
        {
323
          KeySym *syms = keymap_x11->keymap + (keycode - keymap_x11->min_keycode) * keymap_x11->keysyms_per_keycode;
324 325 326 327 328 329
          /* Check both groups */
          for (i = 0 ; i < 2 ; i++)
            {
              if (get_symbol (syms, keymap_x11, i, 0) == GDK_KEY_Tab)
                set_symbol (syms, keymap_x11, i, 1, GDK_KEY_ISO_Left_Tab);
            }
330 331 332 333 334

          /*
           * If there is one keysym and the key symbol has upper and lower
           * case variants fudge the keymap
           */
335
          if (get_symbol (syms, keymap_x11, 0, 1) == 0)
336 337 338 339
            {
              guint lower;
              guint upper;

340
              gdk_keyval_convert_case (get_symbol (syms, keymap_x11, 0, 0), &lower, &upper);
341 342
              if (lower != upper)
                {
343 344
                  set_symbol (syms, keymap_x11, 0, 0, lower);
                  set_symbol (syms, keymap_x11, 0, 1, upper);
345 346
                }
            }
347

348 349 350
          ++keycode;
        }

351
      keymap_x11->mod_keymap = XGetModifierMapping (xdisplay);
Havoc Pennington's avatar
Havoc Pennington committed
352

353
      keymap_x11->lock_keysym = GDK_KEY_VoidSymbol;
354
      keymap_x11->group_switch_mask = 0;
355
      keymap_x11->num_lock_mask = 0;
356 357

      for (i = 0; i < 8; i++)
358 359
        keymap_x11->modmap[i] = 1 << i;

360 361
      /* There are 8 sets of modifiers, with each set containing
       * max_keypermod keycodes.
Havoc Pennington's avatar
Havoc Pennington committed
362
       */
363
      map_size = 8 * keymap_x11->mod_keymap->max_keypermod;
364
      for (i = 0; i < map_size; i++)
Havoc Pennington's avatar
Havoc Pennington committed
365
        {
366
          /* Get the key code at this point in the map. */
367
          gint keycode = keymap_x11->mod_keymap->modifiermap[i];
368 369
          gint j;
          KeySym *syms;
370
          guint mask;
371 372 373 374 375 376 377 378

          /* Ignore invalid keycodes. */
          if (keycode < keymap_x11->min_keycode ||
              keycode > keymap_x11->max_keycode)
            continue;

          syms = keymap_x11->keymap + (keycode - keymap_x11->min_keycode) * keymap_x11->keysyms_per_keycode;

379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
          mask = 0;
          for (j = 0; j < keymap_x11->keysyms_per_keycode; j++)
            {
              if (syms[j] == GDK_KEY_Meta_L ||
                  syms[j] == GDK_KEY_Meta_R)
                mask |= GDK_META_MASK;
              else if (syms[j] == GDK_KEY_Hyper_L ||
                       syms[j] == GDK_KEY_Hyper_R)
                mask |= GDK_HYPER_MASK;
              else if (syms[j] == GDK_KEY_Super_L ||
                       syms[j] == GDK_KEY_Super_R)
                mask |= GDK_SUPER_MASK;
            }

          keymap_x11->modmap[i/keymap_x11->mod_keymap->max_keypermod] |= mask;
394

395
          /* The fourth modifier, GDK_MOD1_MASK is 1 << 3.
396
           * Each group of max_keypermod entries refers to the same modifier.
397
           */
398
          mask = 1 << (i / keymap_x11->mod_keymap->max_keypermod);
399 400

          switch (mask)
Havoc Pennington's avatar
Havoc Pennington committed
401
            {
402 403 404 405 406
            case GDK_LOCK_MASK:
              /* Get the Lock keysym.  If any keysym bound to the Lock modifier
               * is Caps_Lock, we will interpret the modifier as Caps_Lock;
               * otherwise, if any is bound to Shift_Lock, we will interpret
               * the modifier as Shift_Lock. Otherwise, the lock modifier
407
               * has no effect.
408
               */
409 410 411 412 413 414 415 416
              for (j = 0; j < keymap_x11->keysyms_per_keycode; j++)
                {
                  if (syms[j] == GDK_KEY_Caps_Lock)
                    keymap_x11->lock_keysym = GDK_KEY_Caps_Lock;
                  else if (syms[j] == GDK_KEY_Shift_Lock &&
                           keymap_x11->lock_keysym == GDK_KEY_VoidSymbol)
                    keymap_x11->lock_keysym = GDK_KEY_Shift_Lock;
                }
417 418 419 420 421 422 423 424 425 426 427 428 429
              break;

            case GDK_CONTROL_MASK:
            case GDK_SHIFT_MASK:
            case GDK_MOD1_MASK:
              /* Some keyboard maps are known to map Mode_Switch as an
               * extra Mod1 key. In circumstances like that, it won't be
               * used to switch groups.
               */
              break;

            default:
              /* Find the Mode_Switch and Num_Lock modifiers. */
430
              for (j = 0; j < keymap_x11->keysyms_per_keycode; j++)
Havoc Pennington's avatar
Havoc Pennington committed
431
                {
432
                  if (syms[j] == GDK_KEY_Mode_switch)
Havoc Pennington's avatar
Havoc Pennington committed
433 434
                    {
                      /* This modifier swaps groups */
435
                      keymap_x11->group_switch_mask |= mask;
Havoc Pennington's avatar
Havoc Pennington committed
436
                    }
437
                  else if (syms[j] == GDK_KEY_Num_Lock)
438
                    {
439
                      /* This modifier is used for Num_Lock */
440 441
                      keymap_x11->num_lock_mask |= mask;
                    }
Havoc Pennington's avatar
Havoc Pennington committed
442
                }
443
              break;
Havoc Pennington's avatar
Havoc Pennington committed
444 445 446 447 448 449
            }
        }
    }
}

static const KeySym*
450
get_keymap (GdkX11Keymap *keymap_x11)
Havoc Pennington's avatar
Havoc Pennington committed
451
{
452
  update_keymaps (keymap_x11);
453

454
  return keymap_x11->keymap;
Havoc Pennington's avatar
Havoc Pennington committed
455 456
}

457
#ifdef HAVE_XKB
458
static PangoDirection
459
get_direction (XkbDescRec *xkb,
460
               gint        group)
461 462 463 464 465 466 467
{
  gint code;

  gint rtl_minus_ltr = 0; /* total number of RTL keysyms minus LTR ones */

  for (code = xkb->min_key_code; code <= xkb->max_key_code; code++)
    {
468 469 470
      gint level = 0;
      KeySym sym = XkbKeySymEntry (xkb, code, level, group);
      PangoDirection dir = pango_unichar_direction (gdk_keyval_to_unicode (sym));
471

472
      switch (dir)
473 474 475 476 477 478 479 480 481 482
        {
        case PANGO_DIRECTION_RTL:
          rtl_minus_ltr++;
          break;
        case PANGO_DIRECTION_LTR:
          rtl_minus_ltr--;
          break;
        default:
          break;
        }
483
    }
484

485 486 487 488 489 490
  if (rtl_minus_ltr > 0)
    return PANGO_DIRECTION_RTL;
  else
    return PANGO_DIRECTION_LTR;
}

491
static PangoDirection
492 493 494
get_direction_from_cache (GdkX11Keymap *keymap_x11,
                          XkbDescPtr    xkb,
                          gint          group)
495
{
496
  Atom group_atom = xkb->names->groups[group];
497

498 499
  gboolean cache_hit = FALSE;
  DirectionCacheEntry *cache = keymap_x11->group_direction_cache;
500

501 502
  PangoDirection direction = PANGO_DIRECTION_NEUTRAL;
  gint i;
503

504 505 506 507 508
  if (keymap_x11->have_direction)
    {
      /* lookup in cache */
      for (i = 0; i < G_N_ELEMENTS (keymap_x11->group_direction_cache); i++)
      {
509 510 511 512 513 514 515 516
        if (cache[i].group_atom == group_atom)
          {
            cache_hit = TRUE;
            cache[i].serial = keymap_x11->current_cache_serial++; /* freshen */
            direction = cache[i].direction;
            group_atom = cache[i].group_atom;
            break;
          }
517 518 519 520 521 522
      }
    }
  else
    {
      /* initialize cache */
      for (i = 0; i < G_N_ELEMENTS (keymap_x11->group_direction_cache); i++)
523 524 525 526
        {
          cache[i].group_atom = 0;
          cache[i].serial = keymap_x11->current_cache_serial;
        }
527 528
      keymap_x11->current_cache_serial++;
    }
529

530 531 532 533
  /* insert in cache */
  if (!cache_hit)
    {
      gint oldest = 0;
534

535
      direction = get_direction (xkb, group);
536

537 538
      /* remove the oldest entry */
      for (i = 0; i < G_N_ELEMENTS (keymap_x11->group_direction_cache); i++)
539 540 541 542 543
        {
          if (cache[i].serial < cache[oldest].serial)
            oldest = i;
        }

544 545 546 547
      cache[oldest].group_atom = group_atom;
      cache[oldest].direction = direction;
      cache[oldest].serial = keymap_x11->current_cache_serial++;
    }
548

549 550 551 552 553
  return direction;
}

static int
get_num_groups (GdkKeymap *keymap,
554
                XkbDescPtr xkb)
555 556 557 558
{
      Display *display = KEYMAP_XDISPLAY (keymap);
      XkbGetControls(display, XkbSlowKeysMask, xkb);
      XkbGetUpdatedMap (display, XkbKeySymsMask | XkbKeyTypesMask |
559
                        XkbModifierMapMask | XkbVirtualModsMask, xkb);
560 561
      return xkb->ctrls->num_groups;
}
562

563
static gboolean
564
update_direction (GdkX11Keymap *keymap_x11,
565
                  gint          group)
566 567 568
{
  XkbDescPtr xkb = get_xkb (keymap_x11);
  Atom group_atom;
569 570
  gboolean had_direction;
  PangoDirection old_direction;
571

572 573
  had_direction = keymap_x11->have_direction;
  old_direction = keymap_x11->current_direction;
574 575 576 577 578 579 580 581

  group_atom = xkb->names->groups[group];

  /* a group change? */
  if (!keymap_x11->have_direction || keymap_x11->current_group_atom != group_atom)
    {
      keymap_x11->current_direction = get_direction_from_cache (keymap_x11, xkb, group);
      keymap_x11->current_group_atom = group_atom;
582
      keymap_x11->have_direction = TRUE;
583
    }
584 585 586 587 588

  return !had_direction || old_direction != keymap_x11->current_direction;
}

static gboolean
589
update_lock_state (GdkX11Keymap *keymap_x11,
590 591
                   gint          locked_mods,
                   gint          effective_mods)
592
{
593 594
  XkbDescPtr xkb G_GNUC_UNUSED;
  gboolean have_lock_state;
595
  gboolean caps_lock_state;
596
  gboolean num_lock_state;
597
  guint modifier_state;
598

599 600 601 602
  /* ensure keymap_x11->num_lock_mask is initialized */
  xkb = get_xkb (keymap_x11);

  have_lock_state = keymap_x11->have_lock_state;
603
  caps_lock_state = keymap_x11->caps_lock_state;
604
  num_lock_state = keymap_x11->num_lock_state;
605
  modifier_state = keymap_x11->modifier_state;
606

607
  keymap_x11->have_lock_state = TRUE;
608
  keymap_x11->caps_lock_state = (locked_mods & GDK_LOCK_MASK) != 0;
609
  keymap_x11->num_lock_state = (locked_mods & keymap_x11->num_lock_mask) != 0;
610 611
  /* FIXME: sanitize this */
  keymap_x11->modifier_state = (guint)effective_mods;
612

613 614
  return !have_lock_state
         || (caps_lock_state != keymap_x11->caps_lock_state)
615 616
         || (num_lock_state != keymap_x11->num_lock_state)
         || (modifier_state != keymap_x11->modifier_state);
617 618
}

619 620
/* keep this in sync with the XkbSelectEventDetails()
 * call in gdk_display_open()
Matthias Clasen's avatar
Matthias Clasen committed
621
 */
622
void
623 624
_gdk_x11_keymap_state_changed (GdkDisplay *display,
                               XEvent     *xevent)
625
{
626
  GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
Matthias Clasen's avatar
Matthias Clasen committed
627
  XkbEvent *xkb_event = (XkbEvent *)xevent;
628

629
  if (display_x11->keymap)
630
    {
631
      GdkX11Keymap *keymap_x11 = GDK_X11_KEYMAP (display_x11->keymap);
632

633
      if (update_direction (keymap_x11, XkbStateGroup (&xkb_event->state)))
634
        g_signal_emit_by_name (keymap_x11, "direction-changed");
635

636 637 638
      if (update_lock_state (keymap_x11,
                             xkb_event->state.locked_mods,
                             xkb_event->state.mods))
639
        g_signal_emit_by_name (keymap_x11, "state-changed");
640 641
    }
}
642

643 644
#endif /* HAVE_XKB */

645 646 647 648 649 650 651 652 653 654 655 656 657 658
static void
ensure_lock_state (GdkKeymap *keymap)
{
#ifdef HAVE_XKB
  if (KEYMAP_USE_XKB (keymap))
    {
      GdkX11Keymap *keymap_x11 = GDK_X11_KEYMAP (keymap);

      if (!keymap_x11->have_lock_state)
        {
          GdkDisplay *display = keymap->display;
          XkbStateRec state_rec;

          XkbGetState (GDK_DISPLAY_XDISPLAY (display), XkbUseCoreKbd, &state_rec);
659
          update_lock_state (keymap_x11, state_rec.locked_mods, state_rec.mods);
660 661 662 663 664
        }
    }
#endif /* HAVE_XKB */
}

665
void
666
_gdk_x11_keymap_keys_changed (GdkDisplay *display)
667
{
668
  GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
669

670
  ++display_x11->keymap_serial;
671

672 673 674 675
  if (display_x11->keymap)
    g_signal_emit_by_name (display_x11->keymap, "keys_changed", 0);
}

676 677
static PangoDirection
gdk_x11_keymap_get_direction (GdkKeymap *keymap)
678
{
679
#ifdef HAVE_XKB
680
  if (KEYMAP_USE_XKB (keymap))
681
    {
682
      GdkX11Keymap *keymap_x11 = GDK_X11_KEYMAP (keymap);
Matthias Clasen's avatar
Matthias Clasen committed
683

684
      if (!keymap_x11->have_direction)
685
        {
686
          GdkDisplay *display = keymap->display;
687 688 689 690 691 692 693
          XkbStateRec state_rec;

          XkbGetState (GDK_DISPLAY_XDISPLAY (display), XkbUseCoreKbd,
                       &state_rec);
          update_direction (keymap_x11, XkbStateGroup (&state_rec));
        }

694
      return keymap_x11->current_direction;
695 696 697
    }
  else
#endif /* HAVE_XKB */
698
    return PANGO_DIRECTION_NEUTRAL;
699 700
}

701 702
static gboolean
gdk_x11_keymap_have_bidi_layouts (GdkKeymap *keymap)
703
{
704
#ifdef HAVE_XKB
705 706
  if (KEYMAP_USE_XKB (keymap))
    {
707
      GdkX11Keymap *keymap_x11 = GDK_X11_KEYMAP (keymap);
708 709 710 711 712 713 714 715 716
      XkbDescPtr xkb = get_xkb (keymap_x11);
      int num_groups = get_num_groups (keymap, xkb);

      int i;
      gboolean have_ltr_keyboard = FALSE;
      gboolean have_rtl_keyboard = FALSE;

      for (i = 0; i < num_groups; i++)
      {
717 718 719 720
        if (get_direction_from_cache (keymap_x11, xkb, i) == PANGO_DIRECTION_RTL)
          have_rtl_keyboard = TRUE;
        else
          have_ltr_keyboard = TRUE;
721 722 723 724 725 726 727 728 729
      }

      return have_ltr_keyboard && have_rtl_keyboard;
    }
  else
#endif /* HAVE_XKB */
    return FALSE;
}

730 731
static gboolean
gdk_x11_keymap_get_caps_lock_state (GdkKeymap *keymap)
732
{
733
  GdkX11Keymap *keymap_x11 = GDK_X11_KEYMAP (keymap);
734

735 736
  ensure_lock_state (keymap);

737
  return keymap_x11->caps_lock_state;
738 739
}

740 741
static gboolean
gdk_x11_keymap_get_num_lock_state (GdkKeymap *keymap)
742
{
743
  GdkX11Keymap *keymap_x11 = GDK_X11_KEYMAP (keymap);
744

745 746
  ensure_lock_state (keymap);

747
  return keymap_x11->num_lock_state;
748
}
749

750 751 752 753 754 755 756 757 758 759
static guint
gdk_x11_keymap_get_modifier_state (GdkKeymap *keymap)
{
  GdkX11Keymap *keymap_x11 = GDK_X11_KEYMAP (keymap);

  ensure_lock_state (keymap);

  return keymap_x11->modifier_state;
}

760 761
static gboolean
gdk_x11_keymap_get_entries_for_keyval (GdkKeymap     *keymap,
762 763 764
                                       guint          keyval,
                                       GdkKeymapKey **keys,
                                       gint          *n_keys)
Havoc Pennington's avatar
Havoc Pennington committed
765
{
766
  GdkX11Keymap *keymap_x11 = GDK_X11_KEYMAP (keymap);
Havoc Pennington's avatar
Havoc Pennington committed
767
  GArray *retval;
768

Havoc Pennington's avatar
Havoc Pennington committed
769 770 771
  retval = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));

#ifdef HAVE_XKB
772
  if (KEYMAP_USE_XKB (keymap))
Havoc Pennington's avatar
Havoc Pennington committed
773 774 775
    {
      /* See sec 15.3.4 in XKB docs */

776
      XkbDescRec *xkb = get_xkb (keymap_x11);
Havoc Pennington's avatar
Havoc Pennington committed
777
      gint keycode;
778

779
      keycode = keymap_x11->min_keycode;
Havoc Pennington's avatar
Havoc Pennington committed
780

781
      while (keycode <= keymap_x11->max_keycode)
Havoc Pennington's avatar
Havoc Pennington committed
782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811
        {
          gint max_shift_levels = XkbKeyGroupsWidth (xkb, keycode); /* "key width" */
          gint group = 0;
          gint level = 0;
          gint total_syms = XkbKeyNumSyms (xkb, keycode);
          gint i = 0;
          KeySym *entry;

          /* entry is an array with all syms for group 0, all
           * syms for group 1, etc. and for each group the
           * shift level syms are in order
           */
          entry = XkbKeySymsPtr (xkb, keycode);

          while (i < total_syms)
            {
              /* check out our cool loop invariant */
              g_assert (i == (group * max_shift_levels + level));

              if (entry[i] == keyval)
                {
                  /* Found a match */
                  GdkKeymapKey key;

                  key.keycode = keycode;
                  key.group = group;
                  key.level = level;

                  g_array_append_val (retval, key);

812 813
                  g_assert (XkbKeySymEntry (xkb, keycode, level, group) ==
                            keyval);
Havoc Pennington's avatar
Havoc Pennington committed
814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832
                }

              ++level;

              if (level == max_shift_levels)
                {
                  level = 0;
                  ++group;
                }

              ++i;
            }

          ++keycode;
        }
    }
  else
#endif
    {
833
      const KeySym *map = get_keymap (keymap_x11);
Havoc Pennington's avatar
Havoc Pennington committed
834
      gint keycode;
835

836
      keycode = keymap_x11->min_keycode;
837
      while (keycode <= keymap_x11->max_keycode)
Havoc Pennington's avatar
Havoc Pennington committed
838
        {
839
          const KeySym *syms = map + (keycode - keymap_x11->min_keycode) * keymap_x11->keysyms_per_keycode;
Havoc Pennington's avatar
Havoc Pennington committed
840 841
          gint i = 0;

842
          while (i < keymap_x11->keysyms_per_keycode)
Havoc Pennington's avatar
Havoc Pennington committed
843 844 845 846 847 848 849 850 851 852 853 854 855 856
            {
              if (syms[i] == keyval)
                {
                  /* found a match */
                  GdkKeymapKey key;

                  key.keycode = keycode;

                  /* The "classic" non-XKB keymap has 2 levels per group */
                  key.group = i / 2;
                  key.level = i % 2;

                  g_array_append_val (retval, key);
                }
857

Havoc Pennington's avatar
Havoc Pennington committed
858 859
              ++i;
            }
860 861

          ++keycode;
Havoc Pennington's avatar
Havoc Pennington committed
862 863 864 865 866 867 868 869 870 871 872 873 874
        }
    }

  if (retval->len > 0)
    {
      *keys = (GdkKeymapKey*) retval->data;
      *n_keys = retval->len;
    }
  else
    {
      *keys = NULL;
      *n_keys = 0;
    }
875

Havoc Pennington's avatar
Havoc Pennington committed
876 877 878 879 880
  g_array_free (retval, retval->len > 0 ? FALSE : TRUE);

  return *n_keys > 0;
}

881 882
static gboolean
gdk_x11_keymap_get_entries_for_keycode (GdkKeymap     *keymap,
883 884 885 886
                                        guint          hardware_keycode,
                                        GdkKeymapKey **keys,
                                        guint        **keyvals,
                                        gint          *n_entries)
Havoc Pennington's avatar
Havoc Pennington committed
887
{
888
  GdkX11Keymap *keymap_x11 = GDK_X11_KEYMAP (keymap);
Havoc Pennington's avatar
Havoc Pennington committed
889 890 891
  GArray *key_array;
  GArray *keyval_array;

892
  update_keyrange (keymap_x11);
Havoc Pennington's avatar
Havoc Pennington committed
893

894 895
  if (hardware_keycode < keymap_x11->min_keycode ||
      hardware_keycode > keymap_x11->max_keycode)
Havoc Pennington's avatar
Havoc Pennington committed
896 897 898 899 900 901 902 903 904
    {
      if (keys)
        *keys = NULL;
      if (keyvals)
        *keyvals = NULL;

      *n_entries = 0;
      return FALSE;
    }
905

Havoc Pennington's avatar
Havoc Pennington committed
906 907 908 909
  if (keys)
    key_array = g_array_new (FALSE, FALSE, sizeof (GdkKeymapKey));
  else
    key_array = NULL;
910

Havoc Pennington's avatar
Havoc Pennington committed
911 912 913 914
  if (keyvals)
    keyval_array = g_array_new (FALSE, FALSE, sizeof (guint));
  else
    keyval_array = NULL;
915

Havoc Pennington's avatar
Havoc Pennington committed
916
#ifdef HAVE_XKB
917
  if (KEYMAP_USE_XKB (keymap))
Havoc Pennington's avatar
Havoc Pennington committed
918 919 920
    {
      /* See sec 15.3.4 in XKB docs */

921
      XkbDescRec *xkb = get_xkb (keymap_x11);
Havoc Pennington's avatar
Havoc Pennington committed
922 923 924 925 926 927
      gint max_shift_levels;
      gint group = 0;
      gint level = 0;
      gint total_syms;
      gint i = 0;
      KeySym *entry;
928

Havoc Pennington's avatar
Havoc Pennington committed
929 930 931 932 933 934 935 936 937 938
      max_shift_levels = XkbKeyGroupsWidth (xkb, hardware_keycode); /* "key width" */
      total_syms = XkbKeyNumSyms (xkb, hardware_keycode);

      /* entry is an array with all syms for group 0, all
       * syms for group 1, etc. and for each group the
       * shift level syms are in order
       */
      entry = XkbKeySymsPtr (xkb, hardware_keycode);

      while (i < total_syms)
939 940
        {
          /* check out our cool loop invariant */
Havoc Pennington's avatar
Havoc Pennington committed
941 942 943 944 945
          g_assert (i == (group * max_shift_levels + level));

          if (key_array)
            {
              GdkKeymapKey key;
946

Havoc Pennington's avatar
Havoc Pennington committed
947 948 949
              key.keycode = hardware_keycode;
              key.group = group;
              key.level = level;
950

Havoc Pennington's avatar
Havoc Pennington committed
951 952 953 954 955
              g_array_append_val (key_array, key);
            }

          if (keyval_array)
            g_array_append_val (keyval_array, entry[i]);
956

Havoc Pennington's avatar
Havoc Pennington committed
957
          ++level;
958

Havoc Pennington's avatar
Havoc Pennington committed
959 960 961 962 963
          if (level == max_shift_levels)
            {
              level = 0;
              ++group;
            }
964

Havoc Pennington's avatar
Havoc Pennington committed
965 966 967 968 969 970
          ++i;
        }
    }
  else
#endif
    {
971
      const KeySym *map = get_keymap (keymap_x11);
Havoc Pennington's avatar
Havoc Pennington committed
972 973 974
      const KeySym *syms;
      gint i = 0;

975
      syms = map + (hardware_keycode - keymap_x11->min_keycode) * keymap_x11->keysyms_per_keycode;
Havoc Pennington's avatar
Havoc Pennington committed
976

977
      while (i < keymap_x11->keysyms_per_keycode)
Havoc Pennington's avatar
Havoc Pennington committed
978 979 980 981
        {
          if (key_array)
            {
              GdkKeymapKey key;
982

Havoc Pennington's avatar
Havoc Pennington committed
983
              key.keycode = hardware_keycode;
984

Havoc Pennington's avatar
Havoc Pennington committed
985 986 987
              /* The "classic" non-XKB keymap has 2 levels per group */
              key.group = i / 2;
              key.level = i % 2;
988

Havoc Pennington's avatar
Havoc Pennington committed
989 990 991 992 993
              g_array_append_val (key_array, key);
            }

          if (keyval_array)
            g_array_append_val (keyval_array, syms[i]);
994

Havoc Pennington's avatar
Havoc Pennington committed
995 996 997 998
          ++i;
        }
    }

Matthias Clasen's avatar
Matthias Clasen committed
999
  *n_entries = 0;
Havoc Pennington's avatar
Havoc Pennington committed
1000

Matthias Clasen's avatar
Matthias Clasen committed
1001 1002 1003 1004
  if (keys)
    {
      *n_entries = key_array->len;
      *keys = (GdkKeymapKey*) g_array_free (key_array, FALSE);
Havoc Pennington's avatar
Havoc Pennington committed
1005
    }
1006

Matthias Clasen's avatar
Matthias Clasen committed
1007
  if (keyvals)
Havoc Pennington's avatar
Havoc Pennington committed
1008
    {
Matthias Clasen's avatar
Matthias Clasen committed
1009 1010
      *n_entries = keyval_array->len;
      *keyvals = (guint*) g_array_free (keyval_array, FALSE);
Havoc Pennington's avatar
Havoc Pennington committed
1011 1012 1013 1014 1015
    }

  return *n_entries > 0;
}

1016 1017
static guint
gdk_x11_keymap_lookup_key (GdkKeymap          *keymap,
1018
                           const GdkKeymapKey *key)
Havoc Pennington's avatar
Havoc Pennington committed
1019
{
1020
  GdkX11Keymap *keymap_x11 = GDK_X11_KEYMAP (keymap);
1021

Havoc Pennington's avatar
Havoc Pennington committed
1022
  g_return_val_if_fail (key->group < 4, 0);
1023

Havoc Pennington's avatar
Havoc Pennington committed
1024
#ifdef HAVE_XKB
1025
  if (KEYMAP_USE_XKB (keymap))
Havoc Pennington's avatar
Havoc Pennington committed
1026
    {
1027
      XkbDescRec *xkb = get_xkb (keymap_x11);
1028

Havoc Pennington's avatar
Havoc Pennington committed
1029 1030 1031 1032 1033
      return XkbKeySymEntry (xkb, key->keycode, key->level, key->group);
    }
  else
#endif
    {
1034 1035
      const KeySym *map = get_keymap (keymap_x11);
      const KeySym *syms = map + (key->keycode - keymap_x11->min_keycode) * keymap_x11->keysyms_per_keycode;
1036
      return get_symbol (syms, keymap_x11, key->group, key->level);
Havoc Pennington's avatar
Havoc Pennington committed
1037 1038 1039 1040
    }
}

#ifdef HAVE_XKB
1041 1042 1043 1044
/* This is copied straight from XFree86 Xlib, to:
 *  - add the group and level return.
 *  - change the interpretation of mods_rtrn as described
 *    in the docs for gdk_keymap_translate_keyboard_state()
1045
 * It’s unchanged for ease of diff against the Xlib sources; don't
1046
 * reformat it.
Havoc Pennington's avatar
Havoc Pennington committed
1047 1048 1049 1050 1051 1052 1053
 */
static Bool
MyEnhancedXkbTranslateKeyCode(register XkbDescPtr     xkb,
                              KeyCode                 key,
                              register unsigned int   mods,
                              unsigned int *          mods_rtrn,
                              KeySym *                keysym_rtrn,
1054 1055
                              int *                   group_rtrn,
                              int *                   level_rtrn)
Havoc Pennington's avatar
Havoc Pennington committed
1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066