Logo Search packages:      
Sourcecode: faumachine version File versions  Download package

gui-gtk.c

/*
 * $Id: gui-gtk.c,v 1.18 2009-02-03 14:43:04 potyra Exp $
 *
 * Copyright (C) 2003-2009 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */

#include "config.h"

#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>

#define __GTK_ABOUT_DIALOG_H__
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include <gdk/gdkx.h>
#include <X11/Xlib.h>
#include <glib.h>

#include "umutil.h"

#include "glue-gui-gtk.h"
#include "glue-log.h"
#include "glue-main.h"

#include "gui.h"
#include "gui-gtk.h"

#define DEBUG 0

static int grabbed = 0;
static int warped = 0;
static int lastStepUngrab = 0;

static unsigned char pressed_keys[128];

/* Local Variables */
static GtkWidget *fi_window;

static GtkWidget *notebook;
static int npages = 0;
GtkWidget *statusbar;

static struct component_info {
      const char *name;
      GtkWidget *mainvbox;
      GtkWidget *mainhbox;
} components[100];

#define MAX_LAYOUTS 128
static char * layout_names[MAX_LAYOUTS];
static int nlayouts = 0;

static GtkWidget *grabbing_text;


static const struct {
      const char* name;
      int keysym;
} gtk_keysyms[] = {
      /* ascii */
      { "space",                GDK_space},
      { "exclam",               GDK_exclam},
      { "quotedbl",             GDK_quotedbl},
      { "numbersign",           GDK_numbersign},
      { "dollar",               GDK_dollar},
      { "percent",              GDK_percent},
      { "ampersand",            GDK_ampersand},
      { "apostrophe",           GDK_apostrophe},
      { "parenleft",            GDK_parenleft},
      { "parenright",           GDK_parenright},
      { "asterisk",             GDK_asterisk},
      { "plus",                 GDK_plus},
      { "comma",                GDK_comma},
      { "minus",                GDK_minus},
      { "period",               GDK_period},
      { "slash",                GDK_slash},
      { "0",                    GDK_0},
      { "1",                    GDK_1},
      { "2",                    GDK_2},
      { "3",                    GDK_3},
      { "4",                    GDK_4},
      { "5",                    GDK_5},
      { "6",                    GDK_6},
      { "7",                    GDK_7},
      { "8",                    GDK_8},
      { "9",                    GDK_9},
      { "colon",                GDK_colon},
      { "semicolon",            GDK_semicolon},
      { "less",                 GDK_less},
      { "equal",                GDK_equal},
      { "greater",              GDK_greater},
      { "question",             GDK_question},
      { "at",                   GDK_at},
      { "A",                    GDK_A},
      { "B",                    GDK_B},
      { "C",                    GDK_C},
      { "D",                    GDK_D},
      { "E",                    GDK_E},
      { "F",                    GDK_F},
      { "G",                    GDK_G},
      { "H",                    GDK_H},
      { "I",                    GDK_I},
      { "J",                    GDK_J},
      { "K",                    GDK_K},
      { "L",                    GDK_L},
      { "M",                    GDK_M},
      { "N",                    GDK_N},
      { "O",                    GDK_O},
      { "P",                    GDK_P},
      { "Q",                    GDK_Q},
      { "R",                    GDK_R},
      { "S",                    GDK_S},
      { "T",                    GDK_T},
      { "U",                    GDK_U},
      { "V",                    GDK_V},
      { "W",                    GDK_W},
      { "X",                    GDK_X},
      { "Y",                    GDK_Y},
      { "Z",                    GDK_Z},
      { "bracketleft",          GDK_bracketleft},
      { "backslash",            GDK_backslash},
      { "bracketright",         GDK_bracketright},
      { "asciicircum",          GDK_asciicircum},
      { "underscore",           GDK_underscore},
      { "grave",                GDK_grave},
      { "a",                    GDK_a},
      { "b",                    GDK_b},
      { "c",                    GDK_c},
      { "d",                    GDK_d},
      { "e",                    GDK_e},
      { "f",                    GDK_f},
      { "g",                    GDK_g},
      { "h",                    GDK_h},
      { "i",                    GDK_i},
      { "j",                    GDK_j},
      { "k",                    GDK_k},
      { "l",                    GDK_l},
      { "m",                    GDK_m},
      { "n",                    GDK_n},
      { "o",                    GDK_o},
      { "p",                    GDK_p},
      { "q",                    GDK_q},
      { "r",                    GDK_r},
      { "s",                    GDK_s},
      { "t",                    GDK_t},
      { "u",                    GDK_u},
      { "v",                    GDK_v},
      { "w",                    GDK_w},
      { "x",                    GDK_x},
      { "y",                    GDK_y},
      { "z",                    GDK_z},
      { "braceleft",            GDK_braceleft},
      { "bar",                  GDK_bar},
      { "braceright",           GDK_braceright},
      { "asciitilde",           GDK_asciitilde},
      { "dead_tilde",           GDK_dead_tilde},
      { "dead_acute",           GDK_dead_acute},
      { "dead_grave",           GDK_dead_grave},
      { "dead_circumflex",      GDK_dead_circumflex},

      /* latin 1 extensions */
      { "nobreakspace",         GDK_nobreakspace},
      { "exclamdown",           GDK_exclamdown},
      { "cent",                 GDK_cent},
      { "sterling",             GDK_sterling},
      { "currency",             GDK_currency},
      { "yen",                  GDK_yen},
      { "brokenbar",            GDK_brokenbar},
      { "section",              GDK_section},
      { "diaeresis",            GDK_diaeresis},
      { "copyright",            GDK_copyright},
      { "ordfeminine",          GDK_ordfeminine},
      { "guillemotleft",        GDK_guillemotleft},
      { "notsign",              GDK_notsign},
      { "hyphen",               GDK_hyphen},
      { "registered",           GDK_registered},
      { "macron",               GDK_macron},
      { "degree",               GDK_degree},
      { "plusminus",            GDK_plusminus},
      { "twosuperior",          GDK_twosuperior},
      { "threesuperior",        GDK_threesuperior},
      { "acute",                GDK_acute},
      { "caron",                GDK_caron},
      { "breve",                GDK_breve},
      { "ogonek",               GDK_ogonek},
      { "abovedot",             GDK_abovedot},
      { "doubleacute",          GDK_doubleacute},
      { "mu",                   GDK_mu},
      { "paragraph",            GDK_paragraph},
      { "periodcentered",       GDK_periodcentered},
      { "cedilla",              GDK_cedilla},
      { "onesuperior",          GDK_onesuperior},
      { "masculine",            GDK_masculine},
      { "guillemotright",       GDK_guillemotright},
      { "onequarter",           GDK_onequarter},
      { "onehalf",              GDK_onehalf},
      { "threequarters",        GDK_threequarters},
      { "questiondown",         GDK_questiondown},
      { "endash",               GDK_endash},
      { "Agrave",               GDK_Agrave},
      { "Aacute",               GDK_Aacute},
      { "Acircumflex",          GDK_Acircumflex},
      { "Atilde",               GDK_Atilde},
      { "Adiaeresis",           GDK_Adiaeresis},
      { "Aring",                GDK_Aring},
      { "Amacron",              GDK_Amacron},
      { "Aogonek",              GDK_Aogonek},
      { "AE",                   GDK_AE},
      { "Ccedilla",             GDK_Ccedilla},
      { "Gcedilla",             GDK_Gcedilla},
      { "Kcedilla",             GDK_Kcedilla},
      { "Lcedilla",             GDK_Lcedilla},
      { "Ncedilla",             GDK_Ncedilla},
      { "Rcedilla",             GDK_Rcedilla},
      { "Scedilla",             GDK_Scedilla},
      { "Ccaron",               GDK_Ccaron},
      { "Scaron",               GDK_Scaron},
      { "Zcaron",               GDK_Zcaron},
      { "Egrave",               GDK_Egrave},
      { "Cacute",               GDK_Cacute},
      { "Nacute",               GDK_Nacute},
      { "Sacute",               GDK_Sacute},
      { "Zacute",               GDK_Zacute},
      { "Zabovedot",            GDK_Zabovedot},
      { "Eacute",               GDK_Eacute},
      { "Ecircumflex",          GDK_Ecircumflex},
      { "Ediaeresis",           GDK_Ediaeresis},
      { "Emacron",              GDK_Emacron},
      { "Eogonek",              GDK_Eogonek},
      { "Eabovedot",            GDK_Eabovedot},
      { "Igrave",               GDK_Igrave},
      { "Iacute",               GDK_Iacute},
      { "Icircumflex",          GDK_Icircumflex},
      { "Idiaeresis",           GDK_Idiaeresis},
      { "Imacron",              GDK_Imacron},
      { "Iogonek",              GDK_Iogonek},
      { "ETH",                  GDK_ETH},
      { "Eth",                  GDK_Eth},
      { "Ntilde",               GDK_Ntilde},
      { "Ograve",               GDK_Ograve},
      { "Oacute",               GDK_Oacute},
      { "Odoubleacute",         GDK_Odoubleacute},
      { "Ocircumflex",          GDK_Ocircumflex},
      { "Otilde",               GDK_Otilde},
      { "Odiaeresis",           GDK_Odiaeresis},
      { "Ooblique",             GDK_Ooblique},
      { "Omacron",              GDK_Omacron},
      { "OE",                   GDK_OE},
      { "multiply",             GDK_multiply},
      { "Ugrave",               GDK_Ugrave},
      { "Uacute",               GDK_Uacute},
      { "Udoubleacute",         GDK_Udoubleacute},
      { "Ucircumflex",          GDK_Ucircumflex},
      { "Udiaeresis",           GDK_Udiaeresis},
      { "Umacron",              GDK_Umacron},
      { "Uogonek",              GDK_Uogonek},
      { "Yacute",               GDK_Yacute},
      { "THORN",                GDK_THORN},
      { "Thorn",                GDK_Thorn},
      { "ssharp",               GDK_ssharp},
      { "agrave",               GDK_agrave},
      { "aacute",               GDK_aacute},
      { "acircumflex",          GDK_acircumflex},
      { "atilde",               GDK_atilde},
      { "adiaeresis",           GDK_adiaeresis},
      { "aring",                GDK_aring},
      { "amacron",              GDK_amacron},
      { "aogonek",              GDK_aogonek},
      { "ae",                   GDK_ae},
      { "ccedilla",             GDK_ccedilla},
      { "gcedilla",             GDK_gcedilla},
      { "kcedilla",             GDK_kcedilla},
      { "lcedilla",             GDK_lcedilla},
      { "ncedilla",             GDK_ncedilla},
      { "rcedilla",             GDK_rcedilla},
      { "scedilla",             GDK_scedilla},
      { "ccaron",               GDK_ccaron},
      { "scaron",               GDK_scaron},
      { "zcaron",               GDK_zcaron},
      { "cacute",               GDK_cacute},
      { "nacute",               GDK_nacute},
      { "sacute",               GDK_sacute},
      { "zacute",               GDK_zacute},
      { "zabovedot",            GDK_zabovedot},
      { "egrave",               GDK_egrave},
      { "eacute",               GDK_eacute},
      { "ecircumflex",          GDK_ecircumflex},
      { "ediaeresis",           GDK_ediaeresis},
      { "emacron",              GDK_emacron},
      { "eogonek",              GDK_eogonek},
      { "eabovedot",            GDK_eabovedot},
      { "igrave",               GDK_igrave},
      { "iacute",               GDK_iacute},
      { "icircumflex",          GDK_icircumflex},
      { "idiaeresis",           GDK_idiaeresis},
      { "imacron",              GDK_imacron},
      { "iogonek",              GDK_iogonek},
      { "eth",                  GDK_eth},
      { "ntilde",               GDK_ntilde},
      { "ograve",               GDK_ograve},
      { "oacute",               GDK_oacute},
      { "odoubleacute",         GDK_odoubleacute},
      { "ocircumflex",          GDK_ocircumflex},
      { "otilde",               GDK_otilde},
      { "odiaeresis",           GDK_odiaeresis},
      { "oslash",               GDK_oslash},
      { "omacron",              GDK_omacron},
      { "oe",                   GDK_oe},
      { "division",             GDK_division},
      { "ugrave",               GDK_ugrave},
      { "uacute",               GDK_uacute},
      { "udoubleacute",         GDK_udoubleacute},
      { "ucircumflex",          GDK_ucircumflex},
      { "udiaeresis",           GDK_udiaeresis},
      { "umacron",              GDK_umacron},
      { "uogonek",              GDK_uogonek},
      { "yacute",               GDK_yacute},
      { "thorn",                GDK_thorn},
      { "ydiaeresis",           GDK_ydiaeresis},
      { "Iabovedot",            GDK_Iabovedot},
      { "Dstroke",              GDK_Dstroke},
      { "Lstroke",              GDK_Lstroke},
      { "lstroke",              GDK_lstroke},
      { "gbreve",               GDK_gbreve},
      { "Gbreve",               GDK_Gbreve},
      { "EuroSign",             GDK_EuroSign},

      /* arabic extensions */

      {"Arabic_dad", GDK_Arabic_dad},
      {"Arabic_fatha", GDK_Arabic_fatha},
      {"Arabic_sad", GDK_Arabic_sad},
      {"Arabic_fathatan", GDK_Arabic_fathatan},
      {"Arabic_theh", GDK_Arabic_theh},
      {"Arabic_damma", GDK_Arabic_damma},
      {"Arabic_qaf", GDK_Arabic_qaf},
      {"Arabic_dammatan", GDK_Arabic_dammatan},
      {"Arabic_feh", GDK_Arabic_feh},
      {"Arabic_ghain", GDK_Arabic_ghain},
      {"Arabic_hamzaunderalef", GDK_Arabic_hamzaunderalef},
      {"Arabic_ain", GDK_Arabic_ain},
      {"Arabic_ha", GDK_Arabic_ha},
      {"Arabic_khah", GDK_Arabic_khah},
      {"Arabic_hah", GDK_Arabic_hah},
      {"Arabic_semicolon", GDK_Arabic_semicolon},
      {"Arabic_jeem", GDK_Arabic_jeem},
      {"Arabic_dal", GDK_Arabic_dal},
      {"Arabic_sheen", GDK_Arabic_sheen},
      {"Arabic_seen", GDK_Arabic_seen},
      {"Arabic_yeh", GDK_Arabic_yeh},
      {"Arabic_beh", GDK_Arabic_beh},
      {"Arabic_lam", GDK_Arabic_lam},
      {"Arabic_alef", GDK_Arabic_alef},
      {"Arabic_hamzaonalef", GDK_Arabic_hamzaonalef},
      {"Arabic_teh", GDK_Arabic_teh},
      {"Arabic_tatweel", GDK_Arabic_tatweel},
      {"Arabic_noon", GDK_Arabic_noon},
      {"Arabic_comma", GDK_Arabic_comma},
      {"Arabic_meem", GDK_Arabic_meem},
      {"Arabic_kaf", GDK_Arabic_kaf},
      {"Arabic_tah", GDK_Arabic_tah},
      {"Arabic_thal", GDK_Arabic_thal},
      {"Arabic_shadda", GDK_Arabic_shadda},
      {"Arabic_hamzaonyeh", GDK_Arabic_hamzaonyeh},
      {"Arabic_hamza", GDK_Arabic_hamza},
      {"Arabic_sukun", GDK_Arabic_sukun},
      {"Arabic_hamzaonwaw", GDK_Arabic_hamzaonwaw},
      {"Arabic_kasra", GDK_Arabic_kasra},
      {"Arabic_ra", GDK_Arabic_ra},
      {"Arabic_kasratan", GDK_Arabic_kasratan},
      {"Arabic_alefmaksura", GDK_Arabic_alefmaksura},
      {"Arabic_maddaonalef", GDK_Arabic_maddaonalef},
      {"Arabic_tehmarbuta", GDK_Arabic_tehmarbuta},
      {"Arabic_waw", GDK_Arabic_waw},
      {"Arabic_zain", GDK_Arabic_zain},
      {"Arabic_zah", GDK_Arabic_zah},
      {"Arabic_question_mark", GDK_Arabic_question_mark},

      /* cyrillic extensions */

      { "Cyrillic_shorti", GDK_Cyrillic_shorti},
      { "Cyrillic_SHORTI", GDK_Cyrillic_SHORTI},
      { "Cyrillic_tse", GDK_Cyrillic_tse},
      { "Cyrillic_TSE", GDK_Cyrillic_TSE},
      { "Cyrillic_u", GDK_Cyrillic_u},
      { "Cyrillic_U", GDK_Cyrillic_U},
      { "Cyrillic_ka", GDK_Cyrillic_ka},
      { "Cyrillic_KA", GDK_Cyrillic_KA},
      { "Cyrillic_ie", GDK_Cyrillic_ie},
      { "Cyrillic_IE", GDK_Cyrillic_IE},
      { "Cyrillic_en", GDK_Cyrillic_en},
      { "Cyrillic_EN", GDK_Cyrillic_EN},
      { "Cyrillic_ghe", GDK_Cyrillic_ghe},
      { "Cyrillic_GHE", GDK_Cyrillic_GHE},
      { "Cyrillic_sha", GDK_Cyrillic_sha},
      { "Cyrillic_SHA", GDK_Cyrillic_SHA},
      { "Cyrillic_shcha", GDK_Cyrillic_shcha},
      { "Cyrillic_SHCHA", GDK_Cyrillic_SHCHA},
      { "Cyrillic_ze", GDK_Cyrillic_ze},
      { "Cyrillic_ZE", GDK_Cyrillic_ZE},
      { "Cyrillic_ha", GDK_Cyrillic_ha},
      { "Cyrillic_HA", GDK_Cyrillic_HA},
      { "Cyrillic_hardsign", GDK_Cyrillic_hardsign},
      { "Cyrillic_HARDSIGN", GDK_Cyrillic_HARDSIGN},
      { "Cyrillic_ef", GDK_Cyrillic_ef},
      { "Cyrillic_EF", GDK_Cyrillic_EF},
      { "Cyrillic_yeru", GDK_Cyrillic_yeru},
      { "Cyrillic_YERU", GDK_Cyrillic_YERU},
      { "Cyrillic_ve", GDK_Cyrillic_ve},
      { "Cyrillic_VE", GDK_Cyrillic_VE},
      { "Cyrillic_a", GDK_Cyrillic_a},
      { "Cyrillic_A", GDK_Cyrillic_A},
      { "Cyrillic_pe", GDK_Cyrillic_pe},
      { "Cyrillic_PE", GDK_Cyrillic_PE},
      { "Cyrillic_er", GDK_Cyrillic_er},
      { "Cyrillic_ER", GDK_Cyrillic_ER},
      { "Cyrillic_o", GDK_Cyrillic_o},
      { "Cyrillic_O", GDK_Cyrillic_O},
      { "Cyrillic_el", GDK_Cyrillic_el},
      { "Cyrillic_EL", GDK_Cyrillic_EL},
      { "Cyrillic_de", GDK_Cyrillic_de},
      { "Cyrillic_DE", GDK_Cyrillic_DE},
      { "Cyrillic_zhe", GDK_Cyrillic_zhe},
      { "Cyrillic_ZHE", GDK_Cyrillic_ZHE},
      { "Cyrillic_e", GDK_Cyrillic_e},
      { "Cyrillic_E", GDK_Cyrillic_E},
      { "Cyrillic_io", GDK_Cyrillic_io},
      { "Cyrillic_IO", GDK_Cyrillic_IO},
      { "Cyrillic_ya", GDK_Cyrillic_ya},
      { "Cyrillic_YA", GDK_Cyrillic_YA},
      { "Cyrillic_che", GDK_Cyrillic_che},
      { "Cyrillic_CHE", GDK_Cyrillic_CHE},
      { "Cyrillic_es", GDK_Cyrillic_es},
      { "Cyrillic_ES", GDK_Cyrillic_ES},
      { "Cyrillic_em", GDK_Cyrillic_em},
      { "Cyrillic_EM", GDK_Cyrillic_EM},
      { "Cyrillic_i", GDK_Cyrillic_i},
      { "Cyrillic_I", GDK_Cyrillic_I},
      { "Cyrillic_te", GDK_Cyrillic_te},
      { "Cyrillic_TE", GDK_Cyrillic_TE},
      { "Cyrillic_softsign", GDK_Cyrillic_softsign},
      { "Cyrillic_SOFTSIGN", GDK_Cyrillic_SOFTSIGN},
      { "Cyrillic_be", GDK_Cyrillic_be},
      { "Cyrillic_BE", GDK_Cyrillic_BE},
      { "Cyrillic_yu", GDK_Cyrillic_yu},
      { "Cyrillic_YU", GDK_Cyrillic_YU},
      { "Cyrillic_lje", GDK_Cyrillic_lje},
      { "Cyrillic_LJE", GDK_Cyrillic_LJE},
      { "Cyrillic_nje", GDK_Cyrillic_nje},
      { "Cyrillic_NJE", GDK_Cyrillic_NJE},
      { "Cyrillic_je", GDK_Cyrillic_je},
      { "Cyrillic_JE", GDK_Cyrillic_JE},
      { "Cyrillic_dzhe", GDK_Cyrillic_dzhe},
      { "Cyrillic_DZHE", GDK_Cyrillic_DZHE},

      { "Macedonia_dse", GDK_Macedonia_dse},
      { "Macedonia_DSE", GDK_Macedonia_DSE},
      { "Macedonia_gje", GDK_Macedonia_gje},
      { "Macedonia_GJE", GDK_Macedonia_GJE},
      { "Macedonia_kje", GDK_Macedonia_kje},
      { "Macedonia_KJE", GDK_Macedonia_KJE},

      /* thai extensions */

      { "Thai_lakkhangyao", GDK_Thai_lakkhangyao},
      { "Thai_leknung", GDK_Thai_leknung},
      { "Thai_leksong", GDK_Thai_leksong},
      { "Thai_phosamphao", GDK_Thai_phosamphao},
      { "Thai_leksam", GDK_Thai_leksam},
      { "Thai_thothung", GDK_Thai_thothung},
      { "Thai_leksi", GDK_Thai_leksi},
      { "Thai_sarau", GDK_Thai_sarau},
      { "Thai_sarauu", GDK_Thai_sarauu},
      { "Thai_saraue", GDK_Thai_saraue},
      { "Thai_baht", GDK_Thai_baht},
      { "Thai_khokhwai", GDK_Thai_khokhwai},
      { "Thai_lekha", GDK_Thai_lekha},
      { "Thai_totao", GDK_Thai_totao},
      { "Thai_lekhok", GDK_Thai_lekhok},
      { "Thai_chochan", GDK_Thai_chochan},
      { "Thai_lekchet", GDK_Thai_lekchet},
      { "Thai_khokhai", GDK_Thai_khokhai},
      { "Thai_lekpaet", GDK_Thai_lekpaet},
      { "Thai_chochang", GDK_Thai_chochang},
      { "Thai_lekkao", GDK_Thai_lekkao},
      { "Thai_maiyamok", GDK_Thai_maiyamok},
      { "Thai_leksun", GDK_Thai_leksun},
      { "Thai_saraaimaimalai", GDK_Thai_saraaimaimalai},
      { "Thai_saraam", GDK_Thai_saraam},
      { "Thai_dochada", GDK_Thai_dochada},
      { "Thai_phophan", GDK_Thai_phophan},
      { "Thai_thonangmontho", GDK_Thai_thonangmontho},
      { "Thai_saraa", GDK_Thai_saraa},
      { "Thai_thothong", GDK_Thai_thothong},
      { "Thai_maihanakat", GDK_Thai_maihanakat},
      { "Thai_nikhahit", GDK_Thai_nikhahit},
      { "Thai_saraii", GDK_Thai_saraii},
      { "Thai_maitri", GDK_Thai_maitri},
      { "Thai_rorua", GDK_Thai_rorua},
      { "Thai_nonen", GDK_Thai_nonen},
      { "Thai_nonu", GDK_Thai_nonu},
      { "Thai_paiyannoi", GDK_Thai_paiyannoi},
      { "Thai_yoyak", GDK_Thai_yoyak},
      { "Thai_yoying", GDK_Thai_yoying},
      { "Thai_bobaimai", GDK_Thai_bobaimai},
      { "Thai_thothan", GDK_Thai_thothan},
      { "Thai_loling", GDK_Thai_loling},
      { "Thai_fofan", GDK_Thai_fofan},
      { "Thai_ru", GDK_Thai_ru},
      { "Thai_hohip", GDK_Thai_hohip},
      { "Thai_khorakhang", GDK_Thai_khorakhang},
      { "Thai_kokai", GDK_Thai_kokai},
      { "Thai_topatak", GDK_Thai_topatak},
      { "Thai_dodek", GDK_Thai_dodek},
      { "Thai_sarao", GDK_Thai_sarao},
      { "Thai_sarae", GDK_Thai_sarae},
      { "Thai_chochoe", GDK_Thai_chochoe},
      { "Thai_maitho", GDK_Thai_maitho},
      { "Thai_maitaikhu", GDK_Thai_maitaikhu},
      { "Thai_maiek", GDK_Thai_maiek},
      { "Thai_maichattawa", GDK_Thai_maichattawa},
      { "Thai_saraaa", GDK_Thai_saraaa},
      { "Thai_sorusi", GDK_Thai_sorusi},
      { "Thai_sosua", GDK_Thai_sosua},
      { "Thai_sosala", GDK_Thai_sosala},
      { "Thai_wowaen", GDK_Thai_wowaen},
      { "Thai_soso", GDK_Thai_soso},
      { "Thai_ngongu", GDK_Thai_ngongu},
      { "Thai_khokhuat", GDK_Thai_khokhuat},
      { "Thai_khokhon", GDK_Thai_khokhon},
      { "Thai_phophung", GDK_Thai_phophung},
      { "Thai_popla", GDK_Thai_popla},
      { "Thai_saraae", GDK_Thai_saraae},
      { "Thai_choching", GDK_Thai_choching},
      { "Thai_oang", GDK_Thai_oang},
      { "Thai_honokhuk", GDK_Thai_honokhuk},
      { "Thai_sarai", GDK_Thai_sarai},
      { "Thai_phinthu", GDK_Thai_phinthu},
      { "Thai_sarauee", GDK_Thai_sarauee},
      { "Thai_thanthakhat", GDK_Thai_thanthakhat},
      { "Thai_thothahan", GDK_Thai_thothahan},
      { "Thai_moma", GDK_Thai_moma},
      { "Thai_thophuthao", GDK_Thai_thophuthao},
      { "Thai_saraaimaimuan", GDK_Thai_saraaimaimuan},
      { "Thai_lochula", GDK_Thai_lochula},
      { "Thai_fofa", GDK_Thai_fofa},
      { "Thai_lu", GDK_Thai_lu},

      /* japanese extensions */

      { "kana_NU", GDK_kana_NU},
      { "kana_FU", GDK_kana_FU},
      { "kana_A", GDK_kana_A},
      { "kana_a", GDK_kana_a},
      { "kana_U", GDK_kana_U},
      { "kana_u", GDK_kana_u},
      { "kana_E", GDK_kana_E},
      { "kana_e", GDK_kana_e},
      { "kana_O", GDK_kana_O},
      { "kana_o", GDK_kana_o},
      { "kana_YA", GDK_kana_YA},
      { "kana_ya", GDK_kana_ya},
      { "kana_YU", GDK_kana_YU},
      { "kana_yu", GDK_kana_yu},
      { "kana_YO", GDK_kana_YO},
      { "kana_yo", GDK_kana_yo},
      { "kana_WA", GDK_kana_WA},
      { "kana_WO", GDK_kana_WO},
      { "kana_HO", GDK_kana_HO},
      { "kana_HE", GDK_kana_HE},
      { "kana_TA", GDK_kana_TA},
      { "kana_TE", GDK_kana_TE},
      { "kana_I", GDK_kana_I},
      { "kana_i", GDK_kana_i},
      { "kana_SU", GDK_kana_SU},
      { "kana_KA", GDK_kana_KA},
      { "kana_N", GDK_kana_N},
      { "kana_NA", GDK_kana_NA},
      { "kana_NI", GDK_kana_NI},
      { "kana_RA", GDK_kana_RA},
      { "kana_SE", GDK_kana_SE},
      { "voicedsound", GDK_voicedsound},
      { "semivoicedsound", GDK_semivoicedsound},
      { "kana_openingbracket", GDK_kana_openingbracket},
      { "kana_CHI", GDK_kana_CHI},
      { "kana_TO", GDK_kana_TO},
      { "kana_SHI", GDK_kana_SHI},
      { "kana_HA", GDK_kana_HA},
      { "kana_KI", GDK_kana_KI},
      { "kana_KU", GDK_kana_KU},
      { "kana_MA", GDK_kana_MA},
      { "kana_NO", GDK_kana_NO},
      { "kana_RI", GDK_kana_RI},
      { "kana_RE", GDK_kana_RE},
      { "kana_KE", GDK_kana_KE},
      { "Zenkaku_Hankaku", GDK_Zenkaku_Hankaku},
      { "kana_MU", GDK_kana_MU},
      { "kana_closingbracket", GDK_kana_closingbracket},
      { "kana_TSU", GDK_kana_TSU},
      { "kana_tsu", GDK_kana_tsu},
      { "kana_SA", GDK_kana_SA},
      { "kana_SO", GDK_kana_SO},
      { "kana_HI", GDK_kana_HI},
      { "kana_KO", GDK_kana_KO},
      { "kana_MI", GDK_kana_MI},
      { "kana_MO", GDK_kana_MO},
      { "kana_NE", GDK_kana_NE},
      { "kana_comma", GDK_kana_comma},
      { "kana_RU", GDK_kana_RU},
      { "kana_fullstop", GDK_kana_fullstop},
      { "kana_ME", GDK_kana_ME},
      { "kana_conjunctive", GDK_kana_conjunctive},
      { "Eisu_toggle", GDK_Eisu_toggle},
      { "Kanji", GDK_Kanji},
      { "Henkan_Mode", GDK_Henkan_Mode},
      { "Katakana", GDK_Katakana},
      { "Muhenkan", GDK_Muhenkan},

      /* modifiers */

      {"Control_L",           GDK_Control_L},
      {"Control_R",           GDK_Control_R},
      {"Alt_L",         GDK_Alt_L},
      {"Alt_R",         GDK_Alt_R},
      {"ISO_Level3_Shift",    GDK_ISO_Level3_Shift},
      {"Caps_Lock",           GDK_Caps_Lock},
      {"Meta_L",        GDK_Meta_L},
      {"Meta_R",        GDK_Meta_R},
      {"Shift_L",       GDK_Shift_L},
      {"Shift_R",       GDK_Shift_R},
      {"Super_L",       GDK_Super_L},
      {"Super_R",       GDK_Super_R},
      {"ISO_First_Group",     GDK_ISO_First_Group},
      {"ISO_Next_Group",      GDK_ISO_Next_Group},
      {"ISO_Last_Group",      GDK_ISO_Last_Group},

      /* special keys */
      {"BackSpace",     GDK_BackSpace},
      {"Tab",           GDK_Tab},
      {"Return",  GDK_Return},
      {"Right",   GDK_Right},
      {"Left",    GDK_Left},
      {"Up",            GDK_Up},
      {"Down",    GDK_Down},
      {"Page_Down",     GDK_Page_Down},
      {"Page_Up", GDK_Page_Up},
      {"Insert",  GDK_Insert},
      {"Delete",  GDK_Delete},
      {"Home",    GDK_Home},
      {"End",           GDK_End},
      {"Scroll_Lock",   GDK_Scroll_Lock},
      {"F1",            GDK_F1},
      {"F2",            GDK_F2},
      {"F3",            GDK_F3},
      {"F4",            GDK_F4},
      {"F5",            GDK_F5},
      {"F6",            GDK_F6},
      {"F7",            GDK_F7},
      {"F8",            GDK_F8},
      {"F9",            GDK_F9},
      {"F10",           GDK_F10},
      {"F11",           GDK_F11},
      {"F12",           GDK_F12},
      {"F13",           GDK_F13},
      {"F14",           GDK_F14},
      {"F15",           GDK_F15},
      {"F16",           GDK_F16},
      {"F17",           GDK_F17},
      {"F18",           GDK_F18},
      {"F19",           GDK_F19},
      {"F20",           GDK_F20},
      {"F21",           GDK_F21},
      {"F22",           GDK_F22},
      {"F23",           GDK_F23},
      {"F24",           GDK_F24},
      {"F25",           GDK_F25},
      {"F26",           GDK_F26},
      {"F27",           GDK_F27},
      {"F28",           GDK_F28},
      {"F29",           GDK_F29},
      {"F30",           GDK_F30},
      {"F31",           GDK_F31},
      {"F32",           GDK_F32},
      {"F33",           GDK_F33},
      {"F34",           GDK_F34},
      {"F35",           GDK_F35},
      {"Sys_Req", GDK_Sys_Req},
      {"KP_0",    GDK_KP_0},
      {"KP_1",    GDK_KP_1},
      {"KP_2",    GDK_KP_2},
      {"KP_3",    GDK_KP_3},
      {"KP_4",    GDK_KP_4},
      {"KP_5",    GDK_KP_5},
      {"KP_6",    GDK_KP_6},
      {"KP_7",    GDK_KP_7},
      {"KP_8",    GDK_KP_8},
      {"KP_9",    GDK_KP_9},
      {"KP_Add",  GDK_KP_Add},
      {"KP_Decimal",    GDK_KP_Decimal},
      {"KP_Divide",     GDK_KP_Divide},
      {"KP_Enter",      GDK_KP_Enter},
      {"KP_Equal",      GDK_KP_Equal},
      {"KP_Multiply",   GDK_KP_Multiply},
      {"KP_Subtract",   GDK_KP_Subtract},
      {"help",    GDK_Help},
      {"Menu",    GDK_Menu},
      {"Print",   GDK_Print},
      {"Mode_switch",   GDK_Mode_switch},
      {"Multi_Key",     GDK_Multi_key},
      {"Num_Lock",      GDK_Num_Lock},
      {"Pause",   GDK_Pause},
      {"Escape",  GDK_Escape},

      {"ISO_Left_Tab",  GDK_ISO_Left_Tab},
      {"Execute",       GDK_Execute},
      {"KP_Separator",  GDK_KP_Separator},
      {"KP_Delete",           GDK_KP_Delete},
      {"KP_Insert",           GDK_KP_Insert},
      {"KP_End",        GDK_KP_End},
      {"KP_Down",       GDK_KP_Down},
      {"KP_Next",       GDK_KP_Next},
      {"KP_Left",       GDK_KP_Left},
      {"KP_Begin",            GDK_KP_Begin},
      {"KP_Right",            GDK_KP_Right},
      {"KP_Home",       GDK_KP_Home},
      {"KP_Up",         GDK_KP_Up},
      {"KP_Prior",            GDK_KP_Prior},
      {"Multi_key",           GDK_Multi_key},
      {"oneeighth",           GDK_oneeighth},
      {"threeeighths",  GDK_threeeighths},
      {"fiveeighths",         GDK_fiveeighths},
      {"seveneighths",  GDK_seveneighths},
      {"trademark",           GDK_trademark},
      {"dead_cedilla",  GDK_dead_cedilla},
      {"dead_ogonek",         GDK_dead_ogonek},
      {"Greek_OMEGA",         GDK_Greek_OMEGA},
      {"tslash",        GDK_tslash},
      {"Tslash",        GDK_Tslash},
      {"leftarrow",           GDK_leftarrow},
      {"downarrow",           GDK_downarrow},
      {"uparrow",       GDK_uparrow},
      {"rightarrow",          GDK_rightarrow},
      {"idotless",            GDK_idotless},
      {"dead_diaeresis",      GDK_dead_diaeresis},
      {"dead_abovering",      GDK_dead_abovering},
      {"dead_macron",         GDK_dead_macron},
      {"dstroke",       GDK_dstroke},
      {"eng",                 GDK_eng},
      {"ENG",                 GDK_ENG},
      {"hstroke",       GDK_hstroke},
      {"Hstroke",       GDK_Hstroke},
      {"kra",                 GDK_kra},
      {"dead_doubleacute",    GDK_dead_doubleacute},
      {"dead_caron",          GDK_dead_caron},
      {"dead_breve",          GDK_dead_breve},
      {"leftdoublequotemark", GDK_leftdoublequotemark},
      {"rightdoublequotemark",GDK_rightdoublequotemark},
      {"doublelowquotemark",  GDK_doublelowquotemark},
      {"horizconnector",      GDK_horizconnector},
      {"dead_belowdot", GDK_dead_belowdot},
      {"dead_abovedot", GDK_dead_abovedot},

      {NULL, 0},
};

#define MAX_NORMAL_KEYCODE 512
#define MAX_EXTRA_COUNT 256
static struct {
      uint16_t keysym2keycode[MAX_NORMAL_KEYCODE];
      struct {
            int keysym;
            uint16_t keycode;
      } keysym2keycode_extra[MAX_EXTRA_COUNT];
      int extra_count;
} layout;

static const char *locale;

static void
gui_set_keysym(const char * name, int keycode)
{
      int keysym;
      int i;

      for (i = 0; gtk_keysyms[i].name != NULL; i++) {
            if (! strcmp(gtk_keysyms[i].name, name)) {
                  break;
            }
      }

      if (gtk_keysyms[i].name) {
            keysym = gtk_keysyms[i].keysym;
            if (keysym < MAX_NORMAL_KEYCODE) {
                  layout.keysym2keycode[keysym] = keycode;
            } else {
                  if (layout.extra_count >= MAX_EXTRA_COUNT) {
                        faum_log(FAUM_LOG_WARNING, "gtk-GUI", __FUNCTION__,
                                    "could not assignd keysm %s (0x%02x)",
                                    name, keysym);
                  } else {
                        layout.keysym2keycode_extra[layout.extra_count].
                              keysym = keysym;
                        layout.keysym2keycode_extra[layout.extra_count].
                              keycode = keycode;
                        layout.extra_count++;
                  }
            }
      } else {
            faum_log(FAUM_LOG_WARNING, "gtk-GUI", __FUNCTION__,
                        "could not assign \"%s\" to 0x%02x\n",
                        name, keycode);
      }
}

static int
keysym_to_keycode(int keysym)
{
      int i;
      int result = 0;

      if (keysym < MAX_NORMAL_KEYCODE) {
            result = layout.keysym2keycode[keysym];
      } else {
#ifdef XK_ISO_Left_Tab
            if (keysym == XK_ISO_Left_Tab)
                  keysym = XK_Tab;
#endif
            for (i = 0; i < layout.extra_count; i++)
                  if (layout.keysym2keycode_extra[i].keysym == keysym) {
                        result = layout.keysym2keycode_extra[i].keycode;
                        break;
                  }
      }

      if (result == 0) {
            faum_log(FAUM_LOG_WARNING, "gtk-GUI", __FUNCTION__,
                        "no scancode found for keysym %d\n", keysym);
      }

#if DEBUG
      faum_log(FAUM_LOG_DEBUG, "gtk-GUI", __FUNCTION__,
                  "mapped sym=0x%04x to code=0x%02x\n", keysym, result);

#endif

      return result;
}

static int
gui_init_keyboard_layout(const char *language)
{
        FILE *f;
        const char *file_name;
        char line[1024];
        char *end_of_keysym;
        char *pos;
        int len;
        int keycode;

        file_name = buildpath(KEYMAPDIR,language);

        if(!(f = fopen(file_name, "r"))) {
                return 0;
        }
        for(;;) {
                if(fgets(line, 1024, f) == NULL)
                        break;
                len = strlen(line);
                if(len > 0 && line[len - 1] == '\n')
                        line[len - 1] = '\0';
                if(line[0] == '#')
                  continue;
            end_of_keysym = line;
            while(*end_of_keysym != 0 && *end_of_keysym != ' ')
                  end_of_keysym++;
            if(*end_of_keysym) {
                  *end_of_keysym = 0;
                  keycode = strtol(end_of_keysym+1, NULL, 0);
                  gui_set_keysym(line,keycode);
                  end_of_keysym++;
                  while(*end_of_keysym != 0 && *end_of_keysym != ' ')
                        end_of_keysym++;
                  if(*end_of_keysym) {
                        if(strncmp(end_of_keysym+1, "addupper", 8) == 0) {
                              for(pos=line; *pos != '\0'; *pos = toupper(*pos), pos++);
                              gui_set_keysym(line, keycode);
                        }
                  }
            }
      }
      fclose(f);
        return 1;
}

static int
cmpstringp(const void *p1, const void *p2)
{
      return strcmp(* (char * const *) p1, * (char * const *) p2);
}

static void
gui_read_keyboard_layout_dir(void)
{
      const char * path;
      DIR * kmapdir;
      struct dirent * entry;

      path = buildpath(KEYMAPDIR, "/");
      kmapdir = opendir(path);

      if (kmapdir != NULL) {
            while ((entry = readdir(kmapdir)) != NULL
                        && nlayouts < MAX_LAYOUTS) {
                  if (entry->d_type == DT_REG || entry->d_type == DT_LNK) {
                        layout_names[nlayouts++] = strdup(entry->d_name);
                  }
            }

            closedir(kmapdir);
            qsort(&layout_names[0], nlayouts, sizeof(layout_names[0]), cmpstringp);
      }
}

static gboolean
leave_event(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
{
      int i;

      for (i = 0; i < 128; i++) {
            /* release all pressed keys */
            if (pressed_keys[i]) {
#if DEBUG
                  faum_log(FAUM_LOG_DEBUG, "gtk-GUI", __FUNCTION__,
                        "releasing key %d\n", i);
#endif
                  pressed_keys[i] = 0;
                  gui_gtk_keyboard_type(i, 0);
            }
      }
      return 0;
}

static void
on_page_count_changed(
      GtkNotebook *nb,
      GtkWidget *child,
      guint page_num,
      gpointer user_data
)
{
      if (1 < gtk_notebook_get_n_pages(nb)) {
            gtk_notebook_set_show_tabs(nb, TRUE);
      } else {
            gtk_notebook_set_show_tabs(nb, FALSE);
      }
}

static gboolean
on_delete_component_window(GtkWidget *widget, GdkEvent *event, gpointer user_data);

void
gui_create_component_window(struct component_info *comp_info)
{
      GtkWidget *window;

      window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
      g_signal_connect((gpointer) window, "delete-event",
                  G_CALLBACK(on_delete_component_window), comp_info);
      gtk_window_set_title(GTK_WINDOW(window), comp_info->name);
      gtk_widget_show(window);

      gtk_container_add(GTK_CONTAINER(window), comp_info->mainvbox);
}

static void
on_delete_component_tab(GtkWidget *widget, gpointer user_data)
{
      gint pagenr;
      struct component_info * comp_info = (struct component_info *) user_data;

      pagenr = gtk_notebook_page_num(GTK_NOTEBOOK(notebook), comp_info->mainvbox);

      gtk_notebook_remove_page(GTK_NOTEBOOK(notebook), pagenr);

      gui_create_component_window(comp_info);

#if GTK_MINOR_VERSION < 10
      on_page_count_changed(GTK_NOTEBOOK(notebook), NULL, -1, NULL);
#endif
}

static void
gui_create_component_tab(struct component_info *comp_info)
{
      GtkWidget *label;
      GtkWidget *label_box;
      GtkWidget *close_button;
      GtkWidget *image;
      const char * path;

      label_box = gtk_hbox_new(FALSE, 0);
      gtk_widget_show(label_box);

      label = gtk_label_new(comp_info->name);
      gtk_widget_show(label);
      gtk_box_pack_start(GTK_BOX(label_box), label, FALSE, FALSE, 14);

      path = buildpath(PNGDIR, "window.png");
      image = gtk_image_new_from_file(path);
      close_button = gtk_button_new();
      gtk_button_set_image(GTK_BUTTON(close_button), image);
      gtk_button_set_relief(GTK_BUTTON(close_button), GTK_RELIEF_NONE);
      g_signal_connect((gpointer) close_button, "clicked",
                  G_CALLBACK(on_delete_component_tab), comp_info);
      gtk_widget_show(close_button);
      gtk_box_pack_start(GTK_BOX(label_box), close_button, FALSE, FALSE, 1);

      gtk_notebook_append_page(GTK_NOTEBOOK(notebook), comp_info->mainvbox, label_box);

#if GTK_MINOR_VERSION < 10
      on_page_count_changed(GTK_NOTEBOOK(notebook), NULL, -1, NULL);
#endif
}

static gboolean
on_delete_component_window(GtkWidget *widget, GdkEvent *event, gpointer user_data)
{
      GtkWidget *box;
      struct component_info * comp_info = (struct component_info *) user_data;

      box = gtk_bin_get_child(GTK_BIN(widget));

      gtk_container_remove(GTK_CONTAINER(widget), box);

      gui_create_component_tab(comp_info);

      return FALSE;
}

void
gui_page_add(const char *name)
{
      components[npages].name = name;

      components[npages].mainvbox = gtk_vbox_new(FALSE, 0);
      g_object_ref((gpointer) components[npages].mainvbox);
      gtk_widget_show(components[npages].mainvbox);

      components[npages].mainhbox = gtk_hbox_new(FALSE, 0);
      gtk_widget_show(components[npages].mainhbox);
      gtk_box_pack_start(GTK_BOX(components[npages].mainvbox),
                  components[npages].mainhbox, FALSE, FALSE, 0);

      gui_create_component_tab(&components[npages]);

      npages++;
}

void
gui_comp_add(
      unsigned int page,
      const char *comp_type,
      unsigned int comp_index,
      const char *comp_name,
      GtkWidget *main,
      int expand,
      int fill,
      GtkWidget *fi
)
{
      GtkWidget *frame;

      assert(page < npages);
      assert(strchr(comp_name, ':'));

      if (main) {
            GtkRequisition size;

            gtk_widget_size_request(main, &size);

            frame = gtk_frame_new(strrchr(comp_name, ':') + 1);

            gtk_widget_show(main);
            gtk_container_add(GTK_CONTAINER(frame), main);

            gtk_widget_show(frame);
            if (size.width < 300) {
                  gtk_box_pack_start(GTK_BOX(components[page].mainhbox), frame, expand, fill, 2);
            } else {
                  gtk_box_pack_start(GTK_BOX(components[page].mainvbox), frame, expand, fill, 2);
            }
      }
      if (fi) {
            frame = gtk_frame_new(strrchr(comp_name, ':') + 1);

            gtk_widget_show(fi);
            gtk_container_add(GTK_CONTAINER(frame), fi);

            gtk_widget_show(frame);
            gtk_box_pack_start(GTK_BOX(GTK_DIALOG(fi_window)->vbox), frame,
                        FALSE, FALSE, 1);
      }
}

static void
on_exit_activate(GtkMenuItem *menuitem, gpointer _void)
{
        frontend_quit();
}

static void
menubar_fi_dialog_show(GtkWidget *w, gpointer _void)
{
      gtk_widget_show(fi_window);
}

static void
menubar_keymap_change(GtkWidget *w, gpointer _mapname)
{
      const char * mapname = (const char *) _mapname;

      if (gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(w))) {
            memset(&layout, 0, sizeof(layout));
            if (!gui_init_keyboard_layout(mapname)) {
                  faum_log(FAUM_LOG_CRITICAL, "gtk-GUI", __FUNCTION__,
                              "host key map for layout \"%s\" could not be loaded\n",
                              mapname);
            }
      }
}

static GtkWidget *
menubar_new(void)
{
      GtkWidget *menubar;

      GtkWidget *filemenu;
      GtkWidget *filemenu_menu;
      GtkWidget *exit_entry;
      GtkWidget *injectmenu;
      GtkWidget *injectmenu_menu;
      GtkWidget *keymapmenu;
      GtkWidget *keymapmenu_menu;
      GtkWidget *keymapmenu_item;
      GtkWidget *w;
      GSList *group = NULL;
      int i;

      menubar = gtk_menu_bar_new();

      filemenu = gtk_menu_item_new_with_mnemonic (_("_File"));
      gtk_widget_show (filemenu);
      gtk_container_add (GTK_CONTAINER (menubar), filemenu);

      filemenu_menu = gtk_menu_new ();
      gtk_menu_item_set_submenu (GTK_MENU_ITEM (filemenu), filemenu_menu);

      exit_entry = gtk_menu_item_new_with_mnemonic (_("E_xit"));
      g_signal_connect ((gpointer) exit_entry, "activate",
                  G_CALLBACK (on_exit_activate), NULL);
      gtk_widget_show (exit_entry);
      gtk_container_add (GTK_CONTAINER (filemenu_menu), exit_entry);

      injectmenu = gtk_menu_item_new_with_mnemonic (_("_Inject"));
      gtk_widget_show (injectmenu);
      gtk_container_add (GTK_CONTAINER (menubar), injectmenu);

      injectmenu_menu = gtk_menu_new ();
      gtk_menu_item_set_submenu (GTK_MENU_ITEM (injectmenu), injectmenu_menu);

      w = gtk_menu_item_new_with_mnemonic(_("_Show List"));
      g_signal_connect ((gpointer) w, "activate",
                  G_CALLBACK (menubar_fi_dialog_show), NULL);
      gtk_widget_show(w);
      gtk_container_add(GTK_CONTAINER (injectmenu_menu), w);

      gui_read_keyboard_layout_dir();

      keymapmenu = gtk_menu_item_new_with_mnemonic (_("Host _Keymap"));
      gtk_widget_show(keymapmenu);
      gtk_container_add(GTK_CONTAINER(menubar), keymapmenu);

      keymapmenu_menu = gtk_menu_new();
      gtk_menu_item_set_submenu(GTK_MENU_ITEM(keymapmenu), keymapmenu_menu);

      for (i = 0; i < nlayouts; i++) {
            keymapmenu_item = gtk_radio_menu_item_new_with_label(group, layout_names[i]);
            group = gtk_radio_menu_item_get_group(GTK_RADIO_MENU_ITEM(keymapmenu_item));
            gtk_widget_show(keymapmenu_item);
            gtk_container_add(GTK_CONTAINER(keymapmenu_menu), keymapmenu_item);
            g_signal_connect((gpointer) keymapmenu_item, "activate",
                        G_CALLBACK(menubar_keymap_change), layout_names[i]);

            if (strcmp(layout_names[i], locale) == 0) {
                  gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(keymapmenu_item), TRUE);
            }
      }

      return menubar;
}

static void
on_close_fi_dialog(GtkWidget *w, gpointer _dialog)
{
      GtkWidget *dialog = (GtkWidget *) _dialog;

      gtk_widget_hide(dialog);
}

static GtkWidget *
fi_dialog_new(void)
{
      GtkWidget *dialog;
      GtkWidget *button;

      dialog = gtk_dialog_new();
      g_signal_connect((gpointer) dialog, "delete-event",
                  G_CALLBACK(on_close_fi_dialog), dialog);

      button = gtk_button_new_with_label("Close");
      g_signal_connect((gpointer) button, "clicked",
                  G_CALLBACK(on_close_fi_dialog), dialog);

      gtk_widget_show(button);
      gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->action_area), button,
                  FALSE, FALSE, 1);

      return dialog;
}

static void
gui_gtk_create(void)
{
      GtkWidget *FAUmachine;
      GtkWidget *mainwindow;
      GtkWidget *menubar;
      GtkWidget *statusbar_grabbing;
      
#if GTK_MINOR_VERSION < 4
      GtkWidget *new_menu;          
#endif /* GTK_MINOR_VERSION */

      FAUmachine = gtk_window_new(GTK_WINDOW_TOPLEVEL);
      gtk_window_set_title(GTK_WINDOW(FAUmachine), _("FAUmachine"));
      gtk_window_set_destroy_with_parent(GTK_WINDOW(FAUmachine), TRUE);

      /* handle close per window manager */
      g_signal_connect(FAUmachine, "destroy",
                  G_CALLBACK(on_exit_activate), NULL);
      g_signal_connect(FAUmachine, "delete_event",
                  G_CALLBACK(on_exit_activate), NULL);

      mainwindow = gtk_vbox_new(FALSE, 0);
      gtk_widget_show(mainwindow);
      gtk_container_add(GTK_CONTAINER (FAUmachine), mainwindow);

      menubar = menubar_new();
      gtk_widget_show(menubar);
      gtk_box_pack_start(GTK_BOX(mainwindow), menubar, FALSE, FALSE, 0);

      /* status bar */
      statusbar_grabbing = gtk_hbox_new(FALSE, 1);
      gtk_box_pack_start(GTK_BOX (mainwindow), statusbar_grabbing,
                  FALSE, FALSE, 0);

      statusbar = gtk_hbox_new(FALSE, 12);
      gtk_box_pack_start(GTK_BOX(statusbar_grabbing), statusbar, FALSE, FALSE, 0);

      grabbing_text = gtk_label_new (_("Nothing grabbed"));
      gtk_label_set_markup(GTK_LABEL (grabbing_text), "<small>Nothing grabbed</small>"); /* FIXME: Now what? I18N or small? */
      gtk_label_set_justify (GTK_LABEL (grabbing_text), GTK_JUSTIFY_RIGHT);
      gtk_misc_set_alignment (GTK_MISC (grabbing_text), 1, 0.5);
      gtk_box_pack_start (GTK_BOX(statusbar_grabbing), grabbing_text, TRUE, TRUE, 0);

      gtk_widget_show_all(statusbar_grabbing);

      notebook = gtk_notebook_new();
      gtk_widget_show(notebook);
      gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), FALSE);
#if 10 <= GTK_MINOR_VERSION
      g_signal_connect((gpointer) notebook, "page-added",
                  G_CALLBACK(on_page_count_changed), NULL);
      g_signal_connect((gpointer) notebook, "page-removed",
                  G_CALLBACK(on_page_count_changed), NULL);
#endif
      gtk_box_pack_start(GTK_BOX(mainwindow), notebook, TRUE, TRUE, 0);

      /*
       * FI Window
       */
      fi_window = fi_dialog_new();
      /* gtk_widget_show(fi_window); */

      /* resize FAUmachine window before displaying */
      // gtk_window_resize(GTK_WINDOW (FAUmachine), 665, 500);

      /* redraw content of monitor */
      gtk_signal_connect((gpointer) FAUmachine, "leave-notify-event",
                  G_CALLBACK(leave_event), NULL);

      gtk_widget_show(FAUmachine);
}

/* curser bit mask to hide cursor while keyboard and mouse are grabbed */
#define black_width 16
#define black_height 16
static unsigned char black_bits[] = {
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static unsigned char black_mask[] = {
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

static void
grab_all(GtkWidget *widget)
{
      int ret, counter;
      GdkCursor *cursor;
      GdkPixmap *source, *mask;
      GdkColor fg = { 0, 0, 0, 0 };
      GdkColor bg = { 0, 0, 0, 0 };

#ifdef CYGWIN
      /* FIXME */
      return;
#endif /*CYGWIN*/

      assert(!grabbed);
      grabbed = 1;

      /* set pointer to the middle of the screen */
      XWarpPointer(GDK_WINDOW_XDISPLAY(widget->window), None,
                  GDK_WINDOW_XWINDOW(widget->window),
                  0, 0, 0, 0,
                  320, 200); /* FIXME -> set cursor in middle of the window */

      gtk_widget_grab_focus(widget);

      /* create black pointer mask */
      source = gdk_bitmap_create_from_data (NULL, black_bits,
      black_width, black_height);
      mask = gdk_bitmap_create_from_data (NULL, black_mask,
      black_width, black_height);
      cursor = gdk_cursor_new_from_pixmap (source, mask, &fg, &bg, 8, 8);
      gdk_pixmap_unref (source);
      gdk_pixmap_unref (mask);

      /* grab keyboard and mouse pointer */
      gdk_keyboard_grab(widget->window, FALSE, GDK_CURRENT_TIME);
      ret = 1;
      counter = 0;
      while (ret && counter < 10) {
            ret = gdk_pointer_grab(widget->window, FALSE, GDK_BUTTON_PRESS_MASK
                  | GDK_POINTER_MOTION_MASK
                  | GDK_BUTTON_RELEASE_MASK
                  | GDK_SCROLL_MASK,
                  NULL, cursor, GDK_CURRENT_TIME);

            usleep(50);
            ++counter;
      }

      /* notify about grabbing */
#if defined(DARWIN)
      gtk_label_set_markup(GTK_LABEL(grabbing_text), "<small>Press 'Apple-Ctrl-Esc' to ungrab keyboard/mouse!</small>");
#else
      gtk_label_set_markup(GTK_LABEL(grabbing_text), "<small>Press 'Alt-Ctrl-Esc' to ungrab keyboard/mouse!</small>");
#endif
}

static void
ungrab_all(void)
{
      int i;

      grabbed = 0;
      for (i = 0; i < 128; i++) {
            /* release all pressed keys */
            if (pressed_keys[i]) {
                  pressed_keys[i] = 0;
                  gui_gtk_keyboard_type(i, 0);
            }
      }
      gdk_keyboard_ungrab(GDK_CURRENT_TIME);
      gdk_pointer_ungrab(GDK_CURRENT_TIME);

      gtk_label_set_markup(GTK_LABEL(grabbing_text), "<small>Nothing grabbed</small>");
}

static gboolean
keypress_event (GtkWidget *widget, GdkEventKey *key_event, int pressed)
{
      int keycode = keysym_to_keycode(key_event->keyval);

#if DEBUG
      faum_log(FAUM_LOG_DEBUG, "gtk-GUI", __FUNCTION__, 
            ((pressed) ? "key pressed\n" : "key released\n"));
      faum_log(FAUM_LOG_DEBUG, "gtk-GUI", __FUNCTION__,
            "window is %p\n", widget->window);
#endif
      
#if DEBUG
      faum_log(FAUM_LOG_DEBUG, "gtk-GUI", __FUNCTION__,
            "keycode: %08x, keyval %08x - CTRL: %s\t MOD1: %s\t SHIFT: %s <-> MAX: %08x\n",
            keycode, key_event->keyval,
            ((key_event->state & GDK_CONTROL_MASK) ? "yes" : "no"),
            ((key_event->state & GDK_MOD1_MASK) ? "yes" : "no"),
            ((key_event->state & GDK_SHIFT_MASK) ? "yes" : "no"),
            256);
#endif

      /* ungrab if user pressed ctrl+alt+esc */
      if ((key_event->state & GDK_CONTROL_MASK)
#if defined(DARWIN)
       && (key_event->state & GDK_MOD2_MASK)
#else
       && (key_event->state & GDK_MOD1_MASK)
#endif
       && keycode == keysym_to_keycode(GDK_Escape) /* FIXME other order of keypresses */
       && pressed) {
            ungrab_all();
            lastStepUngrab = 2;

#if DEBUG
            faum_log(FAUM_LOG_DEBUG, "gtk-GUI", __FUNCTION__,
                  "leaving grabbing mode succeded\n");
#endif

            return 1;
      }

      /* ignore invalid keycodes which originate from grabbing mode change */
      if (0 == keycode || 128 <= keycode) {
            return 1;
      }

      if (lastStepUngrab && ((keycode == keysym_to_keycode(GDK_Escape))
                       || (keycode == keysym_to_keycode(GDK_Alt_L))
                       || (keycode == keysym_to_keycode(GDK_Control_L)))) {

            /* released CTRL, ALT or ESC after ungrabbing
             * do not grab again
             */
            lastStepUngrab--;
            return 1;
      }

#if 0
      if (! grabbed && pressed) {
            grab_all(widget);
      }
#endif

      /* send keyboard event to simulator */
      assert(keycode < 128);
      gui_gtk_keyboard_type(keycode, pressed);
      pressed_keys[keycode] = pressed;

#if DEBUG
      faum_log(FAUM_LOG_DEBUG, "gtk-GUI", __FUNCTION__,
            "mapped to 0x%08x\n", keycode);
#endif

      return 1;
}

gboolean
key_press_event(GtkWidget *widget, GdkEventKey *key_event, gpointer user_data)
{
      return keypress_event(widget, key_event, 1);
}

gboolean
key_release_event(GtkWidget *widget, GdkEventKey *key_event, gpointer user_data)
{
      return keypress_event(widget, key_event, 0);
}

gboolean
pointer_motion_event(
      GtkWidget *widget,
      GdkEventMotion *event,
      gpointer user_data
)
{
      int deltax;
      int deltay;

      if (! grabbed) {
            return 0;
      }
      
#if DEBUG
      faum_log(FAUM_LOG_DEBUG, "gtk-GUI", __FUNCTION__,
            "Pointer moved: event->x: %f | event->y: %f\n", event->x, event->y);
      faum_log(FAUM_LOG_DEBUG, "gtk-GUI", __FUNCTION__,
            "Last position: 320, 200\n");
#endif

      deltax = event->x - 320;
      if (deltax != 0) {
            gui_gtk_mouse_motion(0, deltax);
      }
      deltay = 200 - event->y;
      if (deltay != 0) {
            gui_gtk_mouse_motion(1, deltay);
      }

      if (warped) {
            warped = 0;
            return 0;
      }

      /* FIXME -> set cursor in middle of the window */
      XWarpPointer(GDK_WINDOW_XDISPLAY(widget->window), None,
                  GDK_WINDOW_XWINDOW(widget->window),
                  0, 0, 0, 0,
                  320, 200);

      warped = 1;

      return 1;
}

gboolean
pointer_press_event (GtkWidget *widget, GdkEventButton *event, gpointer user_data)
{
      unsigned int button;
      unsigned int pressed;

      if (! grabbed) {
            if (event->type == GDK_BUTTON_RELEASE) {
                  grab_all(widget);
            } 
            return 1;
      }

      assert(0 < event->button && event->button <= 5);

      button = event->button;
      pressed = (event->type == GDK_BUTTON_RELEASE) ? 0 : 1;
      
#if DEBUG
      faum_log(FAUM_LOG_DEBUG, "gtk-GUI", __FUNCTION__,
            "button %d - %d\n", event->button, ((event->type == GDK_BUTTON_RELEASE) ? 0 : 1)); 
#endif

      assert(1 <= button && button <= 5);
      gui_gtk_mouse_button(button - 1, pressed);

      return 1;

}

gboolean
pointer_scroll_event (GtkWidget *widget, GdkEventScroll *event, gpointer user_data)
{
      if (! grabbed) {
            grab_all(widget);
      }

      if(event->direction == GDK_SCROLL_UP) {
            gui_gtk_mouse_motion(2, -1);
      } else if(event->direction == GDK_SCROLL_DOWN) {
            gui_gtk_mouse_motion(2, 1);
      }

      return 1;
}

void
gui_usage(void)
{
      fprintf(stderr, "\t-k <keymap>: set the key translation map to <keymap>\n");
}

/* handle gtk - gui options, if any  */
int
gui_handle_args(int *argcp, char ***argvp)
{
        int i;
        char **current_arg;

      gtk_init(argcp, argvp);

      locale = "en-us";

        /* check for -k keymap */
        i = *argcp;
        for (current_arg = *argvp; i && strcmp(*current_arg, "-k"); current_arg++) {
                i--;
        }

        if (i && strcmp(*current_arg, "-k") == 0 && *argcp > i) {
                /* remember locale */
                locale = current_arg[1];

                /* remove -k keymap from argument list */
                while (current_arg[2]) {
                        current_arg[0] = current_arg[2];
                        current_arg++;
                }
                current_arg[0] = NULL;
                *argcp -= 2;
        }

      return 0;
}

void
gui_init(void)
{
      gui_gtk_init();
}

void
gui_exit(void)
{
      gui_gtk_exit();
}

void
gui_create(void)
{
      gui_gtk_create();
}

void
gui_destroy(void)
{
}

Generated by  Doxygen 1.6.0   Back to index