summaryrefslogtreecommitdiff
path: root/libgnomekbd
diff options
context:
space:
mode:
authorSergey V. Udaltsov <svu@src.gnome.org>2006-09-27 20:27:09 +0000
committerSergey V. Udaltsov <svu@src.gnome.org>2006-09-27 20:27:09 +0000
commit7699e660c678df45a7d0ce2edaec1611e210d583 (patch)
treea1e92bed7f668a851e276ec79a9bca846d70a2a1 /libgnomekbd
downloadlibgnomekbd-7699e660c678df45a7d0ce2edaec1611e210d583.tar.gz
Initial revision
Diffstat (limited to 'libgnomekbd')
-rw-r--r--libgnomekbd/.indent.pro2
-rw-r--r--libgnomekbd/Makefile.am125
-rw-r--r--libgnomekbd/backup/Makefile718
-rw-r--r--libgnomekbd/backup/Makefile.am91
-rw-r--r--libgnomekbd/backup/gkb-config-private.h98
-rw-r--r--libgnomekbd/backup/gkb-config-registry.c166
-rw-r--r--libgnomekbd/backup/gkb-config-registry.h44
-rw-r--r--libgnomekbd/backup/gkb-config-registry.xml14
-rw-r--r--libgnomekbd/backup/gkb-desktop-config.c403
-rw-r--r--libgnomekbd/backup/gkb-desktop-config.h96
-rw-r--r--libgnomekbd/backup/gkb-indicator-config.c360
-rw-r--r--libgnomekbd/backup/gkb-indicator-config.h86
-rw-r--r--libgnomekbd/backup/gkb-indicator-marshal.list1
-rw-r--r--libgnomekbd/backup/gkb-indicator-plugin-manager.c391
-rw-r--r--libgnomekbd/backup/gkb-indicator-plugin-manager.h110
-rw-r--r--libgnomekbd/backup/gkb-indicator-plugin.h120
-rw-r--r--libgnomekbd/backup/gkb-indicator.c826
-rw-r--r--libgnomekbd/backup/gkb-indicator.h77
-rw-r--r--libgnomekbd/backup/gkb-keyboard-config.c822
-rw-r--r--libgnomekbd/backup/gkb-keyboard-config.h123
-rw-r--r--libgnomekbd/backup/gkb-keyboard-drawing-marshal.list2
-rw-r--r--libgnomekbd/backup/gkb-keyboard-drawing.c1845
-rw-r--r--libgnomekbd/backup/gkb-keyboard-drawing.h185
-rw-r--r--libgnomekbd/backup/gkb-util.c149
-rw-r--r--libgnomekbd/backup/gkb-util.h30
-rw-r--r--libgnomekbd/desktop_gnome_peripherals_keyboard_xkb.schemas.in193
-rw-r--r--libgnomekbd/gkbd-config-private.h99
-rw-r--r--libgnomekbd/gkbd-config-registry.c166
-rw-r--r--libgnomekbd/gkbd-config-registry.h44
-rw-r--r--libgnomekbd/gkbd-config-registry.xml14
-rw-r--r--libgnomekbd/gkbd-desktop-config.c400
-rw-r--r--libgnomekbd/gkbd-desktop-config.h97
-rw-r--r--libgnomekbd/gkbd-indicator-config.c361
-rw-r--r--libgnomekbd/gkbd-indicator-config.h89
-rw-r--r--libgnomekbd/gkbd-indicator-marshal.list1
-rw-r--r--libgnomekbd/gkbd-indicator-plugin-manager.c404
-rw-r--r--libgnomekbd/gkbd-indicator-plugin-manager.h113
-rw-r--r--libgnomekbd/gkbd-indicator-plugin.h122
-rw-r--r--libgnomekbd/gkbd-indicator.c825
-rw-r--r--libgnomekbd/gkbd-indicator.h77
-rw-r--r--libgnomekbd/gkbd-keyboard-config.c825
-rw-r--r--libgnomekbd/gkbd-keyboard-config.h120
-rw-r--r--libgnomekbd/gkbd-keyboard-drawing-marshal.list2
-rw-r--r--libgnomekbd/gkbd-keyboard-drawing.c1848
-rw-r--r--libgnomekbd/gkbd-keyboard-drawing.h189
-rw-r--r--libgnomekbd/gkbd-util.c148
-rw-r--r--libgnomekbd/gkbd-util.h30
47 files changed, 13051 insertions, 0 deletions
diff --git a/libgnomekbd/.indent.pro b/libgnomekbd/.indent.pro
new file mode 100644
index 0000000..bdff074
--- /dev/null
+++ b/libgnomekbd/.indent.pro
@@ -0,0 +1,2 @@
+-kr -i8 -pcs -lps -psl
+
diff --git a/libgnomekbd/Makefile.am b/libgnomekbd/Makefile.am
new file mode 100644
index 0000000..01bb0cc
--- /dev/null
+++ b/libgnomekbd/Makefile.am
@@ -0,0 +1,125 @@
+lib_LTLIBRARIES = libgnomekbd.la libgnomekbdui.la
+
+common_CFLAGS = \
+ -I$(top_srcdir) -Wall -Werror \
+ $(GDK_CFLAGS) \
+ $(DBUS_CFLAGS) \
+ $(GCONF_CFLAGS) \
+ $(LIBGNOME_CFLAGS) \
+ $(LIBXKLAVIER_CFLAGS) \
+ -I$(top_srcdir)/intl \
+ -DSYS_PLUGIN_DIR=\"$(libdir)/gnomekbd/\" \
+ -DG_LOG_DOMAIN=\"GnomeKbdIndicator\" \
+ -DGLADEDIR=\"$(gladedir)\" \
+ -DDATADIR=\"$(datadir)\" \
+ -DSYSCONFDIR=\"$(sysconfdir)\" \
+ -DLIBDIR=\"$(libdir)\"
+
+libgnomekbd_la_CFLAGS = $(common_CFLAGS)
+
+libgnomekbdui_la_CFLAGS = $(common_CFLAGS) \
+ $(GTK_CFLAGS)
+
+common_LDFLAGS = \
+ $(DBUS_LIBS) \
+ $(GDK_LIBS) \
+ $(GCONF_LIBS) \
+ $(LIBXKLAVIER_LIBS)
+
+libgnomekbd_la_LDFLAGS = $(common_LDFLAGS)
+
+libgnomekbdui_la_LDFLAGS = $(common_LDFLAGS) $(GTK_LIBS)
+
+libgnomekbd_la_SOURCES = \
+ gkbd-config-registry.c \
+ gkbd-desktop-config.c \
+ gkbd-keyboard-config.c \
+ gkbd-util.c
+
+libgnomekbdui_la_SOURCES = \
+ gkbd-indicator-config.c \
+ gkbd-indicator.c \
+ gkbd-indicator-marshal.c \
+ gkbd-indicator-plugin-manager.c \
+ gkbd-keyboard-drawing-marshal.c \
+ gkbd-keyboard-drawing.c
+
+BUILT_SOURCES = gkbd-indicator-marshal.c \
+ gkbd-indicator-marshal.h \
+ gkbd-config-registry-server.h \
+ gkbd-config-registry-client.h \
+ gkbd-keyboard-drawing-marshal.c \
+ gkbd-keyboard-drawing-marshal.h
+
+CLEANFILES = $(BUILT_SOURCES) $(schema_DATA)
+
+gnomekbdincdir = $(includedir)/libgnomekbd
+gnomekbdinc_HEADERS = \
+ gkbd-desktop-config.h \
+ gkbd-keyboard-config.h \
+ gkbd-config-registry-client.h \
+ gkbd-config-registry.h \
+ gkbd-indicator.h \
+ gkbd-indicator-config.h \
+ gkbd-indicator-plugin.h \
+ gkbd-keyboard-drawing.h \
+ gkbd-util.h
+
+@INTLTOOL_DESKTOP_RULE@
+
+@INTLTOOL_SCHEMAS_RULE@
+
+noinst_HEADERS = gkbd-indicator-plugin-manager.h \
+ $(extra_nih) \
+ gkbd-config-private.h \
+ gkbd-config-registry-server.h
+
+EXTRA_DIST = gkbd-indicator-marshal.list \
+ gkbd-keyboard-drawing-marshal.list \
+ gkbd-config-registry.xml \
+ $(glade_DATA) \
+ $(schema_in_files)
+
+GLIB_GENMARSHAL = $(shell pkg-config --variable=glib_genmarshal glib-2.0)
+
+gkbd-indicator-marshal.h: gkbd-indicator-marshal.list
+ $(GLIB_GENMARSHAL) --prefix=gkbd_indicator $(srcdir)/gkbd-indicator-marshal.list --header > $@
+
+gkbd-indicator-marshal.c: gkbd-indicator-marshal.h
+ $(GLIB_GENMARSHAL) --prefix=gkbd_indicator $(srcdir)/gkbd-indicator-marshal.list --body > $@
+
+gkbd-config-registry-server.h: gkbd-config-registry.xml
+ dbus-binding-tool --prefix=gkbd_config_registry --mode=glib-server $< > $@
+
+gkbd-config-registry-client.h: gkbd-config-registry.xml
+ dbus-binding-tool --prefix=gkbd_config_registry --mode=glib-client $< > $@
+
+gkbd-keyboard-drawing-marshal.h: gkbd-keyboard-drawing-marshal.list
+ ( $(GLIB_GENMARSHAL) --prefix=gkbd_keyboard_drawing $(srcdir)/gkbd-keyboard-drawing-marshal.list \
+ --header > gkbd-keyboard-drawing-marshal.tmp \
+ && mv gkbd-keyboard-drawing-marshal.tmp gkbd-keyboard-drawing-marshal.h ) \
+ || ( rm -f gkbd-keyboard-drawing-marshal.tmp && exit 1 )
+
+gkbd-keyboard-drawing-marshal.c: gkbd-keyboard-drawing-marshal.h
+ ( $(GLIB_GENMARSHAL) --prefix=gkbd_keyboard_drawing $(srcdir)/gkbd-keyboard-drawing-marshal.list \
+ --body > gkbd-keyboard-drawing-marshal.tmp \
+ && mv gkbd-keyboard-drawing-marshal.tmp gkbd-keyboard-drawing-marshal.c ) \
+ || ( rm -f gkbd-keyboard-drawing-marshal.tmp && exit 1 )
+
+schemadir = $(GCONF_SCHEMA_FILE_DIR)
+schema_in_files= desktop_gnome_peripherals_keyboard_xkb.schemas.in
+
+schema_DATA = $(schema_in_files:.schemas.in=.schemas)
+
+if GCONF_SCHEMAS_INSTALL
+# don't do this if we are building in eg. rpm
+install-data-local:
+ if test -z "$(DESTDIR)" ; then \
+ for p in $(schema_DATA) ; do \
+ GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-install-rule $$p; \
+ done \
+ fi
+else
+install-data-local:
+endif
+
diff --git a/libgnomekbd/backup/Makefile b/libgnomekbd/backup/Makefile
new file mode 100644
index 0000000..3d83f1c
--- /dev/null
+++ b/libgnomekbd/backup/Makefile
@@ -0,0 +1,718 @@
+# Makefile.in generated by automake 1.9.6 from Makefile.am.
+# libgnomekbd/Makefile. Generated from Makefile.in by configure.
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+
+
+srcdir = .
+top_srcdir = ..
+
+pkgdatadir = $(datadir)/libgnomekbd
+pkglibdir = $(libdir)/libgnomekbd
+pkgincludedir = $(includedir)/libgnomekbd
+top_builddir = ..
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+INSTALL = /usr/bin/install -c
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = i686-pc-linux-gnu
+host_triplet = i686-pc-linux-gnu
+subdir = libgnomekbd
+DIST_COMMON = $(gnomekbdinc_HEADERS) $(noinst_HEADERS) \
+ $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/intltool.m4 \
+ $(top_srcdir)/configure.in
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = `echo $$p | sed -e 's|^.*/||'`;
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(gnomekbdincdir)"
+libLTLIBRARIES_INSTALL = $(INSTALL)
+LTLIBRARIES = $(lib_LTLIBRARIES)
+libgnomekbd_la_LIBADD =
+am_libgnomekbd_la_OBJECTS = libgnomekbd_la-gkb-keyboard-config.lo \
+ libgnomekbd_la-gkb-desktop-config.lo \
+ libgnomekbd_la-gkb-indicator-config.lo \
+ libgnomekbd_la-gkb-util.lo libgnomekbd_la-gkb-indicator.lo \
+ libgnomekbd_la-gkb-indicator-marshal.lo \
+ libgnomekbd_la-gkb-indicator-plugin-manager.lo \
+ libgnomekbd_la-gkb-config-registry.lo \
+ libgnomekbd_la-gkb-keyboard-drawing-marshal.lo \
+ libgnomekbd_la-gkb-keyboard-drawing.lo
+libgnomekbd_la_OBJECTS = $(am_libgnomekbd_la_OBJECTS)
+DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --tag=CC --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+SOURCES = $(libgnomekbd_la_SOURCES)
+DIST_SOURCES = $(libgnomekbd_la_SOURCES)
+gnomekbdincHEADERS_INSTALL = $(INSTALL_HEADER)
+HEADERS = $(gnomekbdinc_HEADERS) $(noinst_HEADERS)
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = ${SHELL} /home/svu/CVS/libgnomekbd/missing --run aclocal-1.9
+ALL_LINGUAS = ru
+AMDEP_FALSE = #
+AMDEP_TRUE =
+AMTAR = ${SHELL} /home/svu/CVS/libgnomekbd/missing --run tar
+AR = ar
+AUTOCONF = ${SHELL} /home/svu/CVS/libgnomekbd/missing --run autoconf
+AUTOHEADER = ${SHELL} /home/svu/CVS/libgnomekbd/missing --run autoheader
+AUTOMAKE = ${SHELL} /home/svu/CVS/libgnomekbd/missing --run automake-1.9
+AWK = gawk
+CATALOGS = ru.gmo
+CATOBJEXT = .gmo
+CC = gcc
+CCDEPMODE = depmode=gcc3
+CFLAGS = -g -O2
+CPP = gcc -E
+CPPFLAGS =
+CXX = g++
+CXXCPP = g++ -E
+CXXDEPMODE = depmode=gcc3
+CXXFLAGS = -g -O2
+CYGPATH_W = echo
+DATADIRNAME = share
+DBUS_CFLAGS = -I/usr/include/dbus-1.0 -I/usr/lib/dbus-1.0/include -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include
+DBUS_LIBS = -ldbus-glib-1 -ldbus-1 -lglib-2.0
+DEFS = -DHAVE_CONFIG_H
+DEPDIR = .deps
+ECHO = echo
+ECHO_C =
+ECHO_N = -n
+ECHO_T =
+EGREP = /bin/grep -E
+EXEEXT =
+F77 =
+FFLAGS =
+GCONF_CFLAGS = -DORBIT2=1 -pthread -I/usr/include/gconf/2 -I/usr/include/orbit-2.0 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include
+GCONF_LIBS = -pthread -lgconf-2 -lORBit-2 -lm -lgmodule-2.0 -ldl -lgthread-2.0 -lglib-2.0
+GETTEXT_PACKAGE = libgnomekbd
+GMOFILES = ru.gmo
+GMSGFMT = /usr/bin/msgfmt
+GREP = /bin/grep
+GTK_CFLAGS = -I/usr/include/gtk-2.0 -I/usr/lib/gtk-2.0/include -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include
+GTK_LIBS = -lgtk-x11-2.0 -latk-1.0 -lgdk-x11-2.0 -lgdk_pixbuf-2.0 -lm -lpangocairo-1.0 -lfontconfig -lXext -lXrender -lXinerama -lXi -lXrandr -lXcursor -lXfixes -lpango-1.0 -lcairo -lgobject-2.0 -lgmodule-2.0 -ldl -lglib-2.0 -lX11
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_SCRIPT = ${INSTALL}
+INSTALL_STRIP_PROGRAM = ${SHELL} $(install_sh) -c -s
+INSTOBJEXT = .mo
+INTLLIBS =
+INTLTOOL_CAVES_RULE = %.caves: %.caves.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+INTLTOOL_DESKTOP_RULE = %.desktop: %.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+INTLTOOL_DIRECTORY_RULE = %.directory: %.directory.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+INTLTOOL_EXTRACT = $(top_builddir)/intltool-extract
+INTLTOOL_ICONV = /usr/bin/iconv
+INTLTOOL_KBD_RULE = %.kbd: %.kbd.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -x -u -m -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+INTLTOOL_KEYS_RULE = %.keys: %.keys.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -k -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+INTLTOOL_MERGE = $(top_builddir)/intltool-merge
+INTLTOOL_MSGFMT = /usr/bin/msgfmt
+INTLTOOL_MSGMERGE = /usr/bin/msgmerge
+INTLTOOL_OAF_RULE = %.oaf: %.oaf.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -o -p $(top_srcdir)/po $< $@
+INTLTOOL_PERL = /usr/bin/perl
+INTLTOOL_PONG_RULE = %.pong: %.pong.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -x -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+INTLTOOL_PROP_RULE = %.prop: %.prop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+INTLTOOL_SCHEMAS_RULE = %.schemas: %.schemas.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -s -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+INTLTOOL_SERVER_RULE = %.server: %.server.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -o -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+INTLTOOL_SERVICE_RULE = %.service: %.service.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+INTLTOOL_SHEET_RULE = %.sheet: %.sheet.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -x -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+INTLTOOL_SOUNDLIST_RULE = %.soundlist: %.soundlist.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+INTLTOOL_THEME_RULE = %.theme: %.theme.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+INTLTOOL_UI_RULE = %.ui: %.ui.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -x -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+INTLTOOL_UPDATE = $(top_builddir)/intltool-update
+INTLTOOL_XAM_RULE = %.xam: %.xml.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -x -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+INTLTOOL_XGETTEXT = /usr/bin/xgettext
+INTLTOOL_XML_NOMERGE_RULE = %.xml: %.xml.in $(INTLTOOL_MERGE) ; LC_ALL=C $(INTLTOOL_MERGE) -x -u /tmp $< $@
+INTLTOOL_XML_RULE = %.xml: %.xml.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -x -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+LDFLAGS =
+LIBGLADE_CFLAGS = -I/usr/include/libglade-2.0 -I/usr/include/gtk-2.0 -I/usr/include/libxml2 -I/usr/lib/gtk-2.0/include -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include
+LIBGLADE_LIBS = -lglade-2.0 -lgtk-x11-2.0 -lxml2 -lgdk-x11-2.0 -latk-1.0 -lgdk_pixbuf-2.0 -lm -lpangocairo-1.0 -lfontconfig -lXext -lXrender -lXinerama -lXi -lXrandr -lXcursor -lXfixes -lpango-1.0 -lcairo -lX11 -lgobject-2.0 -lgmodule-2.0 -ldl -lglib-2.0
+LIBGNOMEUI_CFLAGS = -DORBIT2=1 -pthread -I/usr/include/libgnomeui-2.0 -I/usr/include/libgnome-2.0 -I/usr/include/libgnomecanvas-2.0 -I/usr/include/gtk-2.0 -I/usr/include/libart-2.0 -I/usr/include/gconf/2 -I/usr/include/libbonoboui-2.0 -I/usr/include/gnome-vfs-2.0 -I/usr/lib/gnome-vfs-2.0/include -I/usr/include/gnome-keyring-1 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/orbit-2.0 -I/usr/include/libbonobo-2.0 -I/usr/include/bonobo-activation-2.0 -I/usr/include/pango-1.0 -I/usr/include/freetype2 -I/usr/lib/gtk-2.0/include -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/libxml2
+LIBGNOMEUI_LIBS = -pthread -lgnomeui-2 -lSM -lICE -lbonoboui-2 -lgnome-keyring -lxml2 -lgnomecanvas-2 -lgnome-2 -lpopt -lart_lgpl_2 -lpangoft2-1.0 -lgtk-x11-2.0 -lgdk-x11-2.0 -latk-1.0 -lgdk_pixbuf-2.0 -lpangocairo-1.0 -lfontconfig -lXext -lXrender -lXinerama -lXi -lXrandr -lXcursor -lXfixes -lpango-1.0 -lcairo -lX11 -lbonobo-2 -lgnomevfs-2 -lbonobo-activation -lgconf-2 -lgobject-2.0 -lORBit-2 -lm -lgmodule-2.0 -ldl -lgthread-2.0 -lglib-2.0
+LIBGNOME_CFLAGS = -DORBIT2=1 -pthread -I/usr/include/libgnome-2.0 -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/orbit-2.0 -I/usr/include/libbonobo-2.0 -I/usr/include/gconf/2 -I/usr/include/gnome-vfs-2.0 -I/usr/lib/gnome-vfs-2.0/include -I/usr/include/bonobo-activation-2.0
+LIBGNOME_LIBS = -pthread -lgnome-2 -lpopt -lbonobo-2 -lgnomevfs-2 -lbonobo-activation -lgconf-2 -lgobject-2.0 -lORBit-2 -lm -lgmodule-2.0 -ldl -lgthread-2.0 -lglib-2.0
+LIBOBJS =
+LIBS =
+LIBTOOL = $(SHELL) $(top_builddir)/libtool
+LIBXKLAVIER_CFLAGS = -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/include/libxml2
+LIBXKLAVIER_LIBS = -lxklavier -lgobject-2.0 -lglib-2.0 -lxml2
+LN_S = ln -s
+LTLIBOBJS =
+MAINT =
+MAINTAINER_MODE_FALSE = #
+MAINTAINER_MODE_TRUE =
+MAKEINFO = ${SHELL} /home/svu/CVS/libgnomekbd/missing --run makeinfo
+MKINSTALLDIRS = ./mkinstalldirs
+MSGFMT = /usr/bin/msgfmt
+OBJEXT = o
+PACKAGE = libgnomekbd
+PACKAGE_BUGREPORT =
+PACKAGE_NAME = libgnomekbd
+PACKAGE_STRING = libgnomekbd 0.1
+PACKAGE_TARNAME = libgnomekbd
+PACKAGE_VERSION = 0.1
+PATH_SEPARATOR = :
+PKG_CONFIG = /usr/bin/pkg-config
+POFILES = ru.po
+POSUB = po
+PO_IN_DATADIR_FALSE =
+PO_IN_DATADIR_TRUE =
+RANLIB = ranlib
+SET_MAKE =
+SHELL = /bin/bash
+STRIP = strip
+USE_NLS = yes
+VERSION = 0.1
+WARN_CFLAGS = -Wall -Wmissing-prototypes
+XGETTEXT = /usr/bin/xgettext
+ac_ct_CC = gcc
+ac_ct_CXX = g++
+ac_ct_F77 =
+am__fastdepCC_FALSE = #
+am__fastdepCC_TRUE =
+am__fastdepCXX_FALSE = #
+am__fastdepCXX_TRUE =
+am__include = include
+am__leading_dot = .
+am__quote =
+am__tar = ${AMTAR} chof - "$$tardir"
+am__untar = ${AMTAR} xf -
+bindir = ${exec_prefix}/bin
+build = i686-pc-linux-gnu
+build_alias =
+build_cpu = i686
+build_os = linux-gnu
+build_vendor = pc
+datadir = ${datarootdir}
+datarootdir = ${prefix}/share
+docdir = ${datarootdir}/doc/${PACKAGE_TARNAME}
+dvidir = ${docdir}
+exec_prefix = ${prefix}
+host = i686-pc-linux-gnu
+host_alias =
+host_cpu = i686
+host_os = linux-gnu
+host_vendor = pc
+htmldir = ${docdir}
+includedir = ${prefix}/include
+infodir = ${datarootdir}/info
+install_sh = /home/svu/CVS/libgnomekbd/install-sh
+libdir = ${exec_prefix}/lib
+libexecdir = ${exec_prefix}/libexec
+localedir = ${prefix}/share/locale
+localstatedir = ${prefix}/var
+mandir = ${datarootdir}/man
+mkdir_p = mkdir -p --
+oldincludedir = /usr/include
+pdfdir = ${docdir}
+prefix = /usr/local
+program_transform_name = s,x,x,
+psdir = ${docdir}
+sbindir = ${exec_prefix}/sbin
+sharedstatedir = ${prefix}/com
+sysconfdir = ${prefix}/etc
+target_alias =
+lib_LTLIBRARIES = libgnomekbd.la
+libgnomekbd_la_CFLAGS = \
+ -I$(top_srcdir) -Wall -Werror \
+ $(DBUS_CFLAGS) \
+ $(GTK_CFLAGS) \
+ $(GCONF_CFLAGS) \
+ $(LIBGNOME_CFLAGS) \
+ $(LIBXKLAVIER_CFLAGS) \
+ -I$(top_srcdir)/intl \
+ -DSYS_PLUGIN_DIR=\"$(libdir)/gnomekbd/\" \
+ -DG_LOG_DOMAIN=\"GnomeKbdIndicator\" \
+ -DGLADEDIR=\"$(gladedir)\" \
+ -DDATADIR=\"$(datadir)\" \
+ -DSYSCONFDIR=\"$(sysconfdir)\" \
+ -DLIBDIR=\"$(libdir)\"
+
+libgnomekbd_la_LDFLAGS = \
+ $(GCONF_LIBS)
+
+libgnomekbd_la_SOURCES = gkb-keyboard-config.c \
+ gkb-desktop-config.c \
+ gkb-indicator-config.c \
+ gkb-util.c \
+ gkb-indicator.c \
+ gkb-indicator-marshal.c \
+ gkb-indicator-plugin-manager.c \
+ gkb-config-registry.c \
+ gkb-keyboard-drawing-marshal.c \
+ gkb-keyboard-drawing.c
+
+BUILT_SOURCES = gkb-indicator-marshal.c \
+ gkb-indicator-marshal.h \
+ gkb-config-registry-server.h \
+ gkb-config-registry-client.h \
+ gkb-keyboard-drawing-marshal.c \
+ gkb-keyboard-drawing-marshal.h
+
+CLEANFILES = \
+ $(BUILT_SOURCES)
+
+gnomekbdincdir = $(includedir)/libgnomekbd
+gnomekbdinc_HEADERS = \
+ gkb-desktop-config.h \
+ gkb-keyboard-config.h \
+ gkb-config-registry-client.h \
+ gkb-config-registry.h \
+ gkb-indicator.h \
+ gkb-indicator-config.h \
+ gkb-indicator-plugin.h \
+ gkb-keyboard-drawing.h \
+ gkb-util.h
+
+noinst_HEADERS = gkb-indicator-plugin-manager.h \
+ $(extra_nih) \
+ gkb-config-private.h \
+ gkb-config-registry-server.h
+
+EXTRA_DIST = gkb-indicator-marshal.list \
+ gkb-keyboard-drawing-marshal.list \
+ gkb-config-registry.xml \
+ $(glade_DATA)
+
+GLIB_GENMARSHAL = $(shell pkg-config --variable=glib_genmarshal glib-2.0)
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu libgnomekbd/Makefile'; \
+ cd $(top_srcdir) && \
+ $(AUTOMAKE) --gnu libgnomekbd/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)"
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ if test -f $$p; then \
+ f=$(am__strip_dir) \
+ echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \
+ else :; fi; \
+ done
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @set -x; list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ p=$(am__strip_dir) \
+ echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \
+ $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libgnomekbd.la: $(libgnomekbd_la_OBJECTS) $(libgnomekbd_la_DEPENDENCIES)
+ $(LINK) -rpath $(libdir) $(libgnomekbd_la_LDFLAGS) $(libgnomekbd_la_OBJECTS) $(libgnomekbd_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+include ./$(DEPDIR)/libgnomekbd_la-gkb-config-registry.Plo
+include ./$(DEPDIR)/libgnomekbd_la-gkb-desktop-config.Plo
+include ./$(DEPDIR)/libgnomekbd_la-gkb-indicator-config.Plo
+include ./$(DEPDIR)/libgnomekbd_la-gkb-indicator-marshal.Plo
+include ./$(DEPDIR)/libgnomekbd_la-gkb-indicator-plugin-manager.Plo
+include ./$(DEPDIR)/libgnomekbd_la-gkb-indicator.Plo
+include ./$(DEPDIR)/libgnomekbd_la-gkb-keyboard-config.Plo
+include ./$(DEPDIR)/libgnomekbd_la-gkb-keyboard-drawing-marshal.Plo
+include ./$(DEPDIR)/libgnomekbd_la-gkb-keyboard-drawing.Plo
+include ./$(DEPDIR)/libgnomekbd_la-gkb-util.Plo
+
+.c.o:
+ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+# source='$<' object='$@' libtool=no \
+# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \
+# $(COMPILE) -c $<
+
+.c.obj:
+ if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
+ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+# source='$<' object='$@' libtool=no \
+# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \
+# $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+ if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
+ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
+# source='$<' object='$@' libtool=yes \
+# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \
+# $(LTCOMPILE) -c -o $@ $<
+
+libgnomekbd_la-gkb-keyboard-config.lo: gkb-keyboard-config.c
+ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgnomekbd_la_CFLAGS) $(CFLAGS) -MT libgnomekbd_la-gkb-keyboard-config.lo -MD -MP -MF "$(DEPDIR)/libgnomekbd_la-gkb-keyboard-config.Tpo" -c -o libgnomekbd_la-gkb-keyboard-config.lo `test -f 'gkb-keyboard-config.c' || echo '$(srcdir)/'`gkb-keyboard-config.c; \
+ then mv -f "$(DEPDIR)/libgnomekbd_la-gkb-keyboard-config.Tpo" "$(DEPDIR)/libgnomekbd_la-gkb-keyboard-config.Plo"; else rm -f "$(DEPDIR)/libgnomekbd_la-gkb-keyboard-config.Tpo"; exit 1; fi
+# source='gkb-keyboard-config.c' object='libgnomekbd_la-gkb-keyboard-config.lo' libtool=yes \
+# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \
+# $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgnomekbd_la_CFLAGS) $(CFLAGS) -c -o libgnomekbd_la-gkb-keyboard-config.lo `test -f 'gkb-keyboard-config.c' || echo '$(srcdir)/'`gkb-keyboard-config.c
+
+libgnomekbd_la-gkb-desktop-config.lo: gkb-desktop-config.c
+ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgnomekbd_la_CFLAGS) $(CFLAGS) -MT libgnomekbd_la-gkb-desktop-config.lo -MD -MP -MF "$(DEPDIR)/libgnomekbd_la-gkb-desktop-config.Tpo" -c -o libgnomekbd_la-gkb-desktop-config.lo `test -f 'gkb-desktop-config.c' || echo '$(srcdir)/'`gkb-desktop-config.c; \
+ then mv -f "$(DEPDIR)/libgnomekbd_la-gkb-desktop-config.Tpo" "$(DEPDIR)/libgnomekbd_la-gkb-desktop-config.Plo"; else rm -f "$(DEPDIR)/libgnomekbd_la-gkb-desktop-config.Tpo"; exit 1; fi
+# source='gkb-desktop-config.c' object='libgnomekbd_la-gkb-desktop-config.lo' libtool=yes \
+# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \
+# $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgnomekbd_la_CFLAGS) $(CFLAGS) -c -o libgnomekbd_la-gkb-desktop-config.lo `test -f 'gkb-desktop-config.c' || echo '$(srcdir)/'`gkb-desktop-config.c
+
+libgnomekbd_la-gkb-indicator-config.lo: gkb-indicator-config.c
+ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgnomekbd_la_CFLAGS) $(CFLAGS) -MT libgnomekbd_la-gkb-indicator-config.lo -MD -MP -MF "$(DEPDIR)/libgnomekbd_la-gkb-indicator-config.Tpo" -c -o libgnomekbd_la-gkb-indicator-config.lo `test -f 'gkb-indicator-config.c' || echo '$(srcdir)/'`gkb-indicator-config.c; \
+ then mv -f "$(DEPDIR)/libgnomekbd_la-gkb-indicator-config.Tpo" "$(DEPDIR)/libgnomekbd_la-gkb-indicator-config.Plo"; else rm -f "$(DEPDIR)/libgnomekbd_la-gkb-indicator-config.Tpo"; exit 1; fi
+# source='gkb-indicator-config.c' object='libgnomekbd_la-gkb-indicator-config.lo' libtool=yes \
+# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \
+# $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgnomekbd_la_CFLAGS) $(CFLAGS) -c -o libgnomekbd_la-gkb-indicator-config.lo `test -f 'gkb-indicator-config.c' || echo '$(srcdir)/'`gkb-indicator-config.c
+
+libgnomekbd_la-gkb-util.lo: gkb-util.c
+ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgnomekbd_la_CFLAGS) $(CFLAGS) -MT libgnomekbd_la-gkb-util.lo -MD -MP -MF "$(DEPDIR)/libgnomekbd_la-gkb-util.Tpo" -c -o libgnomekbd_la-gkb-util.lo `test -f 'gkb-util.c' || echo '$(srcdir)/'`gkb-util.c; \
+ then mv -f "$(DEPDIR)/libgnomekbd_la-gkb-util.Tpo" "$(DEPDIR)/libgnomekbd_la-gkb-util.Plo"; else rm -f "$(DEPDIR)/libgnomekbd_la-gkb-util.Tpo"; exit 1; fi
+# source='gkb-util.c' object='libgnomekbd_la-gkb-util.lo' libtool=yes \
+# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \
+# $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgnomekbd_la_CFLAGS) $(CFLAGS) -c -o libgnomekbd_la-gkb-util.lo `test -f 'gkb-util.c' || echo '$(srcdir)/'`gkb-util.c
+
+libgnomekbd_la-gkb-indicator.lo: gkb-indicator.c
+ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgnomekbd_la_CFLAGS) $(CFLAGS) -MT libgnomekbd_la-gkb-indicator.lo -MD -MP -MF "$(DEPDIR)/libgnomekbd_la-gkb-indicator.Tpo" -c -o libgnomekbd_la-gkb-indicator.lo `test -f 'gkb-indicator.c' || echo '$(srcdir)/'`gkb-indicator.c; \
+ then mv -f "$(DEPDIR)/libgnomekbd_la-gkb-indicator.Tpo" "$(DEPDIR)/libgnomekbd_la-gkb-indicator.Plo"; else rm -f "$(DEPDIR)/libgnomekbd_la-gkb-indicator.Tpo"; exit 1; fi
+# source='gkb-indicator.c' object='libgnomekbd_la-gkb-indicator.lo' libtool=yes \
+# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \
+# $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgnomekbd_la_CFLAGS) $(CFLAGS) -c -o libgnomekbd_la-gkb-indicator.lo `test -f 'gkb-indicator.c' || echo '$(srcdir)/'`gkb-indicator.c
+
+libgnomekbd_la-gkb-indicator-marshal.lo: gkb-indicator-marshal.c
+ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgnomekbd_la_CFLAGS) $(CFLAGS) -MT libgnomekbd_la-gkb-indicator-marshal.lo -MD -MP -MF "$(DEPDIR)/libgnomekbd_la-gkb-indicator-marshal.Tpo" -c -o libgnomekbd_la-gkb-indicator-marshal.lo `test -f 'gkb-indicator-marshal.c' || echo '$(srcdir)/'`gkb-indicator-marshal.c; \
+ then mv -f "$(DEPDIR)/libgnomekbd_la-gkb-indicator-marshal.Tpo" "$(DEPDIR)/libgnomekbd_la-gkb-indicator-marshal.Plo"; else rm -f "$(DEPDIR)/libgnomekbd_la-gkb-indicator-marshal.Tpo"; exit 1; fi
+# source='gkb-indicator-marshal.c' object='libgnomekbd_la-gkb-indicator-marshal.lo' libtool=yes \
+# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \
+# $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgnomekbd_la_CFLAGS) $(CFLAGS) -c -o libgnomekbd_la-gkb-indicator-marshal.lo `test -f 'gkb-indicator-marshal.c' || echo '$(srcdir)/'`gkb-indicator-marshal.c
+
+libgnomekbd_la-gkb-indicator-plugin-manager.lo: gkb-indicator-plugin-manager.c
+ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgnomekbd_la_CFLAGS) $(CFLAGS) -MT libgnomekbd_la-gkb-indicator-plugin-manager.lo -MD -MP -MF "$(DEPDIR)/libgnomekbd_la-gkb-indicator-plugin-manager.Tpo" -c -o libgnomekbd_la-gkb-indicator-plugin-manager.lo `test -f 'gkb-indicator-plugin-manager.c' || echo '$(srcdir)/'`gkb-indicator-plugin-manager.c; \
+ then mv -f "$(DEPDIR)/libgnomekbd_la-gkb-indicator-plugin-manager.Tpo" "$(DEPDIR)/libgnomekbd_la-gkb-indicator-plugin-manager.Plo"; else rm -f "$(DEPDIR)/libgnomekbd_la-gkb-indicator-plugin-manager.Tpo"; exit 1; fi
+# source='gkb-indicator-plugin-manager.c' object='libgnomekbd_la-gkb-indicator-plugin-manager.lo' libtool=yes \
+# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \
+# $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgnomekbd_la_CFLAGS) $(CFLAGS) -c -o libgnomekbd_la-gkb-indicator-plugin-manager.lo `test -f 'gkb-indicator-plugin-manager.c' || echo '$(srcdir)/'`gkb-indicator-plugin-manager.c
+
+libgnomekbd_la-gkb-config-registry.lo: gkb-config-registry.c
+ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgnomekbd_la_CFLAGS) $(CFLAGS) -MT libgnomekbd_la-gkb-config-registry.lo -MD -MP -MF "$(DEPDIR)/libgnomekbd_la-gkb-config-registry.Tpo" -c -o libgnomekbd_la-gkb-config-registry.lo `test -f 'gkb-config-registry.c' || echo '$(srcdir)/'`gkb-config-registry.c; \
+ then mv -f "$(DEPDIR)/libgnomekbd_la-gkb-config-registry.Tpo" "$(DEPDIR)/libgnomekbd_la-gkb-config-registry.Plo"; else rm -f "$(DEPDIR)/libgnomekbd_la-gkb-config-registry.Tpo"; exit 1; fi
+# source='gkb-config-registry.c' object='libgnomekbd_la-gkb-config-registry.lo' libtool=yes \
+# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \
+# $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgnomekbd_la_CFLAGS) $(CFLAGS) -c -o libgnomekbd_la-gkb-config-registry.lo `test -f 'gkb-config-registry.c' || echo '$(srcdir)/'`gkb-config-registry.c
+
+libgnomekbd_la-gkb-keyboard-drawing-marshal.lo: gkb-keyboard-drawing-marshal.c
+ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgnomekbd_la_CFLAGS) $(CFLAGS) -MT libgnomekbd_la-gkb-keyboard-drawing-marshal.lo -MD -MP -MF "$(DEPDIR)/libgnomekbd_la-gkb-keyboard-drawing-marshal.Tpo" -c -o libgnomekbd_la-gkb-keyboard-drawing-marshal.lo `test -f 'gkb-keyboard-drawing-marshal.c' || echo '$(srcdir)/'`gkb-keyboard-drawing-marshal.c; \
+ then mv -f "$(DEPDIR)/libgnomekbd_la-gkb-keyboard-drawing-marshal.Tpo" "$(DEPDIR)/libgnomekbd_la-gkb-keyboard-drawing-marshal.Plo"; else rm -f "$(DEPDIR)/libgnomekbd_la-gkb-keyboard-drawing-marshal.Tpo"; exit 1; fi
+# source='gkb-keyboard-drawing-marshal.c' object='libgnomekbd_la-gkb-keyboard-drawing-marshal.lo' libtool=yes \
+# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \
+# $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgnomekbd_la_CFLAGS) $(CFLAGS) -c -o libgnomekbd_la-gkb-keyboard-drawing-marshal.lo `test -f 'gkb-keyboard-drawing-marshal.c' || echo '$(srcdir)/'`gkb-keyboard-drawing-marshal.c
+
+libgnomekbd_la-gkb-keyboard-drawing.lo: gkb-keyboard-drawing.c
+ if $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgnomekbd_la_CFLAGS) $(CFLAGS) -MT libgnomekbd_la-gkb-keyboard-drawing.lo -MD -MP -MF "$(DEPDIR)/libgnomekbd_la-gkb-keyboard-drawing.Tpo" -c -o libgnomekbd_la-gkb-keyboard-drawing.lo `test -f 'gkb-keyboard-drawing.c' || echo '$(srcdir)/'`gkb-keyboard-drawing.c; \
+ then mv -f "$(DEPDIR)/libgnomekbd_la-gkb-keyboard-drawing.Tpo" "$(DEPDIR)/libgnomekbd_la-gkb-keyboard-drawing.Plo"; else rm -f "$(DEPDIR)/libgnomekbd_la-gkb-keyboard-drawing.Tpo"; exit 1; fi
+# source='gkb-keyboard-drawing.c' object='libgnomekbd_la-gkb-keyboard-drawing.lo' libtool=yes \
+# DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) \
+# $(LIBTOOL) --tag=CC --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libgnomekbd_la_CFLAGS) $(CFLAGS) -c -o libgnomekbd_la-gkb-keyboard-drawing.lo `test -f 'gkb-keyboard-drawing.c' || echo '$(srcdir)/'`gkb-keyboard-drawing.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool
+uninstall-info-am:
+install-gnomekbdincHEADERS: $(gnomekbdinc_HEADERS)
+ @$(NORMAL_INSTALL)
+ test -z "$(gnomekbdincdir)" || $(mkdir_p) "$(DESTDIR)$(gnomekbdincdir)"
+ @list='$(gnomekbdinc_HEADERS)'; for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ f=$(am__strip_dir) \
+ echo " $(gnomekbdincHEADERS_INSTALL) '$$d$$p' '$(DESTDIR)$(gnomekbdincdir)/$$f'"; \
+ $(gnomekbdincHEADERS_INSTALL) "$$d$$p" "$(DESTDIR)$(gnomekbdincdir)/$$f"; \
+ done
+
+uninstall-gnomekbdincHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(gnomekbdinc_HEADERS)'; for p in $$list; do \
+ f=$(am__strip_dir) \
+ echo " rm -f '$(DESTDIR)$(gnomekbdincdir)/$$f'"; \
+ rm -f "$(DESTDIR)$(gnomekbdincdir)/$$f"; \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$tags $$unique; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ tags=; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) ' { files[$$0] = 1; } \
+ END { for (i in files) print i; }'`; \
+ test -z "$(CTAGS_ARGS)$$tags$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$tags $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && cd $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
+ list='$(DISTFILES)'; for file in $$list; do \
+ case $$file in \
+ $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
+ $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
+ esac; \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+ dir="/$$dir"; \
+ $(mkdir_p) "$(distdir)$$dir"; \
+ else \
+ dir=''; \
+ fi; \
+ if test -d $$d/$$file; then \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
+ fi; \
+ cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
+ else \
+ test -f $(distdir)/$$file \
+ || cp -p $$d/$$file $(distdir)/$$file \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(gnomekbdincdir)"; do \
+ test -z "$$dir" || $(mkdir_p) "$$dir"; \
+ done
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+info: info-am
+
+info-am:
+
+install-data-am: install-gnomekbdincHEADERS
+
+install-exec-am: install-libLTLIBRARIES
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-gnomekbdincHEADERS uninstall-info-am \
+ uninstall-libLTLIBRARIES
+
+.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
+ clean-libLTLIBRARIES clean-libtool ctags distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-exec \
+ install-exec-am install-gnomekbdincHEADERS install-info \
+ install-info-am install-libLTLIBRARIES install-man \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags uninstall uninstall-am \
+ uninstall-gnomekbdincHEADERS uninstall-info-am \
+ uninstall-libLTLIBRARIES
+
+
+%.desktop: %.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*.po) ; LC_ALL=C $(INTLTOOL_MERGE) -d -u -c $(top_builddir)/po/.intltool-merge-cache $(top_srcdir)/po $< $@
+
+gkb-indicator-marshal.h: gkb-indicator-marshal.list
+ $(GLIB_GENMARSHAL) --prefix=gkb_indicator $(srcdir)/gkb-indicator-marshal.list --header > $@
+
+gkb-indicator-marshal.c: gkb-indicator-marshal.h
+ $(GLIB_GENMARSHAL) --prefix=gkb_indicator $(srcdir)/gkb-indicator-marshal.list --body > $@
+
+gkb-config-registry-server.h: gkb-config-registry.xml
+ dbus-binding-tool --prefix=gkb_config_registry --mode=glib-server $< > $@
+
+gkb-config-registry-client.h: gkb-config-registry.xml
+ dbus-binding-tool --prefix=gkb_config_registry --mode=glib-client $< > $@
+
+gkb-keyboard-drawing-marshal.h: gkb-keyboard-drawing-marshal.list
+ ( $(GLIB_GENMARSHAL) --prefix=gkb_keyboard_drawing $(srcdir)/gkb-keyboard-drawing-marshal.list \
+ --header > gkb-keyboard-drawing-marshal.tmp \
+ && mv gkb-keyboard-drawing-marshal.tmp gkb-keyboard-drawing-marshal.h ) \
+ || ( rm -f gkb-keyboard-drawing-marshal.tmp && exit 1 )
+
+gkb-keyboard-drawing-marshal.c: gkb-keyboard-drawing-marshal.h
+ ( $(GLIB_GENMARSHAL) --prefix=gkb_keyboard_drawing $(srcdir)/gkb-keyboard-drawing-marshal.list \
+ --body > gkb-keyboard-drawing-marshal.tmp \
+ && mv gkb-keyboard-drawing-marshal.tmp gkb-keyboard-drawing-marshal.c ) \
+ || ( rm -f gkb-keyboard-drawing-marshal.tmp && exit 1 )
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/libgnomekbd/backup/Makefile.am b/libgnomekbd/backup/Makefile.am
new file mode 100644
index 0000000..1052a86
--- /dev/null
+++ b/libgnomekbd/backup/Makefile.am
@@ -0,0 +1,91 @@
+lib_LTLIBRARIES = libgnomekbd.la
+
+libgnomekbd_la_CFLAGS = \
+ -I$(top_srcdir) -Wall -Werror \
+ $(DBUS_CFLAGS) \
+ $(GTK_CFLAGS) \
+ $(GCONF_CFLAGS) \
+ $(LIBGNOME_CFLAGS) \
+ $(LIBXKLAVIER_CFLAGS) \
+ -I$(top_srcdir)/intl \
+ -DSYS_PLUGIN_DIR=\"$(libdir)/gnomekbd/\" \
+ -DG_LOG_DOMAIN=\"GnomeKbdIndicator\" \
+ -DGLADEDIR=\"$(gladedir)\" \
+ -DDATADIR=\"$(datadir)\" \
+ -DSYSCONFDIR=\"$(sysconfdir)\" \
+ -DLIBDIR=\"$(libdir)\"
+
+libgnomekbd_la_LDFLAGS = \
+ $(GCONF_LIBS)
+
+libgnomekbd_la_SOURCES = gkb-keyboard-config.c \
+ gkb-desktop-config.c \
+ gkb-indicator-config.c \
+ gkb-util.c \
+ gkb-indicator.c \
+ gkb-indicator-marshal.c \
+ gkb-indicator-plugin-manager.c \
+ gkb-config-registry.c \
+ gkb-keyboard-drawing-marshal.c \
+ gkb-keyboard-drawing.c
+
+BUILT_SOURCES = gkb-indicator-marshal.c \
+ gkb-indicator-marshal.h \
+ gkb-config-registry-server.h \
+ gkb-config-registry-client.h \
+ gkb-keyboard-drawing-marshal.c \
+ gkb-keyboard-drawing-marshal.h
+
+CLEANFILES = \
+ $(BUILT_SOURCES)
+
+gnomekbdincdir = $(includedir)/libgnomekbd
+gnomekbdinc_HEADERS = \
+ gkb-desktop-config.h \
+ gkb-keyboard-config.h \
+ gkb-config-registry-client.h \
+ gkb-config-registry.h \
+ gkb-indicator.h \
+ gkb-indicator-config.h \
+ gkb-indicator-plugin.h \
+ gkb-keyboard-drawing.h \
+ gkb-util.h
+
+@INTLTOOL_DESKTOP_RULE@
+
+noinst_HEADERS = gkb-indicator-plugin-manager.h \
+ $(extra_nih) \
+ gkb-config-private.h \
+ gkb-config-registry-server.h
+
+EXTRA_DIST = gkb-indicator-marshal.list \
+ gkb-keyboard-drawing-marshal.list \
+ gkb-config-registry.xml \
+ $(glade_DATA)
+
+GLIB_GENMARSHAL = $(shell pkg-config --variable=glib_genmarshal glib-2.0)
+
+gkb-indicator-marshal.h: gkb-indicator-marshal.list
+ $(GLIB_GENMARSHAL) --prefix=gkb_indicator $(srcdir)/gkb-indicator-marshal.list --header > $@
+
+gkb-indicator-marshal.c: gkb-indicator-marshal.h
+ $(GLIB_GENMARSHAL) --prefix=gkb_indicator $(srcdir)/gkb-indicator-marshal.list --body > $@
+
+gkb-config-registry-server.h: gkb-config-registry.xml
+ dbus-binding-tool --prefix=gkb_config_registry --mode=glib-server $< > $@
+
+gkb-config-registry-client.h: gkb-config-registry.xml
+ dbus-binding-tool --prefix=gkb_config_registry --mode=glib-client $< > $@
+
+gkb-keyboard-drawing-marshal.h: gkb-keyboard-drawing-marshal.list
+ ( $(GLIB_GENMARSHAL) --prefix=gkb_keyboard_drawing $(srcdir)/gkb-keyboard-drawing-marshal.list \
+ --header > gkb-keyboard-drawing-marshal.tmp \
+ && mv gkb-keyboard-drawing-marshal.tmp gkb-keyboard-drawing-marshal.h ) \
+ || ( rm -f gkb-keyboard-drawing-marshal.tmp && exit 1 )
+
+gkb-keyboard-drawing-marshal.c: gkb-keyboard-drawing-marshal.h
+ ( $(GLIB_GENMARSHAL) --prefix=gkb_keyboard_drawing $(srcdir)/gkb-keyboard-drawing-marshal.list \
+ --body > gkb-keyboard-drawing-marshal.tmp \
+ && mv gkb-keyboard-drawing-marshal.tmp gkb-keyboard-drawing-marshal.c ) \
+ || ( rm -f gkb-keyboard-drawing-marshal.tmp && exit 1 )
+
diff --git a/libgnomekbd/backup/gkb-config-private.h b/libgnomekbd/backup/gkb-config-private.h
new file mode 100644
index 0000000..a0afba4
--- /dev/null
+++ b/libgnomekbd/backup/gkb-config-private.h
@@ -0,0 +1,98 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GKB_CONFIG_PRIVATE_H__
+#define __GKB_CONFIG_PRIVATE_H__
+
+#include "libgnomekbd/gkb-desktop-config.h"
+#include "libgnomekbd/gkb-keyboard-config.h"
+
+#define GKB_CONFIG_KEY_PREFIX "/desktop/gnome/peripherals/keyboard"
+
+extern const gchar GKB_PREVIEW_CONFIG_DIR[];
+extern const gchar GKB_PREVIEW_CONFIG_KEY_X[];
+extern const gchar GKB_PREVIEW_CONFIG_KEY_Y[];
+extern const gchar GKB_PREVIEW_CONFIG_KEY_WIDTH[];
+extern const gchar GKB_PREVIEW_CONFIG_KEY_HEIGHT[];
+
+/**
+ * General config functions (private)
+ */
+extern void
+ gkb_desktop_config_add_listener (GConfClient * conf_client,
+ const gchar * key,
+ GConfClientNotifyFunc func,
+ gpointer user_data, int *pid);
+
+
+extern void
+ gkb_desktop_config_remove_listener (GConfClient * conf_client, int *pid);
+
+extern void gkb_keyboard_config_model_set (GkbKeyboardConfig *
+ kbd_config,
+ const gchar * model_name);
+
+extern void gkb_keyboard_config_layouts_reset (GkbKeyboardConfig *
+ kbd_config);
+extern void gkb_keyboard_config_layouts_add (GkbKeyboardConfig *
+ kbd_config,
+ const gchar * layout_name,
+ const gchar * variant_name);
+
+extern void gkb_keyboard_config_layouts_reset (GkbKeyboardConfig *
+ kbd_config);
+extern void gkb_keyboard_config_options_reset (GkbKeyboardConfig *
+ kbd_config);
+
+extern void gkb_keyboard_config_options_add (GkbKeyboardConfig *
+ kbd_config,
+ const gchar * group_name,
+ const gchar * option_name);
+extern gboolean gkb_keyboard_config_options_is_set (GkbKeyboardConfig *
+ kbd_config,
+ const gchar *
+ group_name,
+ const gchar *
+ option_name);
+
+extern gboolean gkb_keyboard_config_dump_settings (GkbKeyboardConfig *
+ kbd_config,
+ const char *file_name);
+
+extern void gkb_keyboard_config_start_listen (GkbKeyboardConfig *
+ kbd_config,
+ GConfClientNotifyFunc func,
+ gpointer user_data);
+
+extern void gkb_keyboard_config_stop_listen (GkbKeyboardConfig *
+ kbd_config);
+
+extern gboolean gkb_keyboard_config_get_lv_descriptions (XklConfigRegistry
+ * config_registry,
+ const gchar *
+ layout_name,
+ const gchar *
+ variant_name,
+ gchar **
+ layout_short_descr,
+ gchar **
+ layout_descr,
+ gchar **
+ variant_short_descr,
+ gchar **
+ variant_descr);
+
+#endif
diff --git a/libgnomekbd/backup/gkb-config-registry.c b/libgnomekbd/backup/gkb-config-registry.c
new file mode 100644
index 0000000..0f0b71d
--- /dev/null
+++ b/libgnomekbd/backup/gkb-config-registry.c
@@ -0,0 +1,166 @@
+#include <config.h>
+
+#include <gdk/gdkx.h>
+
+#include <gkb-config-registry.h>
+#include <gkb-config-registry-server.h>
+#include <gkb-keyboard-config.h>
+
+static GObjectClass *parent_class = NULL;
+
+gboolean
+ gkb_config_registry_get_current_descriptions_as_utf8
+ (GkbConfigRegistry * registry,
+ gchar *** short_layout_descriptions,
+ gchar *** long_layout_descriptions,
+ gchar *** short_variant_descriptions,
+ gchar *** long_variant_descriptions, GError ** error) {
+ XklConfigRec *xkl_config;
+ char **pl, **pv;
+ guint total_layouts;
+ gchar **sld, **lld, **svd, **lvd;
+
+ if (!registry->registry) {
+ registry->registry =
+ xkl_config_registry_get_instance (registry->engine);
+
+ xkl_config_registry_load (registry->registry);
+ }
+
+ if (!
+ (xkl_engine_get_features (registry->engine) &
+ XKLF_MULTIPLE_LAYOUTS_SUPPORTED))
+ return FALSE;
+
+ xkl_config = xkl_config_rec_new ();
+
+ if (!xkl_config_rec_get_from_server (xkl_config, registry->engine))
+ return FALSE;
+
+ pl = xkl_config->layouts;
+ pv = xkl_config->variants;
+ total_layouts = g_strv_length (xkl_config->layouts);
+ sld = *short_layout_descriptions =
+ g_new0 (char *, total_layouts + 1);
+ lld = *long_layout_descriptions =
+ g_new0 (char *, total_layouts + 1);
+ svd = *short_variant_descriptions =
+ g_new0 (char *, total_layouts + 1);
+ lvd = *long_variant_descriptions =
+ g_new0 (char *, total_layouts + 1);
+
+ while (pl != NULL && *pl != NULL) {
+ XklConfigItem item;
+
+ g_snprintf (item.name, sizeof item.name, "%s", *pl);
+ if (xkl_config_registry_find_layout
+ (registry->registry, &item)) {
+ *sld++ = g_strdup (item.short_description);
+ *lld++ = g_strdup (item.description);
+ } else {
+ *sld++ = g_strdup ("");
+ *lld++ = g_strdup ("");
+ }
+
+ if (*pv != NULL) {
+ g_snprintf (item.name, sizeof item.name, "%s",
+ *pv);
+ if (xkl_config_registry_find_variant
+ (registry->registry, *pl, &item)) {
+ *svd = g_strdup (item.short_description);
+ *lvd = g_strdup (item.description);
+ } else {
+ *svd++ = g_strdup ("");
+ *lvd++ = g_strdup ("");
+ }
+ } else {
+ *svd++ = g_strdup ("");
+ *lvd++ = g_strdup ("");
+ }
+
+ pl++;
+ pv++;
+ }
+ g_object_unref (G_OBJECT (xkl_config));
+
+ return TRUE;
+}
+
+G_DEFINE_TYPE (GkbConfigRegistry, gkb_config_registry, G_TYPE_OBJECT)
+static void
+finalize (GObject * object)
+{
+ GkbConfigRegistry *registry;
+
+ registry = GKB_CONFIG_REGISTRY (object);
+ if (registry->registry == NULL) {
+ return;
+ }
+
+ g_object_unref (registry->registry);
+ registry->registry = NULL;
+
+ g_object_unref (registry->engine);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gkb_config_registry_class_init (GkbConfigRegistryClass * klass)
+{
+ GError *error = NULL;
+ GObjectClass *object_class;
+
+ /* Init the DBus connection, per-klass */
+ klass->connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+ if (klass->connection == NULL) {
+ g_warning ("Unable to connect to dbus: %s",
+ error->message);
+ g_error_free (error);
+ return;
+ }
+
+ dbus_g_object_type_install_info (GKB_CONFIG_TYPE_REGISTRY,
+ &dbus_glib_gkb_config_registry_object_info);
+
+ object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = finalize;
+
+ parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+gkb_config_registry_init (GkbConfigRegistry * registry)
+{
+ GError *error = NULL;
+ DBusGProxy *driver_proxy;
+ GkbConfigRegistryClass *klass =
+ GKB_CONFIG_REGISTRY_GET_CLASS (registry);
+ unsigned request_ret;
+
+ /* Register DBUS path */
+ dbus_g_connection_register_g_object (klass->connection,
+ "/org/gnome/GkbConfigRegistry",
+ G_OBJECT (registry));
+
+ /* Register the service name, the constant here are defined in dbus-glib-bindings.h */
+ driver_proxy = dbus_g_proxy_new_for_name (klass->connection,
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS);
+
+ if (!org_freedesktop_DBus_request_name
+ (driver_proxy, "org.gnome.GkbConfigRegistry", 0,
+ &request_ret, &error)) {
+ g_warning ("Unable to register service: %s",
+ error->message);
+ g_error_free (error);
+ }
+ g_object_unref (driver_proxy);
+
+ /* Init libxklavier stuff */
+ registry->engine = xkl_engine_get_instance (GDK_DISPLAY ());
+ /* Lazy initialization */
+ registry->registry = NULL;
+}
diff --git a/libgnomekbd/backup/gkb-config-registry.h b/libgnomekbd/backup/gkb-config-registry.h
new file mode 100644
index 0000000..cf6d524
--- /dev/null
+++ b/libgnomekbd/backup/gkb-config-registry.h
@@ -0,0 +1,44 @@
+#ifndef __GKB_CONFIG_REGISTRY_H__
+#define __GKB_CONFIG_REGISTRY_H__
+
+#include <dbus/dbus-glib-bindings.h>
+#include <libxklavier/xklavier.h>
+
+typedef struct GkbConfigRegistry GkbConfigRegistry;
+typedef struct GkbConfigRegistryClass GkbConfigRegistryClass;
+
+struct GkbConfigRegistry {
+ GObject parent;
+
+ XklEngine *engine;
+ XklConfigRegistry *registry;
+};
+
+struct GkbConfigRegistryClass {
+ GObjectClass parent;
+ DBusGConnection *connection;
+};
+
+#define GKB_CONFIG_TYPE_REGISTRY (gkb_config_registry_get_type ())
+#define GKB_CONFIG_REGISTRY(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GKB_CONFIG_TYPE_REGISTRY, GkbConfigRegistry))
+#define GKB_CONFIG_REGISTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GKB_CONFIG_TYPE_REGISTRY, GkbConfigRegistryClass))
+#define GKB_IS_CONFIG_REGISTRY(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GKB_CONFIG_TYPE_REGISTRY))
+#define GKB_IS_CONFIG_REGISTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GKB_CONFIG_TYPE_REGISTRY))
+#define GKB_CONFIG_REGISTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GKB_CONFIG_TYPE_REGISTRY, GkbConfigRegistryClass))
+
+
+/**
+ * DBUS server
+ */
+
+extern GType gkb_config_registry_get_type (void);
+
+extern gboolean
+ gkb_config_registry_get_current_descriptions_as_utf8
+ (GkbConfigRegistry * registry,
+ gchar *** short_layout_descriptions,
+ gchar *** long_layout_descriptions,
+ gchar *** short_variant_descriptions,
+ gchar *** long_variant_descriptions, GError ** error);
+
+#endif
diff --git a/libgnomekbd/backup/gkb-config-registry.xml b/libgnomekbd/backup/gkb-config-registry.xml
new file mode 100644
index 0000000..359d874
--- /dev/null
+++ b/libgnomekbd/backup/gkb-config-registry.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<node name="/org/gnome/GkbConfigRegistry">
+ <interface name="org.gnome.GkbConfigRegistry">
+ <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="gkb_config_registry"/>
+ <method name="GetCurrentDescriptionsAsUtf8">
+ <arg type="as" name="shortLayoutDescriptions" direction="out" />
+ <arg type="as" name="longLayoutDescriptions" direction="out" />
+ <arg type="as" name="shortVariantDescriptions" direction="out" />
+ <arg type="as" name="longVariantDescriptions" direction="out" />
+ </method>
+ <!-- Add more methods/signals if you want -->
+ </interface>
+</node>
diff --git a/libgnomekbd/backup/gkb-desktop-config.c b/libgnomekbd/backup/gkb-desktop-config.c
new file mode 100644
index 0000000..fa88455
--- /dev/null
+++ b/libgnomekbd/backup/gkb-desktop-config.c
@@ -0,0 +1,403 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <X11/keysym.h>
+
+#include <glib/gi18n.h>
+#include <gdk/gdkx.h>
+#include <libgnome/gnome-program.h>
+
+#include <gkb-desktop-config.h>
+#include <gkb-config-private.h>
+
+#include <gkb-config-registry-client.h>
+
+/**
+ * GkbDesktopConfig
+ */
+#define GKB_DESKTOP_CONFIG_KEY_PREFIX GKB_CONFIG_KEY_PREFIX "/general"
+
+const gchar GKB_DESKTOP_CONFIG_DIR[] = GKB_DESKTOP_CONFIG_KEY_PREFIX;
+const gchar GKB_DESKTOP_CONFIG_KEY_DEFAULT_GROUP[] =
+ GKB_DESKTOP_CONFIG_KEY_PREFIX "/defaultGroup";
+const gchar GKB_DESKTOP_CONFIG_KEY_GROUP_PER_WINDOW[] =
+ GKB_DESKTOP_CONFIG_KEY_PREFIX "/groupPerWindow";
+const gchar GKB_DESKTOP_CONFIG_KEY_HANDLE_INDICATORS[] =
+ GKB_DESKTOP_CONFIG_KEY_PREFIX "/handleIndicators";
+const gchar GKB_DESKTOP_CONFIG_KEY_LAYOUT_NAMES_AS_GROUP_NAMES[]
+ = GKB_DESKTOP_CONFIG_KEY_PREFIX "/layoutNamesAsGroupNames";
+
+/**
+ * static common functions
+ */
+
+static gboolean
+gkb_desktop_config_get_remote_lv_descriptions_utf8 (gchar *** sld,
+ gchar *** lld,
+ gchar *** svd,
+ gchar *** lvd)
+{
+ DBusGProxy *proxy;
+ DBusGConnection *connection;
+ GError *error = NULL;
+
+ connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+ if (connection == NULL) {
+ g_warning ("Unable to connect to dbus: %s\n",
+ error->message);
+ g_error_free (error);
+ /* Basically here, there is a problem, since there is no dbus :) */
+ return False;
+ }
+
+/* This won't trigger activation! */
+ proxy = dbus_g_proxy_new_for_name (connection,
+ "org.gnome.GkbConfigRegistry",
+ "/org/gnome/GkbConfigRegistry",
+ "org.gnome.GkbConfigRegistry");
+
+/* The method call will trigger activation, more on that later */
+ if (!org_gnome_GkbConfigRegistry_get_current_descriptions_as_utf8
+ (proxy, sld, lld, svd, lvd, &error)) {
+ /* Method failed, the GError is set, let's warn everyone */
+ g_warning ("Woops remote method failed: %s",
+ error->message);
+ g_error_free (error);
+ return False;
+ }
+ return True;
+}
+
+void
+gkb_desktop_config_add_listener (GConfClient * conf_client,
+ const gchar * key,
+ GConfClientNotifyFunc func,
+ gpointer user_data, int *pid)
+{
+ GError *gerror = NULL;
+ xkl_debug (150, "Listening to [%s]\n", key);
+ *pid = gconf_client_notify_add (conf_client,
+ key, func, user_data, NULL,
+ &gerror);
+ if (0 == *pid) {
+ g_warning ("Error listening for configuration: [%s]\n",
+ gerror->message);
+ g_error_free (gerror);
+ }
+}
+
+void
+gkb_desktop_config_remove_listener (GConfClient * conf_client, int *pid)
+{
+ if (*pid != 0) {
+ gconf_client_notify_remove (conf_client, *pid);
+ *pid = 0;
+ }
+}
+
+/**
+ * extern GkbDesktopConfig config functions
+ */
+void
+gkb_desktop_config_init (GkbDesktopConfig * config,
+ GConfClient * conf_client, XklEngine * engine)
+{
+ GError *gerror = NULL;
+
+ memset (config, 0, sizeof (*config));
+ config->conf_client = conf_client;
+ config->engine = engine;
+ g_object_ref (config->conf_client);
+
+ gconf_client_add_dir (config->conf_client,
+ GKB_DESKTOP_CONFIG_DIR,
+ GCONF_CLIENT_PRELOAD_NONE, &gerror);
+ if (gerror != NULL) {
+ g_warning ("err: %s\n", gerror->message);
+ g_error_free (gerror);
+ gerror = NULL;
+ }
+}
+
+void
+gkb_desktop_config_term (GkbDesktopConfig * config)
+{
+ g_object_unref (config->conf_client);
+ config->conf_client = NULL;
+}
+
+void
+gkb_desktop_config_load_from_gconf (GkbDesktopConfig * config)
+{
+ GError *gerror = NULL;
+
+ config->group_per_app =
+ gconf_client_get_bool (config->conf_client,
+ GKB_DESKTOP_CONFIG_KEY_GROUP_PER_WINDOW,
+ &gerror);
+ if (gerror != NULL) {
+ g_warning ("Error reading configuration:%s\n",
+ gerror->message);
+ config->group_per_app = FALSE;
+ g_error_free (gerror);
+ gerror = NULL;
+ }
+ xkl_debug (150, "group_per_app: %d\n", config->group_per_app);
+
+ config->handle_indicators =
+ gconf_client_get_bool (config->conf_client,
+ GKB_DESKTOP_CONFIG_KEY_HANDLE_INDICATORS,
+ &gerror);
+ if (gerror != NULL) {
+ g_warning ("Error reading configuration:%s\n",
+ gerror->message);
+ config->handle_indicators = FALSE;
+ g_error_free (gerror);
+ gerror = NULL;
+ }
+ xkl_debug (150, "handle_indicators: %d\n",
+ config->handle_indicators);
+
+ config->layout_names_as_group_names =
+ gconf_client_get_bool (config->conf_client,
+ GKB_DESKTOP_CONFIG_KEY_LAYOUT_NAMES_AS_GROUP_NAMES,
+ &gerror);
+ if (gerror != NULL) {
+ g_warning ("Error reading configuration:%s\n",
+ gerror->message);
+ config->layout_names_as_group_names = TRUE;
+ g_error_free (gerror);
+ gerror = NULL;
+ }
+ xkl_debug (150, "layout_names_as_group_names: %d\n",
+ config->layout_names_as_group_names);
+
+ config->default_group =
+ gconf_client_get_int (config->conf_client,
+ GKB_DESKTOP_CONFIG_KEY_DEFAULT_GROUP,
+ &gerror);
+ if (gerror != NULL) {
+ g_warning ("Error reading configuration:%s\n",
+ gerror->message);
+ config->default_group = -1;
+ g_error_free (gerror);
+ gerror = NULL;
+ }
+
+ if (config->default_group < -1
+ || config->default_group >=
+ xkl_engine_get_max_num_groups (config->engine))
+ config->default_group = -1;
+ xkl_debug (150, "default_group: %d\n", config->default_group);
+}
+
+void
+gkb_desktop_config_save_to_gconf (GkbDesktopConfig * config)
+{
+ GConfChangeSet *cs;
+ GError *gerror = NULL;
+
+ cs = gconf_change_set_new ();
+
+ gconf_change_set_set_bool (cs,
+ GKB_DESKTOP_CONFIG_KEY_GROUP_PER_WINDOW,
+ config->group_per_app);
+ gconf_change_set_set_bool (cs,
+ GKB_DESKTOP_CONFIG_KEY_HANDLE_INDICATORS,
+ config->handle_indicators);
+ gconf_change_set_set_bool (cs,
+ GKB_DESKTOP_CONFIG_KEY_LAYOUT_NAMES_AS_GROUP_NAMES,
+ config->layout_names_as_group_names);
+ gconf_change_set_set_int (cs,
+ GKB_DESKTOP_CONFIG_KEY_DEFAULT_GROUP,
+ config->default_group);
+
+ gconf_client_commit_change_set (config->conf_client, cs, TRUE,
+ &gerror);
+ if (gerror != NULL) {
+ g_warning ("Error saving active configuration: %s\n",
+ gerror->message);
+ g_error_free (gerror);
+ gerror = NULL;
+ }
+ gconf_change_set_unref (cs);
+}
+
+gboolean
+gkb_desktop_config_activate (GkbDesktopConfig * config)
+{
+ gboolean rv = TRUE;
+
+ xkl_engine_set_group_per_toplevel_window (config->engine,
+ config->group_per_app);
+ xkl_engine_set_indicators_handling (config->engine,
+ config->handle_indicators);
+ xkl_engine_set_default_group (config->engine,
+ config->default_group);
+
+ return rv;
+}
+
+void
+gkb_desktop_config_lock_next_group (GkbDesktopConfig * config)
+{
+ int group = xkl_engine_get_next_group (config->engine);
+ xkl_engine_lock_group (config->engine, group);
+}
+
+void
+gkb_desktop_config_lock_prev_group (GkbDesktopConfig * config)
+{
+ int group = xkl_engine_get_prev_group (config->engine);
+ xkl_engine_lock_group (config->engine, group);
+}
+
+void
+gkb_desktop_config_restore_group (GkbDesktopConfig * config)
+{
+ int group = xkl_engine_get_current_window_group (config->engine);
+ xkl_engine_lock_group (config->engine, group);
+}
+
+void
+gkb_desktop_config_start_listen (GkbDesktopConfig * config,
+ GConfClientNotifyFunc func,
+ gpointer user_data)
+{
+ gkb_desktop_config_add_listener (config->conf_client,
+ GKB_DESKTOP_CONFIG_DIR, func,
+ user_data,
+ &config->config_listener_id);
+}
+
+void
+gkb_desktop_config_stop_listen (GkbDesktopConfig * config)
+{
+ gkb_desktop_config_remove_listener (config->conf_client,
+ &config->config_listener_id);
+}
+
+gboolean
+gkb_desktop_config_load_remote_group_descriptions_utf8 (GkbDesktopConfig *
+ config,
+ gchar ***
+ short_group_names,
+ gchar ***
+ full_group_names)
+{
+ gchar **sld, **lld, **svd, **lvd;
+ gchar **psld, **plld, **plvd;
+ gchar **psgn, **pfgn;
+ gint total_descriptions;
+
+ if (!gkb_desktop_config_get_remote_lv_descriptions_utf8
+ (&sld, &lld, &svd, &lvd)) {
+ return False;
+ }
+
+ total_descriptions = g_strv_length (sld);
+
+ *short_group_names = psgn =
+ g_new0 (gchar *, total_descriptions + 1);
+ *full_group_names = pfgn =
+ g_new0 (gchar *, total_descriptions + 1);
+
+ plld = lld;
+ psld = sld;
+ plvd = lvd;
+ while (plld != NULL && *plld != NULL) {
+ *psgn++ = g_strdup (*psld++);
+ *pfgn++ = g_strdup (gkb_keyboard_config_format_full_layout
+ (*plld++, *plvd++));
+ }
+ g_strfreev (sld);
+ g_strfreev (lld);
+ g_strfreev (svd);
+ g_strfreev (lvd);
+
+ return True;
+}
+
+gchar **
+gkb_desktop_config_load_group_descriptions_utf8 (GkbDesktopConfig * config,
+ XklConfigRegistry *
+ config_registry)
+{
+ int i;
+ const gchar **native_names =
+ xkl_engine_get_groups_names (config->engine);
+ guint total_groups = xkl_engine_get_num_groups (config->engine);
+ guint total_layouts;
+ gchar **rv = g_new0 (char *, total_groups + 1);
+ gchar **current_descr = rv;
+
+ if ((xkl_engine_get_features (config->engine) &
+ XKLF_MULTIPLE_LAYOUTS_SUPPORTED)
+ && config->layout_names_as_group_names) {
+ XklConfigRec *xkl_config = xkl_config_rec_new ();
+ if (xkl_config_rec_get_from_server
+ (xkl_config, config->engine)) {
+ char **pl = xkl_config->layouts;
+ char **pv = xkl_config->variants;
+ i = total_groups;
+ while (pl != NULL && *pl != NULL && i >= 0) {
+ char *ls_descr;
+ char *l_descr;
+ char *vs_descr;
+ char *v_descr;
+ if (gkb_keyboard_config_get_lv_descriptions
+ (config_registry, *pl++, *pv++,
+ &ls_descr, &l_descr, &vs_descr,
+ &v_descr)) {
+ char *name_utf =
+ g_locale_to_utf8
+ (gkb_keyboard_config_format_full_layout
+ (l_descr, v_descr), -1, NULL,
+ NULL, NULL);
+ *current_descr++ = name_utf;
+ } else {
+ *current_descr++ = g_strdup ("");
+ }
+ }
+ }
+ g_object_unref (G_OBJECT (xkl_config));
+ /* Worst case - multiple layous - but SOME of them are multigrouped :(((
+ * We cannot do much - just add empty descriptions.
+ * The UI is going to be messy.
+ * Canadian layouts are famous for this sh.t. */
+ total_layouts = g_strv_length (rv);
+ if (total_layouts != total_groups) {
+ xkl_debug (0,
+ "The mismatch between "
+ "the number of groups: %d and number of layouts: %d\n",
+ total_groups, total_layouts);
+ current_descr = rv + total_layouts;
+ for (i = total_groups - total_layouts; --i >= 0;)
+ *current_descr++ = g_strdup ("");
+ }
+ }
+ total_layouts = g_strv_length (rv);
+ if (!total_layouts)
+ for (i = total_groups; --i >= 0;)
+ *current_descr++ = g_strdup (*native_names++);
+
+ return rv;
+}
diff --git a/libgnomekbd/backup/gkb-desktop-config.h b/libgnomekbd/backup/gkb-desktop-config.h
new file mode 100644
index 0000000..2cf27a0
--- /dev/null
+++ b/libgnomekbd/backup/gkb-desktop-config.h
@@ -0,0 +1,96 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GKB_DESKTOP_CONFIG_H__
+#define __GKB_DESKTOP_CONFIG_H__
+
+#include <X11/Xlib.h>
+
+#include <glib.h>
+#include <glib/gslist.h>
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gconf/gconf-client.h>
+
+#include <libxklavier/xklavier.h>
+
+extern const gchar GKB_DESKTOP_CONFIG_DIR[];
+extern const gchar GKB_DESKTOP_CONFIG_KEY_DEFAULT_GROUP[];
+extern const gchar GKB_DESKTOP_CONFIG_KEY_GROUP_PER_WINDOW[];
+extern const gchar GKB_DESKTOP_CONFIG_KEY_HANDLE_INDICATORS[];
+extern const gchar GKB_DESKTOP_CONFIG_KEY_LAYOUT_NAMES_AS_GROUP_NAMES[];
+
+/*
+ * General configuration
+ */
+typedef struct _GkbDesktopConfig {
+ gint default_group;
+ gboolean group_per_app;
+ gboolean handle_indicators;
+ gboolean layout_names_as_group_names;
+
+ /* private, transient */
+ GConfClient *conf_client;
+ int config_listener_id;
+ XklEngine *engine;
+} GkbDesktopConfig;
+
+/**
+ * GkbDesktopConfig functions
+ */
+extern void gkb_desktop_config_init (GkbDesktopConfig * config,
+ GConfClient * conf_client,
+ XklEngine * engine);
+extern void gkb_desktop_config_term (GkbDesktopConfig * config);
+
+extern void gkb_desktop_config_load_from_gconf (GkbDesktopConfig * config);
+
+extern void gkb_desktop_config_save_to_gconf (GkbDesktopConfig * config);
+
+extern gboolean gkb_desktop_config_activate (GkbDesktopConfig * config);
+
+/* Affected by XKB and XKB/GConf configuration */
+extern gchar
+ ** gkb_desktop_config_load_group_descriptions_utf8 (GkbDesktopConfig *
+ config,
+ XklConfigRegistry *
+ config_registry);
+
+
+/* Using DBUS */
+extern gboolean
+gkb_desktop_config_load_remote_group_descriptions_utf8 (GkbDesktopConfig *
+ config,
+ gchar ***
+ short_group_names,
+ gchar ***
+ full_group_names);
+
+extern void gkb_desktop_config_lock_next_group (GkbDesktopConfig * config);
+
+extern void gkb_desktop_config_lock_prev_group (GkbDesktopConfig * config);
+
+extern void gkb_desktop_config_restore_group (GkbDesktopConfig * config);
+
+extern void gkb_desktop_config_start_listen (GkbDesktopConfig * config,
+ GConfClientNotifyFunc func,
+ gpointer user_data);
+
+extern void gkb_desktop_config_stop_listen (GkbDesktopConfig * config);
+
+#endif
diff --git a/libgnomekbd/backup/gkb-indicator-config.c b/libgnomekbd/backup/gkb-indicator-config.c
new file mode 100644
index 0000000..f90dadc
--- /dev/null
+++ b/libgnomekbd/backup/gkb-indicator-config.c
@@ -0,0 +1,360 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <X11/keysym.h>
+
+#include <glib/gi18n.h>
+#include <gdk/gdkx.h>
+#include <libgnome/gnome-program.h>
+
+#include <gkb-keyboard-config.h>
+#include <gkb-indicator-config.h>
+
+#include <gkb-config-private.h>
+
+#include <gkb-config-registry-client.h>
+
+/**
+ * GkbIndicatorConfig
+ */
+#define GKB_INDICATOR_CONFIG_KEY_PREFIX GKB_CONFIG_KEY_PREFIX "/indicator"
+
+const gchar GKB_INDICATOR_CONFIG_DIR[] = GKB_INDICATOR_CONFIG_KEY_PREFIX;
+const gchar GKB_INDICATOR_CONFIG_KEY_SHOW_FLAGS[] =
+ GKB_INDICATOR_CONFIG_KEY_PREFIX "/showFlags";
+const gchar GKB_INDICATOR_CONFIG_KEY_ENABLED_PLUGINS[] =
+ GKB_INDICATOR_CONFIG_KEY_PREFIX "/enabledPlugins";
+const gchar GKB_INDICATOR_CONFIG_KEY_SECONDARIES[] =
+ GKB_INDICATOR_CONFIG_KEY_PREFIX "/secondary";
+
+/**
+ * static applet config functions
+ */
+static void
+gkb_indicator_config_free_enabled_plugins (GkbIndicatorConfig * ind_config)
+{
+ GSList *plugin_node = ind_config->enabled_plugins;
+ if (plugin_node != NULL) {
+ do {
+ if (plugin_node->data != NULL) {
+ g_free (plugin_node->data);
+ plugin_node->data = NULL;
+ }
+ plugin_node = g_slist_next (plugin_node);
+ } while (plugin_node != NULL);
+ g_slist_free (ind_config->enabled_plugins);
+ ind_config->enabled_plugins = NULL;
+ }
+}
+
+/**
+ * extern applet kbdConfig functions
+ */
+void
+gkb_indicator_config_free_images (GkbIndicatorConfig * ind_config)
+{
+ GdkPixbuf *pi;
+ GSList *img_node;
+ while ((img_node = ind_config->images) != NULL) {
+ pi = GDK_PIXBUF (img_node->data);
+ /* It can be NULL - some images may be missing */
+ if (pi != NULL) {
+ gdk_pixbuf_unref (pi);
+ }
+ ind_config->images =
+ g_slist_remove_link (ind_config->images, img_node);
+ g_slist_free_1 (img_node);
+ }
+}
+
+char *
+gkb_indicator_config_get_images_file (GkbIndicatorConfig *
+ ind_config,
+ GkbKeyboardConfig *
+ kbd_config, int group)
+{
+ char *image_file = NULL;
+ GtkIconInfo *icon_info = NULL;
+
+ if (!ind_config->show_flags)
+ return NULL;
+
+ if ((kbd_config->layouts != NULL) &&
+ (g_slist_length (kbd_config->layouts) > group)) {
+ char *full_layout_name =
+ (char *) g_slist_nth_data (kbd_config->layouts, group);
+
+ if (full_layout_name != NULL) {
+ char *l, *v;
+ gkb_keyboard_config_split_items (full_layout_name,
+ &l, &v);
+ if (l != NULL) {
+ // probably there is something in theme?
+ icon_info = gtk_icon_theme_lookup_icon
+ (ind_config->icon_theme, l, 48, 0);
+ }
+ }
+ }
+ // fallback to the default value
+ if (icon_info == NULL) {
+ icon_info = gtk_icon_theme_lookup_icon
+ (ind_config->icon_theme, "stock_dialog-error", 48, 0);
+ }
+ if (icon_info != NULL) {
+ image_file =
+ g_strdup (gtk_icon_info_get_filename (icon_info));
+ gtk_icon_info_free (icon_info);
+ }
+
+ return image_file;
+}
+
+void
+gkb_indicator_config_load_images (GkbIndicatorConfig * ind_config,
+ GkbKeyboardConfig * kbd_config)
+{
+ int i;
+ ind_config->images = NULL;
+
+ if (!ind_config->show_flags)
+ return;
+
+ for (i = xkl_engine_get_max_num_groups (ind_config->engine);
+ --i >= 0;) {
+ GdkPixbuf *image = NULL;
+ char *image_file =
+ gkb_indicator_config_get_images_file (ind_config,
+ kbd_config,
+ i);
+
+ if (image_file != NULL) {
+ GError *gerror = NULL;
+ image =
+ gdk_pixbuf_new_from_file (image_file, &gerror);
+ if (image == NULL) {
+ GtkWidget *dialog =
+ gtk_message_dialog_new (NULL,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _
+ ("There was an error loading an image: %s"),
+ gerror->
+ message);
+ g_signal_connect (G_OBJECT (dialog),
+ "response",
+ G_CALLBACK
+ (gtk_widget_destroy),
+ NULL);
+
+ gtk_window_set_resizable (GTK_WINDOW
+ (dialog), FALSE);
+
+ gtk_widget_show (dialog);
+ g_error_free (gerror);
+ }
+ xkl_debug (150,
+ "Image %d[%s] loaded -> %p[%dx%d]\n",
+ i, image_file, image,
+ gdk_pixbuf_get_width (image),
+ gdk_pixbuf_get_height (image));
+ g_free (image_file);
+ }
+ /* We append the image anyway - even if it is NULL! */
+ ind_config->images =
+ g_slist_prepend (ind_config->images, image);
+ }
+}
+
+void
+gkb_indicator_config_init (GkbIndicatorConfig * ind_config,
+ GConfClient * conf_client, XklEngine * engine)
+{
+ GError *gerror = NULL;
+ gchar *sp, *datadir;
+
+ memset (ind_config, 0, sizeof (*ind_config));
+ ind_config->conf_client = conf_client;
+ ind_config->engine = engine;
+ g_object_ref (ind_config->conf_client);
+
+ gconf_client_add_dir (ind_config->conf_client,
+ GKB_INDICATOR_CONFIG_DIR,
+ GCONF_CLIENT_PRELOAD_NONE, &gerror);
+ if (gerror != NULL) {
+ g_warning ("err1:%s\n", gerror->message);
+ g_error_free (gerror);
+ gerror = NULL;
+ }
+
+ ind_config->icon_theme = gtk_icon_theme_get_default ();
+
+ datadir =
+ gnome_program_locate_file (NULL, GNOME_FILE_DOMAIN_APP_DATADIR,
+ "", FALSE, NULL);
+ gtk_icon_theme_append_search_path (ind_config->icon_theme, sp =
+ g_build_filename (g_get_home_dir
+ (),
+ ".icons/flags",
+ NULL));
+ g_free (sp);
+
+ gtk_icon_theme_append_search_path (ind_config->icon_theme,
+ sp =
+ g_build_filename (datadir,
+ "pixmaps/flags",
+ NULL));
+ g_free (sp);
+
+ gtk_icon_theme_append_search_path (ind_config->icon_theme,
+ sp =
+ g_build_filename (datadir,
+ "icons/flags",
+ NULL));
+ g_free (sp);
+ g_free (datadir);
+}
+
+void
+gkb_indicator_config_term (GkbIndicatorConfig * ind_config)
+{
+#if 0
+ g_object_unref (G_OBJECT (ind_config->icon_theme));
+#endif
+ ind_config->icon_theme = NULL;
+
+ gkb_indicator_config_free_images (ind_config);
+
+ gkb_indicator_config_free_enabled_plugins (ind_config);
+ g_object_unref (ind_config->conf_client);
+ ind_config->conf_client = NULL;
+}
+
+void
+gkb_indicator_config_update_images (GkbIndicatorConfig *
+ ind_config,
+ GkbKeyboardConfig * kbd_config)
+{
+ gkb_indicator_config_free_images (ind_config);
+ gkb_indicator_config_load_images (ind_config, kbd_config);
+}
+
+void
+gkb_indicator_config_load_from_gconf (GkbIndicatorConfig * ind_config)
+{
+ GError *gerror = NULL;
+
+ ind_config->secondary_groups_mask =
+ gconf_client_get_int (ind_config->conf_client,
+ GKB_INDICATOR_CONFIG_KEY_SECONDARIES,
+ &gerror);
+ if (gerror != NULL) {
+ g_warning ("Error reading configuration:%s\n",
+ gerror->message);
+ ind_config->secondary_groups_mask = 0;
+ g_error_free (gerror);
+ gerror = NULL;
+ }
+
+ ind_config->show_flags =
+ gconf_client_get_bool (ind_config->conf_client,
+ GKB_INDICATOR_CONFIG_KEY_SHOW_FLAGS,
+ &gerror);
+ if (gerror != NULL) {
+ g_warning ("Error reading kbdConfiguration:%s\n",
+ gerror->message);
+ ind_config->show_flags = FALSE;
+ g_error_free (gerror);
+ gerror = NULL;
+ }
+
+ gkb_indicator_config_free_enabled_plugins (ind_config);
+ ind_config->enabled_plugins =
+ gconf_client_get_list (ind_config->conf_client,
+ GKB_INDICATOR_CONFIG_KEY_ENABLED_PLUGINS,
+ GCONF_VALUE_STRING, &gerror);
+
+ if (gerror != NULL) {
+ g_warning ("Error reading kbd_configuration:%s\n",
+ gerror->message);
+ ind_config->enabled_plugins = NULL;
+ g_error_free (gerror);
+ gerror = NULL;
+ }
+}
+
+void
+gkb_indicator_config_save_to_gconf (GkbIndicatorConfig * ind_config)
+{
+ GConfChangeSet *cs;
+ GError *gerror = NULL;
+
+ cs = gconf_change_set_new ();
+
+ gconf_change_set_set_int (cs,
+ GKB_INDICATOR_CONFIG_KEY_SECONDARIES,
+ ind_config->secondary_groups_mask);
+ gconf_change_set_set_bool (cs,
+ GKB_INDICATOR_CONFIG_KEY_SHOW_FLAGS,
+ ind_config->show_flags);
+ gconf_change_set_set_list (cs,
+ GKB_INDICATOR_CONFIG_KEY_ENABLED_PLUGINS,
+ GCONF_VALUE_STRING,
+ ind_config->enabled_plugins);
+
+ gconf_client_commit_change_set (ind_config->conf_client, cs,
+ TRUE, &gerror);
+ if (gerror != NULL) {
+ g_warning ("Error saving configuration: %s\n",
+ gerror->message);
+ g_error_free (gerror);
+ gerror = NULL;
+ }
+ gconf_change_set_unref (cs);
+}
+
+void
+gkb_indicator_config_activate (GkbIndicatorConfig * ind_config)
+{
+ xkl_engine_set_secondary_groups_mask (ind_config->engine,
+ ind_config->
+ secondary_groups_mask);
+}
+
+void
+gkb_indicator_config_start_listen (GkbIndicatorConfig *
+ ind_config,
+ GConfClientNotifyFunc func,
+ gpointer user_data)
+{
+ gkb_desktop_config_add_listener (ind_config->conf_client,
+ GKB_INDICATOR_CONFIG_DIR, func,
+ user_data,
+ &ind_config->config_listener_id);
+}
+
+void
+gkb_indicator_config_stop_listen (GkbIndicatorConfig * ind_config)
+{
+ gkb_desktop_config_remove_listener (ind_config->conf_client,
+ &ind_config->
+ config_listener_id);
+}
diff --git a/libgnomekbd/backup/gkb-indicator-config.h b/libgnomekbd/backup/gkb-indicator-config.h
new file mode 100644
index 0000000..ac838e0
--- /dev/null
+++ b/libgnomekbd/backup/gkb-indicator-config.h
@@ -0,0 +1,86 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GKB_INDICATOR_CONFIG_H__
+#define __GKB_INDICATOR_CONFIG_H__
+
+#include "libgnomekbd/gkb-keyboard-config.h"
+
+/*
+ * Indicator configuration
+ */
+typedef struct _GkbIndicatorConfig {
+ int secondary_groups_mask;
+ gboolean show_flags;
+
+ GSList *enabled_plugins;
+
+ /* private, transient */
+ GConfClient *conf_client;
+ GSList *images;
+ GtkIconTheme *icon_theme;
+ int config_listener_id;
+ XklEngine *engine;
+} GkbIndicatorConfig;
+
+/**
+ * GkbIndicatorConfig functions -
+ * some of them require GkbKeyboardConfig as well -
+ * for loading approptiate images
+ */
+extern void gkb_indicator_config_init (GkbIndicatorConfig *
+ applet_config,
+ GConfClient * conf_client,
+ XklEngine * engine);
+extern void gkb_indicator_config_term (GkbIndicatorConfig * applet_config);
+
+extern void gkb_indicator_config_load_from_gconf (GkbIndicatorConfig
+ * applet_config);
+extern void gkb_indicator_config_save_to_gconf (GkbIndicatorConfig *
+ applet_config);
+
+extern gchar
+ * gkb_indicator_config_get_images_file (GkbIndicatorConfig *
+ applet_config,
+ GkbKeyboardConfig *
+ kbd_config, int group);
+
+extern void gkb_indicator_config_load_images (GkbIndicatorConfig *
+ applet_config,
+ GkbKeyboardConfig *
+ kbd_config);
+extern void gkb_indicator_config_free_images (GkbIndicatorConfig *
+ applet_config);
+
+/* Should be updated on Indicator/GConf and Kbd/GConf configuration change */
+extern void gkb_indicator_config_update_images (GkbIndicatorConfig *
+ applet_config,
+ GkbKeyboardConfig *
+ kbd_config);
+
+/* Should be updated on Indicator/GConf configuration change */
+extern void gkb_indicator_config_activate (GkbIndicatorConfig *
+ applet_config);
+
+extern void gkb_indicator_config_start_listen (GkbIndicatorConfig *
+ applet_config,
+ GConfClientNotifyFunc
+ func, gpointer user_data);
+
+extern void gkb_indicator_config_stop_listen (GkbIndicatorConfig *
+ applet_config);
+
+#endif
diff --git a/libgnomekbd/backup/gkb-indicator-marshal.list b/libgnomekbd/backup/gkb-indicator-marshal.list
new file mode 100644
index 0000000..5b76282
--- /dev/null
+++ b/libgnomekbd/backup/gkb-indicator-marshal.list
@@ -0,0 +1 @@
+VOID:VOID
diff --git a/libgnomekbd/backup/gkb-indicator-plugin-manager.c b/libgnomekbd/backup/gkb-indicator-plugin-manager.c
new file mode 100644
index 0000000..5da7348
--- /dev/null
+++ b/libgnomekbd/backup/gkb-indicator-plugin-manager.c
@@ -0,0 +1,391 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <libxklavier/xklavier.h>
+
+#include <gkb-indicator-plugin-manager.h>
+
+#define FOREACH_INITED_PLUGIN() \
+{ \
+ GSList *prec; \
+ for( prec = manager->inited_plugin_recs; prec != NULL; prec = prec->next ) \
+ { \
+ const GkbIndicatorPlugin *plugin = \
+ ( ( GkbIndicatorPluginManagerRecord * ) ( prec->data ) )->plugin; \
+ if( plugin != NULL ) \
+ {
+
+#define NEXT_INITED_PLUGIN() \
+ } \
+ } \
+}
+
+static void
+gkb_indicator_plugin_manager_add_plugins_dir (GkbIndicatorPluginManager * manager,
+ const char *dirname)
+{
+ GDir *dir = g_dir_open (dirname, 0, NULL);
+ const gchar *filename;
+ if (dir == NULL)
+ return;
+
+ xkl_debug (100, "Scanning [%s]...\n", dirname);
+ while ((filename = g_dir_read_name (dir)) != NULL) {
+ gchar *full_path =
+ g_build_filename (dirname, filename, NULL);
+ xkl_debug (100, "Loading plugin module [%s]...\n",
+ full_path);
+ if (full_path != NULL) {
+ GModule *module = g_module_open (full_path, 0);
+ if (module != NULL) {
+ gpointer get_plugin_func;
+ if (g_module_symbol
+ (module, "GetPlugin",
+ &get_plugin_func)) {
+ const GkbIndicatorPlugin *plugin =
+ ((GkbIndicatorPluginGetPluginFunc)
+ get_plugin_func) ();
+ if (plugin != NULL) {
+ GkbIndicatorPluginManagerRecord
+ * rec =
+ g_new0
+ (GkbIndicatorPluginManagerRecord,
+ 1);
+ xkl_debug (100,
+ "Loaded plugin from [%s]: [%s]/[%s]...\n",
+ full_path,
+ plugin->name,
+ plugin->
+ description);
+ rec->full_path = full_path;
+ rec->module = module;
+ rec->plugin = plugin;
+ g_hash_table_insert
+ (manager->
+ all_plugin_recs,
+ full_path, rec);
+ continue;
+ }
+ } else
+ xkl_debug (0,
+ "Bad plugin: [%s]\n",
+ full_path);
+ g_module_close (module);
+ } else
+ xkl_debug (0, "Bad module: [%s], %s\n",
+ full_path, g_module_error ());
+ g_free (full_path);
+ }
+ }
+ g_dir_close (dir);
+}
+
+static void
+gkb_indicator_plugin_manager_load_all (GkbIndicatorPluginManager * manager)
+{
+ if (!g_module_supported ()) {
+ xkl_debug (0, "Modules are not supported - no plugins!\n");
+ return;
+ }
+ gkb_indicator_plugin_manager_add_plugins_dir (manager, SYS_PLUGIN_DIR);
+}
+
+static void
+gkb_indicator_plugin_manager_rec_term (GkbIndicatorPluginManagerRecord * rec,
+ void *user_data)
+{
+ const GkbIndicatorPlugin *plugin = rec->plugin;
+ if (plugin != NULL) {
+ xkl_debug (100, "Terminating plugin: [%s]...\n",
+ plugin->name);
+ if (plugin->term_callback)
+ (*plugin->term_callback) ();
+ }
+}
+
+static void
+gkb_indicator_plugin_manager_rec_destroy (GkbIndicatorPluginManagerRecord * rec)
+{
+ xkl_debug (100, "Unloading plugin: [%s]...\n", rec->plugin->name);
+
+ g_module_close (rec->module);
+ g_free (rec);
+}
+
+void
+gkb_indicator_plugin_manager_init (GkbIndicatorPluginManager * manager)
+{
+ manager->all_plugin_recs =
+ g_hash_table_new_full (g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify)
+ gkb_indicator_plugin_manager_rec_destroy);
+ gkb_indicator_plugin_manager_load_all (manager);
+}
+
+void
+gkb_indicator_plugin_manager_term (GkbIndicatorPluginManager * manager)
+{
+ gkb_indicator_plugin_manager_term_initialized_plugins (manager);
+ if (manager->all_plugin_recs != NULL) {
+ g_hash_table_destroy (manager->all_plugin_recs);
+ manager->all_plugin_recs = NULL;
+ }
+}
+
+void
+gkb_indicator_plugin_manager_init_enabled_plugins (GkbIndicatorPluginManager *
+ manager,
+ GkbIndicatorPluginContainer
+ * pc,
+ GSList * enabled_plugins)
+{
+ GSList *plugin_name_node = enabled_plugins;
+ if (manager->all_plugin_recs == NULL)
+ return;
+ xkl_debug (100, "Initializing all enabled plugins...\n");
+ while (plugin_name_node != NULL) {
+ const char *full_path = plugin_name_node->data;
+ if (full_path != NULL) {
+ GkbIndicatorPluginManagerRecord *rec =
+ (GkbIndicatorPluginManagerRecord *)
+ g_hash_table_lookup (manager->all_plugin_recs,
+ full_path);
+
+ if (rec != NULL) {
+ const GkbIndicatorPlugin *plugin =
+ rec->plugin;
+ gboolean initialized = FALSE;
+ xkl_debug (100,
+ "Initializing plugin: [%s] from [%s]...\n",
+ plugin->name, full_path);
+ if (plugin->init_callback != NULL)
+ initialized =
+ (*plugin->init_callback) (pc);
+ else
+ initialized = TRUE;
+
+ manager->inited_plugin_recs =
+ g_slist_append (manager->
+ inited_plugin_recs,
+ rec);
+ xkl_debug (100,
+ "Plugin [%s] initialized: %d\n",
+ plugin->name, initialized);
+ }
+ }
+ plugin_name_node = g_slist_next (plugin_name_node);
+ }
+}
+
+void
+gkb_indicator_plugin_manager_term_initialized_plugins (GkbIndicatorPluginManager *
+ manager)
+{
+
+ if (manager->inited_plugin_recs == NULL)
+ return;
+ g_slist_foreach (manager->inited_plugin_recs,
+ (GFunc) gkb_indicator_plugin_manager_rec_term, NULL);
+ g_slist_free (manager->inited_plugin_recs);
+ manager->inited_plugin_recs = NULL;
+}
+
+void
+gkb_indicator_plugin_manager_toggle_plugins (GkbIndicatorPluginManager * manager,
+ GkbIndicatorPluginContainer * pc,
+ GSList * enabled_plugins)
+{
+ gkb_indicator_plugin_manager_term_initialized_plugins (manager);
+ gkb_indicator_plugin_manager_init_enabled_plugins (manager, pc,
+ enabled_plugins);
+}
+
+void
+gkb_indicator_plugin_manager_group_changed (GkbIndicatorPluginManager * manager,
+ GtkWidget * notebook,
+ int new_group)
+{
+ FOREACH_INITED_PLUGIN ();
+ if (plugin->group_changed_callback)
+ (*plugin->group_changed_callback) (notebook, new_group);
+ NEXT_INITED_PLUGIN ();
+}
+
+void
+gkb_indicator_plugin_manager_config_changed (GkbIndicatorPluginManager * manager,
+ GkbKeyboardConfig * from,
+ GkbKeyboardConfig * to)
+{
+ FOREACH_INITED_PLUGIN ();
+ if (plugin->config_changed_callback)
+ (*plugin->config_changed_callback) (from, to);
+ NEXT_INITED_PLUGIN ();
+}
+
+const GkbIndicatorPlugin *
+gkb_indicator_plugin_manager_get_plugin (GkbIndicatorPluginManager * manager,
+ const char *full_path)
+{
+ GkbIndicatorPluginManagerRecord *rec =
+ (GkbIndicatorPluginManagerRecord *) g_hash_table_lookup (manager->
+ all_plugin_recs,
+ full_path);
+ if (rec == NULL)
+ return NULL;
+ return rec->plugin;
+}
+
+void
+gkb_indicator_plugin_manager_promote_plugin (GkbIndicatorPluginManager * manager,
+ GSList * enabled_plugins,
+ const char *full_path)
+{
+ GSList *the_node = enabled_plugins;
+ GSList *prev_node = NULL;
+
+ while (the_node != NULL) {
+ if (!strcmp (the_node->data, full_path)) {
+ if (prev_node != NULL) {
+ char *tmp = (char *) prev_node->data;
+ prev_node->data = the_node->data;
+ the_node->data = tmp;
+ }
+ break;
+ }
+ prev_node = the_node;
+ the_node = g_slist_next (the_node);
+ }
+}
+
+void
+gkb_indicator_plugin_manager_demote_plugin (GkbIndicatorPluginManager * manager,
+ GSList * enabled_plugins,
+ const char *full_path)
+{
+ GSList *the_node = g_slist_find_custom (enabled_plugins, full_path,
+ (GCompareFunc) strcmp);
+ if (the_node != NULL) {
+ GSList *next_node = g_slist_next (the_node);
+ if (next_node != NULL) {
+ char *tmp = (char *) next_node->data;
+ next_node->data = the_node->data;
+ the_node->data = tmp;
+ }
+ }
+}
+
+void
+gkb_indicator_plugin_manager_enable_plugin (GkbIndicatorPluginManager * manager,
+ GSList ** enabled_plugins,
+ const char *full_path)
+{
+ if (NULL !=
+ gkb_indicator_plugin_manager_get_plugin (manager, full_path)) {
+ *enabled_plugins =
+ g_slist_append (*enabled_plugins,
+ (gpointer) g_strdup (full_path));
+ }
+}
+
+void
+gkb_indicator_plugin_manager_disable_plugin (GkbIndicatorPluginManager * manager,
+ GSList ** enabled_plugins,
+ const char *full_path)
+{
+ GSList *the_node =
+ g_slist_find_custom (*enabled_plugins, full_path,
+ (GCompareFunc) strcmp);
+ if (the_node != NULL) {
+ g_free (the_node->data);
+ *enabled_plugins =
+ g_slist_delete_link (*enabled_plugins, the_node);
+ }
+}
+
+int
+gkb_indicator_plugin_manager_window_created (GkbIndicatorPluginManager * manager,
+ Window win, Window parent)
+{
+ FOREACH_INITED_PLUGIN ();
+ if (plugin->window_created_callback) {
+ int group_to_assign =
+ (*plugin->window_created_callback) (win, parent);
+ if (group_to_assign != -1) {
+ xkl_debug (100,
+ "Plugin [%s] assigned group %d to new window %ld\n",
+ plugin->name, group_to_assign, win);
+ return group_to_assign;
+ }
+ }
+ NEXT_INITED_PLUGIN ();
+ return -1;
+}
+
+GtkWidget *
+gkb_indicator_plugin_manager_decorate_widget (GkbIndicatorPluginManager * manager,
+ GtkWidget * widget,
+ const gint group,
+ const char *group_description,
+ GkbKeyboardConfig * kbd_config)
+{
+ FOREACH_INITED_PLUGIN ();
+ if (plugin->decorate_widget_callback) {
+ GtkWidget *decorated_widget =
+ (*plugin->decorate_widget_callback) (widget, group,
+ group_description,
+ kbd_config);
+ if (decorated_widget != NULL) {
+ xkl_debug (100,
+ "Plugin [%s] decorated widget %p to %p\n",
+ plugin->name, widget, decorated_widget);
+ return decorated_widget;
+ }
+ }
+ NEXT_INITED_PLUGIN ();
+ return NULL;
+}
+
+void
+gkb_indicator_plugin_manager_configure_plugin (GkbIndicatorPluginManager *
+ manager,
+ GkbIndicatorPluginContainer *
+ pc, const char *full_path,
+ GtkWindow * parent)
+{
+ const GkbIndicatorPlugin *plugin =
+ gkb_indicator_plugin_manager_get_plugin (manager, full_path);
+ if (plugin->configure_properties_callback != NULL)
+ plugin->configure_properties_callback (pc, parent);
+}
+
+void
+gkb_indicator_plugin_container_init (GkbIndicatorPluginContainer * pc,
+ GConfClient * conf_client)
+{
+ pc->conf_client = conf_client;
+ g_object_ref (pc->conf_client);
+}
+
+void
+gkb_indicator_plugin_container_term (GkbIndicatorPluginContainer * pc)
+{
+ g_object_unref (pc->conf_client);
+}
diff --git a/libgnomekbd/backup/gkb-indicator-plugin-manager.h b/libgnomekbd/backup/gkb-indicator-plugin-manager.h
new file mode 100644
index 0000000..6ebfdf5
--- /dev/null
+++ b/libgnomekbd/backup/gkb-indicator-plugin-manager.h
@@ -0,0 +1,110 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GSWITCHIT_PLUGIN_MANAGER_H__
+#define __GSWITCHIT_PLUGIN_MANAGER_H__
+
+#include <gmodule.h>
+#include <libgnomekbd/gkb-indicator-plugin.h>
+
+typedef struct _GkbIndicatorPluginManager {
+ GHashTable *all_plugin_recs;
+ GSList *inited_plugin_recs;
+} GkbIndicatorPluginManager;
+
+typedef struct _GkbIndicatorPluginManagerRecord {
+ const char *full_path;
+ GModule *module;
+ const GkbIndicatorPlugin *plugin;
+} GkbIndicatorPluginManagerRecord;
+
+extern void
+ gkb_indicator_plugin_manager_init (GkbIndicatorPluginManager * manager);
+
+extern void
+ gkb_indicator_plugin_manager_term (GkbIndicatorPluginManager * manager);
+
+extern void
+ gkb_indicator_plugin_manager_init_enabled_plugins (GkbIndicatorPluginManager * manager,
+ GkbIndicatorPluginContainer
+ * pc,
+ GSList * enabled_plugins);
+
+extern void
+ gkb_indicator_plugin_manager_term_initialized_plugins (GkbIndicatorPluginManager * manager);
+
+extern void
+ gkb_indicator_plugin_manager_toggle_plugins (GkbIndicatorPluginManager * manager,
+ GkbIndicatorPluginContainer * pc,
+ GSList * enabled_plugins);
+
+extern const GkbIndicatorPlugin
+ * gkb_indicator_plugin_manager_get_plugin (GkbIndicatorPluginManager *
+ manager, const char *full_path);
+
+extern void
+ gkb_indicator_plugin_manager_promote_plugin (GkbIndicatorPluginManager * manager,
+ GSList * enabled_plugins,
+ const char *full_path);
+
+extern void
+ gkb_indicator_plugin_manager_demote_plugin (GkbIndicatorPluginManager * manager,
+ GSList * enabled_plugins,
+ const char *full_path);
+
+extern void
+ gkb_indicator_plugin_manager_enable_plugin (GkbIndicatorPluginManager * manager,
+ GSList ** enabled_plugins,
+ const char *full_path);
+
+extern void
+ gkb_indicator_plugin_manager_disable_plugin (GkbIndicatorPluginManager * manager,
+ GSList ** enabled_plugins,
+ const char *full_path);
+
+extern void
+ gkb_indicator_plugin_manager_configure_plugin (GkbIndicatorPluginManager * manager,
+ GkbIndicatorPluginContainer *
+ pc, const char *full_path,
+ GtkWindow * parent);
+
+// actual calling plugin notification methods
+
+extern void
+ gkb_indicator_plugin_manager_group_changed (GkbIndicatorPluginManager * manager,
+ GtkWidget * notebook,
+ int new_group);
+
+extern void
+ gkb_indicator_plugin_manager_config_changed (GkbIndicatorPluginManager * manager,
+ GkbKeyboardConfig * from,
+ GkbKeyboardConfig * to);
+
+extern int
+ gkb_indicator_plugin_manager_window_created (GkbIndicatorPluginManager * manager,
+ Window win, Window parent);
+
+extern GtkWidget
+ * gkb_indicator_plugin_manager_decorate_widget (GkbIndicatorPluginManager *
+ manager,
+ GtkWidget * widget,
+ const gint group,
+ const char
+ *group_description,
+ GkbKeyboardConfig *
+ config);
+
+#endif
diff --git a/libgnomekbd/backup/gkb-indicator-plugin.h b/libgnomekbd/backup/gkb-indicator-plugin.h
new file mode 100644
index 0000000..d7d8316
--- /dev/null
+++ b/libgnomekbd/backup/gkb-indicator-plugin.h
@@ -0,0 +1,120 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GKB_INDICATOR_PLUGIN_H__
+#define __GKB_INDICATOR_PLUGIN_H__
+
+#include <gtk/gtk.h>
+#include <gconf/gconf-client.h>
+#include <libgnomekbd/gkb-keyboard-config.h>
+
+#define MAX_LOCAL_NAME_BUF_LENGTH 512
+
+struct _GkbIndicatorPlugin;
+
+typedef struct _GkbIndicatorPluginContainer {
+ GConfClient *conf_client;
+} GkbIndicatorPluginContainer;
+
+typedef const struct _GkbIndicatorPlugin
+*(*GkbIndicatorPluginGetPluginFunc) (void);
+
+typedef gboolean (*GkbIndicatorPluginInitFunc) (GkbIndicatorPluginContainer
+ * pc);
+
+typedef void (*GkbIndicatorPluginGroupChangedFunc) (GtkWidget * notebook,
+ int new_group);
+
+typedef void (*GkbIndicatorPluginConfigChangedFunc) (const
+ GkbKeyboardConfig *
+ from,
+ const
+ GkbKeyboardConfig *
+ to);
+
+typedef int (*GkbIndicatorPluginWindowCreatedFunc) (const Window win,
+ const Window parent);
+
+typedef void (*GkbIndicatorPluginTermFunc) (void);
+
+typedef GtkWidget *(*GkbIndicatorPluginCreateWidget) (void);
+
+typedef GtkWidget *(*GkbIndicatorPluginDecorateWidget) (GtkWidget * widget,
+ const gint group,
+ const char
+ *group_description,
+ GkbKeyboardConfig *
+ config);
+
+typedef
+void (*GkbIndicatorPluginConfigureProperties) (GkbIndicatorPluginContainer
+ * pc, GtkWindow * parent);
+
+typedef struct _GkbIndicatorPlugin {
+ const char *name;
+
+ const char *description;
+
+// implemented
+ GkbIndicatorPluginInitFunc init_callback;
+
+// implemented
+ GkbIndicatorPluginTermFunc term_callback;
+
+// implemented
+ GkbIndicatorPluginConfigureProperties
+ configure_properties_callback;
+
+// implemented
+ GkbIndicatorPluginGroupChangedFunc group_changed_callback;
+
+// implemented
+ GkbIndicatorPluginWindowCreatedFunc window_created_callback;
+
+// implemented
+ GkbIndicatorPluginDecorateWidget decorate_widget_callback;
+
+// non implemented
+ GkbIndicatorPluginConfigChangedFunc config_changed_callback;
+
+// non implemented
+ GkbIndicatorPluginCreateWidget create_widget_callback;
+
+} GkbIndicatorPlugin;
+
+/**
+ * Functions accessible for plugins
+ */
+
+extern void gkb_indicator_plugin_container_init (GkbIndicatorPluginContainer *
+ pc,
+ GConfClient * conf_client);
+
+extern void gkb_indicator_plugin_container_term (GkbIndicatorPluginContainer *
+ pc);
+
+extern void
+ gkb_indicator_plugin_container_reinit_ui (GkbIndicatorPluginContainer * pc);
+
+extern guint gkb_indicator_plugin_get_num_groups (GkbIndicatorPluginContainer *
+ pc);
+
+extern gchar
+ **
+gkb_indicator_plugin_load_localized_group_names (GkbIndicatorPluginContainer *
+ pc);
+
+#endif
diff --git a/libgnomekbd/backup/gkb-indicator.c b/libgnomekbd/backup/gkb-indicator.c
new file mode 100644
index 0000000..4363b4b
--- /dev/null
+++ b/libgnomekbd/backup/gkb-indicator.c
@@ -0,0 +1,826 @@
+#include <memory.h>
+
+#include <gdk/gdkkeysyms.h>
+#include <gdk/gdkx.h>
+#include <glib/gi18n.h>
+
+#include <gkb-indicator.h>
+#include <gkb-indicator-marshal.h>
+
+#include <gkb-desktop-config.h>
+#include <gkb-indicator-config.h>
+
+#include <gkb-indicator-plugin-manager.h>
+
+#include <gkb-config-registry-client.h>
+
+typedef struct _gki_globals {
+ XklEngine *engine;
+
+ GkbDesktopConfig cfg;
+ GkbIndicatorConfig ind_cfg;
+ GkbKeyboardConfig kbd_cfg;
+
+ GkbIndicatorPluginContainer plugin_container;
+ GkbIndicatorPluginManager plugin_manager;
+
+ const gchar *tooltips_format;
+ gchar **full_group_names;
+ gchar **short_group_names;
+ GSList *widget_instances;
+} gki_globals;
+
+struct _GkbIndicatorPrivate {
+ gboolean set_parent_tooltips;
+ gdouble angle;
+};
+
+/* one instance for ALL widgets */
+static gki_globals globals;
+
+#define ForAllIndicators() \
+ { \
+ GSList* cur; \
+ for (cur = globals.widget_instances; cur != NULL; cur = cur->next) { \
+ GkbIndicator * gki = (GkbIndicator*)cur->data;
+#define NextIndicator() \
+ } \
+ }
+
+G_DEFINE_TYPE (GkbIndicator, gkb_indicator, GTK_TYPE_NOTEBOOK)
+
+static void
+gkb_indicator_global_init (void);
+static void
+gkb_indicator_global_term (void);
+static GtkWidget *
+gkb_indicator_prepare_drawing (GkbIndicator * gki, int group);
+static void
+gkb_indicator_set_current_page_for_group (GkbIndicator * gki, int group);
+static void
+gkb_indicator_set_current_page (GkbIndicator * gki);
+static void
+gkb_indicator_cleanup (GkbIndicator * gki);
+static void
+gkb_indicator_fill (GkbIndicator * gki);
+static void
+gkb_indicator_set_tooltips (GkbIndicator * gki, const char *str);
+
+void
+gkb_indicator_set_tooltips (GkbIndicator * gki, const char *str)
+{
+ GtkTooltips *tooltips;
+
+ if (str == NULL)
+ return;
+ tooltips = gtk_tooltips_new ();
+ g_object_ref (G_OBJECT (tooltips));
+ gtk_object_sink (GTK_OBJECT (tooltips));
+ g_object_set_data_full (G_OBJECT (gki), "tooltips",
+ tooltips, (GDestroyNotify) g_object_unref);
+ gtk_tooltips_set_tip (tooltips, GTK_WIDGET (gki), str, NULL);
+
+ if (gki->priv->set_parent_tooltips) {
+ GtkWidget *parent =
+ gtk_widget_get_parent (GTK_WIDGET (gki));
+ if (parent != NULL) {
+ gtk_tooltips_set_tip (tooltips,
+ GTK_WIDGET (parent), str,
+ NULL);
+ g_object_ref (G_OBJECT (tooltips));
+ g_object_set_data_full (G_OBJECT (parent),
+ "gnome-kbd-indicator.tooltips",
+ tooltips, (GDestroyNotify)
+ g_object_unref);
+ }
+ }
+ gtk_tooltips_enable (tooltips);
+}
+
+void
+gkb_indicator_cleanup (GkbIndicator * gki)
+{
+ int i;
+ GtkNotebook *notebook = GTK_NOTEBOOK (gki);
+
+ /* Do not remove the first page! It is the default page */
+ for (i = gtk_notebook_get_n_pages (notebook); --i > 0;) {
+ gtk_notebook_remove_page (notebook, i);
+ }
+}
+
+void
+gkb_indicator_fill (GkbIndicator * gki)
+{
+ int grp;
+ int total_groups = xkl_engine_get_num_groups (globals.engine);
+ GtkNotebook *notebook = GTK_NOTEBOOK (gki);
+
+ for (grp = 0; grp < total_groups; grp++) {
+ GtkWidget *page, *decorated_page;
+ page = gkb_indicator_prepare_drawing (gki, grp);
+
+ if (page == NULL)
+ page = gtk_label_new ("");
+
+ decorated_page =
+ gkb_indicator_plugin_manager_decorate_widget (&globals.
+ plugin_manager,
+ page, grp,
+ globals.
+ full_group_names
+ [grp],
+ &globals.
+ kbd_cfg);
+
+ page = decorated_page == NULL ? page : decorated_page;
+
+ gtk_notebook_append_page (notebook, page, NULL);
+ gtk_widget_show_all (page);
+ }
+}
+
+static gboolean
+gkb_indicator_key_pressed (GtkWidget *
+ widget, GdkEventKey * event, GkbIndicator * gki)
+{
+ switch (event->keyval) {
+ case GDK_KP_Enter:
+ case GDK_ISO_Enter:
+ case GDK_3270_Enter:
+ case GDK_Return:
+ case GDK_space:
+ case GDK_KP_Space:
+ gkb_desktop_config_lock_next_group (&globals.cfg);
+ return TRUE;
+ default:
+ break;
+ }
+ return FALSE;
+}
+
+static gboolean
+gkb_indicator_button_pressed (GtkWidget *
+ widget,
+ GdkEventButton * event, GkbIndicator * gki)
+{
+ GtkWidget *img = gtk_bin_get_child (GTK_BIN (widget));
+ xkl_debug (150, "Flag img size %d x %d\n",
+ img->allocation.width, img->allocation.height);
+ if (event->button == 1 && event->type == GDK_BUTTON_PRESS) {
+ xkl_debug (150, "Mouse button pressed on applet\n");
+ gkb_desktop_config_lock_next_group (&globals.cfg);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void
+flag_exposed (GtkWidget * flag, GdkEventExpose * event, GdkPixbuf * image)
+{
+ /* Image width and height */
+ int iw = gdk_pixbuf_get_width (image);
+ int ih = gdk_pixbuf_get_height (image);
+ /* widget-to-image scales, X and Y */
+ double xwiratio = 1.0 * flag->allocation.width / iw;
+ double ywiratio = 1.0 * flag->allocation.height / ih;
+ double wiratio = xwiratio < ywiratio ? xwiratio : ywiratio;
+
+ /* scaled width and height */
+ int sw = iw * wiratio;
+ int sh = ih * wiratio;
+
+ /* offsets */
+ int ox = (flag->allocation.width - sw) >> 1;
+ int oy = (flag->allocation.height - sh) >> 1;
+
+ GdkPixbuf *scaled = gdk_pixbuf_scale_simple (image, sw, sh,
+ GDK_INTERP_HYPER);
+
+ gdk_draw_pixbuf (GDK_DRAWABLE (flag->window),
+ NULL,
+ scaled,
+ 0, 0,
+ ox, oy, sw, sh, GDK_RGB_DITHER_NORMAL, 0, 0);
+ g_object_unref (G_OBJECT (scaled));
+}
+
+static GtkWidget *
+gkb_indicator_prepare_drawing (GkbIndicator * gki, int group)
+{
+ gpointer pimage;
+ GdkPixbuf *image;
+ GtkWidget *ebox;
+
+ pimage = g_slist_nth_data (globals.ind_cfg.images, group);
+ ebox = gtk_event_box_new ();
+ if (globals.ind_cfg.show_flags) {
+ GtkWidget *flag;
+ if (pimage == NULL)
+ return NULL;
+ image = GDK_PIXBUF (pimage);
+ flag = gtk_drawing_area_new ();
+ g_signal_connect (G_OBJECT (flag),
+ "expose_event",
+ G_CALLBACK (flag_exposed), image);
+ gtk_container_add (GTK_CONTAINER (ebox), flag);
+ } else {
+ gpointer pcounter = NULL;
+ char *prev_layout_name = NULL, **ppln;
+ char *lbl_title = NULL;
+ int counter = 0;
+ char *layout_name = NULL;
+ XklConfigItem cfg_item;
+ GtkWidget *align, *label;
+ /**
+ * Map "short desciption" ->
+ * number of layouts in the configuration
+ * having this short description
+ */
+ static GHashTable *short_descrs = NULL;
+
+ if (group == 0)
+ short_descrs =
+ g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, NULL);
+
+ if (xkl_engine_get_features (globals.engine) &
+ XKLF_MULTIPLE_LAYOUTS_SUPPORTED) {
+ char *full_layout_name =
+ (char *) g_slist_nth_data (globals.kbd_cfg.
+ layouts,
+ group);
+ char *variant_name;
+ if (!gkb_keyboard_config_split_items
+ (full_layout_name, &layout_name,
+ &variant_name))
+ /* just in case */
+ layout_name = g_strdup (full_layout_name);
+
+ g_snprintf (cfg_item.name,
+ sizeof (cfg_item.name), "%s",
+ layout_name);
+
+ if (globals.short_group_names != NULL) {
+ char *short_group_name =
+ globals.short_group_names[group];
+ if (short_group_name != NULL
+ && *short_group_name != '\0') {
+ layout_name =
+ g_strdup (short_group_name);
+ }
+ }
+ } else
+ layout_name =
+ g_strdup (globals.full_group_names[group]);
+
+ if (layout_name == NULL)
+ layout_name = g_strdup ("?");
+
+ /* Process layouts with repeating description */
+ ppln = &prev_layout_name;
+ if (g_hash_table_lookup_extended
+ (short_descrs, layout_name,
+ (gpointer *) ppln, &pcounter)) {
+ /* "next" same description */
+ gchar appendix[10] = "";
+ gint utf8length;
+ gunichar cidx;
+ counter = GPOINTER_TO_INT (pcounter);
+ /* Unicode subscript 2, 3, 4 */
+ cidx = 0x2081 + counter;
+ utf8length = g_unichar_to_utf8 (cidx, appendix);
+ appendix[utf8length] = '\0';
+ lbl_title =
+ g_strconcat (layout_name, appendix, NULL);
+ } else {
+ /* "first" time this description */
+ lbl_title = g_strdup (layout_name);
+ }
+ g_hash_table_insert (short_descrs, layout_name,
+ GINT_TO_POINTER (counter + 1));
+
+ align = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+ label = gtk_label_new (lbl_title);
+ g_free (lbl_title);
+ gtk_label_set_angle (GTK_LABEL (label), gki->priv->angle);
+
+ if (group == xkl_engine_get_num_groups (globals.engine)) {
+ g_hash_table_destroy (short_descrs);
+ short_descrs = NULL;
+ }
+
+ gtk_container_add (GTK_CONTAINER (align), label);
+ gtk_container_add (GTK_CONTAINER (ebox), align);
+
+ gtk_container_set_border_width (GTK_CONTAINER (align), 2);
+ }
+ g_signal_connect (G_OBJECT (ebox),
+ "button_press_event",
+ G_CALLBACK (gkb_indicator_button_pressed), gki);
+
+ g_signal_connect (G_OBJECT (gki),
+ "key_press_event",
+ G_CALLBACK (gkb_indicator_key_pressed), gki);
+
+ /* We have everything prepared for that size */
+
+ return ebox;
+}
+
+static void
+gkb_indicator_update_tooltips (GkbIndicator * gki)
+{
+ XklState *state = xkl_engine_get_current_state (globals.engine);
+ gchar *buf;
+ if (state == NULL || state->group < 0)
+ return;
+
+ buf = g_strdup_printf (globals.tooltips_format,
+ globals.full_group_names[state->group]);
+
+ gkb_indicator_set_tooltips (gki, buf);
+ g_free (buf);
+}
+
+static void
+gkb_indicator_parent_set (GtkWidget * gki, GtkWidget * previous_parent)
+{
+ gkb_indicator_update_tooltips (GKB_INDICATOR (gki));
+}
+
+
+void
+gkb_indicator_reinit_ui (GkbIndicator * gki)
+{
+ gkb_indicator_cleanup (gki);
+ gkb_indicator_fill (gki);
+
+ gkb_indicator_set_current_page (gki);
+
+ g_signal_emit_by_name (gki, "reinit-ui");
+}
+
+/* Should be called once for all widgets */
+static void
+gkb_indicator_cfg_changed (GConfClient * client,
+ guint cnxn_id, GConfEntry * entry)
+{
+ xkl_debug (100,
+ "General configuration changed in GConf - reiniting...\n");
+ gkb_desktop_config_load_from_gconf (&globals.cfg);
+ gkb_desktop_config_activate (&globals.cfg);
+ ForAllIndicators () {
+ gkb_indicator_reinit_ui (gki);
+ } NextIndicator ();
+}
+
+/* Should be called once for all widgets */
+static void
+gkb_indicator_ind_cfg_changed (GConfClient * client,
+ guint cnxn_id, GConfEntry * entry)
+{
+ xkl_debug (100,
+ "Applet configuration changed in GConf - reiniting...\n");
+ gkb_indicator_config_load_from_gconf (&globals.ind_cfg);
+ gkb_indicator_config_update_images (&globals.ind_cfg,
+ &globals.kbd_cfg);
+ gkb_indicator_config_activate (&globals.ind_cfg);
+
+ gkb_indicator_plugin_manager_toggle_plugins (&globals.plugin_manager,
+ &globals.plugin_container,
+ globals.ind_cfg.
+ enabled_plugins);
+
+ ForAllIndicators () {
+ gkb_indicator_reinit_ui (gki);
+ } NextIndicator ();
+}
+
+static void
+gkb_indicator_load_group_names (void)
+{
+ if (!gkb_desktop_config_load_remote_group_descriptions_utf8
+ (&globals.cfg, &globals.short_group_names,
+ &globals.full_group_names)) {
+ gint i, total_groups =
+ xkl_engine_get_num_groups (globals.engine);
+ globals.full_group_names =
+ g_new0 (char *, total_groups + 1);
+
+ if (xkl_engine_get_features (globals.engine) &
+ XKLF_MULTIPLE_LAYOUTS_SUPPORTED) {
+ GSList *lst = globals.kbd_cfg.layouts;
+ for (i = 0; lst; lst = lst->next) {
+ globals.full_group_names[i++] =
+ g_strdup ((char *) lst->data);
+ }
+ } else {
+ for (i = total_groups; --i >= 0;) {
+ globals.full_group_names[i] =
+ g_strdup_printf ("Group %d", i);
+ }
+ }
+ }
+}
+
+/* Should be called once for all widgets */
+static void
+gkb_indicator_kbd_cfg_callback (GkbIndicator * gki)
+{
+ xkl_debug (100,
+ "XKB configuration changed on X Server - reiniting...\n");
+
+ gkb_keyboard_config_load_from_x_current (&globals.kbd_cfg);
+ gkb_indicator_config_update_images (&globals.ind_cfg,
+ &globals.kbd_cfg);
+
+ g_strfreev (globals.full_group_names);
+ g_strfreev (globals.short_group_names);
+ gkb_indicator_load_group_names ();
+
+ ForAllIndicators () {
+ gkb_indicator_reinit_ui (gki);
+ } NextIndicator ();
+}
+
+/* Should be called once for all applets */
+static void
+gkb_indicator_state_callback (XklEngine * engine,
+ XklEngineStateChange changeType,
+ gint group, gboolean restore)
+{
+ xkl_debug (150, "group is now %d, restore: %d\n", group, restore);
+
+ if (changeType == GROUP_CHANGED) {
+ ForAllIndicators () {
+ gkb_indicator_plugin_manager_group_changed (&globals.
+ plugin_manager,
+ GTK_WIDGET
+ (gki),
+ group);
+ xkl_debug (200, "do repaint\n");
+ gkb_indicator_set_current_page_for_group
+ (gki, group);
+ }
+ NextIndicator ();
+ }
+}
+
+
+void
+gkb_indicator_set_current_page (GkbIndicator * gki)
+{
+ XklState *cur_state;
+ cur_state = xkl_engine_get_current_state (globals.engine);
+ if (cur_state->group >= 0)
+ gkb_indicator_set_current_page_for_group (gki,
+ cur_state->
+ group);
+}
+
+void
+gkb_indicator_set_current_page_for_group (GkbIndicator * gki, int group)
+{
+ xkl_debug (200, "Revalidating for group %d\n", group);
+
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (gki), group + 1);
+
+ gkb_indicator_update_tooltips (gki);
+}
+
+/* Should be called once for all widgets */
+static GdkFilterReturn
+gkb_indicator_filter_x_evt (GdkXEvent * xev, GdkEvent * event)
+{
+ XEvent *xevent = (XEvent *) xev;
+
+ xkl_engine_filter_events (globals.engine, xevent);
+ switch (xevent->type) {
+ case ReparentNotify:
+ {
+ XReparentEvent *rne = (XReparentEvent *) xev;
+
+ ForAllIndicators () {
+ GdkWindow *w =
+ gtk_widget_get_parent_window
+ (GTK_WIDGET (gki));
+
+ /* compare the indicator's parent window with the even window */
+ if (w != NULL
+ && GDK_WINDOW_XID (w) == rne->window) {
+ /* if so - make it transparent... */
+ xkl_engine_set_window_transparent
+ (globals.engine, rne->window,
+ TRUE);
+ }
+ }
+ NextIndicator ()
+ }
+ break;
+ }
+ return GDK_FILTER_CONTINUE;
+}
+
+
+/* Should be called once for all widgets */
+static void
+gkb_indicator_start_listen (void)
+{
+ gdk_window_add_filter (NULL, (GdkFilterFunc)
+ gkb_indicator_filter_x_evt, NULL);
+ gdk_window_add_filter (gdk_get_default_root_window (),
+ (GdkFilterFunc)
+ gkb_indicator_filter_x_evt, NULL);
+
+ xkl_engine_start_listen (globals.engine,
+ XKLL_TRACK_KEYBOARD_STATE);
+}
+
+/* Should be called once for all widgets */
+static void
+gkb_indicator_stop_listen (void)
+{
+ xkl_engine_stop_listen (globals.engine);
+
+ gdk_window_remove_filter (NULL, (GdkFilterFunc)
+ gkb_indicator_filter_x_evt, NULL);
+ gdk_window_remove_filter
+ (gdk_get_default_root_window (),
+ (GdkFilterFunc) gkb_indicator_filter_x_evt, NULL);
+}
+
+static gboolean
+gkb_indicator_scroll (GtkWidget * gki, GdkEventScroll * event)
+{
+ /* mouse wheel events should be ignored, otherwise funny effects appear */
+ return TRUE;
+}
+
+static void
+gkb_indicator_init (GkbIndicator * gki)
+{
+ GtkWidget *def_drawing;
+ GtkNotebook *notebook;
+
+ if (!g_slist_length (globals.widget_instances))
+ gkb_indicator_global_init ();
+
+ gki->priv = g_new0 (GkbIndicatorPrivate, 1);
+
+ notebook = GTK_NOTEBOOK (gki);
+
+ xkl_debug (100, "Initiating the widget startup process for %p\n",
+ gki);
+
+ gtk_notebook_set_show_tabs (notebook, FALSE);
+ gtk_notebook_set_show_border (notebook, FALSE);
+
+ def_drawing =
+ gtk_image_new_from_stock (GTK_STOCK_STOP,
+ GTK_ICON_SIZE_BUTTON);
+
+ gtk_notebook_append_page (notebook, def_drawing,
+ gtk_label_new (""));
+
+ if (globals.engine == NULL) {
+ gkb_indicator_set_tooltips (gki,
+ _("XKB initialization error"));
+ return;
+ }
+
+ gkb_indicator_set_tooltips (gki, "");
+
+ gkb_indicator_fill (gki);
+ gkb_indicator_set_current_page (gki);
+
+ gtk_widget_add_events (GTK_WIDGET (gki), GDK_BUTTON_PRESS_MASK);
+
+ /* append AFTER all initialization work is finished */
+ globals.widget_instances =
+ g_slist_append (globals.widget_instances, gki);
+}
+
+static void
+gkb_indicator_finalize (GObject * obj)
+{
+ GkbIndicator *gki = GKB_INDICATOR (obj);
+ xkl_debug (100,
+ "Starting the gnome-kbd-indicator widget shutdown process for %p\n",
+ gki);
+
+ /* remove BEFORE all termination work is finished */
+ globals.widget_instances =
+ g_slist_remove (globals.widget_instances, gki);
+
+ gkb_indicator_cleanup (gki);
+
+ xkl_debug (100,
+ "The instance of gnome-kbd-indicator successfully finalized\n");
+
+ g_free (gki->priv);
+
+ G_OBJECT_CLASS (gkb_indicator_parent_class)->finalize (obj);
+
+ if (!g_slist_length (globals.widget_instances))
+ gkb_indicator_global_term ();
+}
+
+static void
+gkb_indicator_global_term (void)
+{
+ xkl_debug (100, "*** Last GkbIndicator instance *** \n");
+ gkb_indicator_stop_listen ();
+
+ gkb_desktop_config_stop_listen (&globals.cfg);
+ gkb_indicator_config_stop_listen (&globals.ind_cfg);
+
+ gkb_indicator_plugin_manager_term_initialized_plugins (&globals.
+ plugin_manager);
+ gkb_indicator_plugin_manager_term (&globals.plugin_manager);
+
+ gkb_indicator_config_term (&globals.ind_cfg);
+ gkb_keyboard_config_term (&globals.kbd_cfg);
+ gkb_desktop_config_term (&globals.cfg);
+
+ gkb_indicator_plugin_container_term (&globals.plugin_container);
+
+ g_object_unref (G_OBJECT (globals.engine));
+ globals.engine = NULL;
+ xkl_debug (100, "*** Terminated globals *** \n");
+}
+
+static void
+gkb_indicator_class_init (GkbIndicatorClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ xkl_debug (100, "*** First GkbIndicator instance *** \n");
+
+ memset (&globals, 0, sizeof (globals));
+
+ /* Initing some global vars */
+ globals.tooltips_format = "%s";
+
+ /* Initing vtable */
+ object_class->finalize = gkb_indicator_finalize;
+
+ widget_class->scroll_event = gkb_indicator_scroll;
+ widget_class->parent_set = gkb_indicator_parent_set;
+
+ /* Signals */
+ g_signal_new ("reinit-ui", GKB_TYPE_INDICATOR,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GkbIndicatorClass, reinit_ui),
+ NULL, NULL, gkb_indicator_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+static void
+gkb_indicator_global_init (void)
+{
+ GConfClient *gconf_client;
+
+ globals.engine = xkl_engine_get_instance (GDK_DISPLAY ());
+ if (globals.engine == NULL) {
+ xkl_debug (0, "Libxklavier initialization error");
+ return;
+ }
+
+ gconf_client = gconf_client_get_default ();
+
+ g_signal_connect (globals.engine, "X-state-changed",
+ G_CALLBACK (gkb_indicator_state_callback), NULL);
+ g_signal_connect (globals.engine, "X-config-changed",
+ G_CALLBACK
+ (gkb_indicator_kbd_cfg_callback), NULL);
+
+ gkb_indicator_plugin_container_init (&globals.plugin_container,
+ gconf_client);
+
+ gkb_desktop_config_init (&globals.cfg, gconf_client,
+ globals.engine);
+ gkb_keyboard_config_init (&globals.kbd_cfg, gconf_client,
+ globals.engine);
+ gkb_indicator_config_init (&globals.ind_cfg, gconf_client,
+ globals.engine);
+
+ g_object_unref (gconf_client);
+
+ gkb_desktop_config_load_from_gconf (&globals.cfg);
+ gkb_desktop_config_activate (&globals.cfg);
+ gkb_keyboard_config_load_from_x_current (&globals.kbd_cfg);
+ gkb_indicator_config_load_from_gconf (&globals.ind_cfg);
+ gkb_indicator_config_update_images (&globals.ind_cfg,
+ &globals.kbd_cfg);
+ gkb_indicator_config_activate (&globals.ind_cfg);
+
+ gkb_indicator_load_group_names ();
+
+ gkb_indicator_plugin_manager_init (&globals.plugin_manager);
+ gkb_indicator_plugin_manager_init_enabled_plugins (&globals.
+ plugin_manager,
+ &globals.
+ plugin_container,
+ globals.
+ ind_cfg.
+ enabled_plugins);
+ gkb_desktop_config_start_listen (&globals.cfg,
+ (GConfClientNotifyFunc)
+ gkb_indicator_cfg_changed, NULL);
+ gkb_indicator_config_start_listen (&globals.ind_cfg,
+ (GConfClientNotifyFunc)
+ gkb_indicator_ind_cfg_changed,
+ NULL);
+ gkb_indicator_start_listen ();
+
+ xkl_debug (100, "*** Inited globals *** \n");
+}
+
+GtkWidget *
+gkb_indicator_new (void)
+{
+ return GTK_WIDGET (g_object_new (gkb_indicator_get_type (), NULL));
+}
+
+void
+gkb_indicator_set_parent_tooltips (GkbIndicator * gki, gboolean spt)
+{
+ gki->priv->set_parent_tooltips = spt;
+ gkb_indicator_update_tooltips (gki);
+}
+
+void
+gkb_indicator_set_tooltips_format (const gchar format[])
+{
+ globals.tooltips_format = format;
+ ForAllIndicators ()
+ gkb_indicator_update_tooltips (gki);
+ NextIndicator ()
+}
+
+XklEngine *
+gkb_indicator_get_xkl_engine ()
+{
+ return globals.engine;
+}
+
+gchar **
+gkb_indicator_get_group_names ()
+{
+ return globals.full_group_names;
+}
+
+gchar *
+gkb_indicator_get_image_filename (guint group)
+{
+ if (!globals.ind_cfg.show_flags)
+ return NULL;
+ return gkb_indicator_config_get_images_file (&globals.
+ ind_cfg,
+ &globals.
+ kbd_cfg, group);
+}
+
+gdouble
+gkb_indicator_get_max_width_height_ratio (void)
+{
+ gdouble rv = 0.0;
+ GSList *ip = globals.ind_cfg.images;
+ if (!globals.ind_cfg.show_flags)
+ return 0;
+ while (ip != NULL) {
+ GdkPixbuf *img = GDK_PIXBUF (ip->data);
+ gdouble r =
+ 1.0 * gdk_pixbuf_get_width (img) /
+ gdk_pixbuf_get_height (img);
+ if (r > rv)
+ rv = r;
+ ip = ip->next;
+ }
+ return rv;
+}
+
+void
+gkb_indicator_set_angle (GkbIndicator * gki, gdouble angle)
+{
+ gki->priv->angle = angle;
+}
+
+/* Plugin support */
+/* Preserve the plugin container functions during the linking */
+void
+gkb_indicator_plugin_container_reinit_ui (GkbIndicatorPluginContainer * pc)
+{
+ ForAllIndicators () {
+ gkb_indicator_reinit_ui (gki);
+ } NextIndicator ();
+}
+
+gchar **
+gkb_indicator_plugin_load_localized_group_names (GkbIndicatorPluginContainer *
+ pc)
+{
+ return globals.full_group_names;
+}
diff --git a/libgnomekbd/backup/gkb-indicator.h b/libgnomekbd/backup/gkb-indicator.h
new file mode 100644
index 0000000..07f6bfc
--- /dev/null
+++ b/libgnomekbd/backup/gkb-indicator.h
@@ -0,0 +1,77 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GKB_INDICATOR_H__
+#define __GKB_INDICATOR_H__
+
+#include <gtk/gtk.h>
+
+#include <libxklavier/xklavier.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ typedef struct _GkbIndicator GkbIndicator;
+ typedef struct _GkbIndicatorPrivate GkbIndicatorPrivate;
+ typedef struct _GkbIndicatorClass GkbIndicatorClass;
+
+#define GKB_TYPE_INDICATOR (gkb_indicator_get_type ())
+#define GKB_INDICATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GKB_TYPE_INDICATOR, GkbIndicator))
+#define GKB_INDCATOR_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), GKB_TYPE_INDICATOR, GkbIndicatorClass))
+#define GKB_IS_INDICATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GKB_TYPE_INDICATOR))
+#define GKB_IS_INDICATOR_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), GKB_TYPE_INDICATOR))
+#define GKB_INDICATOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GKB_TYPE_INDICATOR, GkbIndicatorClass))
+
+ struct _GkbIndicator {
+ GtkNotebook parent;
+ GkbIndicatorPrivate *priv;
+ };
+
+ struct _GkbIndicatorClass {
+ GtkNotebookClass parent_class;
+
+ void (*reinit_ui) (GkbIndicator * gki);
+ };
+
+ extern GType gkb_indicator_get_type (void);
+
+ extern GtkWidget *gkb_indicator_new (void);
+
+ extern void gkb_indicator_reinit_ui (GkbIndicator * gki);
+
+ extern void gkb_indicator_set_angle (GkbIndicator * gki,
+ gdouble angle);
+
+ extern XklEngine *gkb_indicator_get_xkl_engine (void);
+
+ extern gchar **gkb_indicator_get_group_names (void);
+
+ extern gchar *gkb_indicator_get_image_filename (guint group);
+
+ extern gdouble gkb_indicator_get_max_width_height_ratio (void);
+
+ extern void
+ gkb_indicator_set_parent_tooltips (GkbIndicator *
+ gki, gboolean ifset);
+
+ extern void
+ gkb_indicator_set_tooltips_format (const gchar str[]);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/libgnomekbd/backup/gkb-keyboard-config.c b/libgnomekbd/backup/gkb-keyboard-config.c
new file mode 100644
index 0000000..8a1ea3e
--- /dev/null
+++ b/libgnomekbd/backup/gkb-keyboard-config.c
@@ -0,0 +1,822 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <X11/keysym.h>
+
+#include <glib/gi18n.h>
+#include <gdk/gdkx.h>
+#include <libgnome/gnome-program.h>
+
+#include <gkb-keyboard-config.h>
+#include <gkb-config-private.h>
+
+#include <gkb-config-registry-client.h>
+
+/**
+ * GkbKeyboardConfig
+ */
+#define GKB_KEYBOARD_CONFIG_KEY_PREFIX GKB_CONFIG_KEY_PREFIX "/kbd"
+
+const gchar GKB_KEYBOARD_CONFIG_DIR[] = GKB_KEYBOARD_CONFIG_KEY_PREFIX;
+const gchar GKB_KEYBOARD_CONFIG_KEY_MODEL[] =
+ GKB_KEYBOARD_CONFIG_KEY_PREFIX "/model";
+const gchar GKB_KEYBOARD_CONFIG_KEY_LAYOUTS[] =
+ GKB_KEYBOARD_CONFIG_KEY_PREFIX "/layouts";
+const gchar GKB_KEYBOARD_CONFIG_KEY_OPTIONS[] =
+ GKB_KEYBOARD_CONFIG_KEY_PREFIX "/options";
+
+const gchar *GKB_KEYBOARD_CONFIG_ACTIVE[] = {
+ GKB_KEYBOARD_CONFIG_KEY_MODEL,
+ GKB_KEYBOARD_CONFIG_KEY_LAYOUTS,
+ GKB_KEYBOARD_CONFIG_KEY_OPTIONS
+};
+
+#define GKB_KEYBOARD_CONFIG_SYSBACKUP_KEY_PREFIX GKB_CONFIG_KEY_PREFIX "/kbd.sysbackup"
+
+const gchar GKB_KEYBOARD_CONFIG_SYSBACKUP_DIR[] =
+ GKB_KEYBOARD_CONFIG_SYSBACKUP_KEY_PREFIX;
+const gchar GKB_KEYBOARD_CONFIG_SYSBACKUP_KEY_MODEL[] =
+ GKB_KEYBOARD_CONFIG_SYSBACKUP_KEY_PREFIX "/model";
+const gchar GKB_KEYBOARD_CONFIG_SYSBACKUP_KEY_LAYOUTS[] =
+ GKB_KEYBOARD_CONFIG_SYSBACKUP_KEY_PREFIX "/layouts";
+const gchar GKB_KEYBOARD_CONFIG_SYSBACKUP_KEY_OPTIONS[] =
+ GKB_KEYBOARD_CONFIG_SYSBACKUP_KEY_PREFIX "/options";
+
+const gchar *GKB_KEYBOARD_CONFIG_SYSBACKUP[] = {
+ GKB_KEYBOARD_CONFIG_SYSBACKUP_KEY_MODEL,
+ GKB_KEYBOARD_CONFIG_SYSBACKUP_KEY_LAYOUTS,
+ GKB_KEYBOARD_CONFIG_SYSBACKUP_KEY_OPTIONS
+};
+
+/**
+ * static common functions
+ */
+static void
+gkb_keyboard_config_string_list_reset (GSList ** plist)
+{
+ while (*plist != NULL) {
+ GSList *p = *plist;
+ *plist = (*plist)->next;
+ g_free (p->data);
+ g_slist_free_1 (p);
+ }
+}
+
+static gboolean
+gslist_str_equal (GSList * l1, GSList * l2)
+{
+ if (l1 == l2)
+ return TRUE;
+ while (l1 != NULL && l2 != NULL) {
+ if ((l1->data != l2->data) &&
+ (l1->data != NULL) &&
+ (l2->data != NULL) &&
+ g_ascii_strcasecmp (l1->data, l2->data))
+ return False;
+
+ l1 = l1->next;
+ l2 = l2->next;
+ }
+ return (l1 == NULL && l2 == NULL);
+}
+
+gboolean
+gkb_keyboard_config_get_lv_descriptions (XklConfigRegistry *
+ config_registry,
+ const gchar * layout_name,
+ const gchar * variant_name,
+ gchar ** layout_short_descr,
+ gchar ** layout_descr,
+ gchar ** variant_short_descr,
+ gchar ** variant_descr)
+{
+ static XklConfigItem litem;
+ static XklConfigItem vitem;
+
+ layout_name = g_strdup (layout_name);
+
+ g_snprintf (litem.name, sizeof litem.name, "%s", layout_name);
+ if (xkl_config_registry_find_layout (config_registry, &litem)) {
+ *layout_short_descr = litem.short_description;
+ *layout_descr = litem.description;
+ } else
+ *layout_short_descr = *layout_descr = NULL;
+
+ if (variant_name != NULL) {
+ variant_name = g_strdup (variant_name);
+ g_snprintf (vitem.name, sizeof vitem.name, "%s",
+ variant_name);
+ if (xkl_config_registry_find_variant
+ (config_registry, layout_name, &vitem)) {
+ *variant_short_descr = vitem.short_description;
+ *variant_descr = vitem.description;
+ } else
+ *variant_short_descr = *variant_descr = NULL;
+
+ g_free ((char *) variant_name);
+ } else
+ *variant_descr = NULL;
+
+ g_free ((char *) layout_name);
+ return *layout_descr != NULL;
+}
+
+/**
+ * extern common functions
+ */
+const gchar *
+gkb_keyboard_config_merge_items (const gchar * parent, const gchar * child)
+{
+ static gchar buffer[XKL_MAX_CI_NAME_LENGTH * 2 - 1];
+ *buffer = '\0';
+ if (parent != NULL) {
+ if (strlen (parent) >= XKL_MAX_CI_NAME_LENGTH)
+ return NULL;
+ strcat (buffer, parent);
+ }
+ if (child != NULL) {
+ if (strlen (child) >= XKL_MAX_CI_NAME_LENGTH)
+ return NULL;
+ strcat (buffer, "\t");
+ strcat (buffer, child);
+ }
+ return buffer;
+}
+
+gboolean
+gkb_keyboard_config_split_items (const gchar * merged, gchar ** parent,
+ gchar ** child)
+{
+ static gchar pbuffer[XKL_MAX_CI_NAME_LENGTH];
+ static gchar cbuffer[XKL_MAX_CI_NAME_LENGTH];
+ int plen, clen;
+ const gchar *pos;
+ *parent = *child = NULL;
+
+ if (merged == NULL)
+ return FALSE;
+
+ pos = strchr (merged, '\t');
+ if (pos == NULL) {
+ plen = strlen (merged);
+ clen = 0;
+ } else {
+ plen = pos - merged;
+ clen = strlen (pos + 1);
+ if (clen >= XKL_MAX_CI_NAME_LENGTH)
+ return FALSE;
+ strcpy (*child = cbuffer, pos + 1);
+ }
+ if (plen >= XKL_MAX_CI_NAME_LENGTH)
+ return FALSE;
+ memcpy (*parent = pbuffer, merged, plen);
+ pbuffer[plen] = '\0';
+ return TRUE;
+}
+
+/**
+ * static GkbKeyboardConfig functions
+ */
+static void
+gkb_keyboard_config_options_add_full (GkbKeyboardConfig * kbd_config,
+ const gchar * full_option_name)
+{
+ kbd_config->options =
+ g_slist_append (kbd_config->options,
+ g_strdup (full_option_name));
+}
+
+static void
+gkb_keyboard_config_layouts_add_full (GkbKeyboardConfig * kbd_config,
+ const gchar * full_layout_name)
+{
+ kbd_config->layouts =
+ g_slist_append (kbd_config->layouts,
+ g_strdup (full_layout_name));
+}
+
+static void
+gkb_keyboard_config_copy_from_xkl_config (GkbKeyboardConfig * kbd_config,
+ XklConfigRec * pdata)
+{
+ char **p, **p1;
+ gkb_keyboard_config_model_set (kbd_config, pdata->model);
+ xkl_debug (150, "Loaded Kbd model: [%s]\n", pdata->model);
+
+ gkb_keyboard_config_layouts_reset (kbd_config);
+ p = pdata->layouts;
+ p1 = pdata->variants;
+ while (p != NULL && *p != NULL) {
+ if (*p1 == NULL || **p1 == '\0') {
+ xkl_debug (150, "Loaded Kbd layout: [%s]\n", *p);
+ gkb_keyboard_config_layouts_add_full (kbd_config,
+ *p);
+ } else {
+ char full_layout[XKL_MAX_CI_NAME_LENGTH * 2];
+ g_snprintf (full_layout, sizeof (full_layout),
+ "%s\t%s", *p, *p1);
+ xkl_debug (150,
+ "Loaded Kbd layout with variant: [%s]\n",
+ full_layout);
+ gkb_keyboard_config_layouts_add_full (kbd_config,
+ full_layout);
+ }
+ p++;
+ p1++;
+ }
+
+ gkb_keyboard_config_options_reset (kbd_config);
+ p = pdata->options;
+ while (p != NULL && *p != NULL) {
+ char group[XKL_MAX_CI_NAME_LENGTH];
+ char *option = *p;
+ char *delim =
+ (option != NULL) ? strchr (option, ':') : NULL;
+ int len;
+ if ((delim != NULL) &&
+ ((len = (delim - option)) < XKL_MAX_CI_NAME_LENGTH)) {
+ strncpy (group, option, len);
+ group[len] = 0;
+ xkl_debug (150, "Loaded Kbd option: [%s][%s]\n",
+ group, option);
+ gkb_keyboard_config_options_add (kbd_config,
+ group, option);
+ }
+ p++;
+ }
+}
+
+static void
+gkb_keyboard_config_copy_to_xkl_config (GkbKeyboardConfig * kbd_config,
+ XklConfigRec * pdata)
+{
+ int i;
+ int num_layouts, num_options;
+ pdata->model =
+ (kbd_config->model ==
+ NULL) ? NULL : g_strdup (kbd_config->model);
+
+ num_layouts =
+ (kbd_config->layouts ==
+ NULL) ? 0 : g_slist_length (kbd_config->layouts);
+ num_options =
+ (kbd_config->options ==
+ NULL) ? 0 : g_slist_length (kbd_config->options);
+
+ xkl_debug (150, "Taking %d layouts\n", num_layouts);
+ if (num_layouts != 0) {
+ GSList *the_layout = kbd_config->layouts;
+ char **p1 = pdata->layouts =
+ g_new0 (char *, num_layouts + 1);
+ char **p2 = pdata->variants =
+ g_new0 (char *, num_layouts + 1);
+ for (i = num_layouts; --i >= 0;) {
+ char *layout, *variant;
+ if (gkb_keyboard_config_split_items
+ (the_layout->data, &layout, &variant)
+ && variant != NULL) {
+ *p1 =
+ (layout ==
+ NULL) ? g_strdup ("") :
+ g_strdup (layout);
+ *p2 =
+ (variant ==
+ NULL) ? g_strdup ("") :
+ g_strdup (variant);
+ } else {
+ *p1 =
+ (the_layout->data ==
+ NULL) ? g_strdup ("") :
+ g_strdup (the_layout->data);
+ *p2 = g_strdup ("");
+ }
+ xkl_debug (150, "Adding [%s]/%p and [%s]/%p\n",
+ *p1 ? *p1 : "(nil)", *p1,
+ *p2 ? *p2 : "(nil)", *p2);
+ p1++;
+ p2++;
+ the_layout = the_layout->next;
+ }
+ }
+
+ if (num_options != 0) {
+ GSList *the_option = kbd_config->options;
+ char **p = pdata->options =
+ g_new0 (char *, num_options + 1);
+ for (i = num_options; --i >= 0;) {
+ char *group, *option;
+ if (gkb_keyboard_config_split_items
+ (the_option->data, &group, &option)
+ && option != NULL)
+ *(p++) = g_strdup (option);
+ else {
+ *(p++) = g_strdup ("");
+ xkl_debug (150, "Could not split [%s]\n",
+ the_option->data);
+ }
+ the_option = the_option->next;
+ }
+ }
+}
+
+static void
+gkb_keyboard_config_load_params (GkbKeyboardConfig * kbd_config,
+ const gchar * param_names[])
+{
+ GError *gerror = NULL;
+ gchar *pc;
+ GSList *pl;
+
+ pc = gconf_client_get_string (kbd_config->conf_client,
+ param_names[0], &gerror);
+ if (pc == NULL || gerror != NULL) {
+ if (gerror != NULL) {
+ g_warning ("Error reading configuration:%s\n",
+ gerror->message);
+ g_error_free (gerror);
+ g_free (pc);
+ gerror = NULL;
+ }
+ gkb_keyboard_config_model_set (kbd_config, NULL);
+ } else {
+ gkb_keyboard_config_model_set (kbd_config, pc);
+ g_free (pc);
+ }
+ xkl_debug (150, "Loaded Kbd model: [%s]\n",
+ kbd_config->model ? kbd_config->model : "(null)");
+
+ gkb_keyboard_config_layouts_reset (kbd_config);
+
+ pl = gconf_client_get_list (kbd_config->conf_client,
+ param_names[1],
+ GCONF_VALUE_STRING, &gerror);
+ if (pl == NULL || gerror != NULL) {
+ if (gerror != NULL) {
+ g_warning ("Error reading configuration:%s\n",
+ gerror->message);
+ g_error_free (gerror);
+ gerror = NULL;
+ }
+ }
+
+ while (pl != NULL) {
+ xkl_debug (150, "Loaded Kbd layout: [%s]\n", pl->data);
+ gkb_keyboard_config_layouts_add_full (kbd_config,
+ pl->data);
+ pl = pl->next;
+ }
+ gkb_keyboard_config_string_list_reset (&pl);
+
+ gkb_keyboard_config_options_reset (kbd_config);
+
+ pl = gconf_client_get_list (kbd_config->conf_client,
+ param_names[2],
+ GCONF_VALUE_STRING, &gerror);
+ if (pl == NULL || gerror != NULL) {
+ if (gerror != NULL) {
+ g_warning ("Error reading configuration:%s\n",
+ gerror->message);
+ g_error_free (gerror);
+ gerror = NULL;
+ }
+ }
+
+ while (pl != NULL) {
+ xkl_debug (150, "Loaded Kbd option: [%s]\n", pl->data);
+ gkb_keyboard_config_options_add_full (kbd_config,
+ (const gchar *) pl->
+ data);
+ pl = pl->next;
+ }
+ gkb_keyboard_config_string_list_reset (&pl);
+}
+
+static void
+gkb_keyboard_config_save_params (GkbKeyboardConfig * kbd_config,
+ GConfChangeSet * cs,
+ const gchar * param_names[])
+{
+ GSList *pl;
+
+ if (kbd_config->model)
+ gconf_change_set_set_string (cs, param_names[0],
+ kbd_config->model);
+ else
+ gconf_change_set_unset (cs, param_names[0]);
+ xkl_debug (150, "Saved Kbd model: [%s]\n",
+ kbd_config->model ? kbd_config->model : "(null)");
+
+ if (kbd_config->layouts) {
+ pl = kbd_config->layouts;
+ while (pl != NULL) {
+ xkl_debug (150, "Saved Kbd layout: [%s]\n",
+ pl->data);
+ pl = pl->next;
+ }
+ gconf_change_set_set_list (cs,
+ param_names[1],
+ GCONF_VALUE_STRING,
+ kbd_config->layouts);
+ } else {
+ xkl_debug (150, "Saved Kbd layouts: []\n");
+ gconf_change_set_unset (cs, param_names[1]);
+ }
+
+ if (kbd_config->options) {
+ pl = kbd_config->options;
+ while (pl != NULL) {
+ xkl_debug (150, "Saved Kbd option: [%s]\n",
+ pl->data);
+ pl = pl->next;
+ }
+ gconf_change_set_set_list (cs,
+ param_names[2],
+ GCONF_VALUE_STRING,
+ kbd_config->options);
+ } else {
+ xkl_debug (150, "Saved Kbd options: []\n");
+ gconf_change_set_unset (cs, param_names[2]);
+ }
+}
+
+/**
+ * extern GkbKeyboardConfig config functions
+ */
+void
+gkb_keyboard_config_init (GkbKeyboardConfig * kbd_config,
+ GConfClient * conf_client, XklEngine * engine)
+{
+ GError *gerror = NULL;
+
+ memset (kbd_config, 0, sizeof (*kbd_config));
+ kbd_config->conf_client = conf_client;
+ kbd_config->engine = engine;
+ g_object_ref (kbd_config->conf_client);
+
+ gconf_client_add_dir (kbd_config->conf_client,
+ GKB_KEYBOARD_CONFIG_DIR,
+ GCONF_CLIENT_PRELOAD_NONE, &gerror);
+ if (gerror != NULL) {
+ g_warning ("err: %s\n", gerror->message);
+ g_error_free (gerror);
+ gerror = NULL;
+ }
+}
+
+void
+gkb_keyboard_config_term (GkbKeyboardConfig * kbd_config)
+{
+ gkb_keyboard_config_model_set (kbd_config, NULL);
+
+ gkb_keyboard_config_layouts_reset (kbd_config);
+
+ g_object_unref (kbd_config->conf_client);
+ kbd_config->conf_client = NULL;
+}
+
+void
+gkb_keyboard_config_load_from_gconf (GkbKeyboardConfig * kbd_config,
+ GkbKeyboardConfig *
+ kbd_config_default)
+{
+ gkb_keyboard_config_load_params (kbd_config,
+ GKB_KEYBOARD_CONFIG_ACTIVE);
+
+ if (kbd_config_default != NULL) {
+ GSList *pl;
+
+ if (kbd_config->model == NULL)
+ kbd_config->model =
+ g_strdup (kbd_config_default->model);
+
+ if (kbd_config->layouts == NULL) {
+ pl = kbd_config_default->layouts;
+ while (pl != NULL) {
+ kbd_config->layouts =
+ g_slist_append (kbd_config->layouts,
+ g_strdup (pl->data));
+ pl = pl->next;
+ }
+ }
+
+ if (kbd_config->options == NULL) {
+ pl = kbd_config_default->options;
+ while (pl != NULL) {
+ kbd_config->options =
+ g_slist_append (kbd_config->options,
+ g_strdup (pl->data));
+ pl = pl->next;
+ }
+ }
+ }
+}
+
+void
+gkb_keyboard_config_load_from_gconf_backup (GkbKeyboardConfig * kbd_config)
+{
+ gkb_keyboard_config_load_params (kbd_config,
+ GKB_KEYBOARD_CONFIG_SYSBACKUP);
+}
+
+void
+gkb_keyboard_config_load_from_x_current (GkbKeyboardConfig * kbd_config)
+{
+ XklConfigRec *data = xkl_config_rec_new ();
+ if (xkl_config_rec_get_from_server (data, kbd_config->engine))
+ gkb_keyboard_config_copy_from_xkl_config (kbd_config,
+ data);
+ else
+ xkl_debug (150,
+ "Could not load keyboard config from server: [%s]\n",
+ xkl_get_last_error ());
+ g_object_unref (G_OBJECT (data));
+}
+
+void
+gkb_keyboard_config_load_from_x_initial (GkbKeyboardConfig * kbd_config)
+{
+ XklConfigRec *data = xkl_config_rec_new ();
+ if (xkl_config_rec_get_from_backup (data, kbd_config->engine))
+ gkb_keyboard_config_copy_from_xkl_config (kbd_config,
+ data);
+ else
+ xkl_debug (150,
+ "Could not load keyboard config from backup: [%s]\n",
+ xkl_get_last_error ());
+ g_object_unref (G_OBJECT (data));
+}
+
+gboolean
+gkb_keyboard_config_equals (GkbKeyboardConfig * kbd_config1,
+ GkbKeyboardConfig * kbd_config2)
+{
+ if (kbd_config1 == kbd_config2)
+ return True;
+ if ((kbd_config1->model != kbd_config2->model) &&
+ (kbd_config1->model != NULL) &&
+ (kbd_config2->model != NULL) &&
+ g_ascii_strcasecmp (kbd_config1->model, kbd_config2->model))
+ return False;
+ return gslist_str_equal (kbd_config1->layouts,
+ kbd_config2->layouts)
+ && gslist_str_equal (kbd_config1->options,
+ kbd_config2->options);
+}
+
+void
+gkb_keyboard_config_save_to_gconf (GkbKeyboardConfig * kbd_config)
+{
+ GConfChangeSet *cs;
+ GError *gerror = NULL;
+
+ cs = gconf_change_set_new ();
+
+ gkb_keyboard_config_save_params (kbd_config, cs,
+ GKB_KEYBOARD_CONFIG_ACTIVE);
+
+ gconf_client_commit_change_set (kbd_config->conf_client, cs, TRUE,
+ &gerror);
+ if (gerror != NULL) {
+ g_warning ("Error saving active configuration: %s\n",
+ gerror->message);
+ g_error_free (gerror);
+ gerror = NULL;
+ }
+ gconf_change_set_unref (cs);
+}
+
+void
+gkb_keyboard_config_save_to_gconf_backup (GkbKeyboardConfig * kbd_config)
+{
+ GConfChangeSet *cs;
+ GError *gerror = NULL;
+
+ cs = gconf_change_set_new ();
+
+ gkb_keyboard_config_save_params (kbd_config, cs,
+ GKB_KEYBOARD_CONFIG_SYSBACKUP);
+
+ gconf_client_commit_change_set (kbd_config->conf_client, cs, TRUE,
+ &gerror);
+ if (gerror != NULL) {
+ g_warning ("Error saving backup configuration: %s\n",
+ gerror->message);
+ g_error_free (gerror);
+ gerror = NULL;
+ }
+ gconf_change_set_unref (cs);
+}
+
+void
+gkb_keyboard_config_model_set (GkbKeyboardConfig * kbd_config,
+ const gchar * model_name)
+{
+ if (kbd_config->model != NULL)
+ g_free (kbd_config->model);
+ kbd_config->model =
+ (model_name == NULL
+ || model_name[0] == '\0') ? NULL : g_strdup (model_name);
+}
+
+void
+gkb_keyboard_config_layouts_add (GkbKeyboardConfig * kbd_config,
+ const gchar * layout_name,
+ const gchar * variant_name)
+{
+ const gchar *merged;
+ if (layout_name == NULL)
+ return;
+ merged =
+ gkb_keyboard_config_merge_items (layout_name, variant_name);
+ if (merged == NULL)
+ return;
+ gkb_keyboard_config_layouts_add_full (kbd_config, merged);
+}
+
+void
+gkb_keyboard_config_layouts_reset (GkbKeyboardConfig * kbd_config)
+{
+ gkb_keyboard_config_string_list_reset (&kbd_config->layouts);
+}
+
+void
+gkb_keyboard_config_options_reset (GkbKeyboardConfig * kbd_config)
+{
+ gkb_keyboard_config_string_list_reset (&kbd_config->options);
+}
+
+void
+gkb_keyboard_config_options_add (GkbKeyboardConfig * kbd_config,
+ const gchar * group_name,
+ const gchar * option_name)
+{
+ const gchar *merged;
+ if (group_name == NULL || option_name == NULL)
+ return;
+ merged = gkb_keyboard_config_merge_items (group_name, option_name);
+ if (merged == NULL)
+ return;
+ gkb_keyboard_config_options_add_full (kbd_config, merged);
+}
+
+gboolean
+gkb_keyboard_config_options_is_set (GkbKeyboardConfig * kbd_config,
+ const gchar * group_name,
+ const gchar * option_name)
+{
+ const gchar *merged =
+ gkb_keyboard_config_merge_items (group_name, option_name);
+ if (merged == NULL)
+ return FALSE;
+
+ return NULL != g_slist_find_custom (kbd_config->options, (gpointer)
+ merged, (GCompareFunc)
+ g_ascii_strcasecmp);
+}
+
+gboolean
+gkb_keyboard_config_activate (GkbKeyboardConfig * kbd_config)
+{
+ gboolean rv;
+ XklConfigRec *data = xkl_config_rec_new ();
+
+ gkb_keyboard_config_copy_to_xkl_config (kbd_config, data);
+ rv = xkl_config_rec_activate (data, kbd_config->engine);
+ g_object_unref (G_OBJECT (data));
+
+ return rv;
+}
+
+void
+gkb_keyboard_config_start_listen (GkbKeyboardConfig * kbd_config,
+ GConfClientNotifyFunc func,
+ gpointer user_data)
+{
+ gkb_desktop_config_add_listener (kbd_config->conf_client,
+ GKB_KEYBOARD_CONFIG_DIR, func,
+ user_data,
+ &kbd_config->config_listener_id);
+}
+
+void
+gkb_keyboard_config_stop_listen (GkbKeyboardConfig * kbd_config)
+{
+ gkb_desktop_config_remove_listener (kbd_config->conf_client,
+ &kbd_config->
+ config_listener_id);
+}
+
+gboolean
+gkb_keyboard_config_get_descriptions (XklConfigRegistry * config_registry,
+ const gchar * name,
+ gchar ** layout_short_descr,
+ gchar ** layout_descr,
+ gchar ** variant_short_descr,
+ gchar ** variant_descr)
+{
+ char *layout_name = NULL, *variant_name = NULL;
+ if (!gkb_keyboard_config_split_items
+ (name, &layout_name, &variant_name))
+ return FALSE;
+ return gkb_keyboard_config_get_lv_descriptions (config_registry,
+ layout_name,
+ variant_name,
+ layout_short_descr,
+ layout_descr,
+ variant_short_descr,
+ variant_descr);
+}
+
+const gchar *
+gkb_keyboard_config_format_full_layout (const gchar * layout_descr,
+ const gchar * variant_descr)
+{
+ static gchar full_descr[XKL_MAX_CI_DESC_LENGTH * 2];
+ if (variant_descr == NULL)
+ g_snprintf (full_descr, sizeof (full_descr), "%s",
+ layout_descr);
+ else
+ g_snprintf (full_descr, sizeof (full_descr), "%s %s",
+ layout_descr, variant_descr);
+ return full_descr;
+}
+
+gchar *
+gkb_keyboard_config_to_string (const GkbKeyboardConfig * config)
+{
+ gchar *layouts = NULL, *options = NULL;
+ GString *buffer = g_string_new (NULL);
+
+ GSList *iter;
+ gint count;
+ gchar *result;
+
+ if (config->layouts) {
+ /* g_slist_length is "expensive", so we determinate the length on the fly */
+ for (iter = config->layouts, count = 0; iter;
+ iter = iter->next, ++count) {
+ if (buffer->len)
+ g_string_append (buffer, " ");
+
+ g_string_append (buffer,
+ (const gchar *) iter->data);
+ }
+
+ /* TRANS: The count is related to the number of options. The %s format specifier should not be modified,
+ * left "as is". */
+ layouts =
+ g_strdup_printf (ngettext
+ ("layout \"%s\"", "layouts \"%s\"",
+ count), buffer->str);
+ g_string_truncate (buffer, 0);
+ }
+ if (config->options) {
+ /* g_slist_length is "expensive", so we determinate the length on the fly */
+ for (iter = config->options, count = 0; iter;
+ iter = iter->next, ++count) {
+ if (buffer->len)
+ g_string_append (buffer, " ");
+
+ g_string_append (buffer,
+ (const gchar *) iter->data);
+ }
+
+ /* TRANS: The count is related to the number of options. The %s format specifier should not be modified,
+ * left "as is". */
+ options =
+ g_strdup_printf (ngettext
+ ("option \"%s\"", "options \"%s\"",
+ count), buffer->str);
+ g_string_truncate (buffer, 0);
+ }
+
+ g_string_free (buffer, TRUE);
+
+ result =
+ g_strdup_printf (_("model \"%s\", %s and %s"), config->model,
+ layouts ? layouts : _("no layout"),
+ options ? options : _("no options"));
+
+ g_free (options);
+ g_free (layouts);
+
+ return result;
+}
diff --git a/libgnomekbd/backup/gkb-keyboard-config.h b/libgnomekbd/backup/gkb-keyboard-config.h
new file mode 100644
index 0000000..b833b23
--- /dev/null
+++ b/libgnomekbd/backup/gkb-keyboard-config.h
@@ -0,0 +1,123 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GKB_KEYBOARD_CONFIG_H__
+#define __GKB_KEYBOARD_CONFIG_H__
+
+#include <X11/Xlib.h>
+
+#include <glib.h>
+#include <glib/gslist.h>
+#include <gdk/gdk.h>
+#include <gtk/gtk.h>
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gconf/gconf-client.h>
+
+#include <libxklavier/xklavier.h>
+
+extern const gchar GKB_KEYBOARD_CONFIG_DIR[];
+extern const gchar GKB_KEYBOARD_CONFIG_KEY_MODEL[];
+extern const gchar GKB_KEYBOARD_CONFIG_KEY_LAYOUTS[];
+extern const gchar GKB_KEYBOARD_CONFIG_KEY_OPTIONS[];
+
+/*
+ * Keyboard Configuration
+ */
+typedef struct _GkbKeyboardConfig {
+ gchar *model;
+ GSList *layouts;
+ GSList *options;
+
+ /* private, transient */
+ GConfClient *conf_client;
+ int config_listener_id;
+ XklEngine *engine;
+} GkbKeyboardConfig;
+
+/**
+ * GkbKeyboardConfig functions
+ */
+extern void gkb_keyboard_config_init (GkbKeyboardConfig * kbd_config,
+ GConfClient * conf_client,
+ XklEngine * engine);
+extern void gkb_keyboard_config_term (GkbKeyboardConfig * kbd_config);
+
+extern void gkb_keyboard_config_load_from_gconf (GkbKeyboardConfig *
+ kbd_config,
+ GkbKeyboardConfig *
+ kbd_config_default);
+
+extern void gkb_keyboard_config_save_to_gconf (GkbKeyboardConfig *
+ kbd_config);
+
+extern void gkb_keyboard_config_load_from_gconf_backup (GkbKeyboardConfig
+ * kbd_config);
+
+extern void gkb_keyboard_config_save_to_gconf_backup (GkbKeyboardConfig *
+ kbd_config);
+
+extern void gkb_keyboard_config_load_from_x_initial (GkbKeyboardConfig *
+ kbd_config);
+
+extern void gkb_keyboard_config_load_from_x_current (GkbKeyboardConfig *
+ kbd_config);
+
+extern void gkb_keyboard_config_start_listen (GkbKeyboardConfig *
+ kbd_config,
+ GConfClientNotifyFunc func,
+ gpointer user_data);
+
+extern void gkb_keyboard_config_stop_listen (GkbKeyboardConfig *
+ kbd_config);
+
+extern gboolean gkb_keyboard_config_equals (GkbKeyboardConfig *
+ kbd_config1,
+ GkbKeyboardConfig *
+ kbd_config2);
+
+extern gboolean gkb_keyboard_config_activate (GkbKeyboardConfig *
+ kbd_config);
+
+extern const gchar *gkb_keyboard_config_merge_items (const gchar * parent,
+ const gchar * child);
+
+extern gboolean gkb_keyboard_config_split_items (const gchar * merged,
+ gchar ** parent,
+ gchar ** child);
+
+extern gboolean gkb_keyboard_config_get_descriptions (XklConfigRegistry *
+ config_registry,
+ const gchar * name,
+ gchar **
+ layout_short_descr,
+ gchar **
+ layout_descr,
+ gchar **
+ variant_short_descr,
+ gchar **
+ variant_descr);
+
+extern const gchar *gkb_keyboard_config_format_full_layout (const gchar
+ *
+ layout_descr,
+ const gchar *
+ variant_descr);
+
+extern gchar *gkb_keyboard_config_to_string (const GkbKeyboardConfig *
+ config);
+
+#endif
diff --git a/libgnomekbd/backup/gkb-keyboard-drawing-marshal.list b/libgnomekbd/backup/gkb-keyboard-drawing-marshal.list
new file mode 100644
index 0000000..88a875f
--- /dev/null
+++ b/libgnomekbd/backup/gkb-keyboard-drawing-marshal.list
@@ -0,0 +1,2 @@
+# $Id$
+VOID:UINT
diff --git a/libgnomekbd/backup/gkb-keyboard-drawing.c b/libgnomekbd/backup/gkb-keyboard-drawing.c
new file mode 100644
index 0000000..3ec085e
--- /dev/null
+++ b/libgnomekbd/backup/gkb-keyboard-drawing.c
@@ -0,0 +1,1845 @@
+/* $Id$ */
+/*
+ * keyboard-drawing.c: implementation of a gtk+ widget that is a drawing of
+ * the keyboard of the default display
+ *
+ * Copyright (c) 2004 Noah Levitt
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+#include <gdk/gdkkeysyms.h>
+#include <X11/XKBlib.h>
+#include <X11/extensions/XKBgeom.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <math.h>
+
+#include <gkb-keyboard-drawing.h>
+#include <gkb-keyboard-drawing-marshal.h>
+
+#define noKBDRAW_DEBUG
+
+enum {
+ BAD_KEYCODE = 0,
+ NUM_SIGNALS
+};
+
+static guint gkb_keyboard_drawing_signals[NUM_SIGNALS] = { 0 };
+
+static void gkb_keyboard_drawing_set_mods (GkbKeyboardDrawing * drawing,
+ guint mods);
+
+static gint
+xkb_to_pixmap_coord (GkbKeyboardDrawing * drawing, gint n)
+{
+ return n * drawing->scale_numerator / drawing->scale_denominator;
+}
+
+/* angle is in tenths of a degree; coordinates can be anything as (xkb,
+ * pixels, pango) as long as they are all the same */
+static void
+rotate_coordinate (gint origin_x,
+ gint origin_y,
+ gint x,
+ gint y, gint angle, gint * rotated_x, gint * rotated_y)
+{
+ *rotated_x =
+ origin_x + (x - origin_x) * cos (M_PI * angle / 1800.0) - (y -
+ origin_y)
+ * sin (M_PI * angle / 1800.0);
+ *rotated_y =
+ origin_y + (x - origin_x) * sin (M_PI * angle / 1800.0) + (y -
+ origin_y)
+ * cos (M_PI * angle / 1800.0);
+}
+
+static void
+draw_polygon (GkbKeyboardDrawing * drawing,
+ GdkColor * fill_color,
+ gint xkb_x,
+ gint xkb_y, XkbPointRec * xkb_points, guint num_points)
+{
+ GtkStateType state = GTK_WIDGET_STATE (GTK_WIDGET (drawing));
+ GdkGC *gc;
+ GdkPoint *points;
+ gboolean filled;
+ gint i;
+
+ if (drawing->pixmap == NULL)
+ return;
+
+ if (fill_color) {
+ gc = gdk_gc_new (GTK_WIDGET (drawing)->window);
+ gdk_gc_set_rgb_fg_color (gc, fill_color);
+ filled = TRUE;
+ } else {
+ gc = GTK_WIDGET (drawing)->style->dark_gc[state];
+ filled = FALSE;
+ }
+
+ points = g_new (GdkPoint, num_points);
+
+ for (i = 0; i < num_points; i++) {
+ points[i].x =
+ xkb_to_pixmap_coord (drawing, xkb_x + xkb_points[i].x);
+ points[i].y =
+ xkb_to_pixmap_coord (drawing, xkb_y + xkb_points[i].y);
+ }
+
+ gdk_draw_polygon (drawing->pixmap, gc, filled, points, num_points);
+
+ g_free (points);
+ if (fill_color)
+ g_object_unref (gc);
+}
+
+/* x, y, width, height are in the xkb coordinate system */
+static void
+draw_rectangle (GkbKeyboardDrawing * drawing,
+ GdkColor * fill_color,
+ gint angle,
+ gint xkb_x, gint xkb_y, gint xkb_width, gint xkb_height)
+{
+ if (drawing->pixmap == NULL)
+ return;
+
+ if (angle == 0) {
+ GtkStateType state =
+ GTK_WIDGET_STATE (GTK_WIDGET (drawing));
+ gint x, y, width, height;
+ gboolean filled;
+ GdkGC *gc;
+
+ if (fill_color) {
+ gc = gdk_gc_new (GTK_WIDGET (drawing)->window);
+ gdk_gc_set_rgb_fg_color (gc, fill_color);
+ filled = TRUE;
+ } else {
+ gc = GTK_WIDGET (drawing)->style->dark_gc[state];
+ filled = FALSE;
+ }
+
+ x = xkb_to_pixmap_coord (drawing, xkb_x);
+ y = xkb_to_pixmap_coord (drawing, xkb_y);
+ width =
+ xkb_to_pixmap_coord (drawing, xkb_x + xkb_width) - x;
+ height =
+ xkb_to_pixmap_coord (drawing, xkb_y + xkb_height) - y;
+
+ gdk_draw_rectangle (drawing->pixmap, gc, filled, x, y,
+ width, height);
+
+ if (fill_color)
+ g_object_unref (gc);
+ } else {
+ XkbPointRec points[4];
+ gint x, y;
+
+ points[0].x = xkb_x;
+ points[0].y = xkb_y;
+ rotate_coordinate (xkb_x, xkb_y, xkb_x + xkb_width, xkb_y,
+ angle, &x, &y);
+ points[1].x = x;
+ points[1].y = y;
+ rotate_coordinate (xkb_x, xkb_y, xkb_x + xkb_width,
+ xkb_y + xkb_height, angle, &x, &y);
+ points[2].x = x;
+ points[2].y = y;
+ rotate_coordinate (xkb_x, xkb_y, xkb_x, xkb_y + xkb_height,
+ angle, &x, &y);
+ points[3].x = x;
+ points[3].y = y;
+
+ /* the points we've calculated are relative to 0,0 */
+ draw_polygon (drawing, fill_color, 0, 0, points, 4);
+ }
+}
+
+static void
+draw_outline (GkbKeyboardDrawing * drawing,
+ XkbOutlineRec * outline,
+ GdkColor * color, gint angle, gint origin_x, gint origin_y)
+{
+#ifdef KBDRAW_DEBUG
+ printf ("num_points in %p: %d\n", outline, outline->num_points);
+#endif
+
+ if (outline->num_points == 1) {
+ if (color)
+ draw_rectangle (drawing, color, angle, origin_x,
+ origin_y, outline->points[0].x,
+ outline->points[0].y);
+
+#ifdef KBDRAW_DEBUG
+ printf ("points:%p\n", outline->points);
+ printf ("pointsxy:%d %d\n", outline->points[0].x,
+ outline->points[0].y);
+#endif
+
+ draw_rectangle (drawing, NULL, angle, origin_x, origin_y,
+ outline->points[0].x,
+ outline->points[0].y);
+ } else if (outline->num_points == 2) {
+ gint rotated_x0, rotated_y0;
+
+ rotate_coordinate (origin_x, origin_y,
+ origin_x + outline->points[0].x,
+ origin_y + outline->points[0].y,
+ angle, &rotated_x0, &rotated_y0);
+ if (color)
+ draw_rectangle (drawing, color, angle, rotated_x0,
+ rotated_y0, outline->points[1].x,
+ outline->points[1].y);
+
+ draw_rectangle (drawing, NULL, angle, rotated_x0,
+ rotated_y0, outline->points[1].x,
+ outline->points[1].y);
+ } else {
+ if (color)
+ draw_polygon (drawing, color, origin_x, origin_y,
+ outline->points,
+ outline->num_points);
+
+ draw_polygon (drawing, NULL, origin_x, origin_y,
+ outline->points, outline->num_points);
+ }
+}
+
+/* see PSColorDef in xkbprint */
+static gboolean
+parse_xkb_color_spec (gchar * colorspec, GdkColor * color)
+{
+ glong level;
+
+ if (g_ascii_strcasecmp (colorspec, "black") == 0) {
+ color->red = 0;
+ color->green = 0;
+ color->blue = 0;
+ } else if (g_ascii_strcasecmp (colorspec, "white") == 0) {
+ color->red = 65535;
+ color->green = 65535;
+ color->blue = 65535;
+ } else if (g_ascii_strncasecmp (colorspec, "grey", 4) == 0 ||
+ g_ascii_strncasecmp (colorspec, "gray", 4) == 0) {
+ level = strtol (colorspec + 4, NULL, 10);
+
+ color->red = 65535 - 65535 * level / 100;
+ color->green = 65535 - 65535 * level / 100;
+ color->blue = 65535 - 65535 * level / 100;
+ } else if (g_ascii_strcasecmp (colorspec, "red") == 0) {
+ color->red = 65535;
+ color->green = 0;
+ color->blue = 0;
+ } else if (g_ascii_strcasecmp (colorspec, "green") == 0) {
+ color->red = 0;
+ color->green = 65535;
+ color->blue = 0;
+ } else if (g_ascii_strcasecmp (colorspec, "blue") == 0) {
+ color->red = 0;
+ color->green = 0;
+ color->blue = 65535;
+ } else if (g_ascii_strncasecmp (colorspec, "red", 3) == 0) {
+ level = strtol (colorspec + 3, NULL, 10);
+
+ color->red = 65535 * level / 100;
+ color->green = 0;
+ color->blue = 0;
+ } else if (g_ascii_strncasecmp (colorspec, "green", 5) == 0) {
+ level = strtol (colorspec + 5, NULL, 10);
+
+ color->red = 0;
+ color->green = 65535 * level / 100;;
+ color->blue = 0;
+ } else if (g_ascii_strncasecmp (colorspec, "blue", 4) == 0) {
+ level = strtol (colorspec + 4, NULL, 10);
+
+ color->red = 0;
+ color->green = 0;
+ color->blue = 65535 * level / 100;
+ } else
+ return FALSE;
+
+ return TRUE;
+}
+
+
+static guint
+find_keycode (GkbKeyboardDrawing * drawing, gchar * key_name)
+{
+ guint i;
+
+ if (!drawing->xkb)
+ return (gint) (-1);
+
+ for (i = drawing->xkb->min_key_code;
+ i <= drawing->xkb->max_key_code; i++) {
+ if (drawing->xkb->names->keys[i].name[0] == key_name[0]
+ && drawing->xkb->names->keys[i].name[1] == key_name[1]
+ && drawing->xkb->names->keys[i].name[2] == key_name[2]
+ && drawing->xkb->names->keys[i].name[3] == key_name[3])
+ return i;
+ }
+
+ return (guint) (-1);
+}
+
+
+static void
+fit_width (GkbKeyboardDrawing * drawing, gint width)
+{
+ PangoRectangle logical_rect;
+ gint old_size;
+
+ pango_layout_get_extents (drawing->layout, NULL, &logical_rect);
+
+ if (logical_rect.width > 0 && logical_rect.width > width) {
+ old_size =
+ pango_font_description_get_size (drawing->font_desc);
+ pango_font_description_set_size (drawing->font_desc,
+ old_size * width /
+ logical_rect.width);
+ pango_layout_set_font_description (drawing->layout,
+ drawing->font_desc);
+ }
+}
+
+static void
+set_key_label_in_layout (GkbKeyboardDrawing * drawing,
+ PangoLayout * layout, guint keyval)
+{
+ gchar buf[5];
+ gunichar uc;
+
+ switch (keyval) {
+ case GDK_Scroll_Lock:
+ pango_layout_set_text (layout, "Scroll\nLock", -1);
+ break;
+
+ case GDK_space:
+ pango_layout_set_text (layout, "", -1);
+ break;
+
+ case GDK_Sys_Req:
+ pango_layout_set_text (layout, "Sys Rq", -1);
+ break;
+
+ case GDK_Page_Up:
+ pango_layout_set_text (layout, "Page\nUp", -1);
+ break;
+
+ case GDK_Page_Down:
+ pango_layout_set_text (layout, "Page\nDown", -1);
+ break;
+
+ case GDK_Num_Lock:
+ pango_layout_set_text (layout, "Num\nLock", -1);
+ break;
+
+ case GDK_KP_Page_Up:
+ pango_layout_set_text (layout, "Pg Up", -1);
+ break;
+
+ case GDK_KP_Page_Down:
+ pango_layout_set_text (layout, "Pg Dn", -1);
+ break;
+
+ case GDK_KP_Home:
+ pango_layout_set_text (layout, "Home", -1);
+ break;
+
+ case GDK_KP_Left:
+ pango_layout_set_text (layout, "Left", -1);
+ break;
+
+ case GDK_KP_End:
+ pango_layout_set_text (layout, "End", -1);
+ break;
+
+ case GDK_KP_Up:
+ pango_layout_set_text (layout, "Up", -1);
+ break;
+
+ case GDK_KP_Begin:
+ pango_layout_set_text (layout, "Begin", -1);
+ break;
+
+ case GDK_KP_Right:
+ pango_layout_set_text (layout, "Right", -1);
+ break;
+
+ case GDK_KP_Enter:
+ pango_layout_set_text (layout, "Enter", -1);
+ break;
+
+ case GDK_KP_Down:
+ pango_layout_set_text (layout, "Down", -1);
+ break;
+
+ case GDK_KP_Insert:
+ pango_layout_set_text (layout, "Ins", -1);
+ break;
+
+ case GDK_KP_Delete:
+ pango_layout_set_text (layout, "Del", -1);
+ break;
+
+ case GDK_dead_grave:
+ pango_layout_set_text (layout, "ˋ", -1);
+ break;
+
+ case GDK_dead_acute:
+ pango_layout_set_text (layout, "ˊ", -1);
+ break;
+
+ case GDK_dead_circumflex:
+ pango_layout_set_text (layout, "ˆ", -1);
+ break;
+
+ case GDK_dead_tilde:
+ pango_layout_set_text (layout, "~", -1);
+ break;
+
+ case GDK_dead_macron:
+ pango_layout_set_text (layout, "ˉ", -1);
+ break;
+
+ case GDK_dead_breve:
+ pango_layout_set_text (layout, "˘", -1);
+ break;
+
+ case GDK_dead_abovedot:
+ pango_layout_set_text (layout, "˙", -1);
+ break;
+
+ case GDK_dead_diaeresis:
+ pango_layout_set_text (layout, "¨", -1);
+ break;
+
+ case GDK_dead_abovering:
+ pango_layout_set_text (layout, "˚", -1);
+ break;
+
+ case GDK_dead_doubleacute:
+ pango_layout_set_text (layout, "˝", -1);
+ break;
+
+ case GDK_dead_caron:
+ pango_layout_set_text (layout, "ˇ", -1);
+ break;
+
+ case GDK_dead_cedilla:
+ pango_layout_set_text (layout, "¸", -1);
+ break;
+
+ case GDK_dead_ogonek:
+ pango_layout_set_text (layout, "˛", -1);
+ break;
+
+ /* case GDK_dead_iota:
+ * case GDK_dead_voiced_sound:
+ * case GDK_dead_semivoiced_sound: */
+
+ case GDK_dead_belowdot:
+ pango_layout_set_text (layout, " ̣", -1);
+ break;
+
+ case GDK_horizconnector:
+ pango_layout_set_text (layout, "horiz\nconn", -1);
+ break;
+
+ case GDK_Mode_switch:
+ pango_layout_set_text (layout, "AltGr", -1);
+ break;
+
+ case GDK_Multi_key:
+ pango_layout_set_text (layout, "Compose", -1);
+ break;
+
+ default:
+ uc = gdk_keyval_to_unicode (keyval);
+ if (uc != 0 && g_unichar_isgraph (uc)) {
+ buf[g_unichar_to_utf8 (uc, buf)] = '\0';
+ pango_layout_set_text (layout, buf, -1);
+ } else {
+ gchar *name = gdk_keyval_name (keyval);
+ if (name)
+ pango_layout_set_text (layout, name, -1);
+ else
+ pango_layout_set_text (layout, "", -1);
+ }
+ }
+}
+
+
+static void
+draw_layout (GkbKeyboardDrawing * drawing,
+ gint angle, gint x, gint y, PangoLayout * layout)
+{
+ GtkStateType state = GTK_WIDGET_STATE (GTK_WIDGET (drawing));
+ PangoLayoutLine *line;
+ gint x_off, y_off;
+ gint i;
+
+ if (drawing->pixmap == NULL)
+ return;
+
+ if (angle != drawing->angle) {
+ PangoMatrix matrix = PANGO_MATRIX_INIT;
+ pango_matrix_rotate (&matrix, -angle / 10.0);
+ pango_context_set_matrix (gtk_widget_get_pango_context
+ (GTK_WIDGET (drawing)), &matrix);
+ pango_layout_context_changed (drawing->layout);
+ drawing->angle = angle;
+ }
+
+ i = 0;
+ y_off = 0;
+ for (line = pango_layout_get_line (drawing->layout, i);
+ line != NULL;
+ line = pango_layout_get_line (drawing->layout, ++i)) {
+ GSList *runp;
+ PangoRectangle line_extents;
+
+ x_off = 0;
+
+ for (runp = line->runs; runp != NULL; runp = runp->next) {
+ PangoGlyphItem *run = runp->data;
+ gint j;
+
+ for (j = 0; j < run->glyphs->num_glyphs; j++) {
+ PangoGlyphGeometry *geometry;
+ gint xx, yy;
+
+ geometry =
+ &run->glyphs->glyphs[j].geometry;
+
+ rotate_coordinate (0, 0, x_off, y_off,
+ angle, &xx, &yy);
+ geometry->x_offset -= x_off - xx;
+ geometry->y_offset -= y_off - yy;
+
+ x_off += geometry->width;
+ }
+ }
+
+ pango_layout_line_get_extents (line, NULL, &line_extents);
+ y_off +=
+ line_extents.height +
+ pango_layout_get_spacing (drawing->layout);
+ }
+
+ gdk_draw_layout (drawing->pixmap,
+ GTK_WIDGET (drawing)->style->text_gc[state], x, y,
+ drawing->layout);
+}
+
+static void
+draw_key_label_helper (GkbKeyboardDrawing * drawing,
+ KeySym keysym,
+ gint angle,
+ GkbKeyboardDrawingGroupLevelPosition glp,
+ gint x,
+ gint y, gint width, gint height, gint padding)
+{
+ gint old_size;
+ gint label_x, label_y, label_max_width, ycell;
+
+ if (keysym == 0)
+ return;
+#ifdef KBDRAW_DEBUG
+ printf ("keysym: %04X(%c) at glp: %d\n",
+ (unsigned) keysym, (char) keysym, (int) glp);
+#endif
+
+ switch (glp) {
+ case GKB_KEYBOARD_DRAWING_POS_TOPLEFT:
+ case GKB_KEYBOARD_DRAWING_POS_BOTTOMLEFT:
+ {
+ ycell = glp == GKB_KEYBOARD_DRAWING_POS_BOTTOMLEFT;
+
+ rotate_coordinate (x, y, x + padding,
+ y + padding + (height -
+ 2 * padding) *
+ ycell * 4 / 7, angle, &label_x,
+ &label_y);
+ label_max_width =
+ PANGO_SCALE * (width - 2 * padding);
+ break;
+ }
+ case GKB_KEYBOARD_DRAWING_POS_TOPRIGHT:
+ case GKB_KEYBOARD_DRAWING_POS_BOTTOMRIGHT:
+ {
+ ycell =
+ glp == GKB_KEYBOARD_DRAWING_POS_BOTTOMRIGHT;
+
+ rotate_coordinate (x, y,
+ x + padding + (width -
+ 2 * padding) *
+ 4 / 7,
+ y + padding + (height -
+ 2 * padding) *
+ ycell * 4 / 7, angle, &label_x,
+ &label_y);
+ label_max_width =
+ PANGO_SCALE * ((width - 2 * padding) -
+ (width - 2 * padding) * 4 / 7);
+ break;
+ }
+ default:
+ return;
+ }
+ set_key_label_in_layout (drawing, drawing->layout, keysym);
+
+ old_size = pango_font_description_get_size (drawing->font_desc);
+ fit_width (drawing, label_max_width);
+
+ draw_layout (drawing, angle, label_x, label_y, drawing->layout);
+
+ if (pango_font_description_get_size (drawing->font_desc) !=
+ old_size) {
+ pango_font_description_set_size (drawing->font_desc,
+ old_size);
+ pango_layout_set_font_description (drawing->layout,
+ drawing->font_desc);
+ }
+}
+
+static void
+draw_key_label (GkbKeyboardDrawing * drawing,
+ guint keycode,
+ gint angle,
+ gint xkb_origin_x,
+ gint xkb_origin_y, gint xkb_width, gint xkb_height)
+{
+ gint x, y, width, height;
+ gint padding;
+ gint g, l, glp;
+
+ if (!drawing->xkb)
+ return;
+
+ padding = 23 * drawing->scale_numerator / drawing->scale_denominator; /* 2.3mm */
+
+ x = xkb_to_pixmap_coord (drawing, xkb_origin_x);
+ y = xkb_to_pixmap_coord (drawing, xkb_origin_y);
+ width =
+ xkb_to_pixmap_coord (drawing, xkb_origin_x + xkb_width) - x;
+ height =
+ xkb_to_pixmap_coord (drawing, xkb_origin_y + xkb_height) - y;
+
+ for (glp = GKB_KEYBOARD_DRAWING_POS_TOPLEFT;
+ glp < GKB_KEYBOARD_DRAWING_POS_TOTAL; glp++) {
+ if (drawing->groupLevels[glp] == NULL)
+ continue;
+ g = drawing->groupLevels[glp]->group;
+ l = drawing->groupLevels[glp]->level;
+
+ if (g < 0 || g >= XkbKeyNumGroups (drawing->xkb, keycode))
+ continue;
+ if (l < 0
+ || l >= XkbKeyGroupWidth (drawing->xkb, keycode, g))
+ continue;
+
+ if (drawing->track_modifiers) {
+ uint mods_rtrn;
+ KeySym keysym;
+
+ if (XkbTranslateKeyCode (drawing->xkb, keycode,
+ XkbBuildCoreState
+ (drawing->mods, g),
+ &mods_rtrn, &keysym)) {
+ draw_key_label_helper (drawing, keysym,
+ angle, glp, x, y,
+ width, height,
+ padding);
+ /* reverse y order */
+ }
+ } else {
+ KeySym keysym;
+
+ keysym =
+ XkbKeySymEntry (drawing->xkb, keycode, l, g);
+
+ draw_key_label_helper (drawing, keysym, angle, glp,
+ x, y, width, height,
+ padding);
+ /* reverse y order */
+ }
+ }
+}
+
+/* groups are from 0-3 */
+static void
+draw_key (GkbKeyboardDrawing * drawing, GkbKeyboardDrawingKey * key)
+{
+ XkbShapeRec *shape;
+ GdkColor *color;
+ gint i;
+
+ if (!drawing->xkb)
+ return;
+
+#ifdef KBDRAW_DEBUG
+ printf ("shape: %p (%p + %d)\n",
+ drawing->xkb->geom->shapes + key->xkbkey->shape_ndx,
+ drawing->xkb->geom->shapes, key->xkbkey->shape_ndx);
+#endif
+
+ shape = drawing->xkb->geom->shapes + key->xkbkey->shape_ndx;
+
+ if (key->pressed)
+ color =
+ &(GTK_WIDGET (drawing)->style->
+ base[GTK_STATE_SELECTED]);
+ else
+ color = drawing->colors + key->xkbkey->color_ndx;
+
+#ifdef KBDRAW_DEBUG
+ printf ("outlines: %p(%d)\n", shape->outlines,
+ shape->num_outlines);
+#endif
+
+ for (i = 0; i < 1 /* shape->num_outlines */ ; i++)
+ draw_outline (drawing, shape->outlines + i, color,
+ key->angle, key->origin_x, key->origin_y);
+
+ draw_key_label (drawing, key->keycode, key->angle, key->origin_x,
+ key->origin_y, shape->bounds.x2, shape->bounds.y2);
+}
+
+static void
+invalidate_region (GkbKeyboardDrawing * drawing,
+ gdouble angle,
+ gint origin_x, gint origin_y, XkbShapeRec * shape)
+{
+ GdkPoint points[4];
+ gint x_min, x_max, y_min, y_max;
+ gint x, y, width, height;
+ gint xx, yy;
+
+ rotate_coordinate (0, 0, 0, 0, angle, &xx, &yy);
+ points[0].x = xx;
+ points[0].y = yy;
+ rotate_coordinate (0, 0, shape->bounds.x2, 0, angle, &xx, &yy);
+ points[1].x = xx;
+ points[1].y = yy;
+ rotate_coordinate (0, 0, shape->bounds.x2, shape->bounds.y2, angle,
+ &xx, &yy);
+ points[2].x = xx;
+ points[2].y = yy;
+ rotate_coordinate (0, 0, 0, shape->bounds.y2, angle, &xx, &yy);
+ points[3].x = xx;
+ points[3].y = yy;
+
+ x_min =
+ MIN (MIN (points[0].x, points[1].x),
+ MIN (points[2].x, points[3].x));
+ x_max =
+ MAX (MAX (points[0].x, points[1].x),
+ MAX (points[2].x, points[3].x));
+ y_min =
+ MIN (MIN (points[0].y, points[1].y),
+ MIN (points[2].y, points[3].y));
+ y_max =
+ MAX (MAX (points[0].y, points[1].y),
+ MAX (points[2].y, points[3].y));
+
+ x = xkb_to_pixmap_coord (drawing, origin_x + x_min) - 6;
+ y = xkb_to_pixmap_coord (drawing, origin_y + y_min) - 6;
+ width = xkb_to_pixmap_coord (drawing, x_max - x_min) + 12;
+ height = xkb_to_pixmap_coord (drawing, y_max - y_min) + 12;
+
+ gtk_widget_queue_draw_area (GTK_WIDGET (drawing), x, y, width,
+ height);
+}
+
+static void
+invalidate_indicator_doodad_region (GkbKeyboardDrawing * drawing,
+ GkbKeyboardDrawingDoodad * doodad)
+{
+ if (!drawing->xkb)
+ return;
+
+ invalidate_region (drawing,
+ doodad->angle,
+ doodad->origin_x +
+ doodad->doodad->indicator.left,
+ doodad->origin_y +
+ doodad->doodad->indicator.top,
+ &drawing->xkb->geom->shapes[doodad->doodad->
+ indicator.
+ shape_ndx]);
+}
+
+static void
+invalidate_key_region (GkbKeyboardDrawing * drawing,
+ GkbKeyboardDrawingKey * key)
+{
+ if (!drawing->xkb)
+ return;
+
+ invalidate_region (drawing,
+ key->angle,
+ key->origin_x,
+ key->origin_y,
+ &drawing->xkb->geom->shapes[key->xkbkey->
+ shape_ndx]);
+}
+
+static void
+draw_text_doodad (GkbKeyboardDrawing * drawing,
+ GkbKeyboardDrawingDoodad * doodad,
+ XkbTextDoodadRec * text_doodad)
+{
+ gint x, y;
+ if (!drawing->xkb)
+ return;
+
+ x = xkb_to_pixmap_coord (drawing,
+ doodad->origin_x + text_doodad->left);
+ y = xkb_to_pixmap_coord (drawing,
+ doodad->origin_y + text_doodad->top);
+
+ pango_layout_set_text (drawing->layout, text_doodad->text, -1);
+ draw_layout (drawing, doodad->angle, x, y, drawing->layout);
+}
+
+static void
+draw_indicator_doodad (GkbKeyboardDrawing * drawing,
+ GkbKeyboardDrawingDoodad * doodad,
+ XkbIndicatorDoodadRec * indicator_doodad)
+{
+ GdkColor *color;
+ XkbShapeRec *shape;
+ gint i;
+
+ if (!drawing->xkb)
+ return;
+
+ shape = drawing->xkb->geom->shapes + indicator_doodad->shape_ndx;
+
+ color = drawing->colors + (doodad->on ?
+ indicator_doodad->on_color_ndx :
+ indicator_doodad->off_color_ndx);
+
+ for (i = 0; i < 1; i++)
+ draw_outline (drawing, shape->outlines + i, color,
+ doodad->angle,
+ doodad->origin_x + indicator_doodad->left,
+ doodad->origin_y + indicator_doodad->top);
+}
+
+static void
+draw_shape_doodad (GkbKeyboardDrawing * drawing,
+ GkbKeyboardDrawingDoodad * doodad,
+ XkbShapeDoodadRec * shape_doodad)
+{
+ XkbShapeRec *shape;
+ GdkColor *color;
+ gint i;
+
+ if (!drawing->xkb)
+ return;
+
+ shape = drawing->xkb->geom->shapes + shape_doodad->shape_ndx;
+ color = drawing->colors + shape_doodad->color_ndx;
+
+ for (i = 0; i < shape->num_outlines; i++)
+ draw_outline (drawing, shape->outlines + i, color,
+ doodad->angle,
+ doodad->origin_x + shape_doodad->left,
+ doodad->origin_y + shape_doodad->top);
+}
+
+static void
+draw_doodad (GkbKeyboardDrawing * drawing,
+ GkbKeyboardDrawingDoodad * doodad)
+{
+ switch (doodad->doodad->any.type) {
+ case XkbOutlineDoodad:
+ case XkbSolidDoodad:
+ draw_shape_doodad (drawing, doodad,
+ &doodad->doodad->shape);
+ break;
+
+ case XkbTextDoodad:
+ draw_text_doodad (drawing, doodad, &doodad->doodad->text);
+ break;
+
+ case XkbIndicatorDoodad:
+ draw_indicator_doodad (drawing, doodad,
+ &doodad->doodad->indicator);
+ break;
+
+ case XkbLogoDoodad:
+ /* g_print ("draw_doodad: logo: %s\n", doodad->doodad->logo.logo_name); */
+ /* XkbLogoDoodadRec is essentially a subclass of XkbShapeDoodadRec */
+ draw_shape_doodad (drawing, doodad,
+ &doodad->doodad->shape);
+ break;
+ }
+}
+
+static void
+draw_keyboard_item (GkbKeyboardDrawingItem * item,
+ GkbKeyboardDrawing * drawing)
+{
+ if (!drawing->xkb)
+ return;
+
+ switch (item->type) {
+ case GKB_KEYBOARD_DRAWING_ITEM_TYPE_KEY:
+ draw_key (drawing, (GkbKeyboardDrawingKey *) item);
+ break;
+
+ case GKB_KEYBOARD_DRAWING_ITEM_TYPE_DOODAD:
+ draw_doodad (drawing, (GkbKeyboardDrawingDoodad *) item);
+ break;
+ }
+}
+
+static void
+draw_keyboard (GkbKeyboardDrawing * drawing)
+{
+ GtkStateType state = GTK_WIDGET_STATE (GTK_WIDGET (drawing));
+ gint pixw, pixh;
+
+ if (!drawing->xkb)
+ return;
+
+ pixw = GTK_WIDGET (drawing)->allocation.width;
+ pixh = GTK_WIDGET (drawing)->allocation.height;
+
+ drawing->pixmap =
+ gdk_pixmap_new (GTK_WIDGET (drawing)->window, pixw, pixh, -1);
+
+ /* blank background */
+ gdk_draw_rectangle (drawing->pixmap,
+ GTK_WIDGET (drawing)->style->base_gc[state],
+ TRUE, 0, 0, pixw, pixh);
+
+ if (drawing->xkb == NULL)
+ return;
+
+#ifdef KBDRAW_DEBUG
+ printf ("mods: %d\n", drawing->mods);
+#endif
+
+ g_list_foreach (drawing->keyboard_items,
+ (GFunc) draw_keyboard_item, drawing);
+}
+
+static void
+alloc_pango_layout (GkbKeyboardDrawing * drawing)
+{
+ PangoContext *context =
+ gtk_widget_get_pango_context (GTK_WIDGET (drawing));
+ drawing->layout = pango_layout_new (context);
+}
+
+static void
+free_pango_layout (GkbKeyboardDrawing * drawing)
+{
+ g_object_unref (G_OBJECT (drawing->layout));
+ drawing->layout = NULL;
+}
+
+static gboolean
+expose_event (GtkWidget * widget,
+ GdkEventExpose * event, GkbKeyboardDrawing * drawing)
+{
+ GtkStateType state = GTK_WIDGET_STATE (GTK_WIDGET (drawing));
+
+ if (!drawing->xkb)
+ return FALSE;
+
+ if (drawing->pixmap == NULL)
+ draw_keyboard (drawing);
+
+ gdk_draw_drawable (widget->window,
+ widget->style->fg_gc[state],
+ drawing->pixmap,
+ event->area.x, event->area.y,
+ event->area.x, event->area.y,
+ event->area.width, event->area.height);
+
+ if (GTK_WIDGET_HAS_FOCUS (widget))
+ gtk_paint_focus (widget->style, widget->window,
+ GTK_WIDGET_STATE (widget), &event->area,
+ widget, "keyboard-drawing",
+ 0, 0,
+ widget->allocation.width,
+ widget->allocation.height);
+
+ return FALSE;
+}
+
+static void
+size_allocate (GtkWidget * widget,
+ GtkAllocation * allocation, GkbKeyboardDrawing * drawing)
+{
+ if (!drawing->xkb)
+ return;
+
+ if (drawing->pixmap) {
+ g_object_unref (drawing->pixmap);
+ drawing->pixmap = NULL;
+ }
+
+ if (drawing->xkb->geom->width_mm <= 0
+ || drawing->xkb->geom->height_mm <= 0) {
+ g_critical
+ ("keyboard geometry reports width or height as zero!");
+ return;
+ }
+
+ if (allocation->width * drawing->xkb->geom->height_mm <
+ allocation->height * drawing->xkb->geom->width_mm) {
+ drawing->scale_numerator = allocation->width;
+ drawing->scale_denominator = drawing->xkb->geom->width_mm;
+ } else {
+ drawing->scale_numerator = allocation->height;
+ drawing->scale_denominator = drawing->xkb->geom->height_mm;
+ }
+
+ pango_font_description_set_size (drawing->font_desc,
+ 36000 * drawing->scale_numerator /
+ drawing->scale_denominator);
+ pango_layout_set_spacing (drawing->layout,
+ -8000 * drawing->scale_numerator /
+ drawing->scale_denominator);
+ pango_layout_set_font_description (drawing->layout,
+ drawing->font_desc);
+}
+
+static gint
+key_event (GtkWidget * widget,
+ GdkEventKey * event, GkbKeyboardDrawing * drawing)
+{
+ GkbKeyboardDrawingKey *key;
+ if (!drawing->xkb)
+ return FALSE;
+
+ key = drawing->keys + event->hardware_keycode;
+
+ if (event->hardware_keycode > drawing->xkb->max_key_code ||
+ event->hardware_keycode < drawing->xkb->min_key_code ||
+ key->xkbkey == NULL) {
+ g_signal_emit (drawing,
+ gkb_keyboard_drawing_signals[BAD_KEYCODE],
+ 0, event->hardware_keycode);
+ return TRUE;
+ }
+
+ if ((event->type == GDK_KEY_PRESS && key->pressed) ||
+ (event->type == GDK_KEY_RELEASE && !key->pressed))
+ return TRUE;
+ /* otherwise this event changes the state we believed we had before */
+
+ key->pressed = (event->type == GDK_KEY_PRESS);
+
+ draw_key (drawing, key);
+
+ invalidate_key_region (drawing, key);
+
+ return TRUE;
+}
+
+static gint
+button_press_event (GtkWidget * widget,
+ GdkEventButton * event, GkbKeyboardDrawing * drawing)
+{
+ if (!drawing->xkb)
+ return FALSE;
+
+ gtk_widget_grab_focus (widget);
+ return FALSE;
+}
+
+static gboolean
+unpress_keys (GkbKeyboardDrawing * drawing)
+{
+ gint i;
+
+ if (!drawing->xkb)
+ return FALSE;
+
+ for (i = drawing->xkb->min_key_code;
+ i <= drawing->xkb->max_key_code; i++)
+ if (drawing->keys[i].pressed) {
+ drawing->keys[i].pressed = FALSE;
+ draw_key (drawing, drawing->keys + i);
+ invalidate_key_region (drawing, drawing->keys + i);
+ }
+
+ return FALSE;
+}
+
+static gint
+focus_event (GtkWidget * widget,
+ GdkEventFocus * event, GkbKeyboardDrawing * drawing)
+{
+ if (event->in && drawing->timeout > 0) {
+ g_source_remove (drawing->timeout);
+ drawing->timeout = 0;
+ } else
+ drawing->timeout =
+ g_timeout_add (120, (GSourceFunc) unpress_keys,
+ drawing);
+
+ return FALSE;
+}
+
+static gint
+compare_keyboard_item_priorities (GkbKeyboardDrawingItem * a,
+ GkbKeyboardDrawingItem * b)
+{
+ if (a->priority > b->priority)
+ return 1;
+ else if (a->priority < b->priority)
+ return -1;
+ else
+ return 0;
+}
+
+static void
+init_indicator_doodad (GkbKeyboardDrawing * drawing,
+ XkbDoodadRec * xkbdoodad,
+ GkbKeyboardDrawingDoodad * doodad)
+{
+ if (!drawing->xkb)
+ return;
+
+ if (xkbdoodad->any.type == XkbIndicatorDoodad) {
+ gint index;
+ Atom iname = 0;
+ Atom sname = xkbdoodad->indicator.name;
+ unsigned long phys_indicators =
+ drawing->xkb->indicators->phys_indicators;
+ Atom *pind = drawing->xkb->names->indicators;
+
+#ifdef KBDRAW_DEBUG
+ printf ("Looking for %d[%s]\n",
+ (int) sname, XGetAtomName (drawing->display,
+ sname));
+#endif
+
+ for (index = 0; index < XkbNumIndicators; index++) {
+ iname = *pind++;
+ /* name matches and it is real */
+ if (iname == sname
+ && (phys_indicators & (1 << index)))
+ break;
+ if (iname == 0)
+ break;
+ }
+ if (iname == 0)
+ g_warning ("Could not find indicator %d [%s]\n",
+ (int) sname,
+ XGetAtomName (drawing->display, sname));
+ else {
+#ifdef KBDRAW_DEBUG
+ printf ("Found in xkbdesc as %d\n", index);
+#endif
+ drawing->physical_indicators[index] = doodad;
+ /* Trying to obtain the real state, but if fail - just assume OFF */
+ if (!XkbGetNamedIndicator
+ (drawing->display, sname, NULL, &doodad->on,
+ NULL, NULL))
+ doodad->on = 0;
+ }
+ }
+}
+
+static void
+init_keys_and_doodads (GkbKeyboardDrawing * drawing)
+{
+ gint i, j, k;
+ gint x, y;
+
+ if (!drawing->xkb)
+ return;
+
+ for (i = 0; i < drawing->xkb->geom->num_doodads; i++) {
+ XkbDoodadRec *xkbdoodad = drawing->xkb->geom->doodads + i;
+ GkbKeyboardDrawingDoodad *doodad =
+ g_new (GkbKeyboardDrawingDoodad, 1);
+
+ doodad->type = GKB_KEYBOARD_DRAWING_ITEM_TYPE_DOODAD;
+ doodad->origin_x = 0;
+ doodad->origin_y = 0;
+ doodad->angle = 0;
+ doodad->priority = xkbdoodad->any.priority * 256 * 256;
+ doodad->doodad = xkbdoodad;
+
+ init_indicator_doodad (drawing, xkbdoodad, doodad);
+
+ drawing->keyboard_items =
+ g_list_append (drawing->keyboard_items, doodad);
+ }
+
+ for (i = 0; i < drawing->xkb->geom->num_sections; i++) {
+#ifdef KBDRAW_DEBUG
+ printf ("initing section %d\n", i);
+#endif
+ XkbSectionRec *section = drawing->xkb->geom->sections + i;
+ guint priority;
+
+ x = section->left;
+ y = section->top;
+ priority = section->priority * 256 * 256;
+
+ for (j = 0; j < section->num_rows; j++) {
+ XkbRowRec *row = section->rows + j;
+
+#ifdef KBDRAW_DEBUG
+ printf (" initing row %d\n", j);
+#endif
+ x = section->left + row->left;
+ y = section->top + row->top;
+
+ for (k = 0; k < row->num_keys; k++) {
+ XkbKeyRec *xkbkey = row->keys + k;
+ GkbKeyboardDrawingKey *key;
+ XkbShapeRec *shape =
+ drawing->xkb->geom->shapes +
+ xkbkey->shape_ndx;
+ guint keycode = find_keycode (drawing,
+ xkbkey->name.
+ name);
+
+#ifdef KBDRAW_DEBUG
+ printf
+ (" initing key %d, shape: %p(%p + %d), code: %d\n",
+ k, shape, drawing->xkb->geom->shapes,
+ xkbkey->shape_ndx, keycode);
+#endif
+ if (row->vertical)
+ y += xkbkey->gap;
+ else
+ x += xkbkey->gap;
+
+ if (keycode >= drawing->xkb->min_key_code
+ && keycode <=
+ drawing->xkb->max_key_code)
+ key = drawing->keys + keycode;
+ else {
+ g_warning
+ ("key %4.4s: keycode = %u; not in range %d..%d\n",
+ xkbkey->name.name, keycode,
+ drawing->xkb->min_key_code,
+ drawing->xkb->max_key_code);
+
+ key =
+ g_new0 (GkbKeyboardDrawingKey,
+ 1);
+ }
+
+ key->type =
+ GKB_KEYBOARD_DRAWING_ITEM_TYPE_KEY;
+ key->xkbkey = xkbkey;
+ key->angle = section->angle;
+ rotate_coordinate (section->left,
+ section->top, x, y,
+ section->angle,
+ &key->origin_x,
+ &key->origin_y);
+ key->priority = priority;
+ key->keycode = keycode;
+
+ drawing->keyboard_items =
+ g_list_append (drawing->keyboard_items,
+ key);
+
+ if (row->vertical)
+ y += shape->bounds.y2;
+ else
+ x += shape->bounds.x2;
+
+ priority++;
+ }
+ }
+
+ for (j = 0; j < section->num_doodads; j++) {
+ XkbDoodadRec *xkbdoodad = section->doodads + j;
+ GkbKeyboardDrawingDoodad *doodad =
+ g_new (GkbKeyboardDrawingDoodad, 1);
+
+ doodad->type =
+ GKB_KEYBOARD_DRAWING_ITEM_TYPE_DOODAD;
+ doodad->origin_x = x;
+ doodad->origin_y = y;
+ doodad->angle = section->angle;
+ doodad->priority =
+ priority + xkbdoodad->any.priority;
+ doodad->doodad = xkbdoodad;
+
+ init_indicator_doodad (drawing, xkbdoodad, doodad);
+
+ drawing->keyboard_items =
+ g_list_append (drawing->keyboard_items,
+ doodad);
+ }
+ }
+
+ drawing->keyboard_items = g_list_sort (drawing->keyboard_items,
+ (GCompareFunc)
+ compare_keyboard_item_priorities);
+}
+
+static void
+init_colors (GkbKeyboardDrawing * drawing)
+{
+ gboolean result;
+ gint i;
+
+ if (!drawing->xkb)
+ return;
+
+ drawing->colors = g_new (GdkColor, drawing->xkb->geom->num_colors);
+
+ for (i = 0; i < drawing->xkb->geom->num_colors; i++) {
+ result =
+ parse_xkb_color_spec (drawing->xkb->geom->colors[i].
+ spec, drawing->colors + i);
+
+ if (!result)
+ g_warning
+ ("init_colors: unable to parse color %s\n",
+ drawing->xkb->geom->colors[i].spec);
+ }
+}
+
+static void
+free_cdik ( /*colors doodads indicators keys */
+ GkbKeyboardDrawing * drawing)
+{
+ GList *itemp;
+
+ if (!drawing->xkb)
+ return;
+
+ for (itemp = drawing->keyboard_items; itemp; itemp = itemp->next) {
+ GkbKeyboardDrawingItem *item = itemp->data;
+ GkbKeyboardDrawingKey *key;
+
+ switch (item->type) {
+ case GKB_KEYBOARD_DRAWING_ITEM_TYPE_DOODAD:
+ g_free (item);
+ break;
+
+ case GKB_KEYBOARD_DRAWING_ITEM_TYPE_KEY:
+ key = (GkbKeyboardDrawingKey *) item;
+ if (key->keycode < drawing->xkb->min_key_code ||
+ key->keycode > drawing->xkb->max_key_code)
+ g_free (key);
+ /* otherwise it's part of the array */
+ break;
+ }
+ }
+
+ g_list_free (drawing->keyboard_items);
+ drawing->keyboard_items = NULL;
+
+ g_free (drawing->keys);
+ g_free (drawing->colors);
+}
+
+static void
+alloc_cdik (GkbKeyboardDrawing * drawing)
+{
+ drawing->physical_indicators_size =
+ drawing->xkb->indicators->phys_indicators + 1;
+ drawing->physical_indicators =
+ g_new0 (GkbKeyboardDrawingDoodad *,
+ drawing->physical_indicators_size);
+ drawing->keys =
+ g_new0 (GkbKeyboardDrawingKey, drawing->xkb->max_key_code + 1);
+}
+
+static GdkFilterReturn
+xkb_state_notify_event_filter (GdkXEvent * gdkxev,
+ GdkEvent * event,
+ GkbKeyboardDrawing * drawing)
+{
+#define group_change_mask (XkbGroupStateMask | XkbGroupBaseMask | XkbGroupLatchMask | XkbGroupLockMask)
+#define modifier_change_mask (XkbModifierStateMask | XkbModifierBaseMask | XkbModifierLatchMask | XkbModifierLockMask)
+
+ if (!drawing->xkb)
+ return GDK_FILTER_CONTINUE;
+
+ if (((XEvent *) gdkxev)->type == drawing->xkb_event_type) {
+ XkbEvent *kev = (XkbEvent *) gdkxev;
+ switch (kev->any.xkb_type) {
+ case XkbStateNotify:
+ if (((kev->state.changed & modifier_change_mask) &&
+ drawing->track_modifiers)) {
+ free_cdik (drawing);
+ if (drawing->track_modifiers)
+ gkb_keyboard_drawing_set_mods
+ (drawing,
+ kev->state.compat_state);
+ drawing->keys =
+ g_new0 (GkbKeyboardDrawingKey,
+ drawing->xkb->max_key_code +
+ 1);
+ size_allocate (GTK_WIDGET (drawing),
+ &(GTK_WIDGET (drawing)->
+ allocation), drawing);
+
+ init_keys_and_doodads (drawing);
+ init_colors (drawing);
+ }
+ break;
+
+ case XkbIndicatorStateNotify:
+ {
+ /* Good question: should we track indicators when the keyboard is
+ NOT really taken from the screen */
+ XkbIndicatorNotifyEvent *iev =
+ &((XkbEvent *) gdkxev)->indicators;
+ gint i;
+
+ for (i = 0;
+ i <=
+ drawing->xkb->indicators->
+ phys_indicators; i++)
+ if (drawing->
+ physical_indicators[i] != NULL
+ && (iev->changed & 1 << i)) {
+ gint state =
+ (iev->
+ state & 1 << i) !=
+ FALSE;
+
+ if ((state
+ && !drawing->
+ physical_indicators
+ [i]->on) || (!state
+ &&
+ drawing->
+ physical_indicators
+ [i]->
+ on)) {
+ drawing->
+ physical_indicators
+ [i]->on =
+ state;
+ draw_doodad
+ (drawing,
+ drawing->
+ physical_indicators
+ [i]);
+ invalidate_indicator_doodad_region
+ (drawing,
+ drawing->
+ physical_indicators
+ [i]);
+ }
+ }
+ }
+ break;
+
+ case XkbIndicatorMapNotify:
+ case XkbControlsNotify:
+ case XkbNamesNotify:
+ case XkbNewKeyboardNotify:
+ {
+ XkbStateRec state;
+ memset (&state, 0, sizeof (state));
+ XkbGetState (drawing->display,
+ XkbUseCoreKbd, &state);
+ if (drawing->track_modifiers)
+ gkb_keyboard_drawing_set_mods
+ (drawing, state.compat_state);
+ if (drawing->track_config)
+ gkb_keyboard_drawing_set_keyboard
+ (drawing, NULL);
+ }
+ break;
+ }
+ }
+
+ return GDK_FILTER_CONTINUE;
+}
+
+static void
+destroy (GkbKeyboardDrawing * drawing)
+{
+ free_pango_layout (drawing);
+ gdk_window_remove_filter (NULL, (GdkFilterFunc)
+ xkb_state_notify_event_filter, drawing);
+ if (drawing->timeout > 0) {
+ g_source_remove (drawing->timeout);
+ drawing->timeout = 0;
+ }
+
+ g_object_unref (drawing->pixmap);
+}
+
+static void
+style_changed (GkbKeyboardDrawing * drawing)
+{
+ pango_layout_context_changed (drawing->layout);
+}
+
+static void
+gkb_keyboard_drawing_init (GkbKeyboardDrawing * drawing)
+{
+ gint opcode = 0, error = 0, major = 1, minor = 0;
+ gint mask;
+
+ drawing->display =
+ GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
+ printf ("dpy: %p\n", drawing->display);
+
+ if (!XkbQueryExtension
+ (drawing->display, &opcode, &drawing->xkb_event_type, &error,
+ &major, &minor))
+ g_critical
+ ("XkbQueryExtension failed! Stuff probably won't work.");
+
+ printf ("evt/error/major/minor: %d/%d/%d/%d\n",
+ drawing->xkb_event_type, error, major, minor);
+
+ /* XXX: this stuff probably doesn't matter.. also, gdk_screen_get_default can fail */
+ if (gtk_widget_has_screen (GTK_WIDGET (drawing)))
+ drawing->screen_num =
+ gdk_screen_get_number (gtk_widget_get_screen
+ (GTK_WIDGET (drawing)));
+ else
+ drawing->screen_num =
+ gdk_screen_get_number (gdk_screen_get_default ());
+
+ drawing->pixmap = NULL;
+ alloc_pango_layout (drawing);
+
+ drawing->font_desc =
+ pango_font_description_copy (GTK_WIDGET (drawing)->style->
+ font_desc);
+ drawing->keyboard_items = NULL;
+ drawing->colors = NULL;
+ drawing->angle = 0;
+ drawing->scale_numerator = 1;
+ drawing->scale_denominator = 1;
+
+ drawing->track_modifiers = 0;
+ drawing->track_config = 0;
+
+ gtk_widget_set_double_buffered (GTK_WIDGET (drawing), FALSE);
+
+ /* XXX: XkbClientMapMask | XkbIndicatorMapMask | XkbNamesMask | XkbGeometryMask */
+ drawing->xkb = XkbGetKeyboard (drawing->display,
+ XkbGBN_GeometryMask |
+ XkbGBN_KeyNamesMask |
+ XkbGBN_OtherNamesMask |
+ XkbGBN_SymbolsMask |
+ XkbGBN_IndicatorMapMask,
+ XkbUseCoreKbd);
+ if (drawing->xkb == NULL) {
+ g_critical
+ ("XkbGetKeyboard failed to get keyboard from the server!");
+ return;
+ }
+
+ XkbGetNames (drawing->display, XkbAllNamesMask, drawing->xkb);
+
+ drawing->xkbOnDisplay = TRUE;
+
+ alloc_cdik (drawing);
+
+ XkbSelectEventDetails (drawing->display, XkbUseCoreKbd,
+ XkbIndicatorStateNotify,
+ drawing->xkb->indicators->phys_indicators,
+ drawing->xkb->indicators->phys_indicators);
+
+ mask =
+ (XkbStateNotifyMask | XkbNamesNotifyMask |
+ XkbControlsNotifyMask | XkbIndicatorMapNotifyMask |
+ XkbNewKeyboardNotifyMask);
+ XkbSelectEvents (drawing->display, XkbUseCoreKbd, mask, mask);
+
+ mask = XkbGroupStateMask | XkbModifierStateMask;
+ XkbSelectEventDetails (drawing->display, XkbUseCoreKbd,
+ XkbStateNotify, mask, mask);
+
+ mask = (XkbGroupNamesMask | XkbIndicatorNamesMask);
+ XkbSelectEventDetails (drawing->display, XkbUseCoreKbd,
+ XkbNamesNotify, mask, mask);
+ init_keys_and_doodads (drawing);
+ init_colors (drawing);
+
+ /* required to get key events */
+ GTK_WIDGET_SET_FLAGS (GTK_WIDGET (drawing), GTK_CAN_FOCUS);
+
+ gtk_widget_set_events (GTK_WIDGET (drawing),
+ GDK_EXPOSURE_MASK | GDK_KEY_PRESS_MASK |
+ GDK_KEY_RELEASE_MASK | GDK_BUTTON_PRESS_MASK
+ | GDK_FOCUS_CHANGE_MASK);
+ g_signal_connect (G_OBJECT (drawing), "expose-event",
+ G_CALLBACK (expose_event), drawing);
+ g_signal_connect (G_OBJECT (drawing), "key-press-event",
+ G_CALLBACK (key_event), drawing);
+ g_signal_connect (G_OBJECT (drawing), "key-release-event",
+ G_CALLBACK (key_event), drawing);
+ g_signal_connect (G_OBJECT (drawing), "button-press-event",
+ G_CALLBACK (button_press_event), drawing);
+ g_signal_connect (G_OBJECT (drawing), "focus-out-event",
+ G_CALLBACK (focus_event), drawing);
+ g_signal_connect (G_OBJECT (drawing), "focus-in-event",
+ G_CALLBACK (focus_event), drawing);
+ g_signal_connect (G_OBJECT (drawing), "size-allocate",
+ G_CALLBACK (size_allocate), drawing);
+ g_signal_connect (G_OBJECT (drawing), "destroy",
+ G_CALLBACK (destroy), drawing);
+ g_signal_connect (G_OBJECT (drawing), "style-set",
+ G_CALLBACK (style_changed), drawing);
+
+ gdk_window_add_filter (NULL, (GdkFilterFunc)
+ xkb_state_notify_event_filter, drawing);
+}
+
+GtkWidget *
+gkb_keyboard_drawing_new (void)
+{
+ return
+ GTK_WIDGET (g_object_new
+ (gkb_keyboard_drawing_get_type (), NULL));
+}
+
+static void
+gkb_keyboard_drawing_class_init (GkbKeyboardDrawingClass * klass)
+{
+ klass->bad_keycode = NULL;
+
+ gkb_keyboard_drawing_signals[BAD_KEYCODE] =
+ g_signal_new ("bad-keycode", gkb_keyboard_drawing_get_type (),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GkbKeyboardDrawingClass,
+ bad_keycode), NULL, NULL,
+ gkb_keyboard_drawing_VOID__UINT, G_TYPE_NONE, 1,
+ G_TYPE_UINT);
+}
+
+GType
+gkb_keyboard_drawing_get_type (void)
+{
+ static GType gkb_keyboard_drawing_type = 0;
+
+ if (!gkb_keyboard_drawing_type) {
+ static const GTypeInfo gkb_keyboard_drawing_info = {
+ sizeof (GkbKeyboardDrawingClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) gkb_keyboard_drawing_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (GkbKeyboardDrawing),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) gkb_keyboard_drawing_init,
+ };
+
+ gkb_keyboard_drawing_type =
+ g_type_register_static (GTK_TYPE_DRAWING_AREA,
+ "GkbKeyboardDrawing",
+ &gkb_keyboard_drawing_info, 0);
+ }
+
+ return gkb_keyboard_drawing_type;
+}
+
+void
+gkb_keyboard_drawing_set_mods (GkbKeyboardDrawing * drawing, guint mods)
+{
+#ifdef KBDRAW_DEBUG
+ printf ("set_mods: %d\n", mods);
+#endif
+ if (mods != drawing->mods) {
+ drawing->mods = mods;
+ gtk_widget_queue_draw (GTK_WIDGET (drawing));
+ }
+}
+
+/* returns a pixbuf with the keyboard drawing at the current pixel size
+ * (which can then be saved to disk, etc) */
+GdkPixbuf *
+gkb_keyboard_drawing_get_pixbuf (GkbKeyboardDrawing * drawing)
+{
+ if (drawing->pixmap == NULL)
+ draw_keyboard (drawing);
+
+ return gdk_pixbuf_get_from_drawable (NULL, drawing->pixmap, NULL,
+ 0, 0, 0, 0,
+ xkb_to_pixmap_coord (drawing,
+ drawing->
+ xkb->
+ geom->
+ width_mm),
+ xkb_to_pixmap_coord (drawing,
+ drawing->
+ xkb->
+ geom->
+ height_mm));
+}
+
+gboolean
+gkb_keyboard_drawing_set_keyboard (GkbKeyboardDrawing * drawing,
+ XkbComponentNamesRec * names)
+{
+ free_cdik (drawing);
+ if (drawing->xkb)
+ XkbFreeKeyboard (drawing->xkb, 0, TRUE); /* free_all = TRUE */
+ drawing->xkb = NULL;
+
+ if (names) {
+ drawing->xkb =
+ XkbGetKeyboardByName (drawing->display, XkbUseCoreKbd,
+ names, 0,
+ XkbGBN_GeometryMask |
+ XkbGBN_KeyNamesMask |
+ XkbGBN_OtherNamesMask |
+ XkbGBN_ClientSymbolsMask |
+ XkbGBN_IndicatorMapMask, FALSE);
+ drawing->xkbOnDisplay = FALSE;
+ } else {
+ drawing->xkb = XkbGetKeyboard (drawing->display,
+ XkbGBN_GeometryMask |
+ XkbGBN_KeyNamesMask |
+ XkbGBN_OtherNamesMask |
+ XkbGBN_SymbolsMask |
+ XkbGBN_IndicatorMapMask,
+ XkbUseCoreKbd);
+ XkbGetNames (drawing->display, XkbAllNamesMask,
+ drawing->xkb);
+ drawing->xkbOnDisplay = TRUE;
+ }
+
+ if (drawing->xkb == NULL)
+ return FALSE;
+
+ alloc_cdik (drawing);
+
+ init_keys_and_doodads (drawing);
+ init_colors (drawing);
+
+ size_allocate (GTK_WIDGET (drawing),
+ &(GTK_WIDGET (drawing)->allocation), drawing);
+ gtk_widget_queue_draw (GTK_WIDGET (drawing));
+
+ return TRUE;
+}
+
+G_CONST_RETURN gchar *
+gkb_keyboard_drawing_get_keycodes (GkbKeyboardDrawing * drawing)
+{
+ if (!drawing->xkb || drawing->xkb->names->keycodes <= 0)
+ return NULL;
+ else
+ return XGetAtomName (drawing->display,
+ drawing->xkb->names->keycodes);
+}
+
+G_CONST_RETURN gchar *
+gkb_keyboard_drawing_get_geometry (GkbKeyboardDrawing * drawing)
+{
+ if (!drawing->xkb || drawing->xkb->names->geometry <= 0)
+ return NULL;
+ else
+ return XGetAtomName (drawing->display,
+ drawing->xkb->names->geometry);
+}
+
+G_CONST_RETURN gchar *
+gkb_keyboard_drawing_get_symbols (GkbKeyboardDrawing * drawing)
+{
+ if (!drawing->xkb || drawing->xkb->names->symbols <= 0)
+ return NULL;
+ else
+ return XGetAtomName (drawing->display,
+ drawing->xkb->names->symbols);
+}
+
+G_CONST_RETURN gchar *
+gkb_keyboard_drawing_get_types (GkbKeyboardDrawing * drawing)
+{
+ if (!drawing->xkb || drawing->xkb->names->types <= 0)
+ return NULL;
+ else
+ return XGetAtomName (drawing->display,
+ drawing->xkb->names->types);
+}
+
+G_CONST_RETURN gchar *
+gkb_keyboard_drawing_get_compat (GkbKeyboardDrawing * drawing)
+{
+ if (!drawing->xkb || drawing->xkb->names->compat <= 0)
+ return NULL;
+ else
+ return XGetAtomName (drawing->display,
+ drawing->xkb->names->compat);
+}
+
+void
+gkb_keyboard_drawing_set_track_modifiers (GkbKeyboardDrawing * drawing,
+ gboolean enable)
+{
+ if (enable) {
+ XkbStateRec state;
+ drawing->track_modifiers = 1;
+ memset (&state, 0, sizeof (state));
+ XkbGetState (drawing->display, XkbUseCoreKbd, &state);
+ gkb_keyboard_drawing_set_mods (drawing,
+ state.compat_state);
+ } else
+ drawing->track_modifiers = 0;
+}
+
+void
+gkb_keyboard_drawing_set_track_config (GkbKeyboardDrawing * drawing,
+ gboolean enable)
+{
+ if (enable)
+ drawing->track_config = 1;
+ else
+ drawing->track_config = 0;
+}
+
+void
+gkb_keyboard_drawing_set_groups_levels (GkbKeyboardDrawing * drawing,
+ GkbKeyboardDrawingGroupLevel *
+ groupLevels[])
+{
+#ifdef KBDRAW_DEBUG
+ printf ("set_group_levels [topLeft]: %d %d \n",
+ groupLevels[GKB_KEYBOARD_DRAWING_POS_TOPLEFT]->group,
+ groupLevels[GKB_KEYBOARD_DRAWING_POS_TOPLEFT]->level);
+ printf ("set_group_levels [topRight]: %d %d \n",
+ groupLevels[GKB_KEYBOARD_DRAWING_POS_TOPRIGHT]->group,
+ groupLevels[GKB_KEYBOARD_DRAWING_POS_TOPRIGHT]->level);
+ printf ("set_group_levels [bottomLeft]: %d %d \n",
+ groupLevels[GKB_KEYBOARD_DRAWING_POS_BOTTOMLEFT]->group,
+ groupLevels[GKB_KEYBOARD_DRAWING_POS_BOTTOMLEFT]->level);
+ printf ("set_group_levels [bottomRight]: %d %d \n",
+ groupLevels[GKB_KEYBOARD_DRAWING_POS_BOTTOMRIGHT]->group,
+ groupLevels[GKB_KEYBOARD_DRAWING_POS_BOTTOMRIGHT]->level);
+#endif
+ drawing->groupLevels = groupLevels;
+
+ gtk_widget_queue_draw (GTK_WIDGET (drawing));
+}
diff --git a/libgnomekbd/backup/gkb-keyboard-drawing.h b/libgnomekbd/backup/gkb-keyboard-drawing.h
new file mode 100644
index 0000000..253de33
--- /dev/null
+++ b/libgnomekbd/backup/gkb-keyboard-drawing.h
@@ -0,0 +1,185 @@
+/* $Id$ */
+/*
+ * keyboard-drawing.h: header file for a gtk+ widget that is a drawing of
+ * the keyboard of the default display
+ *
+ * Copyright (c) 2003 Noah Levitt
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef GKB_KEYBOARD_DRAWING_H
+#define GKB_KEYBOARD_DRAWING_H 1
+
+#include <gtk/gtk.h>
+#include <X11/XKBlib.h>
+#include <X11/extensions/XKBgeom.h>
+
+G_BEGIN_DECLS
+#define GKB_KEYBOARD_DRAWING(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), gkb_keyboard_drawing_get_type (), \
+ GkbKeyboardDrawing))
+#define GKB_KEYBOARD_DRAWING_CLASS(clazz) (G_TYPE_CHECK_CLASS_CAST ((clazz), gkb_keyboard_drawing_get_type () \
+ GkbKeyboardDrawingClass))
+#define GKB_IS_KEYBOARD_DRAWING(obj) G_TYPE_CHECK_INSTANCE_TYPE ((obj), gkb_keyboard_drawing_get_type ())
+typedef struct _GkbKeyboardDrawing GkbKeyboardDrawing;
+typedef struct _GkbKeyboardDrawingClass GkbKeyboardDrawingClass;
+
+typedef struct _GkbKeyboardDrawingItem GkbKeyboardDrawingItem;
+typedef struct _GkbKeyboardDrawingKey GkbKeyboardDrawingKey;
+typedef struct _GkbKeyboardDrawingDoodad GkbKeyboardDrawingDoodad;
+typedef struct _GkbKeyboardDrawingGroupLevel GkbKeyboardDrawingGroupLevel;
+
+typedef enum {
+ GKB_KEYBOARD_DRAWING_ITEM_TYPE_KEY,
+ GKB_KEYBOARD_DRAWING_ITEM_TYPE_DOODAD
+} GkbKeyboardDrawingItemType;
+
+typedef enum {
+ GKB_KEYBOARD_DRAWING_POS_TOPLEFT,
+ GKB_KEYBOARD_DRAWING_POS_TOPRIGHT,
+ GKB_KEYBOARD_DRAWING_POS_BOTTOMLEFT,
+ GKB_KEYBOARD_DRAWING_POS_BOTTOMRIGHT,
+ GKB_KEYBOARD_DRAWING_POS_TOTAL,
+ GKB_KEYBOARD_DRAWING_POS_FIRST = GKB_KEYBOARD_DRAWING_POS_TOPLEFT,
+ GKB_KEYBOARD_DRAWING_POS_LAST =
+ GKB_KEYBOARD_DRAWING_POS_BOTTOMRIGHT,
+} GkbKeyboardDrawingGroupLevelPosition;
+
+/* units are in xkb form */
+struct _GkbKeyboardDrawingItem {
+ /*< private > */
+
+ GkbKeyboardDrawingItemType type;
+ gint origin_x;
+ gint origin_y;
+ gint angle;
+ guint priority;
+};
+
+/* units are in xkb form */
+struct _GkbKeyboardDrawingKey {
+ /*< private > */
+
+ GkbKeyboardDrawingItemType type;
+ gint origin_x;
+ gint origin_y;
+ gint angle;
+ guint priority;
+
+ XkbKeyRec *xkbkey;
+ gboolean pressed;
+ guint keycode;
+};
+
+/* units are in xkb form */
+struct _GkbKeyboardDrawingDoodad {
+ /*< private > */
+
+ GkbKeyboardDrawingItemType type;
+ gint origin_x;
+ gint origin_y;
+ gint angle;
+ guint priority;
+
+ XkbDoodadRec *doodad;
+ gboolean on; /* for indicator doodads */
+};
+
+struct _GkbKeyboardDrawingGroupLevel {
+ gint group;
+ gint level;
+};
+
+struct _GkbKeyboardDrawing {
+ /*< private > */
+
+ GtkDrawingArea parent;
+
+ GdkPixmap *pixmap;
+ XkbDescRec *xkb;
+ gboolean xkbOnDisplay;
+
+ gint angle; /* current angle pango is set to draw at, in tenths of a degree */
+ PangoLayout *layout;
+ PangoFontDescription *font_desc;
+
+ gint scale_numerator;
+ gint scale_denominator;
+
+ GkbKeyboardDrawingKey *keys;
+
+ /* list of stuff to draw in priority order */
+ GList *keyboard_items;
+
+ GdkColor *colors;
+
+ guint timeout;
+
+ GkbKeyboardDrawingGroupLevel **groupLevels;
+
+ guint mods;
+
+ Display *display;
+ gint screen_num;
+
+ gint xkb_event_type;
+
+ GkbKeyboardDrawingDoodad **physical_indicators;
+ gint physical_indicators_size;
+
+ guint track_config:1;
+ guint track_modifiers:1;
+};
+
+struct _GkbKeyboardDrawingClass {
+ GtkDrawingAreaClass parent_class;
+
+ /* we send this signal when the user presses a key that "doesn't exist"
+ * according to the keyboard geometry; it probably means their xkb
+ * configuration is incorrect */
+ void (*bad_keycode) (GkbKeyboardDrawing * drawing, guint keycode);
+};
+
+GType gkb_keyboard_drawing_get_type (void);
+GtkWidget *gkb_keyboard_drawing_new (void);
+
+GdkPixbuf *gkb_keyboard_drawing_get_pixbuf (GkbKeyboardDrawing *
+ kbdrawing);
+gboolean gkb_keyboard_drawing_set_keyboard (GkbKeyboardDrawing * kbdrawing,
+ XkbComponentNamesRec * names);
+
+G_CONST_RETURN gchar *gkb_keyboard_drawing_get_keycodes (GkbKeyboardDrawing
+ * kbdrawing);
+G_CONST_RETURN gchar *gkb_keyboard_drawing_get_geometry (GkbKeyboardDrawing
+ * kbdrawing);
+G_CONST_RETURN gchar *gkb_keyboard_drawing_get_symbols (GkbKeyboardDrawing
+ * kbdrawing);
+G_CONST_RETURN gchar *gkb_keyboard_drawing_get_types (GkbKeyboardDrawing *
+ kbdrawing);
+G_CONST_RETURN gchar *gkb_keyboard_drawing_get_compat (GkbKeyboardDrawing *
+ kbdrawing);
+
+void gkb_keyboard_drawing_set_track_modifiers (GkbKeyboardDrawing *
+ kbdrawing, gboolean enable);
+void gkb_keyboard_drawing_set_track_config (GkbKeyboardDrawing * kbdrawing,
+ gboolean enable);
+
+void gkb_keyboard_drawing_set_groups_levels (GkbKeyboardDrawing *
+ kbdrawing,
+ GkbKeyboardDrawingGroupLevel *
+ groupLevels[]);
+
+G_END_DECLS
+#endif /* #ifndef GKB_KEYBOARD_DRAWING_H */
diff --git a/libgnomekbd/backup/gkb-util.c b/libgnomekbd/backup/gkb-util.c
new file mode 100644
index 0000000..845e0bf
--- /dev/null
+++ b/libgnomekbd/backup/gkb-util.c
@@ -0,0 +1,149 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include <gkb-util.h>
+
+#include <time.h>
+
+#include <glib/gi18n.h>
+#include <gtk/gtkmessagedialog.h>
+
+#include <libxklavier/xklavier.h>
+
+#include <gconf/gconf-client.h>
+
+#include <gkb-config-private.h>
+
+static void
+gkb_log_appender (const char file[], const char function[],
+ int level, const char format[], va_list args)
+{
+ time_t now = time (NULL);
+ g_log (NULL, G_LOG_LEVEL_DEBUG, "[%08ld,%03d,%s:%s/] \t",
+ (long) now, level, file, function);
+ g_logv (NULL, G_LOG_LEVEL_DEBUG, format, args);
+}
+
+void
+gkb_install_glib_log_appender (void)
+{
+ xkl_set_log_appender (gkb_log_appender);
+}
+
+#define GKB_PREVIEW_CONFIG_KEY_PREFIX GKB_CONFIG_KEY_PREFIX "/preview"
+
+const gchar GKB_PREVIEW_CONFIG_DIR[] = GKB_PREVIEW_CONFIG_KEY_PREFIX;
+const gchar GKB_PREVIEW_CONFIG_KEY_X[] =
+ GKB_PREVIEW_CONFIG_KEY_PREFIX "/x";
+const gchar GKB_PREVIEW_CONFIG_KEY_Y[] =
+ GKB_PREVIEW_CONFIG_KEY_PREFIX "/y";
+const gchar GKB_PREVIEW_CONFIG_KEY_WIDTH[] =
+ GKB_PREVIEW_CONFIG_KEY_PREFIX "/width";
+const gchar GKB_PREVIEW_CONFIG_KEY_HEIGHT[] =
+ GKB_PREVIEW_CONFIG_KEY_PREFIX "/height";
+
+GdkRectangle *
+gkb_preview_load_position (void)
+{
+ GError *gerror = NULL;
+ GdkRectangle *rv = NULL;
+ gint x, y, w, h;
+ GConfClient *conf_client = gconf_client_get_default ();
+
+ if (conf_client == NULL)
+ return NULL;
+
+ x = gconf_client_get_int (conf_client,
+ GKB_PREVIEW_CONFIG_KEY_X, &gerror);
+ if (gerror != NULL) {
+ xkl_debug (0, "Error getting the preview x: %s\n",
+ gerror->message);
+ g_error_free (gerror);
+ g_object_unref (G_OBJECT (conf_client));
+ return NULL;
+ }
+
+ y = gconf_client_get_int (conf_client,
+ GKB_PREVIEW_CONFIG_KEY_Y, &gerror);
+ if (gerror != NULL) {
+ xkl_debug (0, "Error getting the preview y: %s\n",
+ gerror->message);
+ g_error_free (gerror);
+ g_object_unref (G_OBJECT (conf_client));
+ return NULL;
+ }
+
+ w = gconf_client_get_int (conf_client,
+ GKB_PREVIEW_CONFIG_KEY_WIDTH, &gerror);
+ if (gerror != NULL) {
+ xkl_debug (0, "Error getting the preview width: %s\n",
+ gerror->message);
+ g_error_free (gerror);
+ g_object_unref (G_OBJECT (conf_client));
+ return NULL;
+ }
+
+ h = gconf_client_get_int (conf_client,
+ GKB_PREVIEW_CONFIG_KEY_HEIGHT, &gerror);
+ if (gerror != NULL) {
+ xkl_debug (0, "Error getting the preview height: %s\n",
+ gerror->message);
+ g_error_free (gerror);
+ g_object_unref (G_OBJECT (conf_client));
+ return NULL;
+ }
+
+ g_object_unref (G_OBJECT (conf_client));
+
+ // default values should be just ignored
+ if (x == -1 || y == -1 || w == -1 || h == -1)
+ return NULL;
+
+ rv = g_new (GdkRectangle, 1);
+ rv->x = x;
+ rv->y = y;
+ rv->width = w;
+ rv->height = h;
+ return rv;
+}
+
+void
+gkb_preview_save_position (GdkRectangle * rect)
+{
+ GConfClient *conf_client = gconf_client_get_default ();
+ GConfChangeSet *cs;
+ GError *gerror = NULL;
+
+ cs = gconf_change_set_new ();
+
+ gconf_change_set_set_int (cs, GKB_PREVIEW_CONFIG_KEY_X, rect->x);
+ gconf_change_set_set_int (cs, GKB_PREVIEW_CONFIG_KEY_Y, rect->y);
+ gconf_change_set_set_int (cs, GKB_PREVIEW_CONFIG_KEY_WIDTH,
+ rect->width);
+ gconf_change_set_set_int (cs, GKB_PREVIEW_CONFIG_KEY_HEIGHT,
+ rect->height);
+
+ gconf_client_commit_change_set (conf_client, cs, TRUE, &gerror);
+ if (gerror != NULL) {
+ g_warning ("Error saving preview configuration: %s\n",
+ gerror->message);
+ g_error_free (gerror);
+ }
+ gconf_change_set_unref (cs);
+ g_object_unref (G_OBJECT (conf_client));
+}
diff --git a/libgnomekbd/backup/gkb-util.h b/libgnomekbd/backup/gkb-util.h
new file mode 100644
index 0000000..e441656
--- /dev/null
+++ b/libgnomekbd/backup/gkb-util.h
@@ -0,0 +1,30 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GKB_UTIL_H__
+#define __GKB_UTIL_H__
+
+#include <glib.h>
+#include <gtk/gtkwidget.h>
+
+extern void gkb_install_glib_log_appender (void);
+
+extern GdkRectangle *gkb_preview_load_position (void);
+
+extern void gkb_preview_save_position (GdkRectangle * rect);
+
+
+#endif
diff --git a/libgnomekbd/desktop_gnome_peripherals_keyboard_xkb.schemas.in b/libgnomekbd/desktop_gnome_peripherals_keyboard_xkb.schemas.in
new file mode 100644
index 0000000..1a917e6
--- /dev/null
+++ b/libgnomekbd/desktop_gnome_peripherals_keyboard_xkb.schemas.in
@@ -0,0 +1,193 @@
+<?xml version="1.0"?>
+<gconfschemafile>
+ <schemalist>
+ <schema>
+ <key>/schemas/desktop/gnome/peripherals/keyboard/kbd/overrideSettings</key>
+ <applyto>/desktop/gnome/peripherals/keyboard/kbd/overrideSettings</applyto>
+ <owner>gnome</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Keyboard settings in gconf will be overridden from the system ASAP (deprecated)</short>
+ <long>Very soon, keyboard settings in gconf will be overridden (from the system configuration)
+ This key has been deprecated since GNOME 2.12, please unset the model, layouts and
+ options keys to get the default system configuration.</long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/desktop/gnome/peripherals/keyboard/kbd/model</key>
+ <applyto>/desktop/gnome/peripherals/keyboard/kbd/model</applyto>
+ <owner>gnome</owner>
+ <type>string</type>
+ <default></default>
+ <locale name="C">
+ <short>Keyboard model</short>
+ <long>keyboard model</long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/desktop/gnome/peripherals/keyboard/kbd/layouts</key>
+ <applyto>/desktop/gnome/peripherals/keyboard/kbd/layouts</applyto>
+ <owner>gnome</owner>
+ <type>list</type>
+ <list_type>string</list_type>
+ <default>[]</default>
+ <locale name="C">
+ <short>Keyboard layout</short>
+ <long>keyboard layout</long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/desktop/gnome/peripherals/keyboard/kbd/options</key>
+ <applyto>/desktop/gnome/peripherals/keyboard/kbd/options</applyto>
+ <owner>gnome</owner>
+ <type>list</type>
+ <list_type>string</list_type>
+ <default>[]</default>
+ <locale name="C">
+ <short>Keyboard options</short>
+ <long>Keyboard options</long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/desktop/gnome/peripherals/keyboard/general/update_handlers</key>
+ <applyto>/desktop/gnome/peripherals/keyboard/general/update_handlers</applyto>
+ <owner>gnome</owner>
+ <type>list</type>
+ <list_type>string</list_type>
+ <default>[]</default>
+ <locale name="C">
+ <short>Keyboard Update Handlers</short>
+ <long>A collection of scripts to run whenever the keyboard state is
+ reloaded. Useful for re-applying xmodmap based adjustments</long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/desktop/gnome/peripherals/keyboard/general/known_file_list</key>
+ <applyto>/desktop/gnome/peripherals/keyboard/general/known_file_list</applyto>
+ <owner>gnome</owner>
+ <type>list</type>
+ <list_type>string</list_type>
+ <default>[]</default>
+ <locale name="C">
+ <short>modmap file list</short>
+ <long>A list of modmap files available in the $HOME directory.</long>
+ </locale>
+ </schema>
+
+
+ <schema>
+ <key>/schemas/desktop/gnome/peripherals/keyboard/general/defaultGroup</key>
+ <applyto>/desktop/gnome/peripherals/keyboard/general/defaultGroup</applyto>
+ <owner>gnome</owner>
+ <type>int</type>
+ <default>-1</default>
+ <locale name="C">
+ <short>Default group, assigned on window creation</short>
+ <long>Default group, assigned on window creation</long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/desktop/gnome/peripherals/keyboard/general/groupPerWindow</key>
+ <applyto>/desktop/gnome/peripherals/keyboard/general/groupPerWindow</applyto>
+ <owner>gnome</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Keep and manage separate group per window</short>
+ <long>Keep and manage separate group per window</long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/desktop/gnome/peripherals/keyboard/general/handleIndicators</key>
+ <applyto>/desktop/gnome/peripherals/keyboard/general/handleIndicators</applyto>
+ <owner>gnome</owner>
+ <type>bool</type>
+ <default>false</default>
+ <locale name="C">
+ <short>Save/restore indicators together with layout groups</short>
+ <long>Save/restore indicators together with layout groups</long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/desktop/gnome/peripherals/keyboard/general/layoutNamesAsGroupNames</key>
+ <applyto>/desktop/gnome/peripherals/keyboard/general/layoutNamesAsGroupNames</applyto>
+ <owner>gnome</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Show layout names instead of group names</short>
+ <long>Show layout names instead of group names (only for versions of XFree supporting multiple layouts)</long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/desktop/gnome/peripherals/keyboard/general/disable_sysconfig_changed_warning</key>
+ <applyto>/desktop/gnome/peripherals/keyboard/general/disable_sysconfig_changed_warning</applyto>
+ <owner>gnome</owner>
+ <type>bool</type>
+ <default>false</default>
+ <locale name="C">
+ <short>Suppress the "X sysconfig changed" warning message</short>
+ <long>Suppress the "X sysconfig changed" warning message</long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/gswitchit/preview/x</key>
+ <applyto>/apps/gswitchit/preview/x</applyto>
+ <owner>gnome</owner>
+ <type>int</type>
+ <default>-1</default>
+ <locale name="C">
+ <short>The Keyboard Preview, X offset</short>
+ <long>The Keyboard Preview, X offset</long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/gswitchit/preview/y</key>
+ <applyto>/apps/gswitchit/preview/y</applyto>
+ <owner>gnome</owner>
+ <type>int</type>
+ <default>-1</default>
+ <locale name="C">
+ <short>The Keyboard Preview, Y offset</short>
+ <long>The Keyboard Preview, Y offset</long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/gswitchit/preview/width</key>
+ <applyto>/apps/gswitchit/preview/width</applyto>
+ <owner>gnome</owner>
+ <type>int</type>
+ <default>-1</default>
+ <locale name="C">
+ <short>The Keyboard Preview, width</short>
+ <long>The Keyboard Preview, width</long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/gswitchit/preview/height</key>
+ <applyto>/apps/gswitchit/preview/height</applyto>
+ <owner>gnome</owner>
+ <type>int</type>
+ <default>-1</default>
+ <locale name="C">
+ <short>The Keyboard Preview, height</short>
+ <long>The Keyboard Preview, height</long>
+ </locale>
+ </schema>
+
+ </schemalist>
+</gconfschemafile>
diff --git a/libgnomekbd/gkbd-config-private.h b/libgnomekbd/gkbd-config-private.h
new file mode 100644
index 0000000..998a34b
--- /dev/null
+++ b/libgnomekbd/gkbd-config-private.h
@@ -0,0 +1,99 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GKBD_CONFIG_PRIVATE_H__
+#define __GKBD_CONFIG_PRIVATE_H__
+
+#include "libgnomekbd/gkbd-desktop-config.h"
+#include "libgnomekbd/gkbd-keyboard-config.h"
+
+#define GKBD_CONFIG_KEY_PREFIX "/desktop/gnome/peripherals/keyboard"
+
+extern const gchar GKBD_PREVIEW_CONFIG_DIR[];
+extern const gchar GKBD_PREVIEW_CONFIG_KEY_X[];
+extern const gchar GKBD_PREVIEW_CONFIG_KEY_Y[];
+extern const gchar GKBD_PREVIEW_CONFIG_KEY_WIDTH[];
+extern const gchar GKBD_PREVIEW_CONFIG_KEY_HEIGHT[];
+
+/**
+ * General config functions (private)
+ */
+extern void
+ gkbd_desktop_config_add_listener (GConfClient * conf_client,
+ const gchar * key,
+ GConfClientNotifyFunc func,
+ gpointer user_data, int *pid);
+
+
+extern void
+ gkbd_desktop_config_remove_listener (GConfClient * conf_client, int *pid);
+
+extern void gkbd_keyboard_config_model_set (GkbdKeyboardConfig *
+ kbd_config,
+ const gchar * model_name);
+
+extern void gkbd_keyboard_config_layouts_reset (GkbdKeyboardConfig *
+ kbd_config);
+extern void gkbd_keyboard_config_layouts_add (GkbdKeyboardConfig *
+ kbd_config,
+ const gchar * layout_name,
+ const gchar * variant_name);
+
+extern void gkbd_keyboard_config_layouts_reset (GkbdKeyboardConfig *
+ kbd_config);
+extern void gkbd_keyboard_config_options_reset (GkbdKeyboardConfig *
+ kbd_config);
+
+extern void gkbd_keyboard_config_options_add (GkbdKeyboardConfig *
+ kbd_config,
+ const gchar * group_name,
+ const gchar * option_name);
+extern gboolean gkbd_keyboard_config_options_is_set (GkbdKeyboardConfig *
+ kbd_config,
+ const gchar *
+ group_name,
+ const gchar *
+ option_name);
+
+extern gboolean gkbd_keyboard_config_dump_settings (GkbdKeyboardConfig *
+ kbd_config,
+ const char *file_name);
+
+extern void gkbd_keyboard_config_start_listen (GkbdKeyboardConfig *
+ kbd_config,
+ GConfClientNotifyFunc func,
+ gpointer user_data);
+
+extern void gkbd_keyboard_config_stop_listen (GkbdKeyboardConfig *
+ kbd_config);
+
+extern gboolean gkbd_keyboard_config_get_lv_descriptions (XklConfigRegistry
+ *
+ config_registry,
+ const gchar *
+ layout_name,
+ const gchar *
+ variant_name,
+ gchar **
+ layout_short_descr,
+ gchar **
+ layout_descr,
+ gchar **
+ variant_short_descr,
+ gchar **
+ variant_descr);
+
+#endif
diff --git a/libgnomekbd/gkbd-config-registry.c b/libgnomekbd/gkbd-config-registry.c
new file mode 100644
index 0000000..60dce84
--- /dev/null
+++ b/libgnomekbd/gkbd-config-registry.c
@@ -0,0 +1,166 @@
+#include <config.h>
+
+#include <X11/Xlib.h>
+
+#include <gkbd-config-registry.h>
+#include <gkbd-config-registry-server.h>
+#include <gkbd-keyboard-config.h>
+
+static GObjectClass *parent_class = NULL;
+
+gboolean
+ gkbd_config_registry_get_current_descriptions_as_utf8
+ (GkbdConfigRegistry * registry,
+ gchar *** short_layout_descriptions,
+ gchar *** long_layout_descriptions,
+ gchar *** short_variant_descriptions,
+ gchar *** long_variant_descriptions, GError ** error) {
+ XklConfigRec *xkl_config;
+ char **pl, **pv;
+ guint total_layouts;
+ gchar **sld, **lld, **svd, **lvd;
+
+ if (!registry->registry) {
+ registry->registry =
+ xkl_config_registry_get_instance (registry->engine);
+
+ xkl_config_registry_load (registry->registry);
+ }
+
+ if (!
+ (xkl_engine_get_features (registry->engine) &
+ XKLF_MULTIPLE_LAYOUTS_SUPPORTED))
+ return FALSE;
+
+ xkl_config = xkl_config_rec_new ();
+
+ if (!xkl_config_rec_get_from_server (xkl_config, registry->engine))
+ return FALSE;
+
+ pl = xkl_config->layouts;
+ pv = xkl_config->variants;
+ total_layouts = g_strv_length (xkl_config->layouts);
+ sld = *short_layout_descriptions =
+ g_new0 (char *, total_layouts + 1);
+ lld = *long_layout_descriptions =
+ g_new0 (char *, total_layouts + 1);
+ svd = *short_variant_descriptions =
+ g_new0 (char *, total_layouts + 1);
+ lvd = *long_variant_descriptions =
+ g_new0 (char *, total_layouts + 1);
+
+ while (pl != NULL && *pl != NULL) {
+ XklConfigItem item;
+
+ g_snprintf (item.name, sizeof item.name, "%s", *pl);
+ if (xkl_config_registry_find_layout
+ (registry->registry, &item)) {
+ *sld++ = g_strdup (item.short_description);
+ *lld++ = g_strdup (item.description);
+ } else {
+ *sld++ = g_strdup ("");
+ *lld++ = g_strdup ("");
+ }
+
+ if (*pv != NULL) {
+ g_snprintf (item.name, sizeof item.name, "%s",
+ *pv);
+ if (xkl_config_registry_find_variant
+ (registry->registry, *pl, &item)) {
+ *svd = g_strdup (item.short_description);
+ *lvd = g_strdup (item.description);
+ } else {
+ *svd++ = g_strdup ("");
+ *lvd++ = g_strdup ("");
+ }
+ } else {
+ *svd++ = g_strdup ("");
+ *lvd++ = g_strdup ("");
+ }
+
+ pl++;
+ pv++;
+ }
+ g_object_unref (G_OBJECT (xkl_config));
+
+ return TRUE;
+}
+
+G_DEFINE_TYPE (GkbdConfigRegistry, gkbd_config_registry, G_TYPE_OBJECT)
+static void
+finalize (GObject * object)
+{
+ GkbdConfigRegistry *registry;
+
+ registry = GKBD_CONFIG_REGISTRY (object);
+ if (registry->registry == NULL) {
+ return;
+ }
+
+ g_object_unref (registry->registry);
+ registry->registry = NULL;
+
+ g_object_unref (registry->engine);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gkbd_config_registry_class_init (GkbdConfigRegistryClass * klass)
+{
+ GError *error = NULL;
+ GObjectClass *object_class;
+
+ /* Init the DBus connection, per-klass */
+ klass->connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+ if (klass->connection == NULL) {
+ g_warning ("Unable to connect to dbus: %s",
+ error->message);
+ g_error_free (error);
+ return;
+ }
+
+ dbus_g_object_type_install_info (GKBD_CONFIG_TYPE_REGISTRY,
+ &dbus_glib_gkbd_config_registry_object_info);
+
+ object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = finalize;
+
+ parent_class = g_type_class_peek_parent (klass);
+}
+
+static void
+gkbd_config_registry_init (GkbdConfigRegistry * registry)
+{
+ GError *error = NULL;
+ DBusGProxy *driver_proxy;
+ GkbdConfigRegistryClass *klass =
+ GKBD_CONFIG_REGISTRY_GET_CLASS (registry);
+ unsigned request_ret;
+
+ /* Register DBUS path */
+ dbus_g_connection_register_g_object (klass->connection,
+ "/org/gnome/GkbdConfigRegistry",
+ G_OBJECT (registry));
+
+ /* Register the service name, the constant here are defined in dbus-glib-bindings.h */
+ driver_proxy = dbus_g_proxy_new_for_name (klass->connection,
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS);
+
+ if (!org_freedesktop_DBus_request_name
+ (driver_proxy, "org.gnome.GkbdConfigRegistry", 0,
+ &request_ret, &error)) {
+ g_warning ("Unable to register service: %s",
+ error->message);
+ g_error_free (error);
+ }
+ g_object_unref (driver_proxy);
+
+ /* Init libxklavier stuff */
+ registry->engine = xkl_engine_get_instance (XOpenDisplay (NULL));
+ /* Lazy initialization */
+ registry->registry = NULL;
+}
diff --git a/libgnomekbd/gkbd-config-registry.h b/libgnomekbd/gkbd-config-registry.h
new file mode 100644
index 0000000..c55f5f0
--- /dev/null
+++ b/libgnomekbd/gkbd-config-registry.h
@@ -0,0 +1,44 @@
+#ifndef __GKBD_CONFIG_REGISTRY_H__
+#define __GKBD_CONFIG_REGISTRY_H__
+
+#include <dbus/dbus-glib-bindings.h>
+#include <libxklavier/xklavier.h>
+
+typedef struct GkbdConfigRegistry GkbdConfigRegistry;
+typedef struct GkbdConfigRegistryClass GkbdConfigRegistryClass;
+
+struct GkbdConfigRegistry {
+ GObject parent;
+
+ XklEngine *engine;
+ XklConfigRegistry *registry;
+};
+
+struct GkbdConfigRegistryClass {
+ GObjectClass parent;
+ DBusGConnection *connection;
+};
+
+#define GKBD_CONFIG_TYPE_REGISTRY (gkbd_config_registry_get_type ())
+#define GKBD_CONFIG_REGISTRY(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GKBD_CONFIG_TYPE_REGISTRY, GkbdConfigRegistry))
+#define GKBD_CONFIG_REGISTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GKBD_CONFIG_TYPE_REGISTRY, GkbdConfigRegistryClass))
+#define GKBD_IS_CONFIG_REGISTRY(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GKBD_CONFIG_TYPE_REGISTRY))
+#define GKBD_IS_CONFIG_REGISTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GKBD_CONFIG_TYPE_REGISTRY))
+#define GKBD_CONFIG_REGISTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GKBD_CONFIG_TYPE_REGISTRY, GkbdConfigRegistryClass))
+
+
+/**
+ * DBUS server
+ */
+
+extern GType gkbd_config_registry_get_type (void);
+
+extern gboolean
+ gkbd_config_registry_get_current_descriptions_as_utf8
+ (GkbdConfigRegistry * registry,
+ gchar *** short_layout_descriptions,
+ gchar *** long_layout_descriptions,
+ gchar *** short_variant_descriptions,
+ gchar *** long_variant_descriptions, GError ** error);
+
+#endif
diff --git a/libgnomekbd/gkbd-config-registry.xml b/libgnomekbd/gkbd-config-registry.xml
new file mode 100644
index 0000000..32c4380
--- /dev/null
+++ b/libgnomekbd/gkbd-config-registry.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<node name="/org/gnome/GkbdConfigRegistry">
+ <interface name="org.gnome.GkbdConfigRegistry">
+ <annotation name="org.freedesktop.DBus.GLib.CSymbol" value="gkbd_config_registry"/>
+ <method name="GetCurrentDescriptionsAsUtf8">
+ <arg type="as" name="shortLayoutDescriptions" direction="out" />
+ <arg type="as" name="longLayoutDescriptions" direction="out" />
+ <arg type="as" name="shortVariantDescriptions" direction="out" />
+ <arg type="as" name="longVariantDescriptions" direction="out" />
+ </method>
+ <!-- Add more methods/signals if you want -->
+ </interface>
+</node>
diff --git a/libgnomekbd/gkbd-desktop-config.c b/libgnomekbd/gkbd-desktop-config.c
new file mode 100644
index 0000000..06db6eb
--- /dev/null
+++ b/libgnomekbd/gkbd-desktop-config.c
@@ -0,0 +1,400 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <X11/keysym.h>
+
+#include <glib/gi18n.h>
+#include <libgnome/gnome-program.h>
+
+#include <gkbd-desktop-config.h>
+#include <gkbd-config-private.h>
+
+#include <gkbd-config-registry-client.h>
+
+/**
+ * GkbdDesktopConfig
+ */
+#define GKBD_DESKTOP_CONFIG_KEY_PREFIX GKBD_CONFIG_KEY_PREFIX "/general"
+
+const gchar GKBD_DESKTOP_CONFIG_DIR[] = GKBD_DESKTOP_CONFIG_KEY_PREFIX;
+const gchar GKBD_DESKTOP_CONFIG_KEY_DEFAULT_GROUP[] =
+ GKBD_DESKTOP_CONFIG_KEY_PREFIX "/defaultGroup";
+const gchar GKBD_DESKTOP_CONFIG_KEY_GROUP_PER_WINDOW[] =
+ GKBD_DESKTOP_CONFIG_KEY_PREFIX "/groupPerWindow";
+const gchar GKBD_DESKTOP_CONFIG_KEY_HANDLE_INDICATORS[] =
+ GKBD_DESKTOP_CONFIG_KEY_PREFIX "/handleIndicators";
+const gchar GKBD_DESKTOP_CONFIG_KEY_LAYOUT_NAMES_AS_GROUP_NAMES[]
+ = GKBD_DESKTOP_CONFIG_KEY_PREFIX "/layoutNamesAsGroupNames";
+
+/**
+ * static common functions
+ */
+
+static gboolean
+gkbd_desktop_config_get_remote_lv_descriptions_utf8 (gchar *** sld,
+ gchar *** lld,
+ gchar *** svd,
+ gchar *** lvd)
+{
+ DBusGProxy *proxy;
+ DBusGConnection *connection;
+ GError *error = NULL;
+
+ connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+ if (connection == NULL) {
+ g_warning ("Unable to connect to dbus: %s\n",
+ error->message);
+ g_error_free (error);
+ /* Basically here, there is a problem, since there is no dbus :) */
+ return False;
+ }
+
+/* This won't trigger activation! */
+ proxy = dbus_g_proxy_new_for_name (connection,
+ "org.gnome.GkbdConfigRegistry",
+ "/org/gnome/GkbdConfigRegistry",
+ "org.gnome.GkbdConfigRegistry");
+
+/* The method call will trigger activation, more on that later */
+ if (!org_gnome_GkbdConfigRegistry_get_current_descriptions_as_utf8
+ (proxy, sld, lld, svd, lvd, &error)) {
+ /* Method failed, the GError is set, let's warn everyone */
+ g_warning ("Woops remote method failed: %s",
+ error->message);
+ g_error_free (error);
+ return False;
+ }
+ return True;
+}
+
+void
+gkbd_desktop_config_add_listener (GConfClient * conf_client,
+ const gchar * key,
+ GConfClientNotifyFunc func,
+ gpointer user_data, int *pid)
+{
+ GError *gerror = NULL;
+ xkl_debug (150, "Listening to [%s]\n", key);
+ *pid = gconf_client_notify_add (conf_client,
+ key, func, user_data, NULL,
+ &gerror);
+ if (0 == *pid) {
+ g_warning ("Error listening for configuration: [%s]\n",
+ gerror->message);
+ g_error_free (gerror);
+ }
+}
+
+void
+gkbd_desktop_config_remove_listener (GConfClient * conf_client, int *pid)
+{
+ if (*pid != 0) {
+ gconf_client_notify_remove (conf_client, *pid);
+ *pid = 0;
+ }
+}
+
+/**
+ * extern GkbdDesktopConfig config functions
+ */
+void
+gkbd_desktop_config_init (GkbdDesktopConfig * config,
+ GConfClient * conf_client, XklEngine * engine)
+{
+ GError *gerror = NULL;
+
+ memset (config, 0, sizeof (*config));
+ config->conf_client = conf_client;
+ config->engine = engine;
+ g_object_ref (config->conf_client);
+
+ gconf_client_add_dir (config->conf_client,
+ GKBD_DESKTOP_CONFIG_DIR,
+ GCONF_CLIENT_PRELOAD_NONE, &gerror);
+ if (gerror != NULL) {
+ g_warning ("err: %s\n", gerror->message);
+ g_error_free (gerror);
+ gerror = NULL;
+ }
+}
+
+void
+gkbd_desktop_config_term (GkbdDesktopConfig * config)
+{
+ g_object_unref (config->conf_client);
+ config->conf_client = NULL;
+}
+
+void
+gkbd_desktop_config_load_from_gconf (GkbdDesktopConfig * config)
+{
+ GError *gerror = NULL;
+
+ config->group_per_app =
+ gconf_client_get_bool (config->conf_client,
+ GKBD_DESKTOP_CONFIG_KEY_GROUP_PER_WINDOW,
+ &gerror);
+ if (gerror != NULL) {
+ g_warning ("Error reading configuration:%s\n",
+ gerror->message);
+ config->group_per_app = FALSE;
+ g_error_free (gerror);
+ gerror = NULL;
+ }
+ xkl_debug (150, "group_per_app: %d\n", config->group_per_app);
+
+ config->handle_indicators =
+ gconf_client_get_bool (config->conf_client,
+ GKBD_DESKTOP_CONFIG_KEY_HANDLE_INDICATORS,
+ &gerror);
+ if (gerror != NULL) {
+ g_warning ("Error reading configuration:%s\n",
+ gerror->message);
+ config->handle_indicators = FALSE;
+ g_error_free (gerror);
+ gerror = NULL;
+ }
+ xkl_debug (150, "handle_indicators: %d\n",
+ config->handle_indicators);
+
+ config->layout_names_as_group_names =
+ gconf_client_get_bool (config->conf_client,
+ GKBD_DESKTOP_CONFIG_KEY_LAYOUT_NAMES_AS_GROUP_NAMES,
+ &gerror);
+ if (gerror != NULL) {
+ g_warning ("Error reading configuration:%s\n",
+ gerror->message);
+ config->layout_names_as_group_names = TRUE;
+ g_error_free (gerror);
+ gerror = NULL;
+ }
+ xkl_debug (150, "layout_names_as_group_names: %d\n",
+ config->layout_names_as_group_names);
+
+ config->default_group =
+ gconf_client_get_int (config->conf_client,
+ GKBD_DESKTOP_CONFIG_KEY_DEFAULT_GROUP,
+ &gerror);
+ if (gerror != NULL) {
+ g_warning ("Error reading configuration:%s\n",
+ gerror->message);
+ config->default_group = -1;
+ g_error_free (gerror);
+ gerror = NULL;
+ }
+
+ if (config->default_group < -1
+ || config->default_group >=
+ xkl_engine_get_max_num_groups (config->engine))
+ config->default_group = -1;
+ xkl_debug (150, "default_group: %d\n", config->default_group);
+}
+
+void
+gkbd_desktop_config_save_to_gconf (GkbdDesktopConfig * config)
+{
+ GConfChangeSet *cs;
+ GError *gerror = NULL;
+
+ cs = gconf_change_set_new ();
+
+ gconf_change_set_set_bool (cs,
+ GKBD_DESKTOP_CONFIG_KEY_GROUP_PER_WINDOW,
+ config->group_per_app);
+ gconf_change_set_set_bool (cs,
+ GKBD_DESKTOP_CONFIG_KEY_HANDLE_INDICATORS,
+ config->handle_indicators);
+ gconf_change_set_set_bool (cs,
+ GKBD_DESKTOP_CONFIG_KEY_LAYOUT_NAMES_AS_GROUP_NAMES,
+ config->layout_names_as_group_names);
+ gconf_change_set_set_int (cs,
+ GKBD_DESKTOP_CONFIG_KEY_DEFAULT_GROUP,
+ config->default_group);
+
+ gconf_client_commit_change_set (config->conf_client, cs, TRUE,
+ &gerror);
+ if (gerror != NULL) {
+ g_warning ("Error saving active configuration: %s\n",
+ gerror->message);
+ g_error_free (gerror);
+ gerror = NULL;
+ }
+ gconf_change_set_unref (cs);
+}
+
+gboolean
+gkbd_desktop_config_activate (GkbdDesktopConfig * config)
+{
+ gboolean rv = TRUE;
+
+ xkl_engine_set_group_per_toplevel_window (config->engine,
+ config->group_per_app);
+ xkl_engine_set_indicators_handling (config->engine,
+ config->handle_indicators);
+ xkl_engine_set_default_group (config->engine,
+ config->default_group);
+
+ return rv;
+}
+
+void
+gkbd_desktop_config_lock_next_group (GkbdDesktopConfig * config)
+{
+ int group = xkl_engine_get_next_group (config->engine);
+ xkl_engine_lock_group (config->engine, group);
+}
+
+void
+gkbd_desktop_config_lock_prev_group (GkbdDesktopConfig * config)
+{
+ int group = xkl_engine_get_prev_group (config->engine);
+ xkl_engine_lock_group (config->engine, group);
+}
+
+void
+gkbd_desktop_config_restore_group (GkbdDesktopConfig * config)
+{
+ int group = xkl_engine_get_current_window_group (config->engine);
+ xkl_engine_lock_group (config->engine, group);
+}
+
+void
+gkbd_desktop_config_start_listen (GkbdDesktopConfig * config,
+ GConfClientNotifyFunc func,
+ gpointer user_data)
+{
+ gkbd_desktop_config_add_listener (config->conf_client,
+ GKBD_DESKTOP_CONFIG_DIR, func,
+ user_data,
+ &config->config_listener_id);
+}
+
+void
+gkbd_desktop_config_stop_listen (GkbdDesktopConfig * config)
+{
+ gkbd_desktop_config_remove_listener (config->conf_client,
+ &config->config_listener_id);
+}
+
+gboolean
+gkbd_desktop_config_load_remote_group_descriptions_utf8 (GkbdDesktopConfig
+ * config,
+ gchar ***
+ short_group_names,
+ gchar ***
+ full_group_names)
+{
+ gchar **sld, **lld, **svd, **lvd;
+ gchar **psld, **plld, **plvd;
+ gchar **psgn, **pfgn;
+ gint total_descriptions;
+
+ if (!gkbd_desktop_config_get_remote_lv_descriptions_utf8
+ (&sld, &lld, &svd, &lvd)) {
+ return False;
+ }
+
+ total_descriptions = g_strv_length (sld);
+
+ *short_group_names = psgn =
+ g_new0 (gchar *, total_descriptions + 1);
+ *full_group_names = pfgn =
+ g_new0 (gchar *, total_descriptions + 1);
+
+ plld = lld;
+ psld = sld;
+ plvd = lvd;
+ while (plld != NULL && *plld != NULL) {
+ *psgn++ = g_strdup (*psld++);
+ *pfgn++ = g_strdup (gkbd_keyboard_config_format_full_layout
+ (*plld++, *plvd++));
+ }
+ g_strfreev (sld);
+ g_strfreev (lld);
+ g_strfreev (svd);
+ g_strfreev (lvd);
+
+ return True;
+}
+
+gchar **
+gkbd_desktop_config_load_group_descriptions_utf8 (GkbdDesktopConfig *
+ config,
+ XklConfigRegistry *
+ config_registry)
+{
+ int i;
+ const gchar **native_names =
+ xkl_engine_get_groups_names (config->engine);
+ guint total_groups = xkl_engine_get_num_groups (config->engine);
+ guint total_layouts;
+ gchar **rv = g_new0 (char *, total_groups + 1);
+ gchar **current_descr = rv;
+
+ if ((xkl_engine_get_features (config->engine) &
+ XKLF_MULTIPLE_LAYOUTS_SUPPORTED)
+ && config->layout_names_as_group_names) {
+ XklConfigRec *xkl_config = xkl_config_rec_new ();
+ if (xkl_config_rec_get_from_server
+ (xkl_config, config->engine)) {
+ char **pl = xkl_config->layouts;
+ char **pv = xkl_config->variants;
+ i = total_groups;
+ while (pl != NULL && *pl != NULL && i >= 0) {
+ char *ls_descr;
+ char *l_descr;
+ char *vs_descr;
+ char *v_descr;
+ if (gkbd_keyboard_config_get_lv_descriptions (config_registry, *pl++, *pv++, &ls_descr, &l_descr, &vs_descr, &v_descr)) {
+ char *name_utf =
+ g_locale_to_utf8
+ (gkbd_keyboard_config_format_full_layout
+ (l_descr, v_descr), -1, NULL,
+ NULL, NULL);
+ *current_descr++ = name_utf;
+ } else {
+ *current_descr++ = g_strdup ("");
+ }
+ }
+ }
+ g_object_unref (G_OBJECT (xkl_config));
+ /* Worst case - multiple layous - but SOME of them are multigrouped :(((
+ * We cannot do much - just add empty descriptions.
+ * The UI is going to be messy.
+ * Canadian layouts are famous for this sh.t. */
+ total_layouts = g_strv_length (rv);
+ if (total_layouts != total_groups) {
+ xkl_debug (0,
+ "The mismatch between "
+ "the number of groups: %d and number of layouts: %d\n",
+ total_groups, total_layouts);
+ current_descr = rv + total_layouts;
+ for (i = total_groups - total_layouts; --i >= 0;)
+ *current_descr++ = g_strdup ("");
+ }
+ }
+ total_layouts = g_strv_length (rv);
+ if (!total_layouts)
+ for (i = total_groups; --i >= 0;)
+ *current_descr++ = g_strdup (*native_names++);
+
+ return rv;
+}
diff --git a/libgnomekbd/gkbd-desktop-config.h b/libgnomekbd/gkbd-desktop-config.h
new file mode 100644
index 0000000..3ca5519
--- /dev/null
+++ b/libgnomekbd/gkbd-desktop-config.h
@@ -0,0 +1,97 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GKBD_DESKTOP_CONFIG_H__
+#define __GKBD_DESKTOP_CONFIG_H__
+
+#include <X11/Xlib.h>
+
+#include <glib.h>
+#include <glib/gslist.h>
+
+#include <gconf/gconf-client.h>
+
+#include <libxklavier/xklavier.h>
+
+extern const gchar GKBD_DESKTOP_CONFIG_DIR[];
+extern const gchar GKBD_DESKTOP_CONFIG_KEY_DEFAULT_GROUP[];
+extern const gchar GKBD_DESKTOP_CONFIG_KEY_GROUP_PER_WINDOW[];
+extern const gchar GKBD_DESKTOP_CONFIG_KEY_HANDLE_INDICATORS[];
+extern const gchar GKBD_DESKTOP_CONFIG_KEY_LAYOUT_NAMES_AS_GROUP_NAMES[];
+
+/*
+ * General configuration
+ */
+typedef struct _GkbdDesktopConfig {
+ gint default_group;
+ gboolean group_per_app;
+ gboolean handle_indicators;
+ gboolean layout_names_as_group_names;
+
+ /* private, transient */
+ GConfClient *conf_client;
+ int config_listener_id;
+ XklEngine *engine;
+} GkbdDesktopConfig;
+
+/**
+ * GkbdDesktopConfig functions
+ */
+extern void gkbd_desktop_config_init (GkbdDesktopConfig * config,
+ GConfClient * conf_client,
+ XklEngine * engine);
+extern void gkbd_desktop_config_term (GkbdDesktopConfig * config);
+
+extern void gkbd_desktop_config_load_from_gconf (GkbdDesktopConfig *
+ config);
+
+extern void gkbd_desktop_config_save_to_gconf (GkbdDesktopConfig * config);
+
+extern gboolean gkbd_desktop_config_activate (GkbdDesktopConfig * config);
+
+/* Affected by XKB and XKB/GConf configuration */
+extern gchar
+ **
+gkbd_desktop_config_load_group_descriptions_utf8 (GkbdDesktopConfig *
+ config,
+ XklConfigRegistry *
+ config_registry);
+
+
+/* Using DBUS */
+extern gboolean
+gkbd_desktop_config_load_remote_group_descriptions_utf8 (GkbdDesktopConfig
+ * config,
+ gchar ***
+ short_group_names,
+ gchar ***
+ full_group_names);
+
+extern void gkbd_desktop_config_lock_next_group (GkbdDesktopConfig *
+ config);
+
+extern void gkbd_desktop_config_lock_prev_group (GkbdDesktopConfig *
+ config);
+
+extern void gkbd_desktop_config_restore_group (GkbdDesktopConfig * config);
+
+extern void gkbd_desktop_config_start_listen (GkbdDesktopConfig * config,
+ GConfClientNotifyFunc func,
+ gpointer user_data);
+
+extern void gkbd_desktop_config_stop_listen (GkbdDesktopConfig * config);
+
+#endif
diff --git a/libgnomekbd/gkbd-indicator-config.c b/libgnomekbd/gkbd-indicator-config.c
new file mode 100644
index 0000000..381c671
--- /dev/null
+++ b/libgnomekbd/gkbd-indicator-config.c
@@ -0,0 +1,361 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <X11/keysym.h>
+
+#include <glib/gi18n.h>
+#include <gdk/gdkx.h>
+#include <libgnome/gnome-program.h>
+
+#include <gkbd-keyboard-config.h>
+#include <gkbd-indicator-config.h>
+
+#include <gkbd-config-private.h>
+
+#include <gkbd-config-registry-client.h>
+
+/**
+ * GkbdIndicatorConfig
+ */
+#define GKBD_INDICATOR_CONFIG_KEY_PREFIX GKBD_CONFIG_KEY_PREFIX "/indicator"
+
+const gchar GKBD_INDICATOR_CONFIG_DIR[] = GKBD_INDICATOR_CONFIG_KEY_PREFIX;
+const gchar GKBD_INDICATOR_CONFIG_KEY_SHOW_FLAGS[] =
+ GKBD_INDICATOR_CONFIG_KEY_PREFIX "/showFlags";
+const gchar GKBD_INDICATOR_CONFIG_KEY_ENABLED_PLUGINS[] =
+ GKBD_INDICATOR_CONFIG_KEY_PREFIX "/enabledPlugins";
+const gchar GKBD_INDICATOR_CONFIG_KEY_SECONDARIES[] =
+ GKBD_INDICATOR_CONFIG_KEY_PREFIX "/secondary";
+
+/**
+ * static applet config functions
+ */
+static void
+gkbd_indicator_config_free_enabled_plugins (GkbdIndicatorConfig *
+ ind_config)
+{
+ GSList *plugin_node = ind_config->enabled_plugins;
+ if (plugin_node != NULL) {
+ do {
+ if (plugin_node->data != NULL) {
+ g_free (plugin_node->data);
+ plugin_node->data = NULL;
+ }
+ plugin_node = g_slist_next (plugin_node);
+ } while (plugin_node != NULL);
+ g_slist_free (ind_config->enabled_plugins);
+ ind_config->enabled_plugins = NULL;
+ }
+}
+
+/**
+ * extern applet kbdConfig functions
+ */
+void
+gkbd_indicator_config_free_images (GkbdIndicatorConfig * ind_config)
+{
+ GdkPixbuf *pi;
+ GSList *img_node;
+ while ((img_node = ind_config->images) != NULL) {
+ pi = GDK_PIXBUF (img_node->data);
+ /* It can be NULL - some images may be missing */
+ if (pi != NULL) {
+ gdk_pixbuf_unref (pi);
+ }
+ ind_config->images =
+ g_slist_remove_link (ind_config->images, img_node);
+ g_slist_free_1 (img_node);
+ }
+}
+
+char *
+gkbd_indicator_config_get_images_file (GkbdIndicatorConfig *
+ ind_config,
+ GkbdKeyboardConfig *
+ kbd_config, int group)
+{
+ char *image_file = NULL;
+ GtkIconInfo *icon_info = NULL;
+
+ if (!ind_config->show_flags)
+ return NULL;
+
+ if ((kbd_config->layouts != NULL) &&
+ (g_slist_length (kbd_config->layouts) > group)) {
+ char *full_layout_name =
+ (char *) g_slist_nth_data (kbd_config->layouts, group);
+
+ if (full_layout_name != NULL) {
+ char *l, *v;
+ gkbd_keyboard_config_split_items (full_layout_name,
+ &l, &v);
+ if (l != NULL) {
+ // probably there is something in theme?
+ icon_info = gtk_icon_theme_lookup_icon
+ (ind_config->icon_theme, l, 48, 0);
+ }
+ }
+ }
+ // fallback to the default value
+ if (icon_info == NULL) {
+ icon_info = gtk_icon_theme_lookup_icon
+ (ind_config->icon_theme, "stock_dialog-error", 48, 0);
+ }
+ if (icon_info != NULL) {
+ image_file =
+ g_strdup (gtk_icon_info_get_filename (icon_info));
+ gtk_icon_info_free (icon_info);
+ }
+
+ return image_file;
+}
+
+void
+gkbd_indicator_config_load_images (GkbdIndicatorConfig * ind_config,
+ GkbdKeyboardConfig * kbd_config)
+{
+ int i;
+ ind_config->images = NULL;
+
+ if (!ind_config->show_flags)
+ return;
+
+ for (i = xkl_engine_get_max_num_groups (ind_config->engine);
+ --i >= 0;) {
+ GdkPixbuf *image = NULL;
+ char *image_file =
+ gkbd_indicator_config_get_images_file (ind_config,
+ kbd_config,
+ i);
+
+ if (image_file != NULL) {
+ GError *gerror = NULL;
+ image =
+ gdk_pixbuf_new_from_file (image_file, &gerror);
+ if (image == NULL) {
+ GtkWidget *dialog =
+ gtk_message_dialog_new (NULL,
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _
+ ("There was an error loading an image: %s"),
+ gerror->
+ message);
+ g_signal_connect (G_OBJECT (dialog),
+ "response",
+ G_CALLBACK
+ (gtk_widget_destroy),
+ NULL);
+
+ gtk_window_set_resizable (GTK_WINDOW
+ (dialog), FALSE);
+
+ gtk_widget_show (dialog);
+ g_error_free (gerror);
+ }
+ xkl_debug (150,
+ "Image %d[%s] loaded -> %p[%dx%d]\n",
+ i, image_file, image,
+ gdk_pixbuf_get_width (image),
+ gdk_pixbuf_get_height (image));
+ g_free (image_file);
+ }
+ /* We append the image anyway - even if it is NULL! */
+ ind_config->images =
+ g_slist_prepend (ind_config->images, image);
+ }
+}
+
+void
+gkbd_indicator_config_init (GkbdIndicatorConfig * ind_config,
+ GConfClient * conf_client, XklEngine * engine)
+{
+ GError *gerror = NULL;
+ gchar *sp, *datadir;
+
+ memset (ind_config, 0, sizeof (*ind_config));
+ ind_config->conf_client = conf_client;
+ ind_config->engine = engine;
+ g_object_ref (ind_config->conf_client);
+
+ gconf_client_add_dir (ind_config->conf_client,
+ GKBD_INDICATOR_CONFIG_DIR,
+ GCONF_CLIENT_PRELOAD_NONE, &gerror);
+ if (gerror != NULL) {
+ g_warning ("err1:%s\n", gerror->message);
+ g_error_free (gerror);
+ gerror = NULL;
+ }
+
+ ind_config->icon_theme = gtk_icon_theme_get_default ();
+
+ datadir =
+ gnome_program_locate_file (NULL, GNOME_FILE_DOMAIN_APP_DATADIR,
+ "", FALSE, NULL);
+ gtk_icon_theme_append_search_path (ind_config->icon_theme, sp =
+ g_build_filename (g_get_home_dir
+ (),
+ ".icons/flags",
+ NULL));
+ g_free (sp);
+
+ gtk_icon_theme_append_search_path (ind_config->icon_theme,
+ sp =
+ g_build_filename (datadir,
+ "pixmaps/flags",
+ NULL));
+ g_free (sp);
+
+ gtk_icon_theme_append_search_path (ind_config->icon_theme,
+ sp =
+ g_build_filename (datadir,
+ "icons/flags",
+ NULL));
+ g_free (sp);
+ g_free (datadir);
+}
+
+void
+gkbd_indicator_config_term (GkbdIndicatorConfig * ind_config)
+{
+#if 0
+ g_object_unref (G_OBJECT (ind_config->icon_theme));
+#endif
+ ind_config->icon_theme = NULL;
+
+ gkbd_indicator_config_free_images (ind_config);
+
+ gkbd_indicator_config_free_enabled_plugins (ind_config);
+ g_object_unref (ind_config->conf_client);
+ ind_config->conf_client = NULL;
+}
+
+void
+gkbd_indicator_config_update_images (GkbdIndicatorConfig *
+ ind_config,
+ GkbdKeyboardConfig * kbd_config)
+{
+ gkbd_indicator_config_free_images (ind_config);
+ gkbd_indicator_config_load_images (ind_config, kbd_config);
+}
+
+void
+gkbd_indicator_config_load_from_gconf (GkbdIndicatorConfig * ind_config)
+{
+ GError *gerror = NULL;
+
+ ind_config->secondary_groups_mask =
+ gconf_client_get_int (ind_config->conf_client,
+ GKBD_INDICATOR_CONFIG_KEY_SECONDARIES,
+ &gerror);
+ if (gerror != NULL) {
+ g_warning ("Error reading configuration:%s\n",
+ gerror->message);
+ ind_config->secondary_groups_mask = 0;
+ g_error_free (gerror);
+ gerror = NULL;
+ }
+
+ ind_config->show_flags =
+ gconf_client_get_bool (ind_config->conf_client,
+ GKBD_INDICATOR_CONFIG_KEY_SHOW_FLAGS,
+ &gerror);
+ if (gerror != NULL) {
+ g_warning ("Error reading kbdConfiguration:%s\n",
+ gerror->message);
+ ind_config->show_flags = FALSE;
+ g_error_free (gerror);
+ gerror = NULL;
+ }
+
+ gkbd_indicator_config_free_enabled_plugins (ind_config);
+ ind_config->enabled_plugins =
+ gconf_client_get_list (ind_config->conf_client,
+ GKBD_INDICATOR_CONFIG_KEY_ENABLED_PLUGINS,
+ GCONF_VALUE_STRING, &gerror);
+
+ if (gerror != NULL) {
+ g_warning ("Error reading kbd_configuration:%s\n",
+ gerror->message);
+ ind_config->enabled_plugins = NULL;
+ g_error_free (gerror);
+ gerror = NULL;
+ }
+}
+
+void
+gkbd_indicator_config_save_to_gconf (GkbdIndicatorConfig * ind_config)
+{
+ GConfChangeSet *cs;
+ GError *gerror = NULL;
+
+ cs = gconf_change_set_new ();
+
+ gconf_change_set_set_int (cs,
+ GKBD_INDICATOR_CONFIG_KEY_SECONDARIES,
+ ind_config->secondary_groups_mask);
+ gconf_change_set_set_bool (cs,
+ GKBD_INDICATOR_CONFIG_KEY_SHOW_FLAGS,
+ ind_config->show_flags);
+ gconf_change_set_set_list (cs,
+ GKBD_INDICATOR_CONFIG_KEY_ENABLED_PLUGINS,
+ GCONF_VALUE_STRING,
+ ind_config->enabled_plugins);
+
+ gconf_client_commit_change_set (ind_config->conf_client, cs,
+ TRUE, &gerror);
+ if (gerror != NULL) {
+ g_warning ("Error saving configuration: %s\n",
+ gerror->message);
+ g_error_free (gerror);
+ gerror = NULL;
+ }
+ gconf_change_set_unref (cs);
+}
+
+void
+gkbd_indicator_config_activate (GkbdIndicatorConfig * ind_config)
+{
+ xkl_engine_set_secondary_groups_mask (ind_config->engine,
+ ind_config->
+ secondary_groups_mask);
+}
+
+void
+gkbd_indicator_config_start_listen (GkbdIndicatorConfig *
+ ind_config,
+ GConfClientNotifyFunc func,
+ gpointer user_data)
+{
+ gkbd_desktop_config_add_listener (ind_config->conf_client,
+ GKBD_INDICATOR_CONFIG_DIR, func,
+ user_data,
+ &ind_config->config_listener_id);
+}
+
+void
+gkbd_indicator_config_stop_listen (GkbdIndicatorConfig * ind_config)
+{
+ gkbd_desktop_config_remove_listener (ind_config->conf_client,
+ &ind_config->
+ config_listener_id);
+}
diff --git a/libgnomekbd/gkbd-indicator-config.h b/libgnomekbd/gkbd-indicator-config.h
new file mode 100644
index 0000000..e497e0e
--- /dev/null
+++ b/libgnomekbd/gkbd-indicator-config.h
@@ -0,0 +1,89 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GKBD_INDICATOR_CONFIG_H__
+#define __GKBD_INDICATOR_CONFIG_H__
+
+#include <gtk/gtk.h>
+
+#include "libgnomekbd/gkbd-keyboard-config.h"
+
+/*
+ * Indicator configuration
+ */
+typedef struct _GkbdIndicatorConfig {
+ int secondary_groups_mask;
+ gboolean show_flags;
+
+ GSList *enabled_plugins;
+
+ /* private, transient */
+ GConfClient *conf_client;
+ GSList *images;
+ GtkIconTheme *icon_theme;
+ int config_listener_id;
+ XklEngine *engine;
+} GkbdIndicatorConfig;
+
+/**
+ * GkbdIndicatorConfig functions -
+ * some of them require GkbdKeyboardConfig as well -
+ * for loading approptiate images
+ */
+extern void gkbd_indicator_config_init (GkbdIndicatorConfig *
+ applet_config,
+ GConfClient * conf_client,
+ XklEngine * engine);
+extern void gkbd_indicator_config_term (GkbdIndicatorConfig *
+ applet_config);
+
+extern void gkbd_indicator_config_load_from_gconf (GkbdIndicatorConfig
+ * applet_config);
+extern void gkbd_indicator_config_save_to_gconf (GkbdIndicatorConfig *
+ applet_config);
+
+extern gchar
+ * gkbd_indicator_config_get_images_file (GkbdIndicatorConfig *
+ applet_config,
+ GkbdKeyboardConfig *
+ kbd_config, int group);
+
+extern void gkbd_indicator_config_load_images (GkbdIndicatorConfig *
+ applet_config,
+ GkbdKeyboardConfig *
+ kbd_config);
+extern void gkbd_indicator_config_free_images (GkbdIndicatorConfig *
+ applet_config);
+
+/* Should be updated on Indicator/GConf and Kbd/GConf configuration change */
+extern void gkbd_indicator_config_update_images (GkbdIndicatorConfig *
+ applet_config,
+ GkbdKeyboardConfig *
+ kbd_config);
+
+/* Should be updated on Indicator/GConf configuration change */
+extern void gkbd_indicator_config_activate (GkbdIndicatorConfig *
+ applet_config);
+
+extern void gkbd_indicator_config_start_listen (GkbdIndicatorConfig *
+ applet_config,
+ GConfClientNotifyFunc
+ func, gpointer user_data);
+
+extern void gkbd_indicator_config_stop_listen (GkbdIndicatorConfig *
+ applet_config);
+
+#endif
diff --git a/libgnomekbd/gkbd-indicator-marshal.list b/libgnomekbd/gkbd-indicator-marshal.list
new file mode 100644
index 0000000..5b76282
--- /dev/null
+++ b/libgnomekbd/gkbd-indicator-marshal.list
@@ -0,0 +1 @@
+VOID:VOID
diff --git a/libgnomekbd/gkbd-indicator-plugin-manager.c b/libgnomekbd/gkbd-indicator-plugin-manager.c
new file mode 100644
index 0000000..e59ef77
--- /dev/null
+++ b/libgnomekbd/gkbd-indicator-plugin-manager.c
@@ -0,0 +1,404 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <libxklavier/xklavier.h>
+
+#include <gkbd-indicator-plugin-manager.h>
+
+#define FOREACH_INITED_PLUGIN() \
+{ \
+ GSList *prec; \
+ for( prec = manager->inited_plugin_recs; prec != NULL; prec = prec->next ) \
+ { \
+ const GkbdIndicatorPlugin *plugin = \
+ ( ( GkbdIndicatorPluginManagerRecord * ) ( prec->data ) )->plugin; \
+ if( plugin != NULL ) \
+ {
+
+#define NEXT_INITED_PLUGIN() \
+ } \
+ } \
+}
+
+static void
+gkbd_indicator_plugin_manager_add_plugins_dir (GkbdIndicatorPluginManager *
+ manager,
+ const char *dirname)
+{
+ GDir *dir = g_dir_open (dirname, 0, NULL);
+ const gchar *filename;
+ if (dir == NULL)
+ return;
+
+ xkl_debug (100, "Scanning [%s]...\n", dirname);
+ while ((filename = g_dir_read_name (dir)) != NULL) {
+ gchar *full_path =
+ g_build_filename (dirname, filename, NULL);
+ xkl_debug (100, "Loading plugin module [%s]...\n",
+ full_path);
+ if (full_path != NULL) {
+ GModule *module = g_module_open (full_path, 0);
+ if (module != NULL) {
+ gpointer get_plugin_func;
+ if (g_module_symbol
+ (module, "GetPlugin",
+ &get_plugin_func)) {
+ const GkbdIndicatorPlugin *plugin =
+ ((GkbdIndicatorPluginGetPluginFunc)
+ get_plugin_func) ();
+ if (plugin != NULL) {
+ GkbdIndicatorPluginManagerRecord
+ * rec =
+ g_new0
+ (GkbdIndicatorPluginManagerRecord,
+ 1);
+ xkl_debug (100,
+ "Loaded plugin from [%s]: [%s]/[%s]...\n",
+ full_path,
+ plugin->name,
+ plugin->
+ description);
+ rec->full_path = full_path;
+ rec->module = module;
+ rec->plugin = plugin;
+ g_hash_table_insert
+ (manager->
+ all_plugin_recs,
+ full_path, rec);
+ continue;
+ }
+ } else
+ xkl_debug (0,
+ "Bad plugin: [%s]\n",
+ full_path);
+ g_module_close (module);
+ } else
+ xkl_debug (0, "Bad module: [%s], %s\n",
+ full_path, g_module_error ());
+ g_free (full_path);
+ }
+ }
+ g_dir_close (dir);
+}
+
+static void
+gkbd_indicator_plugin_manager_load_all (GkbdIndicatorPluginManager *
+ manager)
+{
+ if (!g_module_supported ()) {
+ xkl_debug (0, "Modules are not supported - no plugins!\n");
+ return;
+ }
+ gkbd_indicator_plugin_manager_add_plugins_dir (manager,
+ SYS_PLUGIN_DIR);
+}
+
+static void
+gkbd_indicator_plugin_manager_rec_term (GkbdIndicatorPluginManagerRecord *
+ rec, void *user_data)
+{
+ const GkbdIndicatorPlugin *plugin = rec->plugin;
+ if (plugin != NULL) {
+ xkl_debug (100, "Terminating plugin: [%s]...\n",
+ plugin->name);
+ if (plugin->term_callback)
+ (*plugin->term_callback) ();
+ }
+}
+
+static void
+gkbd_indicator_plugin_manager_rec_destroy (GkbdIndicatorPluginManagerRecord
+ * rec)
+{
+ xkl_debug (100, "Unloading plugin: [%s]...\n", rec->plugin->name);
+
+ g_module_close (rec->module);
+ g_free (rec);
+}
+
+void
+gkbd_indicator_plugin_manager_init (GkbdIndicatorPluginManager * manager)
+{
+ manager->all_plugin_recs =
+ g_hash_table_new_full (g_str_hash, g_str_equal,
+ (GDestroyNotify) g_free,
+ (GDestroyNotify)
+ gkbd_indicator_plugin_manager_rec_destroy);
+ gkbd_indicator_plugin_manager_load_all (manager);
+}
+
+void
+gkbd_indicator_plugin_manager_term (GkbdIndicatorPluginManager * manager)
+{
+ gkbd_indicator_plugin_manager_term_initialized_plugins (manager);
+ if (manager->all_plugin_recs != NULL) {
+ g_hash_table_destroy (manager->all_plugin_recs);
+ manager->all_plugin_recs = NULL;
+ }
+}
+
+void
+ gkbd_indicator_plugin_manager_init_enabled_plugins
+ (GkbdIndicatorPluginManager * manager,
+ GkbdIndicatorPluginContainer * pc, GSList * enabled_plugins) {
+ GSList *plugin_name_node = enabled_plugins;
+ if (manager->all_plugin_recs == NULL)
+ return;
+ xkl_debug (100, "Initializing all enabled plugins...\n");
+ while (plugin_name_node != NULL) {
+ const char *full_path = plugin_name_node->data;
+ if (full_path != NULL) {
+ GkbdIndicatorPluginManagerRecord *rec =
+ (GkbdIndicatorPluginManagerRecord *)
+ g_hash_table_lookup (manager->all_plugin_recs,
+ full_path);
+
+ if (rec != NULL) {
+ const GkbdIndicatorPlugin *plugin =
+ rec->plugin;
+ gboolean initialized = FALSE;
+ xkl_debug (100,
+ "Initializing plugin: [%s] from [%s]...\n",
+ plugin->name, full_path);
+ if (plugin->init_callback != NULL)
+ initialized =
+ (*plugin->init_callback) (pc);
+ else
+ initialized = TRUE;
+
+ manager->inited_plugin_recs =
+ g_slist_append (manager->
+ inited_plugin_recs,
+ rec);
+ xkl_debug (100,
+ "Plugin [%s] initialized: %d\n",
+ plugin->name, initialized);
+ }
+ }
+ plugin_name_node = g_slist_next (plugin_name_node);
+ }
+}
+
+void
+ gkbd_indicator_plugin_manager_term_initialized_plugins
+ (GkbdIndicatorPluginManager * manager) {
+
+ if (manager->inited_plugin_recs == NULL)
+ return;
+ g_slist_foreach (manager->inited_plugin_recs,
+ (GFunc) gkbd_indicator_plugin_manager_rec_term,
+ NULL);
+ g_slist_free (manager->inited_plugin_recs);
+ manager->inited_plugin_recs = NULL;
+}
+
+void
+gkbd_indicator_plugin_manager_toggle_plugins (GkbdIndicatorPluginManager *
+ manager,
+ GkbdIndicatorPluginContainer
+ * pc,
+ GSList * enabled_plugins)
+{
+ gkbd_indicator_plugin_manager_term_initialized_plugins (manager);
+ gkbd_indicator_plugin_manager_init_enabled_plugins (manager, pc,
+ enabled_plugins);
+}
+
+void
+gkbd_indicator_plugin_manager_group_changed (GkbdIndicatorPluginManager *
+ manager, GtkWidget * notebook,
+ int new_group)
+{
+ FOREACH_INITED_PLUGIN ();
+ if (plugin->group_changed_callback)
+ (*plugin->group_changed_callback) (notebook, new_group);
+ NEXT_INITED_PLUGIN ();
+}
+
+void
+gkbd_indicator_plugin_manager_config_changed (GkbdIndicatorPluginManager *
+ manager,
+ GkbdKeyboardConfig * from,
+ GkbdKeyboardConfig * to)
+{
+ FOREACH_INITED_PLUGIN ();
+ if (plugin->config_changed_callback)
+ (*plugin->config_changed_callback) (from, to);
+ NEXT_INITED_PLUGIN ();
+}
+
+const GkbdIndicatorPlugin *
+gkbd_indicator_plugin_manager_get_plugin (GkbdIndicatorPluginManager *
+ manager, const char *full_path)
+{
+ GkbdIndicatorPluginManagerRecord *rec =
+ (GkbdIndicatorPluginManagerRecord *)
+ g_hash_table_lookup (manager->all_plugin_recs,
+ full_path);
+ if (rec == NULL)
+ return NULL;
+ return rec->plugin;
+}
+
+void
+gkbd_indicator_plugin_manager_promote_plugin (GkbdIndicatorPluginManager *
+ manager,
+ GSList * enabled_plugins,
+ const char *full_path)
+{
+ GSList *the_node = enabled_plugins;
+ GSList *prev_node = NULL;
+
+ while (the_node != NULL) {
+ if (!strcmp (the_node->data, full_path)) {
+ if (prev_node != NULL) {
+ char *tmp = (char *) prev_node->data;
+ prev_node->data = the_node->data;
+ the_node->data = tmp;
+ }
+ break;
+ }
+ prev_node = the_node;
+ the_node = g_slist_next (the_node);
+ }
+}
+
+void
+gkbd_indicator_plugin_manager_demote_plugin (GkbdIndicatorPluginManager *
+ manager,
+ GSList * enabled_plugins,
+ const char *full_path)
+{
+ GSList *the_node = g_slist_find_custom (enabled_plugins, full_path,
+ (GCompareFunc) strcmp);
+ if (the_node != NULL) {
+ GSList *next_node = g_slist_next (the_node);
+ if (next_node != NULL) {
+ char *tmp = (char *) next_node->data;
+ next_node->data = the_node->data;
+ the_node->data = tmp;
+ }
+ }
+}
+
+void
+gkbd_indicator_plugin_manager_enable_plugin (GkbdIndicatorPluginManager *
+ manager,
+ GSList ** enabled_plugins,
+ const char *full_path)
+{
+ if (NULL !=
+ gkbd_indicator_plugin_manager_get_plugin (manager,
+ full_path)) {
+ *enabled_plugins =
+ g_slist_append (*enabled_plugins,
+ (gpointer) g_strdup (full_path));
+ }
+}
+
+void
+gkbd_indicator_plugin_manager_disable_plugin (GkbdIndicatorPluginManager *
+ manager,
+ GSList ** enabled_plugins,
+ const char *full_path)
+{
+ GSList *the_node =
+ g_slist_find_custom (*enabled_plugins, full_path,
+ (GCompareFunc) strcmp);
+ if (the_node != NULL) {
+ g_free (the_node->data);
+ *enabled_plugins =
+ g_slist_delete_link (*enabled_plugins, the_node);
+ }
+}
+
+int
+gkbd_indicator_plugin_manager_window_created (GkbdIndicatorPluginManager *
+ manager, Window win,
+ Window parent)
+{
+ FOREACH_INITED_PLUGIN ();
+ if (plugin->window_created_callback) {
+ int group_to_assign =
+ (*plugin->window_created_callback) (win, parent);
+ if (group_to_assign != -1) {
+ xkl_debug (100,
+ "Plugin [%s] assigned group %d to new window %ld\n",
+ plugin->name, group_to_assign, win);
+ return group_to_assign;
+ }
+ }
+ NEXT_INITED_PLUGIN ();
+ return -1;
+}
+
+GtkWidget *
+gkbd_indicator_plugin_manager_decorate_widget (GkbdIndicatorPluginManager *
+ manager, GtkWidget * widget,
+ const gint group,
+ const char
+ *group_description,
+ GkbdKeyboardConfig *
+ kbd_config)
+{
+ FOREACH_INITED_PLUGIN ();
+ if (plugin->decorate_widget_callback) {
+ GtkWidget *decorated_widget =
+ (*plugin->decorate_widget_callback) (widget, group,
+ group_description,
+ kbd_config);
+ if (decorated_widget != NULL) {
+ xkl_debug (100,
+ "Plugin [%s] decorated widget %p to %p\n",
+ plugin->name, widget, decorated_widget);
+ return decorated_widget;
+ }
+ }
+ NEXT_INITED_PLUGIN ();
+ return NULL;
+}
+
+void
+gkbd_indicator_plugin_manager_configure_plugin (GkbdIndicatorPluginManager
+ * manager,
+ GkbdIndicatorPluginContainer
+ * pc,
+ const char *full_path,
+ GtkWindow * parent)
+{
+ const GkbdIndicatorPlugin *plugin =
+ gkbd_indicator_plugin_manager_get_plugin (manager, full_path);
+ if (plugin->configure_properties_callback != NULL)
+ plugin->configure_properties_callback (pc, parent);
+}
+
+void
+gkbd_indicator_plugin_container_init (GkbdIndicatorPluginContainer * pc,
+ GConfClient * conf_client)
+{
+ pc->conf_client = conf_client;
+ g_object_ref (pc->conf_client);
+}
+
+void
+gkbd_indicator_plugin_container_term (GkbdIndicatorPluginContainer * pc)
+{
+ g_object_unref (pc->conf_client);
+}
diff --git a/libgnomekbd/gkbd-indicator-plugin-manager.h b/libgnomekbd/gkbd-indicator-plugin-manager.h
new file mode 100644
index 0000000..2d25cd3
--- /dev/null
+++ b/libgnomekbd/gkbd-indicator-plugin-manager.h
@@ -0,0 +1,113 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GSWITCHIT_PLUGIN_MANAGER_H__
+#define __GSWITCHIT_PLUGIN_MANAGER_H__
+
+#include <gmodule.h>
+#include <libgnomekbd/gkbd-indicator-plugin.h>
+
+typedef struct _GkbdIndicatorPluginManager {
+ GHashTable *all_plugin_recs;
+ GSList *inited_plugin_recs;
+} GkbdIndicatorPluginManager;
+
+typedef struct _GkbdIndicatorPluginManagerRecord {
+ const char *full_path;
+ GModule *module;
+ const GkbdIndicatorPlugin *plugin;
+} GkbdIndicatorPluginManagerRecord;
+
+extern void
+ gkbd_indicator_plugin_manager_init (GkbdIndicatorPluginManager * manager);
+
+extern void
+ gkbd_indicator_plugin_manager_term (GkbdIndicatorPluginManager * manager);
+
+extern void
+ gkbd_indicator_plugin_manager_init_enabled_plugins (GkbdIndicatorPluginManager * manager,
+ GkbdIndicatorPluginContainer
+ * pc,
+ GSList *
+ enabled_plugins);
+
+extern void
+ gkbd_indicator_plugin_manager_term_initialized_plugins (GkbdIndicatorPluginManager * manager);
+
+extern void
+ gkbd_indicator_plugin_manager_toggle_plugins (GkbdIndicatorPluginManager * manager,
+ GkbdIndicatorPluginContainer
+ * pc,
+ GSList * enabled_plugins);
+
+extern const GkbdIndicatorPlugin
+ *
+gkbd_indicator_plugin_manager_get_plugin (GkbdIndicatorPluginManager *
+ manager, const char *full_path);
+
+extern void
+ gkbd_indicator_plugin_manager_promote_plugin (GkbdIndicatorPluginManager * manager,
+ GSList * enabled_plugins,
+ const char *full_path);
+
+extern void
+ gkbd_indicator_plugin_manager_demote_plugin (GkbdIndicatorPluginManager * manager,
+ GSList * enabled_plugins,
+ const char *full_path);
+
+extern void
+ gkbd_indicator_plugin_manager_enable_plugin (GkbdIndicatorPluginManager * manager,
+ GSList ** enabled_plugins,
+ const char *full_path);
+
+extern void
+ gkbd_indicator_plugin_manager_disable_plugin (GkbdIndicatorPluginManager * manager,
+ GSList ** enabled_plugins,
+ const char *full_path);
+
+extern void
+ gkbd_indicator_plugin_manager_configure_plugin (GkbdIndicatorPluginManager * manager,
+ GkbdIndicatorPluginContainer
+ * pc,
+ const char *full_path,
+ GtkWindow * parent);
+
+// actual calling plugin notification methods
+
+extern void
+ gkbd_indicator_plugin_manager_group_changed (GkbdIndicatorPluginManager * manager,
+ GtkWidget * notebook,
+ int new_group);
+
+extern void
+ gkbd_indicator_plugin_manager_config_changed (GkbdIndicatorPluginManager * manager,
+ GkbdKeyboardConfig * from,
+ GkbdKeyboardConfig * to);
+
+extern int
+ gkbd_indicator_plugin_manager_window_created (GkbdIndicatorPluginManager * manager,
+ Window win, Window parent);
+
+extern GtkWidget
+ *
+gkbd_indicator_plugin_manager_decorate_widget (GkbdIndicatorPluginManager *
+ manager, GtkWidget * widget,
+ const gint group, const char
+ *group_description,
+ GkbdKeyboardConfig *
+ config);
+
+#endif
diff --git a/libgnomekbd/gkbd-indicator-plugin.h b/libgnomekbd/gkbd-indicator-plugin.h
new file mode 100644
index 0000000..fd2c0bb
--- /dev/null
+++ b/libgnomekbd/gkbd-indicator-plugin.h
@@ -0,0 +1,122 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GKBD_INDICATOR_PLUGIN_H__
+#define __GKBD_INDICATOR_PLUGIN_H__
+
+#include <gtk/gtk.h>
+#include <gconf/gconf-client.h>
+#include <libgnomekbd/gkbd-keyboard-config.h>
+
+#define MAX_LOCAL_NAME_BUF_LENGTH 512
+
+struct _GkbdIndicatorPlugin;
+
+typedef struct _GkbdIndicatorPluginContainer {
+ GConfClient *conf_client;
+} GkbdIndicatorPluginContainer;
+
+typedef const struct _GkbdIndicatorPlugin
+*(*GkbdIndicatorPluginGetPluginFunc) (void);
+
+typedef
+ gboolean (*GkbdIndicatorPluginInitFunc) (GkbdIndicatorPluginContainer *
+ pc);
+
+typedef void (*GkbdIndicatorPluginGroupChangedFunc) (GtkWidget * notebook,
+ int new_group);
+
+typedef void (*GkbdIndicatorPluginConfigChangedFunc) (const
+ GkbdKeyboardConfig *
+ from,
+ const
+ GkbdKeyboardConfig *
+ to);
+
+typedef int (*GkbdIndicatorPluginWindowCreatedFunc) (const Window win,
+ const Window parent);
+
+typedef void (*GkbdIndicatorPluginTermFunc) (void);
+
+typedef GtkWidget *(*GkbdIndicatorPluginCreateWidget) (void);
+
+typedef GtkWidget *(*GkbdIndicatorPluginDecorateWidget) (GtkWidget *
+ widget,
+ const gint group,
+ const char
+ *group_description,
+ GkbdKeyboardConfig
+ * config);
+
+typedef
+void (*GkbdIndicatorPluginConfigureProperties)
+ (GkbdIndicatorPluginContainer * pc, GtkWindow * parent);
+
+typedef struct _GkbdIndicatorPlugin {
+ const char *name;
+
+ const char *description;
+
+// implemented
+ GkbdIndicatorPluginInitFunc init_callback;
+
+// implemented
+ GkbdIndicatorPluginTermFunc term_callback;
+
+// implemented
+ GkbdIndicatorPluginConfigureProperties
+ configure_properties_callback;
+
+// implemented
+ GkbdIndicatorPluginGroupChangedFunc group_changed_callback;
+
+// implemented
+ GkbdIndicatorPluginWindowCreatedFunc window_created_callback;
+
+// implemented
+ GkbdIndicatorPluginDecorateWidget decorate_widget_callback;
+
+// non implemented
+ GkbdIndicatorPluginConfigChangedFunc config_changed_callback;
+
+// non implemented
+ GkbdIndicatorPluginCreateWidget create_widget_callback;
+
+} GkbdIndicatorPlugin;
+
+/**
+ * Functions accessible for plugins
+ */
+
+extern void
+ gkbd_indicator_plugin_container_init (GkbdIndicatorPluginContainer * pc,
+ GConfClient * conf_client);
+
+extern void
+ gkbd_indicator_plugin_container_term (GkbdIndicatorPluginContainer * pc);
+
+extern void
+ gkbd_indicator_plugin_container_reinit_ui (GkbdIndicatorPluginContainer * pc);
+
+extern guint
+gkbd_indicator_plugin_get_num_groups (GkbdIndicatorPluginContainer * pc);
+
+extern gchar
+ **
+ gkbd_indicator_plugin_load_localized_group_names
+ (GkbdIndicatorPluginContainer * pc);
+
+#endif
diff --git a/libgnomekbd/gkbd-indicator.c b/libgnomekbd/gkbd-indicator.c
new file mode 100644
index 0000000..04d6265
--- /dev/null
+++ b/libgnomekbd/gkbd-indicator.c
@@ -0,0 +1,825 @@
+#include <memory.h>
+
+#include <gdk/gdkkeysyms.h>
+#include <gdk/gdkx.h>
+#include <glib/gi18n.h>
+
+#include <gkbd-indicator.h>
+#include <gkbd-indicator-marshal.h>
+
+#include <gkbd-desktop-config.h>
+#include <gkbd-indicator-config.h>
+
+#include <gkbd-indicator-plugin-manager.h>
+
+#include <gkbd-config-registry-client.h>
+
+typedef struct _gki_globals {
+ XklEngine *engine;
+
+ GkbdDesktopConfig cfg;
+ GkbdIndicatorConfig ind_cfg;
+ GkbdKeyboardConfig kbd_cfg;
+
+ GkbdIndicatorPluginContainer plugin_container;
+ GkbdIndicatorPluginManager plugin_manager;
+
+ const gchar *tooltips_format;
+ gchar **full_group_names;
+ gchar **short_group_names;
+ GSList *widget_instances;
+} gki_globals;
+
+struct _GkbdIndicatorPrivate {
+ gboolean set_parent_tooltips;
+ gdouble angle;
+};
+
+/* one instance for ALL widgets */
+static gki_globals globals;
+
+#define ForAllIndicators() \
+ { \
+ GSList* cur; \
+ for (cur = globals.widget_instances; cur != NULL; cur = cur->next) { \
+ GkbdIndicator * gki = (GkbdIndicator*)cur->data;
+#define NextIndicator() \
+ } \
+ }
+
+G_DEFINE_TYPE (GkbdIndicator, gkbd_indicator, GTK_TYPE_NOTEBOOK)
+
+static void
+gkbd_indicator_global_init (void);
+static void
+gkbd_indicator_global_term (void);
+static GtkWidget *
+gkbd_indicator_prepare_drawing (GkbdIndicator * gki, int group);
+static void
+gkbd_indicator_set_current_page_for_group (GkbdIndicator * gki, int group);
+static void
+gkbd_indicator_set_current_page (GkbdIndicator * gki);
+static void
+gkbd_indicator_cleanup (GkbdIndicator * gki);
+static void
+gkbd_indicator_fill (GkbdIndicator * gki);
+static void
+gkbd_indicator_set_tooltips (GkbdIndicator * gki, const char *str);
+
+void
+gkbd_indicator_set_tooltips (GkbdIndicator * gki, const char *str)
+{
+ GtkTooltips *tooltips;
+
+ if (str == NULL)
+ return;
+ tooltips = gtk_tooltips_new ();
+ g_object_ref (G_OBJECT (tooltips));
+ gtk_object_sink (GTK_OBJECT (tooltips));
+ g_object_set_data_full (G_OBJECT (gki), "tooltips",
+ tooltips, (GDestroyNotify) g_object_unref);
+ gtk_tooltips_set_tip (tooltips, GTK_WIDGET (gki), str, NULL);
+
+ if (gki->priv->set_parent_tooltips) {
+ GtkWidget *parent =
+ gtk_widget_get_parent (GTK_WIDGET (gki));
+ if (parent != NULL) {
+ gtk_tooltips_set_tip (tooltips,
+ GTK_WIDGET (parent), str,
+ NULL);
+ g_object_ref (G_OBJECT (tooltips));
+ g_object_set_data_full (G_OBJECT (parent),
+ "gnome-kbd-indicator.tooltips",
+ tooltips, (GDestroyNotify)
+ g_object_unref);
+ }
+ }
+ gtk_tooltips_enable (tooltips);
+}
+
+void
+gkbd_indicator_cleanup (GkbdIndicator * gki)
+{
+ int i;
+ GtkNotebook *notebook = GTK_NOTEBOOK (gki);
+
+ /* Do not remove the first page! It is the default page */
+ for (i = gtk_notebook_get_n_pages (notebook); --i > 0;) {
+ gtk_notebook_remove_page (notebook, i);
+ }
+}
+
+void
+gkbd_indicator_fill (GkbdIndicator * gki)
+{
+ int grp;
+ int total_groups = xkl_engine_get_num_groups (globals.engine);
+ GtkNotebook *notebook = GTK_NOTEBOOK (gki);
+
+ for (grp = 0; grp < total_groups; grp++) {
+ GtkWidget *page, *decorated_page;
+ page = gkbd_indicator_prepare_drawing (gki, grp);
+
+ if (page == NULL)
+ page = gtk_label_new ("");
+
+ decorated_page =
+ gkbd_indicator_plugin_manager_decorate_widget
+ (&globals.plugin_manager, page, grp,
+ globals.full_group_names[grp], &globals.kbd_cfg);
+
+ page = decorated_page == NULL ? page : decorated_page;
+
+ gtk_notebook_append_page (notebook, page, NULL);
+ gtk_widget_show_all (page);
+ }
+}
+
+static gboolean
+gkbd_indicator_key_pressed (GtkWidget *
+ widget, GdkEventKey * event,
+ GkbdIndicator * gki)
+{
+ switch (event->keyval) {
+ case GDK_KP_Enter:
+ case GDK_ISO_Enter:
+ case GDK_3270_Enter:
+ case GDK_Return:
+ case GDK_space:
+ case GDK_KP_Space:
+ gkbd_desktop_config_lock_next_group (&globals.cfg);
+ return TRUE;
+ default:
+ break;
+ }
+ return FALSE;
+}
+
+static gboolean
+gkbd_indicator_button_pressed (GtkWidget *
+ widget,
+ GdkEventButton * event, GkbdIndicator * gki)
+{
+ GtkWidget *img = gtk_bin_get_child (GTK_BIN (widget));
+ xkl_debug (150, "Flag img size %d x %d\n",
+ img->allocation.width, img->allocation.height);
+ if (event->button == 1 && event->type == GDK_BUTTON_PRESS) {
+ xkl_debug (150, "Mouse button pressed on applet\n");
+ gkbd_desktop_config_lock_next_group (&globals.cfg);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void
+flag_exposed (GtkWidget * flag, GdkEventExpose * event, GdkPixbuf * image)
+{
+ /* Image width and height */
+ int iw = gdk_pixbuf_get_width (image);
+ int ih = gdk_pixbuf_get_height (image);
+ /* widget-to-image scales, X and Y */
+ double xwiratio = 1.0 * flag->allocation.width / iw;
+ double ywiratio = 1.0 * flag->allocation.height / ih;
+ double wiratio = xwiratio < ywiratio ? xwiratio : ywiratio;
+
+ /* scaled width and height */
+ int sw = iw * wiratio;
+ int sh = ih * wiratio;
+
+ /* offsets */
+ int ox = (flag->allocation.width - sw) >> 1;
+ int oy = (flag->allocation.height - sh) >> 1;
+
+ GdkPixbuf *scaled = gdk_pixbuf_scale_simple (image, sw, sh,
+ GDK_INTERP_HYPER);
+
+ gdk_draw_pixbuf (GDK_DRAWABLE (flag->window),
+ NULL,
+ scaled,
+ 0, 0,
+ ox, oy, sw, sh, GDK_RGB_DITHER_NORMAL, 0, 0);
+ g_object_unref (G_OBJECT (scaled));
+}
+
+static GtkWidget *
+gkbd_indicator_prepare_drawing (GkbdIndicator * gki, int group)
+{
+ gpointer pimage;
+ GdkPixbuf *image;
+ GtkWidget *ebox;
+
+ pimage = g_slist_nth_data (globals.ind_cfg.images, group);
+ ebox = gtk_event_box_new ();
+ if (globals.ind_cfg.show_flags) {
+ GtkWidget *flag;
+ if (pimage == NULL)
+ return NULL;
+ image = GDK_PIXBUF (pimage);
+ flag = gtk_drawing_area_new ();
+ g_signal_connect (G_OBJECT (flag),
+ "expose_event",
+ G_CALLBACK (flag_exposed), image);
+ gtk_container_add (GTK_CONTAINER (ebox), flag);
+ } else {
+ gpointer pcounter = NULL;
+ char *prev_layout_name = NULL, **ppln;
+ char *lbl_title = NULL;
+ int counter = 0;
+ char *layout_name = NULL;
+ XklConfigItem cfg_item;
+ GtkWidget *align, *label;
+ /**
+ * Map "short desciption" ->
+ * number of layouts in the configuration
+ * having this short description
+ */
+ static GHashTable *short_descrs = NULL;
+
+ if (group == 0)
+ short_descrs =
+ g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, NULL);
+
+ if (xkl_engine_get_features (globals.engine) &
+ XKLF_MULTIPLE_LAYOUTS_SUPPORTED) {
+ char *full_layout_name =
+ (char *) g_slist_nth_data (globals.kbd_cfg.
+ layouts,
+ group);
+ char *variant_name;
+ if (!gkbd_keyboard_config_split_items
+ (full_layout_name, &layout_name,
+ &variant_name))
+ /* just in case */
+ layout_name = g_strdup (full_layout_name);
+
+ g_snprintf (cfg_item.name,
+ sizeof (cfg_item.name), "%s",
+ layout_name);
+
+ if (globals.short_group_names != NULL) {
+ char *short_group_name =
+ globals.short_group_names[group];
+ if (short_group_name != NULL
+ && *short_group_name != '\0') {
+ layout_name =
+ g_strdup (short_group_name);
+ }
+ }
+ } else
+ layout_name =
+ g_strdup (globals.full_group_names[group]);
+
+ if (layout_name == NULL)
+ layout_name = g_strdup ("?");
+
+ /* Process layouts with repeating description */
+ ppln = &prev_layout_name;
+ if (g_hash_table_lookup_extended
+ (short_descrs, layout_name,
+ (gpointer *) ppln, &pcounter)) {
+ /* "next" same description */
+ gchar appendix[10] = "";
+ gint utf8length;
+ gunichar cidx;
+ counter = GPOINTER_TO_INT (pcounter);
+ /* Unicode subscript 2, 3, 4 */
+ cidx = 0x2081 + counter;
+ utf8length = g_unichar_to_utf8 (cidx, appendix);
+ appendix[utf8length] = '\0';
+ lbl_title =
+ g_strconcat (layout_name, appendix, NULL);
+ } else {
+ /* "first" time this description */
+ lbl_title = g_strdup (layout_name);
+ }
+ g_hash_table_insert (short_descrs, layout_name,
+ GINT_TO_POINTER (counter + 1));
+
+ align = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+ label = gtk_label_new (lbl_title);
+ g_free (lbl_title);
+ gtk_label_set_angle (GTK_LABEL (label), gki->priv->angle);
+
+ if (group == xkl_engine_get_num_groups (globals.engine)) {
+ g_hash_table_destroy (short_descrs);
+ short_descrs = NULL;
+ }
+
+ gtk_container_add (GTK_CONTAINER (align), label);
+ gtk_container_add (GTK_CONTAINER (ebox), align);
+
+ gtk_container_set_border_width (GTK_CONTAINER (align), 2);
+ }
+ g_signal_connect (G_OBJECT (ebox),
+ "button_press_event",
+ G_CALLBACK (gkbd_indicator_button_pressed), gki);
+
+ g_signal_connect (G_OBJECT (gki),
+ "key_press_event",
+ G_CALLBACK (gkbd_indicator_key_pressed), gki);
+
+ /* We have everything prepared for that size */
+
+ return ebox;
+}
+
+static void
+gkbd_indicator_update_tooltips (GkbdIndicator * gki)
+{
+ XklState *state = xkl_engine_get_current_state (globals.engine);
+ gchar *buf;
+ if (state == NULL || state->group < 0)
+ return;
+
+ buf = g_strdup_printf (globals.tooltips_format,
+ globals.full_group_names[state->group]);
+
+ gkbd_indicator_set_tooltips (gki, buf);
+ g_free (buf);
+}
+
+static void
+gkbd_indicator_parent_set (GtkWidget * gki, GtkWidget * previous_parent)
+{
+ gkbd_indicator_update_tooltips (GKBD_INDICATOR (gki));
+}
+
+
+void
+gkbd_indicator_reinit_ui (GkbdIndicator * gki)
+{
+ gkbd_indicator_cleanup (gki);
+ gkbd_indicator_fill (gki);
+
+ gkbd_indicator_set_current_page (gki);
+
+ g_signal_emit_by_name (gki, "reinit-ui");
+}
+
+/* Should be called once for all widgets */
+static void
+gkbd_indicator_cfg_changed (GConfClient * client,
+ guint cnxn_id, GConfEntry * entry)
+{
+ xkl_debug (100,
+ "General configuration changed in GConf - reiniting...\n");
+ gkbd_desktop_config_load_from_gconf (&globals.cfg);
+ gkbd_desktop_config_activate (&globals.cfg);
+ ForAllIndicators () {
+ gkbd_indicator_reinit_ui (gki);
+ } NextIndicator ();
+}
+
+/* Should be called once for all widgets */
+static void
+gkbd_indicator_ind_cfg_changed (GConfClient * client,
+ guint cnxn_id, GConfEntry * entry)
+{
+ xkl_debug (100,
+ "Applet configuration changed in GConf - reiniting...\n");
+ gkbd_indicator_config_load_from_gconf (&globals.ind_cfg);
+ gkbd_indicator_config_update_images (&globals.ind_cfg,
+ &globals.kbd_cfg);
+ gkbd_indicator_config_activate (&globals.ind_cfg);
+
+ gkbd_indicator_plugin_manager_toggle_plugins (&globals.
+ plugin_manager,
+ &globals.
+ plugin_container,
+ globals.ind_cfg.
+ enabled_plugins);
+
+ ForAllIndicators () {
+ gkbd_indicator_reinit_ui (gki);
+ } NextIndicator ();
+}
+
+static void
+gkbd_indicator_load_group_names (void)
+{
+ if (!gkbd_desktop_config_load_remote_group_descriptions_utf8
+ (&globals.cfg, &globals.short_group_names,
+ &globals.full_group_names)) {
+ gint i, total_groups =
+ xkl_engine_get_num_groups (globals.engine);
+ globals.full_group_names =
+ g_new0 (char *, total_groups + 1);
+
+ if (xkl_engine_get_features (globals.engine) &
+ XKLF_MULTIPLE_LAYOUTS_SUPPORTED) {
+ GSList *lst = globals.kbd_cfg.layouts;
+ for (i = 0; lst; lst = lst->next) {
+ globals.full_group_names[i++] =
+ g_strdup ((char *) lst->data);
+ }
+ } else {
+ for (i = total_groups; --i >= 0;) {
+ globals.full_group_names[i] =
+ g_strdup_printf ("Group %d", i);
+ }
+ }
+ }
+}
+
+/* Should be called once for all widgets */
+static void
+gkbd_indicator_kbd_cfg_callback (GkbdIndicator * gki)
+{
+ xkl_debug (100,
+ "XKB configuration changed on X Server - reiniting...\n");
+
+ gkbd_keyboard_config_load_from_x_current (&globals.kbd_cfg);
+ gkbd_indicator_config_update_images (&globals.ind_cfg,
+ &globals.kbd_cfg);
+
+ g_strfreev (globals.full_group_names);
+ g_strfreev (globals.short_group_names);
+ gkbd_indicator_load_group_names ();
+
+ ForAllIndicators () {
+ gkbd_indicator_reinit_ui (gki);
+ } NextIndicator ();
+}
+
+/* Should be called once for all applets */
+static void
+gkbd_indicator_state_callback (XklEngine * engine,
+ XklEngineStateChange changeType,
+ gint group, gboolean restore)
+{
+ xkl_debug (150, "group is now %d, restore: %d\n", group, restore);
+
+ if (changeType == GROUP_CHANGED) {
+ ForAllIndicators () {
+ gkbd_indicator_plugin_manager_group_changed
+ (&globals.plugin_manager, GTK_WIDGET (gki),
+ group);
+ xkl_debug (200, "do repaint\n");
+ gkbd_indicator_set_current_page_for_group
+ (gki, group);
+ }
+ NextIndicator ();
+ }
+}
+
+
+void
+gkbd_indicator_set_current_page (GkbdIndicator * gki)
+{
+ XklState *cur_state;
+ cur_state = xkl_engine_get_current_state (globals.engine);
+ if (cur_state->group >= 0)
+ gkbd_indicator_set_current_page_for_group (gki,
+ cur_state->
+ group);
+}
+
+void
+gkbd_indicator_set_current_page_for_group (GkbdIndicator * gki, int group)
+{
+ xkl_debug (200, "Revalidating for group %d\n", group);
+
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (gki), group + 1);
+
+ gkbd_indicator_update_tooltips (gki);
+}
+
+/* Should be called once for all widgets */
+static GdkFilterReturn
+gkbd_indicator_filter_x_evt (GdkXEvent * xev, GdkEvent * event)
+{
+ XEvent *xevent = (XEvent *) xev;
+
+ xkl_engine_filter_events (globals.engine, xevent);
+ switch (xevent->type) {
+ case ReparentNotify:
+ {
+ XReparentEvent *rne = (XReparentEvent *) xev;
+
+ ForAllIndicators () {
+ GdkWindow *w =
+ gtk_widget_get_parent_window
+ (GTK_WIDGET (gki));
+
+ /* compare the indicator's parent window with the even window */
+ if (w != NULL
+ && GDK_WINDOW_XID (w) == rne->window) {
+ /* if so - make it transparent... */
+ xkl_engine_set_window_transparent
+ (globals.engine, rne->window,
+ TRUE);
+ }
+ }
+ NextIndicator ()
+ }
+ break;
+ }
+ return GDK_FILTER_CONTINUE;
+}
+
+
+/* Should be called once for all widgets */
+static void
+gkbd_indicator_start_listen (void)
+{
+ gdk_window_add_filter (NULL, (GdkFilterFunc)
+ gkbd_indicator_filter_x_evt, NULL);
+ gdk_window_add_filter (gdk_get_default_root_window (),
+ (GdkFilterFunc)
+ gkbd_indicator_filter_x_evt, NULL);
+
+ xkl_engine_start_listen (globals.engine,
+ XKLL_TRACK_KEYBOARD_STATE);
+}
+
+/* Should be called once for all widgets */
+static void
+gkbd_indicator_stop_listen (void)
+{
+ xkl_engine_stop_listen (globals.engine);
+
+ gdk_window_remove_filter (NULL, (GdkFilterFunc)
+ gkbd_indicator_filter_x_evt, NULL);
+ gdk_window_remove_filter
+ (gdk_get_default_root_window (),
+ (GdkFilterFunc) gkbd_indicator_filter_x_evt, NULL);
+}
+
+static gboolean
+gkbd_indicator_scroll (GtkWidget * gki, GdkEventScroll * event)
+{
+ /* mouse wheel events should be ignored, otherwise funny effects appear */
+ return TRUE;
+}
+
+static void
+gkbd_indicator_init (GkbdIndicator * gki)
+{
+ GtkWidget *def_drawing;
+ GtkNotebook *notebook;
+
+ if (!g_slist_length (globals.widget_instances))
+ gkbd_indicator_global_init ();
+
+ gki->priv = g_new0 (GkbdIndicatorPrivate, 1);
+
+ notebook = GTK_NOTEBOOK (gki);
+
+ xkl_debug (100, "Initiating the widget startup process for %p\n",
+ gki);
+
+ gtk_notebook_set_show_tabs (notebook, FALSE);
+ gtk_notebook_set_show_border (notebook, FALSE);
+
+ def_drawing =
+ gtk_image_new_from_stock (GTK_STOCK_STOP,
+ GTK_ICON_SIZE_BUTTON);
+
+ gtk_notebook_append_page (notebook, def_drawing,
+ gtk_label_new (""));
+
+ if (globals.engine == NULL) {
+ gkbd_indicator_set_tooltips (gki,
+ _
+ ("XKB initialization error"));
+ return;
+ }
+
+ gkbd_indicator_set_tooltips (gki, "");
+
+ gkbd_indicator_fill (gki);
+ gkbd_indicator_set_current_page (gki);
+
+ gtk_widget_add_events (GTK_WIDGET (gki), GDK_BUTTON_PRESS_MASK);
+
+ /* append AFTER all initialization work is finished */
+ globals.widget_instances =
+ g_slist_append (globals.widget_instances, gki);
+}
+
+static void
+gkbd_indicator_finalize (GObject * obj)
+{
+ GkbdIndicator *gki = GKBD_INDICATOR (obj);
+ xkl_debug (100,
+ "Starting the gnome-kbd-indicator widget shutdown process for %p\n",
+ gki);
+
+ /* remove BEFORE all termination work is finished */
+ globals.widget_instances =
+ g_slist_remove (globals.widget_instances, gki);
+
+ gkbd_indicator_cleanup (gki);
+
+ xkl_debug (100,
+ "The instance of gnome-kbd-indicator successfully finalized\n");
+
+ g_free (gki->priv);
+
+ G_OBJECT_CLASS (gkbd_indicator_parent_class)->finalize (obj);
+
+ if (!g_slist_length (globals.widget_instances))
+ gkbd_indicator_global_term ();
+}
+
+static void
+gkbd_indicator_global_term (void)
+{
+ xkl_debug (100, "*** Last GkbdIndicator instance *** \n");
+ gkbd_indicator_stop_listen ();
+
+ gkbd_desktop_config_stop_listen (&globals.cfg);
+ gkbd_indicator_config_stop_listen (&globals.ind_cfg);
+
+ gkbd_indicator_plugin_manager_term_initialized_plugins (&globals.
+ plugin_manager);
+ gkbd_indicator_plugin_manager_term (&globals.plugin_manager);
+
+ gkbd_indicator_config_term (&globals.ind_cfg);
+ gkbd_keyboard_config_term (&globals.kbd_cfg);
+ gkbd_desktop_config_term (&globals.cfg);
+
+ gkbd_indicator_plugin_container_term (&globals.plugin_container);
+
+ g_object_unref (G_OBJECT (globals.engine));
+ globals.engine = NULL;
+ xkl_debug (100, "*** Terminated globals *** \n");
+}
+
+static void
+gkbd_indicator_class_init (GkbdIndicatorClass * klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+ xkl_debug (100, "*** First GkbdIndicator instance *** \n");
+
+ memset (&globals, 0, sizeof (globals));
+
+ /* Initing some global vars */
+ globals.tooltips_format = "%s";
+
+ /* Initing vtable */
+ object_class->finalize = gkbd_indicator_finalize;
+
+ widget_class->scroll_event = gkbd_indicator_scroll;
+ widget_class->parent_set = gkbd_indicator_parent_set;
+
+ /* Signals */
+ g_signal_new ("reinit-ui", GKBD_TYPE_INDICATOR,
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GkbdIndicatorClass, reinit_ui),
+ NULL, NULL, gkbd_indicator_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+static void
+gkbd_indicator_global_init (void)
+{
+ GConfClient *gconf_client;
+
+ globals.engine = xkl_engine_get_instance (GDK_DISPLAY ());
+ if (globals.engine == NULL) {
+ xkl_debug (0, "Libxklavier initialization error");
+ return;
+ }
+
+ gconf_client = gconf_client_get_default ();
+
+ g_signal_connect (globals.engine, "X-state-changed",
+ G_CALLBACK (gkbd_indicator_state_callback),
+ NULL);
+ g_signal_connect (globals.engine, "X-config-changed",
+ G_CALLBACK (gkbd_indicator_kbd_cfg_callback),
+ NULL);
+
+ gkbd_indicator_plugin_container_init (&globals.plugin_container,
+ gconf_client);
+
+ gkbd_desktop_config_init (&globals.cfg, gconf_client,
+ globals.engine);
+ gkbd_keyboard_config_init (&globals.kbd_cfg, gconf_client,
+ globals.engine);
+ gkbd_indicator_config_init (&globals.ind_cfg, gconf_client,
+ globals.engine);
+
+ g_object_unref (gconf_client);
+
+ gkbd_desktop_config_load_from_gconf (&globals.cfg);
+ gkbd_desktop_config_activate (&globals.cfg);
+ gkbd_keyboard_config_load_from_x_current (&globals.kbd_cfg);
+ gkbd_indicator_config_load_from_gconf (&globals.ind_cfg);
+ gkbd_indicator_config_update_images (&globals.ind_cfg,
+ &globals.kbd_cfg);
+ gkbd_indicator_config_activate (&globals.ind_cfg);
+
+ gkbd_indicator_load_group_names ();
+
+ gkbd_indicator_plugin_manager_init (&globals.plugin_manager);
+ gkbd_indicator_plugin_manager_init_enabled_plugins (&globals.
+ plugin_manager,
+ &globals.
+ plugin_container,
+ globals.
+ ind_cfg.
+ enabled_plugins);
+ gkbd_desktop_config_start_listen (&globals.cfg,
+ (GConfClientNotifyFunc)
+ gkbd_indicator_cfg_changed,
+ NULL);
+ gkbd_indicator_config_start_listen (&globals.ind_cfg,
+ (GConfClientNotifyFunc)
+ gkbd_indicator_ind_cfg_changed,
+ NULL);
+ gkbd_indicator_start_listen ();
+
+ xkl_debug (100, "*** Inited globals *** \n");
+}
+
+GtkWidget *
+gkbd_indicator_new (void)
+{
+ return
+ GTK_WIDGET (g_object_new (gkbd_indicator_get_type (), NULL));
+}
+
+void
+gkbd_indicator_set_parent_tooltips (GkbdIndicator * gki, gboolean spt)
+{
+ gki->priv->set_parent_tooltips = spt;
+ gkbd_indicator_update_tooltips (gki);
+}
+
+void
+gkbd_indicator_set_tooltips_format (const gchar format[])
+{
+ globals.tooltips_format = format;
+ ForAllIndicators ()
+ gkbd_indicator_update_tooltips (gki);
+ NextIndicator ()
+}
+
+XklEngine *
+gkbd_indicator_get_xkl_engine ()
+{
+ return globals.engine;
+}
+
+gchar **
+gkbd_indicator_get_group_names ()
+{
+ return globals.full_group_names;
+}
+
+gchar *
+gkbd_indicator_get_image_filename (guint group)
+{
+ if (!globals.ind_cfg.show_flags)
+ return NULL;
+ return gkbd_indicator_config_get_images_file (&globals.
+ ind_cfg,
+ &globals.
+ kbd_cfg, group);
+}
+
+gdouble
+gkbd_indicator_get_max_width_height_ratio (void)
+{
+ gdouble rv = 0.0;
+ GSList *ip = globals.ind_cfg.images;
+ if (!globals.ind_cfg.show_flags)
+ return 0;
+ while (ip != NULL) {
+ GdkPixbuf *img = GDK_PIXBUF (ip->data);
+ gdouble r =
+ 1.0 * gdk_pixbuf_get_width (img) /
+ gdk_pixbuf_get_height (img);
+ if (r > rv)
+ rv = r;
+ ip = ip->next;
+ }
+ return rv;
+}
+
+void
+gkbd_indicator_set_angle (GkbdIndicator * gki, gdouble angle)
+{
+ gki->priv->angle = angle;
+}
+
+/* Plugin support */
+/* Preserve the plugin container functions during the linking */
+void
+gkbd_indicator_plugin_container_reinit_ui (GkbdIndicatorPluginContainer *
+ pc)
+{
+ ForAllIndicators () {
+ gkbd_indicator_reinit_ui (gki);
+ } NextIndicator ();
+}
+
+gchar **gkbd_indicator_plugin_load_localized_group_names
+ (GkbdIndicatorPluginContainer * pc) {
+ return globals.full_group_names;
+}
diff --git a/libgnomekbd/gkbd-indicator.h b/libgnomekbd/gkbd-indicator.h
new file mode 100644
index 0000000..8cd2e33
--- /dev/null
+++ b/libgnomekbd/gkbd-indicator.h
@@ -0,0 +1,77 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GKBD_INDICATOR_H__
+#define __GKBD_INDICATOR_H__
+
+#include <gtk/gtk.h>
+
+#include <libxklavier/xklavier.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ typedef struct _GkbdIndicator GkbdIndicator;
+ typedef struct _GkbdIndicatorPrivate GkbdIndicatorPrivate;
+ typedef struct _GkbdIndicatorClass GkbdIndicatorClass;
+
+#define GKBD_TYPE_INDICATOR (gkbd_indicator_get_type ())
+#define GKBD_INDICATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GKBD_TYPE_INDICATOR, GkbdIndicator))
+#define GKBD_INDCATOR_CLASS(obj) (G_TYPE_CHECK_CLASS_CAST ((obj), GKBD_TYPE_INDICATOR, GkbdIndicatorClass))
+#define GKBD_IS_INDICATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GKBD_TYPE_INDICATOR))
+#define GKBD_IS_INDICATOR_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE ((obj), GKBD_TYPE_INDICATOR))
+#define GKBD_INDICATOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GKBD_TYPE_INDICATOR, GkbdIndicatorClass))
+
+ struct _GkbdIndicator {
+ GtkNotebook parent;
+ GkbdIndicatorPrivate *priv;
+ };
+
+ struct _GkbdIndicatorClass {
+ GtkNotebookClass parent_class;
+
+ void (*reinit_ui) (GkbdIndicator * gki);
+ };
+
+ extern GType gkbd_indicator_get_type (void);
+
+ extern GtkWidget *gkbd_indicator_new (void);
+
+ extern void gkbd_indicator_reinit_ui (GkbdIndicator * gki);
+
+ extern void gkbd_indicator_set_angle (GkbdIndicator * gki,
+ gdouble angle);
+
+ extern XklEngine *gkbd_indicator_get_xkl_engine (void);
+
+ extern gchar **gkbd_indicator_get_group_names (void);
+
+ extern gchar *gkbd_indicator_get_image_filename (guint group);
+
+ extern gdouble gkbd_indicator_get_max_width_height_ratio (void);
+
+ extern void
+ gkbd_indicator_set_parent_tooltips (GkbdIndicator *
+ gki, gboolean ifset);
+
+ extern void
+ gkbd_indicator_set_tooltips_format (const gchar str[]);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/libgnomekbd/gkbd-keyboard-config.c b/libgnomekbd/gkbd-keyboard-config.c
new file mode 100644
index 0000000..126cbc8
--- /dev/null
+++ b/libgnomekbd/gkbd-keyboard-config.c
@@ -0,0 +1,825 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <X11/keysym.h>
+
+#include <glib/gi18n.h>
+//#include <gdk/gdkx.h>
+#include <libgnome/gnome-program.h>
+
+#include <gkbd-keyboard-config.h>
+#include <gkbd-config-private.h>
+
+#include <gkbd-config-registry-client.h>
+
+/**
+ * GkbdKeyboardConfig
+ */
+#define GKBD_KEYBOARD_CONFIG_KEY_PREFIX GKBD_CONFIG_KEY_PREFIX "/kbd"
+
+const gchar GKBD_KEYBOARD_CONFIG_DIR[] = GKBD_KEYBOARD_CONFIG_KEY_PREFIX;
+const gchar GKBD_KEYBOARD_CONFIG_KEY_MODEL[] =
+ GKBD_KEYBOARD_CONFIG_KEY_PREFIX "/model";
+const gchar GKBD_KEYBOARD_CONFIG_KEY_LAYOUTS[] =
+ GKBD_KEYBOARD_CONFIG_KEY_PREFIX "/layouts";
+const gchar GKBD_KEYBOARD_CONFIG_KEY_OPTIONS[] =
+ GKBD_KEYBOARD_CONFIG_KEY_PREFIX "/options";
+
+const gchar *GKBD_KEYBOARD_CONFIG_ACTIVE[] = {
+ GKBD_KEYBOARD_CONFIG_KEY_MODEL,
+ GKBD_KEYBOARD_CONFIG_KEY_LAYOUTS,
+ GKBD_KEYBOARD_CONFIG_KEY_OPTIONS
+};
+
+#define GKBD_KEYBOARD_CONFIG_SYSBACKUP_KEY_PREFIX GKBD_CONFIG_KEY_PREFIX "/kbd.sysbackup"
+
+const gchar GKBD_KEYBOARD_CONFIG_SYSBACKUP_DIR[] =
+ GKBD_KEYBOARD_CONFIG_SYSBACKUP_KEY_PREFIX;
+const gchar GKBD_KEYBOARD_CONFIG_SYSBACKUP_KEY_MODEL[] =
+ GKBD_KEYBOARD_CONFIG_SYSBACKUP_KEY_PREFIX "/model";
+const gchar GKBD_KEYBOARD_CONFIG_SYSBACKUP_KEY_LAYOUTS[] =
+ GKBD_KEYBOARD_CONFIG_SYSBACKUP_KEY_PREFIX "/layouts";
+const gchar GKBD_KEYBOARD_CONFIG_SYSBACKUP_KEY_OPTIONS[] =
+ GKBD_KEYBOARD_CONFIG_SYSBACKUP_KEY_PREFIX "/options";
+
+const gchar *GKBD_KEYBOARD_CONFIG_SYSBACKUP[] = {
+ GKBD_KEYBOARD_CONFIG_SYSBACKUP_KEY_MODEL,
+ GKBD_KEYBOARD_CONFIG_SYSBACKUP_KEY_LAYOUTS,
+ GKBD_KEYBOARD_CONFIG_SYSBACKUP_KEY_OPTIONS
+};
+
+/**
+ * static common functions
+ */
+static void
+gkbd_keyboard_config_string_list_reset (GSList ** plist)
+{
+ while (*plist != NULL) {
+ GSList *p = *plist;
+ *plist = (*plist)->next;
+ g_free (p->data);
+ g_slist_free_1 (p);
+ }
+}
+
+static gboolean
+gslist_str_equal (GSList * l1, GSList * l2)
+{
+ if (l1 == l2)
+ return TRUE;
+ while (l1 != NULL && l2 != NULL) {
+ if ((l1->data != l2->data) &&
+ (l1->data != NULL) &&
+ (l2->data != NULL) &&
+ g_ascii_strcasecmp (l1->data, l2->data))
+ return False;
+
+ l1 = l1->next;
+ l2 = l2->next;
+ }
+ return (l1 == NULL && l2 == NULL);
+}
+
+gboolean
+gkbd_keyboard_config_get_lv_descriptions (XklConfigRegistry *
+ config_registry,
+ const gchar * layout_name,
+ const gchar * variant_name,
+ gchar ** layout_short_descr,
+ gchar ** layout_descr,
+ gchar ** variant_short_descr,
+ gchar ** variant_descr)
+{
+ static XklConfigItem litem;
+ static XklConfigItem vitem;
+
+ layout_name = g_strdup (layout_name);
+
+ g_snprintf (litem.name, sizeof litem.name, "%s", layout_name);
+ if (xkl_config_registry_find_layout (config_registry, &litem)) {
+ *layout_short_descr = litem.short_description;
+ *layout_descr = litem.description;
+ } else
+ *layout_short_descr = *layout_descr = NULL;
+
+ if (variant_name != NULL) {
+ variant_name = g_strdup (variant_name);
+ g_snprintf (vitem.name, sizeof vitem.name, "%s",
+ variant_name);
+ if (xkl_config_registry_find_variant
+ (config_registry, layout_name, &vitem)) {
+ *variant_short_descr = vitem.short_description;
+ *variant_descr = vitem.description;
+ } else
+ *variant_short_descr = *variant_descr = NULL;
+
+ g_free ((char *) variant_name);
+ } else
+ *variant_descr = NULL;
+
+ g_free ((char *) layout_name);
+ return *layout_descr != NULL;
+}
+
+/**
+ * extern common functions
+ */
+const gchar *
+gkbd_keyboard_config_merge_items (const gchar * parent,
+ const gchar * child)
+{
+ static gchar buffer[XKL_MAX_CI_NAME_LENGTH * 2 - 1];
+ *buffer = '\0';
+ if (parent != NULL) {
+ if (strlen (parent) >= XKL_MAX_CI_NAME_LENGTH)
+ return NULL;
+ strcat (buffer, parent);
+ }
+ if (child != NULL) {
+ if (strlen (child) >= XKL_MAX_CI_NAME_LENGTH)
+ return NULL;
+ strcat (buffer, "\t");
+ strcat (buffer, child);
+ }
+ return buffer;
+}
+
+gboolean
+gkbd_keyboard_config_split_items (const gchar * merged, gchar ** parent,
+ gchar ** child)
+{
+ static gchar pbuffer[XKL_MAX_CI_NAME_LENGTH];
+ static gchar cbuffer[XKL_MAX_CI_NAME_LENGTH];
+ int plen, clen;
+ const gchar *pos;
+ *parent = *child = NULL;
+
+ if (merged == NULL)
+ return FALSE;
+
+ pos = strchr (merged, '\t');
+ if (pos == NULL) {
+ plen = strlen (merged);
+ clen = 0;
+ } else {
+ plen = pos - merged;
+ clen = strlen (pos + 1);
+ if (clen >= XKL_MAX_CI_NAME_LENGTH)
+ return FALSE;
+ strcpy (*child = cbuffer, pos + 1);
+ }
+ if (plen >= XKL_MAX_CI_NAME_LENGTH)
+ return FALSE;
+ memcpy (*parent = pbuffer, merged, plen);
+ pbuffer[plen] = '\0';
+ return TRUE;
+}
+
+/**
+ * static GkbdKeyboardConfig functions
+ */
+static void
+gkbd_keyboard_config_options_add_full (GkbdKeyboardConfig * kbd_config,
+ const gchar * full_option_name)
+{
+ kbd_config->options =
+ g_slist_append (kbd_config->options,
+ g_strdup (full_option_name));
+}
+
+static void
+gkbd_keyboard_config_layouts_add_full (GkbdKeyboardConfig * kbd_config,
+ const gchar * full_layout_name)
+{
+ kbd_config->layouts =
+ g_slist_append (kbd_config->layouts,
+ g_strdup (full_layout_name));
+}
+
+static void
+gkbd_keyboard_config_copy_from_xkl_config (GkbdKeyboardConfig * kbd_config,
+ XklConfigRec * pdata)
+{
+ char **p, **p1;
+ gkbd_keyboard_config_model_set (kbd_config, pdata->model);
+ xkl_debug (150, "Loaded Kbd model: [%s]\n", pdata->model);
+
+ gkbd_keyboard_config_layouts_reset (kbd_config);
+ p = pdata->layouts;
+ p1 = pdata->variants;
+ while (p != NULL && *p != NULL) {
+ if (*p1 == NULL || **p1 == '\0') {
+ xkl_debug (150, "Loaded Kbd layout: [%s]\n", *p);
+ gkbd_keyboard_config_layouts_add_full (kbd_config,
+ *p);
+ } else {
+ char full_layout[XKL_MAX_CI_NAME_LENGTH * 2];
+ g_snprintf (full_layout, sizeof (full_layout),
+ "%s\t%s", *p, *p1);
+ xkl_debug (150,
+ "Loaded Kbd layout with variant: [%s]\n",
+ full_layout);
+ gkbd_keyboard_config_layouts_add_full (kbd_config,
+ full_layout);
+ }
+ p++;
+ p1++;
+ }
+
+ gkbd_keyboard_config_options_reset (kbd_config);
+ p = pdata->options;
+ while (p != NULL && *p != NULL) {
+ char group[XKL_MAX_CI_NAME_LENGTH];
+ char *option = *p;
+ char *delim =
+ (option != NULL) ? strchr (option, ':') : NULL;
+ int len;
+ if ((delim != NULL) &&
+ ((len = (delim - option)) < XKL_MAX_CI_NAME_LENGTH)) {
+ strncpy (group, option, len);
+ group[len] = 0;
+ xkl_debug (150, "Loaded Kbd option: [%s][%s]\n",
+ group, option);
+ gkbd_keyboard_config_options_add (kbd_config,
+ group, option);
+ }
+ p++;
+ }
+}
+
+static void
+gkbd_keyboard_config_copy_to_xkl_config (GkbdKeyboardConfig * kbd_config,
+ XklConfigRec * pdata)
+{
+ int i;
+ int num_layouts, num_options;
+ pdata->model =
+ (kbd_config->model ==
+ NULL) ? NULL : g_strdup (kbd_config->model);
+
+ num_layouts =
+ (kbd_config->layouts ==
+ NULL) ? 0 : g_slist_length (kbd_config->layouts);
+ num_options =
+ (kbd_config->options ==
+ NULL) ? 0 : g_slist_length (kbd_config->options);
+
+ xkl_debug (150, "Taking %d layouts\n", num_layouts);
+ if (num_layouts != 0) {
+ GSList *the_layout = kbd_config->layouts;
+ char **p1 = pdata->layouts =
+ g_new0 (char *, num_layouts + 1);
+ char **p2 = pdata->variants =
+ g_new0 (char *, num_layouts + 1);
+ for (i = num_layouts; --i >= 0;) {
+ char *layout, *variant;
+ if (gkbd_keyboard_config_split_items
+ (the_layout->data, &layout, &variant)
+ && variant != NULL) {
+ *p1 =
+ (layout ==
+ NULL) ? g_strdup ("") :
+ g_strdup (layout);
+ *p2 =
+ (variant ==
+ NULL) ? g_strdup ("") :
+ g_strdup (variant);
+ } else {
+ *p1 =
+ (the_layout->data ==
+ NULL) ? g_strdup ("") :
+ g_strdup (the_layout->data);
+ *p2 = g_strdup ("");
+ }
+ xkl_debug (150, "Adding [%s]/%p and [%s]/%p\n",
+ *p1 ? *p1 : "(nil)", *p1,
+ *p2 ? *p2 : "(nil)", *p2);
+ p1++;
+ p2++;
+ the_layout = the_layout->next;
+ }
+ }
+
+ if (num_options != 0) {
+ GSList *the_option = kbd_config->options;
+ char **p = pdata->options =
+ g_new0 (char *, num_options + 1);
+ for (i = num_options; --i >= 0;) {
+ char *group, *option;
+ if (gkbd_keyboard_config_split_items
+ (the_option->data, &group, &option)
+ && option != NULL)
+ *(p++) = g_strdup (option);
+ else {
+ *(p++) = g_strdup ("");
+ xkl_debug (150, "Could not split [%s]\n",
+ the_option->data);
+ }
+ the_option = the_option->next;
+ }
+ }
+}
+
+static void
+gkbd_keyboard_config_load_params (GkbdKeyboardConfig * kbd_config,
+ const gchar * param_names[])
+{
+ GError *gerror = NULL;
+ gchar *pc;
+ GSList *pl;
+
+ pc = gconf_client_get_string (kbd_config->conf_client,
+ param_names[0], &gerror);
+ if (pc == NULL || gerror != NULL) {
+ if (gerror != NULL) {
+ g_warning ("Error reading configuration:%s\n",
+ gerror->message);
+ g_error_free (gerror);
+ g_free (pc);
+ gerror = NULL;
+ }
+ gkbd_keyboard_config_model_set (kbd_config, NULL);
+ } else {
+ gkbd_keyboard_config_model_set (kbd_config, pc);
+ g_free (pc);
+ }
+ xkl_debug (150, "Loaded Kbd model: [%s]\n",
+ kbd_config->model ? kbd_config->model : "(null)");
+
+ gkbd_keyboard_config_layouts_reset (kbd_config);
+
+ pl = gconf_client_get_list (kbd_config->conf_client,
+ param_names[1],
+ GCONF_VALUE_STRING, &gerror);
+ if (pl == NULL || gerror != NULL) {
+ if (gerror != NULL) {
+ g_warning ("Error reading configuration:%s\n",
+ gerror->message);
+ g_error_free (gerror);
+ gerror = NULL;
+ }
+ }
+
+ while (pl != NULL) {
+ xkl_debug (150, "Loaded Kbd layout: [%s]\n", pl->data);
+ gkbd_keyboard_config_layouts_add_full (kbd_config,
+ pl->data);
+ pl = pl->next;
+ }
+ gkbd_keyboard_config_string_list_reset (&pl);
+
+ gkbd_keyboard_config_options_reset (kbd_config);
+
+ pl = gconf_client_get_list (kbd_config->conf_client,
+ param_names[2],
+ GCONF_VALUE_STRING, &gerror);
+ if (pl == NULL || gerror != NULL) {
+ if (gerror != NULL) {
+ g_warning ("Error reading configuration:%s\n",
+ gerror->message);
+ g_error_free (gerror);
+ gerror = NULL;
+ }
+ }
+
+ while (pl != NULL) {
+ xkl_debug (150, "Loaded Kbd option: [%s]\n", pl->data);
+ gkbd_keyboard_config_options_add_full (kbd_config,
+ (const gchar *) pl->
+ data);
+ pl = pl->next;
+ }
+ gkbd_keyboard_config_string_list_reset (&pl);
+}
+
+static void
+gkbd_keyboard_config_save_params (GkbdKeyboardConfig * kbd_config,
+ GConfChangeSet * cs,
+ const gchar * param_names[])
+{
+ GSList *pl;
+
+ if (kbd_config->model)
+ gconf_change_set_set_string (cs, param_names[0],
+ kbd_config->model);
+ else
+ gconf_change_set_unset (cs, param_names[0]);
+ xkl_debug (150, "Saved Kbd model: [%s]\n",
+ kbd_config->model ? kbd_config->model : "(null)");
+
+ if (kbd_config->layouts) {
+ pl = kbd_config->layouts;
+ while (pl != NULL) {
+ xkl_debug (150, "Saved Kbd layout: [%s]\n",
+ pl->data);
+ pl = pl->next;
+ }
+ gconf_change_set_set_list (cs,
+ param_names[1],
+ GCONF_VALUE_STRING,
+ kbd_config->layouts);
+ } else {
+ xkl_debug (150, "Saved Kbd layouts: []\n");
+ gconf_change_set_unset (cs, param_names[1]);
+ }
+
+ if (kbd_config->options) {
+ pl = kbd_config->options;
+ while (pl != NULL) {
+ xkl_debug (150, "Saved Kbd option: [%s]\n",
+ pl->data);
+ pl = pl->next;
+ }
+ gconf_change_set_set_list (cs,
+ param_names[2],
+ GCONF_VALUE_STRING,
+ kbd_config->options);
+ } else {
+ xkl_debug (150, "Saved Kbd options: []\n");
+ gconf_change_set_unset (cs, param_names[2]);
+ }
+}
+
+/**
+ * extern GkbdKeyboardConfig config functions
+ */
+void
+gkbd_keyboard_config_init (GkbdKeyboardConfig * kbd_config,
+ GConfClient * conf_client, XklEngine * engine)
+{
+ GError *gerror = NULL;
+
+ memset (kbd_config, 0, sizeof (*kbd_config));
+ kbd_config->conf_client = conf_client;
+ kbd_config->engine = engine;
+ g_object_ref (kbd_config->conf_client);
+
+ gconf_client_add_dir (kbd_config->conf_client,
+ GKBD_KEYBOARD_CONFIG_DIR,
+ GCONF_CLIENT_PRELOAD_NONE, &gerror);
+ if (gerror != NULL) {
+ g_warning ("err: %s\n", gerror->message);
+ g_error_free (gerror);
+ gerror = NULL;
+ }
+}
+
+void
+gkbd_keyboard_config_term (GkbdKeyboardConfig * kbd_config)
+{
+ gkbd_keyboard_config_model_set (kbd_config, NULL);
+
+ gkbd_keyboard_config_layouts_reset (kbd_config);
+
+ g_object_unref (kbd_config->conf_client);
+ kbd_config->conf_client = NULL;
+}
+
+void
+gkbd_keyboard_config_load_from_gconf (GkbdKeyboardConfig * kbd_config,
+ GkbdKeyboardConfig *
+ kbd_config_default)
+{
+ gkbd_keyboard_config_load_params (kbd_config,
+ GKBD_KEYBOARD_CONFIG_ACTIVE);
+
+ if (kbd_config_default != NULL) {
+ GSList *pl;
+
+ if (kbd_config->model == NULL)
+ kbd_config->model =
+ g_strdup (kbd_config_default->model);
+
+ if (kbd_config->layouts == NULL) {
+ pl = kbd_config_default->layouts;
+ while (pl != NULL) {
+ kbd_config->layouts =
+ g_slist_append (kbd_config->layouts,
+ g_strdup (pl->data));
+ pl = pl->next;
+ }
+ }
+
+ if (kbd_config->options == NULL) {
+ pl = kbd_config_default->options;
+ while (pl != NULL) {
+ kbd_config->options =
+ g_slist_append (kbd_config->options,
+ g_strdup (pl->data));
+ pl = pl->next;
+ }
+ }
+ }
+}
+
+void
+gkbd_keyboard_config_load_from_gconf_backup (GkbdKeyboardConfig *
+ kbd_config)
+{
+ gkbd_keyboard_config_load_params (kbd_config,
+ GKBD_KEYBOARD_CONFIG_SYSBACKUP);
+}
+
+void
+gkbd_keyboard_config_load_from_x_current (GkbdKeyboardConfig * kbd_config)
+{
+ XklConfigRec *data = xkl_config_rec_new ();
+ if (xkl_config_rec_get_from_server (data, kbd_config->engine))
+ gkbd_keyboard_config_copy_from_xkl_config (kbd_config,
+ data);
+ else
+ xkl_debug (150,
+ "Could not load keyboard config from server: [%s]\n",
+ xkl_get_last_error ());
+ g_object_unref (G_OBJECT (data));
+}
+
+void
+gkbd_keyboard_config_load_from_x_initial (GkbdKeyboardConfig * kbd_config)
+{
+ XklConfigRec *data = xkl_config_rec_new ();
+ if (xkl_config_rec_get_from_backup (data, kbd_config->engine))
+ gkbd_keyboard_config_copy_from_xkl_config (kbd_config,
+ data);
+ else
+ xkl_debug (150,
+ "Could not load keyboard config from backup: [%s]\n",
+ xkl_get_last_error ());
+ g_object_unref (G_OBJECT (data));
+}
+
+gboolean
+gkbd_keyboard_config_equals (GkbdKeyboardConfig * kbd_config1,
+ GkbdKeyboardConfig * kbd_config2)
+{
+ if (kbd_config1 == kbd_config2)
+ return True;
+ if ((kbd_config1->model != kbd_config2->model) &&
+ (kbd_config1->model != NULL) &&
+ (kbd_config2->model != NULL) &&
+ g_ascii_strcasecmp (kbd_config1->model, kbd_config2->model))
+ return False;
+ return gslist_str_equal (kbd_config1->layouts,
+ kbd_config2->layouts)
+ && gslist_str_equal (kbd_config1->options,
+ kbd_config2->options);
+}
+
+void
+gkbd_keyboard_config_save_to_gconf (GkbdKeyboardConfig * kbd_config)
+{
+ GConfChangeSet *cs;
+ GError *gerror = NULL;
+
+ cs = gconf_change_set_new ();
+
+ gkbd_keyboard_config_save_params (kbd_config, cs,
+ GKBD_KEYBOARD_CONFIG_ACTIVE);
+
+ gconf_client_commit_change_set (kbd_config->conf_client, cs, TRUE,
+ &gerror);
+ if (gerror != NULL) {
+ g_warning ("Error saving active configuration: %s\n",
+ gerror->message);
+ g_error_free (gerror);
+ gerror = NULL;
+ }
+ gconf_change_set_unref (cs);
+}
+
+void
+gkbd_keyboard_config_save_to_gconf_backup (GkbdKeyboardConfig * kbd_config)
+{
+ GConfChangeSet *cs;
+ GError *gerror = NULL;
+
+ cs = gconf_change_set_new ();
+
+ gkbd_keyboard_config_save_params (kbd_config, cs,
+ GKBD_KEYBOARD_CONFIG_SYSBACKUP);
+
+ gconf_client_commit_change_set (kbd_config->conf_client, cs, TRUE,
+ &gerror);
+ if (gerror != NULL) {
+ g_warning ("Error saving backup configuration: %s\n",
+ gerror->message);
+ g_error_free (gerror);
+ gerror = NULL;
+ }
+ gconf_change_set_unref (cs);
+}
+
+void
+gkbd_keyboard_config_model_set (GkbdKeyboardConfig * kbd_config,
+ const gchar * model_name)
+{
+ if (kbd_config->model != NULL)
+ g_free (kbd_config->model);
+ kbd_config->model =
+ (model_name == NULL
+ || model_name[0] == '\0') ? NULL : g_strdup (model_name);
+}
+
+void
+gkbd_keyboard_config_layouts_add (GkbdKeyboardConfig * kbd_config,
+ const gchar * layout_name,
+ const gchar * variant_name)
+{
+ const gchar *merged;
+ if (layout_name == NULL)
+ return;
+ merged =
+ gkbd_keyboard_config_merge_items (layout_name, variant_name);
+ if (merged == NULL)
+ return;
+ gkbd_keyboard_config_layouts_add_full (kbd_config, merged);
+}
+
+void
+gkbd_keyboard_config_layouts_reset (GkbdKeyboardConfig * kbd_config)
+{
+ gkbd_keyboard_config_string_list_reset (&kbd_config->layouts);
+}
+
+void
+gkbd_keyboard_config_options_reset (GkbdKeyboardConfig * kbd_config)
+{
+ gkbd_keyboard_config_string_list_reset (&kbd_config->options);
+}
+
+void
+gkbd_keyboard_config_options_add (GkbdKeyboardConfig * kbd_config,
+ const gchar * group_name,
+ const gchar * option_name)
+{
+ const gchar *merged;
+ if (group_name == NULL || option_name == NULL)
+ return;
+ merged =
+ gkbd_keyboard_config_merge_items (group_name, option_name);
+ if (merged == NULL)
+ return;
+ gkbd_keyboard_config_options_add_full (kbd_config, merged);
+}
+
+gboolean
+gkbd_keyboard_config_options_is_set (GkbdKeyboardConfig * kbd_config,
+ const gchar * group_name,
+ const gchar * option_name)
+{
+ const gchar *merged =
+ gkbd_keyboard_config_merge_items (group_name, option_name);
+ if (merged == NULL)
+ return FALSE;
+
+ return NULL != g_slist_find_custom (kbd_config->options, (gpointer)
+ merged, (GCompareFunc)
+ g_ascii_strcasecmp);
+}
+
+gboolean
+gkbd_keyboard_config_activate (GkbdKeyboardConfig * kbd_config)
+{
+ gboolean rv;
+ XklConfigRec *data = xkl_config_rec_new ();
+
+ gkbd_keyboard_config_copy_to_xkl_config (kbd_config, data);
+ rv = xkl_config_rec_activate (data, kbd_config->engine);
+ g_object_unref (G_OBJECT (data));
+
+ return rv;
+}
+
+void
+gkbd_keyboard_config_start_listen (GkbdKeyboardConfig * kbd_config,
+ GConfClientNotifyFunc func,
+ gpointer user_data)
+{
+ gkbd_desktop_config_add_listener (kbd_config->conf_client,
+ GKBD_KEYBOARD_CONFIG_DIR, func,
+ user_data,
+ &kbd_config->config_listener_id);
+}
+
+void
+gkbd_keyboard_config_stop_listen (GkbdKeyboardConfig * kbd_config)
+{
+ gkbd_desktop_config_remove_listener (kbd_config->conf_client,
+ &kbd_config->
+ config_listener_id);
+}
+
+gboolean
+gkbd_keyboard_config_get_descriptions (XklConfigRegistry * config_registry,
+ const gchar * name,
+ gchar ** layout_short_descr,
+ gchar ** layout_descr,
+ gchar ** variant_short_descr,
+ gchar ** variant_descr)
+{
+ char *layout_name = NULL, *variant_name = NULL;
+ if (!gkbd_keyboard_config_split_items
+ (name, &layout_name, &variant_name))
+ return FALSE;
+ return gkbd_keyboard_config_get_lv_descriptions (config_registry,
+ layout_name,
+ variant_name,
+ layout_short_descr,
+ layout_descr,
+ variant_short_descr,
+ variant_descr);
+}
+
+const gchar *
+gkbd_keyboard_config_format_full_layout (const gchar * layout_descr,
+ const gchar * variant_descr)
+{
+ static gchar full_descr[XKL_MAX_CI_DESC_LENGTH * 2];
+ if (variant_descr == NULL)
+ g_snprintf (full_descr, sizeof (full_descr), "%s",
+ layout_descr);
+ else
+ g_snprintf (full_descr, sizeof (full_descr), "%s %s",
+ layout_descr, variant_descr);
+ return full_descr;
+}
+
+gchar *
+gkbd_keyboard_config_to_string (const GkbdKeyboardConfig * config)
+{
+ gchar *layouts = NULL, *options = NULL;
+ GString *buffer = g_string_new (NULL);
+
+ GSList *iter;
+ gint count;
+ gchar *result;
+
+ if (config->layouts) {
+ /* g_slist_length is "expensive", so we determinate the length on the fly */
+ for (iter = config->layouts, count = 0; iter;
+ iter = iter->next, ++count) {
+ if (buffer->len)
+ g_string_append (buffer, " ");
+
+ g_string_append (buffer,
+ (const gchar *) iter->data);
+ }
+
+ /* TRANS: The count is related to the number of options. The %s format specifier should not be modified,
+ * left "as is". */
+ layouts =
+ g_strdup_printf (ngettext
+ ("layout \"%s\"", "layouts \"%s\"",
+ count), buffer->str);
+ g_string_truncate (buffer, 0);
+ }
+ if (config->options) {
+ /* g_slist_length is "expensive", so we determinate the length on the fly */
+ for (iter = config->options, count = 0; iter;
+ iter = iter->next, ++count) {
+ if (buffer->len)
+ g_string_append (buffer, " ");
+
+ g_string_append (buffer,
+ (const gchar *) iter->data);
+ }
+
+ /* TRANS: The count is related to the number of options. The %s format specifier should not be modified,
+ * left "as is". */
+ options =
+ g_strdup_printf (ngettext
+ ("option \"%s\"", "options \"%s\"",
+ count), buffer->str);
+ g_string_truncate (buffer, 0);
+ }
+
+ g_string_free (buffer, TRUE);
+
+ result =
+ g_strdup_printf (_("model \"%s\", %s and %s"), config->model,
+ layouts ? layouts : _("no layout"),
+ options ? options : _("no options"));
+
+ g_free (options);
+ g_free (layouts);
+
+ return result;
+}
diff --git a/libgnomekbd/gkbd-keyboard-config.h b/libgnomekbd/gkbd-keyboard-config.h
new file mode 100644
index 0000000..9e9083c
--- /dev/null
+++ b/libgnomekbd/gkbd-keyboard-config.h
@@ -0,0 +1,120 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GKBD_KEYBOARD_CONFIG_H__
+#define __GKBD_KEYBOARD_CONFIG_H__
+
+#include <X11/Xlib.h>
+
+#include <glib.h>
+#include <glib/gslist.h>
+
+#include <gconf/gconf-client.h>
+
+#include <libxklavier/xklavier.h>
+
+extern const gchar GKBD_KEYBOARD_CONFIG_DIR[];
+extern const gchar GKBD_KEYBOARD_CONFIG_KEY_MODEL[];
+extern const gchar GKBD_KEYBOARD_CONFIG_KEY_LAYOUTS[];
+extern const gchar GKBD_KEYBOARD_CONFIG_KEY_OPTIONS[];
+
+/*
+ * Keyboard Configuration
+ */
+typedef struct _GkbdKeyboardConfig {
+ gchar *model;
+ GSList *layouts;
+ GSList *options;
+
+ /* private, transient */
+ GConfClient *conf_client;
+ int config_listener_id;
+ XklEngine *engine;
+} GkbdKeyboardConfig;
+
+/**
+ * GkbdKeyboardConfig functions
+ */
+extern void gkbd_keyboard_config_init (GkbdKeyboardConfig * kbd_config,
+ GConfClient * conf_client,
+ XklEngine * engine);
+extern void gkbd_keyboard_config_term (GkbdKeyboardConfig * kbd_config);
+
+extern void gkbd_keyboard_config_load_from_gconf (GkbdKeyboardConfig *
+ kbd_config,
+ GkbdKeyboardConfig *
+ kbd_config_default);
+
+extern void gkbd_keyboard_config_save_to_gconf (GkbdKeyboardConfig *
+ kbd_config);
+
+extern void gkbd_keyboard_config_load_from_gconf_backup (GkbdKeyboardConfig
+ * kbd_config);
+
+extern void gkbd_keyboard_config_save_to_gconf_backup (GkbdKeyboardConfig *
+ kbd_config);
+
+extern void gkbd_keyboard_config_load_from_x_initial (GkbdKeyboardConfig *
+ kbd_config);
+
+extern void gkbd_keyboard_config_load_from_x_current (GkbdKeyboardConfig *
+ kbd_config);
+
+extern void gkbd_keyboard_config_start_listen (GkbdKeyboardConfig *
+ kbd_config,
+ GConfClientNotifyFunc func,
+ gpointer user_data);
+
+extern void gkbd_keyboard_config_stop_listen (GkbdKeyboardConfig *
+ kbd_config);
+
+extern gboolean gkbd_keyboard_config_equals (GkbdKeyboardConfig *
+ kbd_config1,
+ GkbdKeyboardConfig *
+ kbd_config2);
+
+extern gboolean gkbd_keyboard_config_activate (GkbdKeyboardConfig *
+ kbd_config);
+
+extern const gchar *gkbd_keyboard_config_merge_items (const gchar * parent,
+ const gchar * child);
+
+extern gboolean gkbd_keyboard_config_split_items (const gchar * merged,
+ gchar ** parent,
+ gchar ** child);
+
+extern gboolean gkbd_keyboard_config_get_descriptions (XklConfigRegistry *
+ config_registry,
+ const gchar * name,
+ gchar **
+ layout_short_descr,
+ gchar **
+ layout_descr,
+ gchar **
+ variant_short_descr,
+ gchar **
+ variant_descr);
+
+extern const gchar *gkbd_keyboard_config_format_full_layout (const gchar
+ *
+ layout_descr,
+ const gchar *
+ variant_descr);
+
+extern gchar *gkbd_keyboard_config_to_string (const GkbdKeyboardConfig *
+ config);
+
+#endif
diff --git a/libgnomekbd/gkbd-keyboard-drawing-marshal.list b/libgnomekbd/gkbd-keyboard-drawing-marshal.list
new file mode 100644
index 0000000..88a875f
--- /dev/null
+++ b/libgnomekbd/gkbd-keyboard-drawing-marshal.list
@@ -0,0 +1,2 @@
+# $Id$
+VOID:UINT
diff --git a/libgnomekbd/gkbd-keyboard-drawing.c b/libgnomekbd/gkbd-keyboard-drawing.c
new file mode 100644
index 0000000..8fa0453
--- /dev/null
+++ b/libgnomekbd/gkbd-keyboard-drawing.c
@@ -0,0 +1,1848 @@
+/* $Id$ */
+/*
+ * keyboard-drawing.c: implementation of a gtk+ widget that is a drawing of
+ * the keyboard of the default display
+ *
+ * Copyright (c) 2004 Noah Levitt
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <config.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkx.h>
+#include <gdk/gdkkeysyms.h>
+#include <X11/XKBlib.h>
+#include <X11/extensions/XKBgeom.h>
+#include <stdlib.h>
+#include <memory.h>
+#include <math.h>
+
+#include <gkbd-keyboard-drawing.h>
+#include <gkbd-keyboard-drawing-marshal.h>
+
+#define noKBDRAW_DEBUG
+
+enum {
+ BAD_KEYCODE = 0,
+ NUM_SIGNALS
+};
+
+static guint gkbd_keyboard_drawing_signals[NUM_SIGNALS] = { 0 };
+
+static void gkbd_keyboard_drawing_set_mods (GkbdKeyboardDrawing * drawing,
+ guint mods);
+
+static gint
+xkb_to_pixmap_coord (GkbdKeyboardDrawing * drawing, gint n)
+{
+ return n * drawing->scale_numerator / drawing->scale_denominator;
+}
+
+/* angle is in tenths of a degree; coordinates can be anything as (xkb,
+ * pixels, pango) as long as they are all the same */
+static void
+rotate_coordinate (gint origin_x,
+ gint origin_y,
+ gint x,
+ gint y, gint angle, gint * rotated_x, gint * rotated_y)
+{
+ *rotated_x =
+ origin_x + (x - origin_x) * cos (M_PI * angle / 1800.0) - (y -
+ origin_y)
+ * sin (M_PI * angle / 1800.0);
+ *rotated_y =
+ origin_y + (x - origin_x) * sin (M_PI * angle / 1800.0) + (y -
+ origin_y)
+ * cos (M_PI * angle / 1800.0);
+}
+
+static void
+draw_polygon (GkbdKeyboardDrawing * drawing,
+ GdkColor * fill_color,
+ gint xkb_x,
+ gint xkb_y, XkbPointRec * xkb_points, guint num_points)
+{
+ GtkStateType state = GTK_WIDGET_STATE (GTK_WIDGET (drawing));
+ GdkGC *gc;
+ GdkPoint *points;
+ gboolean filled;
+ gint i;
+
+ if (drawing->pixmap == NULL)
+ return;
+
+ if (fill_color) {
+ gc = gdk_gc_new (GTK_WIDGET (drawing)->window);
+ gdk_gc_set_rgb_fg_color (gc, fill_color);
+ filled = TRUE;
+ } else {
+ gc = GTK_WIDGET (drawing)->style->dark_gc[state];
+ filled = FALSE;
+ }
+
+ points = g_new (GdkPoint, num_points);
+
+ for (i = 0; i < num_points; i++) {
+ points[i].x =
+ xkb_to_pixmap_coord (drawing, xkb_x + xkb_points[i].x);
+ points[i].y =
+ xkb_to_pixmap_coord (drawing, xkb_y + xkb_points[i].y);
+ }
+
+ gdk_draw_polygon (drawing->pixmap, gc, filled, points, num_points);
+
+ g_free (points);
+ if (fill_color)
+ g_object_unref (gc);
+}
+
+/* x, y, width, height are in the xkb coordinate system */
+static void
+draw_rectangle (GkbdKeyboardDrawing * drawing,
+ GdkColor * fill_color,
+ gint angle,
+ gint xkb_x, gint xkb_y, gint xkb_width, gint xkb_height)
+{
+ if (drawing->pixmap == NULL)
+ return;
+
+ if (angle == 0) {
+ GtkStateType state =
+ GTK_WIDGET_STATE (GTK_WIDGET (drawing));
+ gint x, y, width, height;
+ gboolean filled;
+ GdkGC *gc;
+
+ if (fill_color) {
+ gc = gdk_gc_new (GTK_WIDGET (drawing)->window);
+ gdk_gc_set_rgb_fg_color (gc, fill_color);
+ filled = TRUE;
+ } else {
+ gc = GTK_WIDGET (drawing)->style->dark_gc[state];
+ filled = FALSE;
+ }
+
+ x = xkb_to_pixmap_coord (drawing, xkb_x);
+ y = xkb_to_pixmap_coord (drawing, xkb_y);
+ width =
+ xkb_to_pixmap_coord (drawing, xkb_x + xkb_width) - x;
+ height =
+ xkb_to_pixmap_coord (drawing, xkb_y + xkb_height) - y;
+
+ gdk_draw_rectangle (drawing->pixmap, gc, filled, x, y,
+ width, height);
+
+ if (fill_color)
+ g_object_unref (gc);
+ } else {
+ XkbPointRec points[4];
+ gint x, y;
+
+ points[0].x = xkb_x;
+ points[0].y = xkb_y;
+ rotate_coordinate (xkb_x, xkb_y, xkb_x + xkb_width, xkb_y,
+ angle, &x, &y);
+ points[1].x = x;
+ points[1].y = y;
+ rotate_coordinate (xkb_x, xkb_y, xkb_x + xkb_width,
+ xkb_y + xkb_height, angle, &x, &y);
+ points[2].x = x;
+ points[2].y = y;
+ rotate_coordinate (xkb_x, xkb_y, xkb_x, xkb_y + xkb_height,
+ angle, &x, &y);
+ points[3].x = x;
+ points[3].y = y;
+
+ /* the points we've calculated are relative to 0,0 */
+ draw_polygon (drawing, fill_color, 0, 0, points, 4);
+ }
+}
+
+static void
+draw_outline (GkbdKeyboardDrawing * drawing,
+ XkbOutlineRec * outline,
+ GdkColor * color, gint angle, gint origin_x, gint origin_y)
+{
+#ifdef KBDRAW_DEBUG
+ printf ("num_points in %p: %d\n", outline, outline->num_points);
+#endif
+
+ if (outline->num_points == 1) {
+ if (color)
+ draw_rectangle (drawing, color, angle, origin_x,
+ origin_y, outline->points[0].x,
+ outline->points[0].y);
+
+#ifdef KBDRAW_DEBUG
+ printf ("points:%p\n", outline->points);
+ printf ("pointsxy:%d %d\n", outline->points[0].x,
+ outline->points[0].y);
+#endif
+
+ draw_rectangle (drawing, NULL, angle, origin_x, origin_y,
+ outline->points[0].x,
+ outline->points[0].y);
+ } else if (outline->num_points == 2) {
+ gint rotated_x0, rotated_y0;
+
+ rotate_coordinate (origin_x, origin_y,
+ origin_x + outline->points[0].x,
+ origin_y + outline->points[0].y,
+ angle, &rotated_x0, &rotated_y0);
+ if (color)
+ draw_rectangle (drawing, color, angle, rotated_x0,
+ rotated_y0, outline->points[1].x,
+ outline->points[1].y);
+
+ draw_rectangle (drawing, NULL, angle, rotated_x0,
+ rotated_y0, outline->points[1].x,
+ outline->points[1].y);
+ } else {
+ if (color)
+ draw_polygon (drawing, color, origin_x, origin_y,
+ outline->points,
+ outline->num_points);
+
+ draw_polygon (drawing, NULL, origin_x, origin_y,
+ outline->points, outline->num_points);
+ }
+}
+
+/* see PSColorDef in xkbprint */
+static gboolean
+parse_xkb_color_spec (gchar * colorspec, GdkColor * color)
+{
+ glong level;
+
+ if (g_ascii_strcasecmp (colorspec, "black") == 0) {
+ color->red = 0;
+ color->green = 0;
+ color->blue = 0;
+ } else if (g_ascii_strcasecmp (colorspec, "white") == 0) {
+ color->red = 65535;
+ color->green = 65535;
+ color->blue = 65535;
+ } else if (g_ascii_strncasecmp (colorspec, "grey", 4) == 0 ||
+ g_ascii_strncasecmp (colorspec, "gray", 4) == 0) {
+ level = strtol (colorspec + 4, NULL, 10);
+
+ color->red = 65535 - 65535 * level / 100;
+ color->green = 65535 - 65535 * level / 100;
+ color->blue = 65535 - 65535 * level / 100;
+ } else if (g_ascii_strcasecmp (colorspec, "red") == 0) {
+ color->red = 65535;
+ color->green = 0;
+ color->blue = 0;
+ } else if (g_ascii_strcasecmp (colorspec, "green") == 0) {
+ color->red = 0;
+ color->green = 65535;
+ color->blue = 0;
+ } else if (g_ascii_strcasecmp (colorspec, "blue") == 0) {
+ color->red = 0;
+ color->green = 0;
+ color->blue = 65535;
+ } else if (g_ascii_strncasecmp (colorspec, "red", 3) == 0) {
+ level = strtol (colorspec + 3, NULL, 10);
+
+ color->red = 65535 * level / 100;
+ color->green = 0;
+ color->blue = 0;
+ } else if (g_ascii_strncasecmp (colorspec, "green", 5) == 0) {
+ level = strtol (colorspec + 5, NULL, 10);
+
+ color->red = 0;
+ color->green = 65535 * level / 100;;
+ color->blue = 0;
+ } else if (g_ascii_strncasecmp (colorspec, "blue", 4) == 0) {
+ level = strtol (colorspec + 4, NULL, 10);
+
+ color->red = 0;
+ color->green = 0;
+ color->blue = 65535 * level / 100;
+ } else
+ return FALSE;
+
+ return TRUE;
+}
+
+
+static guint
+find_keycode (GkbdKeyboardDrawing * drawing, gchar * key_name)
+{
+ guint i;
+
+ if (!drawing->xkb)
+ return (gint) (-1);
+
+ for (i = drawing->xkb->min_key_code;
+ i <= drawing->xkb->max_key_code; i++) {
+ if (drawing->xkb->names->keys[i].name[0] == key_name[0]
+ && drawing->xkb->names->keys[i].name[1] == key_name[1]
+ && drawing->xkb->names->keys[i].name[2] == key_name[2]
+ && drawing->xkb->names->keys[i].name[3] == key_name[3])
+ return i;
+ }
+
+ return (guint) (-1);
+}
+
+
+static void
+fit_width (GkbdKeyboardDrawing * drawing, gint width)
+{
+ PangoRectangle logical_rect;
+ gint old_size;
+
+ pango_layout_get_extents (drawing->layout, NULL, &logical_rect);
+
+ if (logical_rect.width > 0 && logical_rect.width > width) {
+ old_size =
+ pango_font_description_get_size (drawing->font_desc);
+ pango_font_description_set_size (drawing->font_desc,
+ old_size * width /
+ logical_rect.width);
+ pango_layout_set_font_description (drawing->layout,
+ drawing->font_desc);
+ }
+}
+
+static void
+set_key_label_in_layout (GkbdKeyboardDrawing * drawing,
+ PangoLayout * layout, guint keyval)
+{
+ gchar buf[5];
+ gunichar uc;
+
+ switch (keyval) {
+ case GDK_Scroll_Lock:
+ pango_layout_set_text (layout, "Scroll\nLock", -1);
+ break;
+
+ case GDK_space:
+ pango_layout_set_text (layout, "", -1);
+ break;
+
+ case GDK_Sys_Req:
+ pango_layout_set_text (layout, "Sys Rq", -1);
+ break;
+
+ case GDK_Page_Up:
+ pango_layout_set_text (layout, "Page\nUp", -1);
+ break;
+
+ case GDK_Page_Down:
+ pango_layout_set_text (layout, "Page\nDown", -1);
+ break;
+
+ case GDK_Num_Lock:
+ pango_layout_set_text (layout, "Num\nLock", -1);
+ break;
+
+ case GDK_KP_Page_Up:
+ pango_layout_set_text (layout, "Pg Up", -1);
+ break;
+
+ case GDK_KP_Page_Down:
+ pango_layout_set_text (layout, "Pg Dn", -1);
+ break;
+
+ case GDK_KP_Home:
+ pango_layout_set_text (layout, "Home", -1);
+ break;
+
+ case GDK_KP_Left:
+ pango_layout_set_text (layout, "Left", -1);
+ break;
+
+ case GDK_KP_End:
+ pango_layout_set_text (layout, "End", -1);
+ break;
+
+ case GDK_KP_Up:
+ pango_layout_set_text (layout, "Up", -1);
+ break;
+
+ case GDK_KP_Begin:
+ pango_layout_set_text (layout, "Begin", -1);
+ break;
+
+ case GDK_KP_Right:
+ pango_layout_set_text (layout, "Right", -1);
+ break;
+
+ case GDK_KP_Enter:
+ pango_layout_set_text (layout, "Enter", -1);
+ break;
+
+ case GDK_KP_Down:
+ pango_layout_set_text (layout, "Down", -1);
+ break;
+
+ case GDK_KP_Insert:
+ pango_layout_set_text (layout, "Ins", -1);
+ break;
+
+ case GDK_KP_Delete:
+ pango_layout_set_text (layout, "Del", -1);
+ break;
+
+ case GDK_dead_grave:
+ pango_layout_set_text (layout, "ˋ", -1);
+ break;
+
+ case GDK_dead_acute:
+ pango_layout_set_text (layout, "ˊ", -1);
+ break;
+
+ case GDK_dead_circumflex:
+ pango_layout_set_text (layout, "ˆ", -1);
+ break;
+
+ case GDK_dead_tilde:
+ pango_layout_set_text (layout, "~", -1);
+ break;
+
+ case GDK_dead_macron:
+ pango_layout_set_text (layout, "ˉ", -1);
+ break;
+
+ case GDK_dead_breve:
+ pango_layout_set_text (layout, "˘", -1);
+ break;
+
+ case GDK_dead_abovedot:
+ pango_layout_set_text (layout, "˙", -1);
+ break;
+
+ case GDK_dead_diaeresis:
+ pango_layout_set_text (layout, "¨", -1);
+ break;
+
+ case GDK_dead_abovering:
+ pango_layout_set_text (layout, "˚", -1);
+ break;
+
+ case GDK_dead_doubleacute:
+ pango_layout_set_text (layout, "˝", -1);
+ break;
+
+ case GDK_dead_caron:
+ pango_layout_set_text (layout, "ˇ", -1);
+ break;
+
+ case GDK_dead_cedilla:
+ pango_layout_set_text (layout, "¸", -1);
+ break;
+
+ case GDK_dead_ogonek:
+ pango_layout_set_text (layout, "˛", -1);
+ break;
+
+ /* case GDK_dead_iota:
+ * case GDK_dead_voiced_sound:
+ * case GDK_dead_semivoiced_sound: */
+
+ case GDK_dead_belowdot:
+ pango_layout_set_text (layout, " ̣", -1);
+ break;
+
+ case GDK_horizconnector:
+ pango_layout_set_text (layout, "horiz\nconn", -1);
+ break;
+
+ case GDK_Mode_switch:
+ pango_layout_set_text (layout, "AltGr", -1);
+ break;
+
+ case GDK_Multi_key:
+ pango_layout_set_text (layout, "Compose", -1);
+ break;
+
+ default:
+ uc = gdk_keyval_to_unicode (keyval);
+ if (uc != 0 && g_unichar_isgraph (uc)) {
+ buf[g_unichar_to_utf8 (uc, buf)] = '\0';
+ pango_layout_set_text (layout, buf, -1);
+ } else {
+ gchar *name = gdk_keyval_name (keyval);
+ if (name)
+ pango_layout_set_text (layout, name, -1);
+ else
+ pango_layout_set_text (layout, "", -1);
+ }
+ }
+}
+
+
+static void
+draw_layout (GkbdKeyboardDrawing * drawing,
+ gint angle, gint x, gint y, PangoLayout * layout)
+{
+ GtkStateType state = GTK_WIDGET_STATE (GTK_WIDGET (drawing));
+ PangoLayoutLine *line;
+ gint x_off, y_off;
+ gint i;
+
+ if (drawing->pixmap == NULL)
+ return;
+
+ if (angle != drawing->angle) {
+ PangoMatrix matrix = PANGO_MATRIX_INIT;
+ pango_matrix_rotate (&matrix, -angle / 10.0);
+ pango_context_set_matrix (gtk_widget_get_pango_context
+ (GTK_WIDGET (drawing)), &matrix);
+ pango_layout_context_changed (drawing->layout);
+ drawing->angle = angle;
+ }
+
+ i = 0;
+ y_off = 0;
+ for (line = pango_layout_get_line (drawing->layout, i);
+ line != NULL;
+ line = pango_layout_get_line (drawing->layout, ++i)) {
+ GSList *runp;
+ PangoRectangle line_extents;
+
+ x_off = 0;
+
+ for (runp = line->runs; runp != NULL; runp = runp->next) {
+ PangoGlyphItem *run = runp->data;
+ gint j;
+
+ for (j = 0; j < run->glyphs->num_glyphs; j++) {
+ PangoGlyphGeometry *geometry;
+ gint xx, yy;
+
+ geometry =
+ &run->glyphs->glyphs[j].geometry;
+
+ rotate_coordinate (0, 0, x_off, y_off,
+ angle, &xx, &yy);
+ geometry->x_offset -= x_off - xx;
+ geometry->y_offset -= y_off - yy;
+
+ x_off += geometry->width;
+ }
+ }
+
+ pango_layout_line_get_extents (line, NULL, &line_extents);
+ y_off +=
+ line_extents.height +
+ pango_layout_get_spacing (drawing->layout);
+ }
+
+ gdk_draw_layout (drawing->pixmap,
+ GTK_WIDGET (drawing)->style->text_gc[state], x, y,
+ drawing->layout);
+}
+
+static void
+draw_key_label_helper (GkbdKeyboardDrawing * drawing,
+ KeySym keysym,
+ gint angle,
+ GkbdKeyboardDrawingGroupLevelPosition glp,
+ gint x,
+ gint y, gint width, gint height, gint padding)
+{
+ gint old_size;
+ gint label_x, label_y, label_max_width, ycell;
+
+ if (keysym == 0)
+ return;
+#ifdef KBDRAW_DEBUG
+ printf ("keysym: %04X(%c) at glp: %d\n",
+ (unsigned) keysym, (char) keysym, (int) glp);
+#endif
+
+ switch (glp) {
+ case GKBD_KEYBOARD_DRAWING_POS_TOPLEFT:
+ case GKBD_KEYBOARD_DRAWING_POS_BOTTOMLEFT:
+ {
+ ycell =
+ glp == GKBD_KEYBOARD_DRAWING_POS_BOTTOMLEFT;
+
+ rotate_coordinate (x, y, x + padding,
+ y + padding + (height -
+ 2 * padding) *
+ ycell * 4 / 7, angle, &label_x,
+ &label_y);
+ label_max_width =
+ PANGO_SCALE * (width - 2 * padding);
+ break;
+ }
+ case GKBD_KEYBOARD_DRAWING_POS_TOPRIGHT:
+ case GKBD_KEYBOARD_DRAWING_POS_BOTTOMRIGHT:
+ {
+ ycell =
+ glp == GKBD_KEYBOARD_DRAWING_POS_BOTTOMRIGHT;
+
+ rotate_coordinate (x, y,
+ x + padding + (width -
+ 2 * padding) *
+ 4 / 7,
+ y + padding + (height -
+ 2 * padding) *
+ ycell * 4 / 7, angle, &label_x,
+ &label_y);
+ label_max_width =
+ PANGO_SCALE * ((width - 2 * padding) -
+ (width - 2 * padding) * 4 / 7);
+ break;
+ }
+ default:
+ return;
+ }
+ set_key_label_in_layout (drawing, drawing->layout, keysym);
+
+ old_size = pango_font_description_get_size (drawing->font_desc);
+ fit_width (drawing, label_max_width);
+
+ draw_layout (drawing, angle, label_x, label_y, drawing->layout);
+
+ if (pango_font_description_get_size (drawing->font_desc) !=
+ old_size) {
+ pango_font_description_set_size (drawing->font_desc,
+ old_size);
+ pango_layout_set_font_description (drawing->layout,
+ drawing->font_desc);
+ }
+}
+
+static void
+draw_key_label (GkbdKeyboardDrawing * drawing,
+ guint keycode,
+ gint angle,
+ gint xkb_origin_x,
+ gint xkb_origin_y, gint xkb_width, gint xkb_height)
+{
+ gint x, y, width, height;
+ gint padding;
+ gint g, l, glp;
+
+ if (!drawing->xkb)
+ return;
+
+ padding = 23 * drawing->scale_numerator / drawing->scale_denominator; /* 2.3mm */
+
+ x = xkb_to_pixmap_coord (drawing, xkb_origin_x);
+ y = xkb_to_pixmap_coord (drawing, xkb_origin_y);
+ width =
+ xkb_to_pixmap_coord (drawing, xkb_origin_x + xkb_width) - x;
+ height =
+ xkb_to_pixmap_coord (drawing, xkb_origin_y + xkb_height) - y;
+
+ for (glp = GKBD_KEYBOARD_DRAWING_POS_TOPLEFT;
+ glp < GKBD_KEYBOARD_DRAWING_POS_TOTAL; glp++) {
+ if (drawing->groupLevels[glp] == NULL)
+ continue;
+ g = drawing->groupLevels[glp]->group;
+ l = drawing->groupLevels[glp]->level;
+
+ if (g < 0 || g >= XkbKeyNumGroups (drawing->xkb, keycode))
+ continue;
+ if (l < 0
+ || l >= XkbKeyGroupWidth (drawing->xkb, keycode, g))
+ continue;
+
+ if (drawing->track_modifiers) {
+ uint mods_rtrn;
+ KeySym keysym;
+
+ if (XkbTranslateKeyCode (drawing->xkb, keycode,
+ XkbBuildCoreState
+ (drawing->mods, g),
+ &mods_rtrn, &keysym)) {
+ draw_key_label_helper (drawing, keysym,
+ angle, glp, x, y,
+ width, height,
+ padding);
+ /* reverse y order */
+ }
+ } else {
+ KeySym keysym;
+
+ keysym =
+ XkbKeySymEntry (drawing->xkb, keycode, l, g);
+
+ draw_key_label_helper (drawing, keysym, angle, glp,
+ x, y, width, height,
+ padding);
+ /* reverse y order */
+ }
+ }
+}
+
+/* groups are from 0-3 */
+static void
+draw_key (GkbdKeyboardDrawing * drawing, GkbdKeyboardDrawingKey * key)
+{
+ XkbShapeRec *shape;
+ GdkColor *color;
+ gint i;
+
+ if (!drawing->xkb)
+ return;
+
+#ifdef KBDRAW_DEBUG
+ printf ("shape: %p (%p + %d)\n",
+ drawing->xkb->geom->shapes + key->xkbkey->shape_ndx,
+ drawing->xkb->geom->shapes, key->xkbkey->shape_ndx);
+#endif
+
+ shape = drawing->xkb->geom->shapes + key->xkbkey->shape_ndx;
+
+ if (key->pressed)
+ color =
+ &(GTK_WIDGET (drawing)->style->
+ base[GTK_STATE_SELECTED]);
+ else
+ color = drawing->colors + key->xkbkey->color_ndx;
+
+#ifdef KBDRAW_DEBUG
+ printf ("outlines: %p(%d)\n", shape->outlines,
+ shape->num_outlines);
+#endif
+
+ for (i = 0; i < 1 /* shape->num_outlines */ ; i++)
+ draw_outline (drawing, shape->outlines + i, color,
+ key->angle, key->origin_x, key->origin_y);
+
+ draw_key_label (drawing, key->keycode, key->angle, key->origin_x,
+ key->origin_y, shape->bounds.x2, shape->bounds.y2);
+}
+
+static void
+invalidate_region (GkbdKeyboardDrawing * drawing,
+ gdouble angle,
+ gint origin_x, gint origin_y, XkbShapeRec * shape)
+{
+ GdkPoint points[4];
+ gint x_min, x_max, y_min, y_max;
+ gint x, y, width, height;
+ gint xx, yy;
+
+ rotate_coordinate (0, 0, 0, 0, angle, &xx, &yy);
+ points[0].x = xx;
+ points[0].y = yy;
+ rotate_coordinate (0, 0, shape->bounds.x2, 0, angle, &xx, &yy);
+ points[1].x = xx;
+ points[1].y = yy;
+ rotate_coordinate (0, 0, shape->bounds.x2, shape->bounds.y2, angle,
+ &xx, &yy);
+ points[2].x = xx;
+ points[2].y = yy;
+ rotate_coordinate (0, 0, 0, shape->bounds.y2, angle, &xx, &yy);
+ points[3].x = xx;
+ points[3].y = yy;
+
+ x_min =
+ MIN (MIN (points[0].x, points[1].x),
+ MIN (points[2].x, points[3].x));
+ x_max =
+ MAX (MAX (points[0].x, points[1].x),
+ MAX (points[2].x, points[3].x));
+ y_min =
+ MIN (MIN (points[0].y, points[1].y),
+ MIN (points[2].y, points[3].y));
+ y_max =
+ MAX (MAX (points[0].y, points[1].y),
+ MAX (points[2].y, points[3].y));
+
+ x = xkb_to_pixmap_coord (drawing, origin_x + x_min) - 6;
+ y = xkb_to_pixmap_coord (drawing, origin_y + y_min) - 6;
+ width = xkb_to_pixmap_coord (drawing, x_max - x_min) + 12;
+ height = xkb_to_pixmap_coord (drawing, y_max - y_min) + 12;
+
+ gtk_widget_queue_draw_area (GTK_WIDGET (drawing), x, y, width,
+ height);
+}
+
+static void
+invalidate_indicator_doodad_region (GkbdKeyboardDrawing * drawing,
+ GkbdKeyboardDrawingDoodad * doodad)
+{
+ if (!drawing->xkb)
+ return;
+
+ invalidate_region (drawing,
+ doodad->angle,
+ doodad->origin_x +
+ doodad->doodad->indicator.left,
+ doodad->origin_y +
+ doodad->doodad->indicator.top,
+ &drawing->xkb->geom->shapes[doodad->doodad->
+ indicator.
+ shape_ndx]);
+}
+
+static void
+invalidate_key_region (GkbdKeyboardDrawing * drawing,
+ GkbdKeyboardDrawingKey * key)
+{
+ if (!drawing->xkb)
+ return;
+
+ invalidate_region (drawing,
+ key->angle,
+ key->origin_x,
+ key->origin_y,
+ &drawing->xkb->geom->shapes[key->xkbkey->
+ shape_ndx]);
+}
+
+static void
+draw_text_doodad (GkbdKeyboardDrawing * drawing,
+ GkbdKeyboardDrawingDoodad * doodad,
+ XkbTextDoodadRec * text_doodad)
+{
+ gint x, y;
+ if (!drawing->xkb)
+ return;
+
+ x = xkb_to_pixmap_coord (drawing,
+ doodad->origin_x + text_doodad->left);
+ y = xkb_to_pixmap_coord (drawing,
+ doodad->origin_y + text_doodad->top);
+
+ pango_layout_set_text (drawing->layout, text_doodad->text, -1);
+ draw_layout (drawing, doodad->angle, x, y, drawing->layout);
+}
+
+static void
+draw_indicator_doodad (GkbdKeyboardDrawing * drawing,
+ GkbdKeyboardDrawingDoodad * doodad,
+ XkbIndicatorDoodadRec * indicator_doodad)
+{
+ GdkColor *color;
+ XkbShapeRec *shape;
+ gint i;
+
+ if (!drawing->xkb)
+ return;
+
+ shape = drawing->xkb->geom->shapes + indicator_doodad->shape_ndx;
+
+ color = drawing->colors + (doodad->on ?
+ indicator_doodad->on_color_ndx :
+ indicator_doodad->off_color_ndx);
+
+ for (i = 0; i < 1; i++)
+ draw_outline (drawing, shape->outlines + i, color,
+ doodad->angle,
+ doodad->origin_x + indicator_doodad->left,
+ doodad->origin_y + indicator_doodad->top);
+}
+
+static void
+draw_shape_doodad (GkbdKeyboardDrawing * drawing,
+ GkbdKeyboardDrawingDoodad * doodad,
+ XkbShapeDoodadRec * shape_doodad)
+{
+ XkbShapeRec *shape;
+ GdkColor *color;
+ gint i;
+
+ if (!drawing->xkb)
+ return;
+
+ shape = drawing->xkb->geom->shapes + shape_doodad->shape_ndx;
+ color = drawing->colors + shape_doodad->color_ndx;
+
+ for (i = 0; i < shape->num_outlines; i++)
+ draw_outline (drawing, shape->outlines + i, color,
+ doodad->angle,
+ doodad->origin_x + shape_doodad->left,
+ doodad->origin_y + shape_doodad->top);
+}
+
+static void
+draw_doodad (GkbdKeyboardDrawing * drawing,
+ GkbdKeyboardDrawingDoodad * doodad)
+{
+ switch (doodad->doodad->any.type) {
+ case XkbOutlineDoodad:
+ case XkbSolidDoodad:
+ draw_shape_doodad (drawing, doodad,
+ &doodad->doodad->shape);
+ break;
+
+ case XkbTextDoodad:
+ draw_text_doodad (drawing, doodad, &doodad->doodad->text);
+ break;
+
+ case XkbIndicatorDoodad:
+ draw_indicator_doodad (drawing, doodad,
+ &doodad->doodad->indicator);
+ break;
+
+ case XkbLogoDoodad:
+ /* g_print ("draw_doodad: logo: %s\n", doodad->doodad->logo.logo_name); */
+ /* XkbLogoDoodadRec is essentially a subclass of XkbShapeDoodadRec */
+ draw_shape_doodad (drawing, doodad,
+ &doodad->doodad->shape);
+ break;
+ }
+}
+
+static void
+draw_keyboard_item (GkbdKeyboardDrawingItem * item,
+ GkbdKeyboardDrawing * drawing)
+{
+ if (!drawing->xkb)
+ return;
+
+ switch (item->type) {
+ case GKBD_KEYBOARD_DRAWING_ITEM_TYPE_KEY:
+ draw_key (drawing, (GkbdKeyboardDrawingKey *) item);
+ break;
+
+ case GKBD_KEYBOARD_DRAWING_ITEM_TYPE_DOODAD:
+ draw_doodad (drawing, (GkbdKeyboardDrawingDoodad *) item);
+ break;
+ }
+}
+
+static void
+draw_keyboard (GkbdKeyboardDrawing * drawing)
+{
+ GtkStateType state = GTK_WIDGET_STATE (GTK_WIDGET (drawing));
+ gint pixw, pixh;
+
+ if (!drawing->xkb)
+ return;
+
+ pixw = GTK_WIDGET (drawing)->allocation.width;
+ pixh = GTK_WIDGET (drawing)->allocation.height;
+
+ drawing->pixmap =
+ gdk_pixmap_new (GTK_WIDGET (drawing)->window, pixw, pixh, -1);
+
+ /* blank background */
+ gdk_draw_rectangle (drawing->pixmap,
+ GTK_WIDGET (drawing)->style->base_gc[state],
+ TRUE, 0, 0, pixw, pixh);
+
+ if (drawing->xkb == NULL)
+ return;
+
+#ifdef KBDRAW_DEBUG
+ printf ("mods: %d\n", drawing->mods);
+#endif
+
+ g_list_foreach (drawing->keyboard_items,
+ (GFunc) draw_keyboard_item, drawing);
+}
+
+static void
+alloc_pango_layout (GkbdKeyboardDrawing * drawing)
+{
+ PangoContext *context =
+ gtk_widget_get_pango_context (GTK_WIDGET (drawing));
+ drawing->layout = pango_layout_new (context);
+}
+
+static void
+free_pango_layout (GkbdKeyboardDrawing * drawing)
+{
+ g_object_unref (G_OBJECT (drawing->layout));
+ drawing->layout = NULL;
+}
+
+static gboolean
+expose_event (GtkWidget * widget,
+ GdkEventExpose * event, GkbdKeyboardDrawing * drawing)
+{
+ GtkStateType state = GTK_WIDGET_STATE (GTK_WIDGET (drawing));
+
+ if (!drawing->xkb)
+ return FALSE;
+
+ if (drawing->pixmap == NULL)
+ draw_keyboard (drawing);
+
+ gdk_draw_drawable (widget->window,
+ widget->style->fg_gc[state],
+ drawing->pixmap,
+ event->area.x, event->area.y,
+ event->area.x, event->area.y,
+ event->area.width, event->area.height);
+
+ if (GTK_WIDGET_HAS_FOCUS (widget))
+ gtk_paint_focus (widget->style, widget->window,
+ GTK_WIDGET_STATE (widget), &event->area,
+ widget, "keyboard-drawing",
+ 0, 0,
+ widget->allocation.width,
+ widget->allocation.height);
+
+ return FALSE;
+}
+
+static void
+size_allocate (GtkWidget * widget,
+ GtkAllocation * allocation, GkbdKeyboardDrawing * drawing)
+{
+ if (!drawing->xkb)
+ return;
+
+ if (drawing->pixmap) {
+ g_object_unref (drawing->pixmap);
+ drawing->pixmap = NULL;
+ }
+
+ if (drawing->xkb->geom->width_mm <= 0
+ || drawing->xkb->geom->height_mm <= 0) {
+ g_critical
+ ("keyboard geometry reports width or height as zero!");
+ return;
+ }
+
+ if (allocation->width * drawing->xkb->geom->height_mm <
+ allocation->height * drawing->xkb->geom->width_mm) {
+ drawing->scale_numerator = allocation->width;
+ drawing->scale_denominator = drawing->xkb->geom->width_mm;
+ } else {
+ drawing->scale_numerator = allocation->height;
+ drawing->scale_denominator = drawing->xkb->geom->height_mm;
+ }
+
+ pango_font_description_set_size (drawing->font_desc,
+ 36000 * drawing->scale_numerator /
+ drawing->scale_denominator);
+ pango_layout_set_spacing (drawing->layout,
+ -8000 * drawing->scale_numerator /
+ drawing->scale_denominator);
+ pango_layout_set_font_description (drawing->layout,
+ drawing->font_desc);
+}
+
+static gint
+key_event (GtkWidget * widget,
+ GdkEventKey * event, GkbdKeyboardDrawing * drawing)
+{
+ GkbdKeyboardDrawingKey *key;
+ if (!drawing->xkb)
+ return FALSE;
+
+ key = drawing->keys + event->hardware_keycode;
+
+ if (event->hardware_keycode > drawing->xkb->max_key_code ||
+ event->hardware_keycode < drawing->xkb->min_key_code ||
+ key->xkbkey == NULL) {
+ g_signal_emit (drawing,
+ gkbd_keyboard_drawing_signals[BAD_KEYCODE],
+ 0, event->hardware_keycode);
+ return TRUE;
+ }
+
+ if ((event->type == GDK_KEY_PRESS && key->pressed) ||
+ (event->type == GDK_KEY_RELEASE && !key->pressed))
+ return TRUE;
+ /* otherwise this event changes the state we believed we had before */
+
+ key->pressed = (event->type == GDK_KEY_PRESS);
+
+ draw_key (drawing, key);
+
+ invalidate_key_region (drawing, key);
+
+ return TRUE;
+}
+
+static gint
+button_press_event (GtkWidget * widget,
+ GdkEventButton * event, GkbdKeyboardDrawing * drawing)
+{
+ if (!drawing->xkb)
+ return FALSE;
+
+ gtk_widget_grab_focus (widget);
+ return FALSE;
+}
+
+static gboolean
+unpress_keys (GkbdKeyboardDrawing * drawing)
+{
+ gint i;
+
+ if (!drawing->xkb)
+ return FALSE;
+
+ for (i = drawing->xkb->min_key_code;
+ i <= drawing->xkb->max_key_code; i++)
+ if (drawing->keys[i].pressed) {
+ drawing->keys[i].pressed = FALSE;
+ draw_key (drawing, drawing->keys + i);
+ invalidate_key_region (drawing, drawing->keys + i);
+ }
+
+ return FALSE;
+}
+
+static gint
+focus_event (GtkWidget * widget,
+ GdkEventFocus * event, GkbdKeyboardDrawing * drawing)
+{
+ if (event->in && drawing->timeout > 0) {
+ g_source_remove (drawing->timeout);
+ drawing->timeout = 0;
+ } else
+ drawing->timeout =
+ g_timeout_add (120, (GSourceFunc) unpress_keys,
+ drawing);
+
+ return FALSE;
+}
+
+static gint
+compare_keyboard_item_priorities (GkbdKeyboardDrawingItem * a,
+ GkbdKeyboardDrawingItem * b)
+{
+ if (a->priority > b->priority)
+ return 1;
+ else if (a->priority < b->priority)
+ return -1;
+ else
+ return 0;
+}
+
+static void
+init_indicator_doodad (GkbdKeyboardDrawing * drawing,
+ XkbDoodadRec * xkbdoodad,
+ GkbdKeyboardDrawingDoodad * doodad)
+{
+ if (!drawing->xkb)
+ return;
+
+ if (xkbdoodad->any.type == XkbIndicatorDoodad) {
+ gint index;
+ Atom iname = 0;
+ Atom sname = xkbdoodad->indicator.name;
+ unsigned long phys_indicators =
+ drawing->xkb->indicators->phys_indicators;
+ Atom *pind = drawing->xkb->names->indicators;
+
+#ifdef KBDRAW_DEBUG
+ printf ("Looking for %d[%s]\n",
+ (int) sname, XGetAtomName (drawing->display,
+ sname));
+#endif
+
+ for (index = 0; index < XkbNumIndicators; index++) {
+ iname = *pind++;
+ /* name matches and it is real */
+ if (iname == sname
+ && (phys_indicators & (1 << index)))
+ break;
+ if (iname == 0)
+ break;
+ }
+ if (iname == 0)
+ g_warning ("Could not find indicator %d [%s]\n",
+ (int) sname,
+ XGetAtomName (drawing->display, sname));
+ else {
+#ifdef KBDRAW_DEBUG
+ printf ("Found in xkbdesc as %d\n", index);
+#endif
+ drawing->physical_indicators[index] = doodad;
+ /* Trying to obtain the real state, but if fail - just assume OFF */
+ if (!XkbGetNamedIndicator
+ (drawing->display, sname, NULL, &doodad->on,
+ NULL, NULL))
+ doodad->on = 0;
+ }
+ }
+}
+
+static void
+init_keys_and_doodads (GkbdKeyboardDrawing * drawing)
+{
+ gint i, j, k;
+ gint x, y;
+
+ if (!drawing->xkb)
+ return;
+
+ for (i = 0; i < drawing->xkb->geom->num_doodads; i++) {
+ XkbDoodadRec *xkbdoodad = drawing->xkb->geom->doodads + i;
+ GkbdKeyboardDrawingDoodad *doodad =
+ g_new (GkbdKeyboardDrawingDoodad, 1);
+
+ doodad->type = GKBD_KEYBOARD_DRAWING_ITEM_TYPE_DOODAD;
+ doodad->origin_x = 0;
+ doodad->origin_y = 0;
+ doodad->angle = 0;
+ doodad->priority = xkbdoodad->any.priority * 256 * 256;
+ doodad->doodad = xkbdoodad;
+
+ init_indicator_doodad (drawing, xkbdoodad, doodad);
+
+ drawing->keyboard_items =
+ g_list_append (drawing->keyboard_items, doodad);
+ }
+
+ for (i = 0; i < drawing->xkb->geom->num_sections; i++) {
+#ifdef KBDRAW_DEBUG
+ printf ("initing section %d\n", i);
+#endif
+ XkbSectionRec *section = drawing->xkb->geom->sections + i;
+ guint priority;
+
+ x = section->left;
+ y = section->top;
+ priority = section->priority * 256 * 256;
+
+ for (j = 0; j < section->num_rows; j++) {
+ XkbRowRec *row = section->rows + j;
+
+#ifdef KBDRAW_DEBUG
+ printf (" initing row %d\n", j);
+#endif
+ x = section->left + row->left;
+ y = section->top + row->top;
+
+ for (k = 0; k < row->num_keys; k++) {
+ XkbKeyRec *xkbkey = row->keys + k;
+ GkbdKeyboardDrawingKey *key;
+ XkbShapeRec *shape =
+ drawing->xkb->geom->shapes +
+ xkbkey->shape_ndx;
+ guint keycode = find_keycode (drawing,
+ xkbkey->name.
+ name);
+
+#ifdef KBDRAW_DEBUG
+ printf
+ (" initing key %d, shape: %p(%p + %d), code: %d\n",
+ k, shape, drawing->xkb->geom->shapes,
+ xkbkey->shape_ndx, keycode);
+#endif
+ if (row->vertical)
+ y += xkbkey->gap;
+ else
+ x += xkbkey->gap;
+
+ if (keycode >= drawing->xkb->min_key_code
+ && keycode <=
+ drawing->xkb->max_key_code)
+ key = drawing->keys + keycode;
+ else {
+ g_warning
+ ("key %4.4s: keycode = %u; not in range %d..%d\n",
+ xkbkey->name.name, keycode,
+ drawing->xkb->min_key_code,
+ drawing->xkb->max_key_code);
+
+ key =
+ g_new0 (GkbdKeyboardDrawingKey,
+ 1);
+ }
+
+ key->type =
+ GKBD_KEYBOARD_DRAWING_ITEM_TYPE_KEY;
+ key->xkbkey = xkbkey;
+ key->angle = section->angle;
+ rotate_coordinate (section->left,
+ section->top, x, y,
+ section->angle,
+ &key->origin_x,
+ &key->origin_y);
+ key->priority = priority;
+ key->keycode = keycode;
+
+ drawing->keyboard_items =
+ g_list_append (drawing->keyboard_items,
+ key);
+
+ if (row->vertical)
+ y += shape->bounds.y2;
+ else
+ x += shape->bounds.x2;
+
+ priority++;
+ }
+ }
+
+ for (j = 0; j < section->num_doodads; j++) {
+ XkbDoodadRec *xkbdoodad = section->doodads + j;
+ GkbdKeyboardDrawingDoodad *doodad =
+ g_new (GkbdKeyboardDrawingDoodad, 1);
+
+ doodad->type =
+ GKBD_KEYBOARD_DRAWING_ITEM_TYPE_DOODAD;
+ doodad->origin_x = x;
+ doodad->origin_y = y;
+ doodad->angle = section->angle;
+ doodad->priority =
+ priority + xkbdoodad->any.priority;
+ doodad->doodad = xkbdoodad;
+
+ init_indicator_doodad (drawing, xkbdoodad, doodad);
+
+ drawing->keyboard_items =
+ g_list_append (drawing->keyboard_items,
+ doodad);
+ }
+ }
+
+ drawing->keyboard_items = g_list_sort (drawing->keyboard_items,
+ (GCompareFunc)
+ compare_keyboard_item_priorities);
+}
+
+static void
+init_colors (GkbdKeyboardDrawing * drawing)
+{
+ gboolean result;
+ gint i;
+
+ if (!drawing->xkb)
+ return;
+
+ drawing->colors = g_new (GdkColor, drawing->xkb->geom->num_colors);
+
+ for (i = 0; i < drawing->xkb->geom->num_colors; i++) {
+ result =
+ parse_xkb_color_spec (drawing->xkb->geom->colors[i].
+ spec, drawing->colors + i);
+
+ if (!result)
+ g_warning
+ ("init_colors: unable to parse color %s\n",
+ drawing->xkb->geom->colors[i].spec);
+ }
+}
+
+static void
+free_cdik ( /*colors doodads indicators keys */
+ GkbdKeyboardDrawing * drawing)
+{
+ GList *itemp;
+
+ if (!drawing->xkb)
+ return;
+
+ for (itemp = drawing->keyboard_items; itemp; itemp = itemp->next) {
+ GkbdKeyboardDrawingItem *item = itemp->data;
+ GkbdKeyboardDrawingKey *key;
+
+ switch (item->type) {
+ case GKBD_KEYBOARD_DRAWING_ITEM_TYPE_DOODAD:
+ g_free (item);
+ break;
+
+ case GKBD_KEYBOARD_DRAWING_ITEM_TYPE_KEY:
+ key = (GkbdKeyboardDrawingKey *) item;
+ if (key->keycode < drawing->xkb->min_key_code ||
+ key->keycode > drawing->xkb->max_key_code)
+ g_free (key);
+ /* otherwise it's part of the array */
+ break;
+ }
+ }
+
+ g_list_free (drawing->keyboard_items);
+ drawing->keyboard_items = NULL;
+
+ g_free (drawing->keys);
+ g_free (drawing->colors);
+}
+
+static void
+alloc_cdik (GkbdKeyboardDrawing * drawing)
+{
+ drawing->physical_indicators_size =
+ drawing->xkb->indicators->phys_indicators + 1;
+ drawing->physical_indicators =
+ g_new0 (GkbdKeyboardDrawingDoodad *,
+ drawing->physical_indicators_size);
+ drawing->keys =
+ g_new0 (GkbdKeyboardDrawingKey,
+ drawing->xkb->max_key_code + 1);
+}
+
+static GdkFilterReturn
+xkb_state_notify_event_filter (GdkXEvent * gdkxev,
+ GdkEvent * event,
+ GkbdKeyboardDrawing * drawing)
+{
+#define group_change_mask (XkbGroupStateMask | XkbGroupBaseMask | XkbGroupLatchMask | XkbGroupLockMask)
+#define modifier_change_mask (XkbModifierStateMask | XkbModifierBaseMask | XkbModifierLatchMask | XkbModifierLockMask)
+
+ if (!drawing->xkb)
+ return GDK_FILTER_CONTINUE;
+
+ if (((XEvent *) gdkxev)->type == drawing->xkb_event_type) {
+ XkbEvent *kev = (XkbEvent *) gdkxev;
+ switch (kev->any.xkb_type) {
+ case XkbStateNotify:
+ if (((kev->state.changed & modifier_change_mask) &&
+ drawing->track_modifiers)) {
+ free_cdik (drawing);
+ if (drawing->track_modifiers)
+ gkbd_keyboard_drawing_set_mods
+ (drawing,
+ kev->state.compat_state);
+ drawing->keys =
+ g_new0 (GkbdKeyboardDrawingKey,
+ drawing->xkb->max_key_code +
+ 1);
+ size_allocate (GTK_WIDGET (drawing),
+ &(GTK_WIDGET (drawing)->
+ allocation), drawing);
+
+ init_keys_and_doodads (drawing);
+ init_colors (drawing);
+ }
+ break;
+
+ case XkbIndicatorStateNotify:
+ {
+ /* Good question: should we track indicators when the keyboard is
+ NOT really taken from the screen */
+ XkbIndicatorNotifyEvent *iev =
+ &((XkbEvent *) gdkxev)->indicators;
+ gint i;
+
+ for (i = 0;
+ i <=
+ drawing->xkb->indicators->
+ phys_indicators; i++)
+ if (drawing->
+ physical_indicators[i] != NULL
+ && (iev->changed & 1 << i)) {
+ gint state =
+ (iev->
+ state & 1 << i) !=
+ FALSE;
+
+ if ((state
+ && !drawing->
+ physical_indicators
+ [i]->on) || (!state
+ &&
+ drawing->
+ physical_indicators
+ [i]->
+ on)) {
+ drawing->
+ physical_indicators
+ [i]->on =
+ state;
+ draw_doodad
+ (drawing,
+ drawing->
+ physical_indicators
+ [i]);
+ invalidate_indicator_doodad_region
+ (drawing,
+ drawing->
+ physical_indicators
+ [i]);
+ }
+ }
+ }
+ break;
+
+ case XkbIndicatorMapNotify:
+ case XkbControlsNotify:
+ case XkbNamesNotify:
+ case XkbNewKeyboardNotify:
+ {
+ XkbStateRec state;
+ memset (&state, 0, sizeof (state));
+ XkbGetState (drawing->display,
+ XkbUseCoreKbd, &state);
+ if (drawing->track_modifiers)
+ gkbd_keyboard_drawing_set_mods
+ (drawing, state.compat_state);
+ if (drawing->track_config)
+ gkbd_keyboard_drawing_set_keyboard
+ (drawing, NULL);
+ }
+ break;
+ }
+ }
+
+ return GDK_FILTER_CONTINUE;
+}
+
+static void
+destroy (GkbdKeyboardDrawing * drawing)
+{
+ free_pango_layout (drawing);
+ gdk_window_remove_filter (NULL, (GdkFilterFunc)
+ xkb_state_notify_event_filter, drawing);
+ if (drawing->timeout > 0) {
+ g_source_remove (drawing->timeout);
+ drawing->timeout = 0;
+ }
+
+ g_object_unref (drawing->pixmap);
+}
+
+static void
+style_changed (GkbdKeyboardDrawing * drawing)
+{
+ pango_layout_context_changed (drawing->layout);
+}
+
+static void
+gkbd_keyboard_drawing_init (GkbdKeyboardDrawing * drawing)
+{
+ gint opcode = 0, error = 0, major = 1, minor = 0;
+ gint mask;
+
+ drawing->display =
+ GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
+ printf ("dpy: %p\n", drawing->display);
+
+ if (!XkbQueryExtension
+ (drawing->display, &opcode, &drawing->xkb_event_type, &error,
+ &major, &minor))
+ g_critical
+ ("XkbQueryExtension failed! Stuff probably won't work.");
+
+ printf ("evt/error/major/minor: %d/%d/%d/%d\n",
+ drawing->xkb_event_type, error, major, minor);
+
+ /* XXX: this stuff probably doesn't matter.. also, gdk_screen_get_default can fail */
+ if (gtk_widget_has_screen (GTK_WIDGET (drawing)))
+ drawing->screen_num =
+ gdk_screen_get_number (gtk_widget_get_screen
+ (GTK_WIDGET (drawing)));
+ else
+ drawing->screen_num =
+ gdk_screen_get_number (gdk_screen_get_default ());
+
+ drawing->pixmap = NULL;
+ alloc_pango_layout (drawing);
+
+ drawing->font_desc =
+ pango_font_description_copy (GTK_WIDGET (drawing)->style->
+ font_desc);
+ drawing->keyboard_items = NULL;
+ drawing->colors = NULL;
+ drawing->angle = 0;
+ drawing->scale_numerator = 1;
+ drawing->scale_denominator = 1;
+
+ drawing->track_modifiers = 0;
+ drawing->track_config = 0;
+
+ gtk_widget_set_double_buffered (GTK_WIDGET (drawing), FALSE);
+
+ /* XXX: XkbClientMapMask | XkbIndicatorMapMask | XkbNamesMask | XkbGeometryMask */
+ drawing->xkb = XkbGetKeyboard (drawing->display,
+ XkbGBN_GeometryMask |
+ XkbGBN_KeyNamesMask |
+ XkbGBN_OtherNamesMask |
+ XkbGBN_SymbolsMask |
+ XkbGBN_IndicatorMapMask,
+ XkbUseCoreKbd);
+ if (drawing->xkb == NULL) {
+ g_critical
+ ("XkbGetKeyboard failed to get keyboard from the server!");
+ return;
+ }
+
+ XkbGetNames (drawing->display, XkbAllNamesMask, drawing->xkb);
+
+ drawing->xkbOnDisplay = TRUE;
+
+ alloc_cdik (drawing);
+
+ XkbSelectEventDetails (drawing->display, XkbUseCoreKbd,
+ XkbIndicatorStateNotify,
+ drawing->xkb->indicators->phys_indicators,
+ drawing->xkb->indicators->phys_indicators);
+
+ mask =
+ (XkbStateNotifyMask | XkbNamesNotifyMask |
+ XkbControlsNotifyMask | XkbIndicatorMapNotifyMask |
+ XkbNewKeyboardNotifyMask);
+ XkbSelectEvents (drawing->display, XkbUseCoreKbd, mask, mask);
+
+ mask = XkbGroupStateMask | XkbModifierStateMask;
+ XkbSelectEventDetails (drawing->display, XkbUseCoreKbd,
+ XkbStateNotify, mask, mask);
+
+ mask = (XkbGroupNamesMask | XkbIndicatorNamesMask);
+ XkbSelectEventDetails (drawing->display, XkbUseCoreKbd,
+ XkbNamesNotify, mask, mask);
+ init_keys_and_doodads (drawing);
+ init_colors (drawing);
+
+ /* required to get key events */
+ GTK_WIDGET_SET_FLAGS (GTK_WIDGET (drawing), GTK_CAN_FOCUS);
+
+ gtk_widget_set_events (GTK_WIDGET (drawing),
+ GDK_EXPOSURE_MASK | GDK_KEY_PRESS_MASK |
+ GDK_KEY_RELEASE_MASK | GDK_BUTTON_PRESS_MASK
+ | GDK_FOCUS_CHANGE_MASK);
+ g_signal_connect (G_OBJECT (drawing), "expose-event",
+ G_CALLBACK (expose_event), drawing);
+ g_signal_connect (G_OBJECT (drawing), "key-press-event",
+ G_CALLBACK (key_event), drawing);
+ g_signal_connect (G_OBJECT (drawing), "key-release-event",
+ G_CALLBACK (key_event), drawing);
+ g_signal_connect (G_OBJECT (drawing), "button-press-event",
+ G_CALLBACK (button_press_event), drawing);
+ g_signal_connect (G_OBJECT (drawing), "focus-out-event",
+ G_CALLBACK (focus_event), drawing);
+ g_signal_connect (G_OBJECT (drawing), "focus-in-event",
+ G_CALLBACK (focus_event), drawing);
+ g_signal_connect (G_OBJECT (drawing), "size-allocate",
+ G_CALLBACK (size_allocate), drawing);
+ g_signal_connect (G_OBJECT (drawing), "destroy",
+ G_CALLBACK (destroy), drawing);
+ g_signal_connect (G_OBJECT (drawing), "style-set",
+ G_CALLBACK (style_changed), drawing);
+
+ gdk_window_add_filter (NULL, (GdkFilterFunc)
+ xkb_state_notify_event_filter, drawing);
+}
+
+GtkWidget *
+gkbd_keyboard_drawing_new (void)
+{
+ return
+ GTK_WIDGET (g_object_new
+ (gkbd_keyboard_drawing_get_type (), NULL));
+}
+
+static void
+gkbd_keyboard_drawing_class_init (GkbdKeyboardDrawingClass * klass)
+{
+ klass->bad_keycode = NULL;
+
+ gkbd_keyboard_drawing_signals[BAD_KEYCODE] =
+ g_signal_new ("bad-keycode", gkbd_keyboard_drawing_get_type (),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GkbdKeyboardDrawingClass,
+ bad_keycode), NULL, NULL,
+ gkbd_keyboard_drawing_VOID__UINT, G_TYPE_NONE, 1,
+ G_TYPE_UINT);
+}
+
+GType
+gkbd_keyboard_drawing_get_type (void)
+{
+ static GType gkbd_keyboard_drawing_type = 0;
+
+ if (!gkbd_keyboard_drawing_type) {
+ static const GTypeInfo gkbd_keyboard_drawing_info = {
+ sizeof (GkbdKeyboardDrawingClass),
+ NULL, /* base_init */
+ NULL, /* base_finalize */
+ (GClassInitFunc) gkbd_keyboard_drawing_class_init,
+ NULL, /* class_finalize */
+ NULL, /* class_data */
+ sizeof (GkbdKeyboardDrawing),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) gkbd_keyboard_drawing_init,
+ };
+
+ gkbd_keyboard_drawing_type =
+ g_type_register_static (GTK_TYPE_DRAWING_AREA,
+ "GkbdKeyboardDrawing",
+ &gkbd_keyboard_drawing_info,
+ 0);
+ }
+
+ return gkbd_keyboard_drawing_type;
+}
+
+void
+gkbd_keyboard_drawing_set_mods (GkbdKeyboardDrawing * drawing, guint mods)
+{
+#ifdef KBDRAW_DEBUG
+ printf ("set_mods: %d\n", mods);
+#endif
+ if (mods != drawing->mods) {
+ drawing->mods = mods;
+ gtk_widget_queue_draw (GTK_WIDGET (drawing));
+ }
+}
+
+/* returns a pixbuf with the keyboard drawing at the current pixel size
+ * (which can then be saved to disk, etc) */
+GdkPixbuf *
+gkbd_keyboard_drawing_get_pixbuf (GkbdKeyboardDrawing * drawing)
+{
+ if (drawing->pixmap == NULL)
+ draw_keyboard (drawing);
+
+ return gdk_pixbuf_get_from_drawable (NULL, drawing->pixmap, NULL,
+ 0, 0, 0, 0,
+ xkb_to_pixmap_coord (drawing,
+ drawing->
+ xkb->
+ geom->
+ width_mm),
+ xkb_to_pixmap_coord (drawing,
+ drawing->
+ xkb->
+ geom->
+ height_mm));
+}
+
+gboolean
+gkbd_keyboard_drawing_set_keyboard (GkbdKeyboardDrawing * drawing,
+ XkbComponentNamesRec * names)
+{
+ free_cdik (drawing);
+ if (drawing->xkb)
+ XkbFreeKeyboard (drawing->xkb, 0, TRUE); /* free_all = TRUE */
+ drawing->xkb = NULL;
+
+ if (names) {
+ drawing->xkb =
+ XkbGetKeyboardByName (drawing->display, XkbUseCoreKbd,
+ names, 0,
+ XkbGBN_GeometryMask |
+ XkbGBN_KeyNamesMask |
+ XkbGBN_OtherNamesMask |
+ XkbGBN_ClientSymbolsMask |
+ XkbGBN_IndicatorMapMask, FALSE);
+ drawing->xkbOnDisplay = FALSE;
+ } else {
+ drawing->xkb = XkbGetKeyboard (drawing->display,
+ XkbGBN_GeometryMask |
+ XkbGBN_KeyNamesMask |
+ XkbGBN_OtherNamesMask |
+ XkbGBN_SymbolsMask |
+ XkbGBN_IndicatorMapMask,
+ XkbUseCoreKbd);
+ XkbGetNames (drawing->display, XkbAllNamesMask,
+ drawing->xkb);
+ drawing->xkbOnDisplay = TRUE;
+ }
+
+ if (drawing->xkb == NULL)
+ return FALSE;
+
+ alloc_cdik (drawing);
+
+ init_keys_and_doodads (drawing);
+ init_colors (drawing);
+
+ size_allocate (GTK_WIDGET (drawing),
+ &(GTK_WIDGET (drawing)->allocation), drawing);
+ gtk_widget_queue_draw (GTK_WIDGET (drawing));
+
+ return TRUE;
+}
+
+G_CONST_RETURN gchar *
+gkbd_keyboard_drawing_get_keycodes (GkbdKeyboardDrawing * drawing)
+{
+ if (!drawing->xkb || drawing->xkb->names->keycodes <= 0)
+ return NULL;
+ else
+ return XGetAtomName (drawing->display,
+ drawing->xkb->names->keycodes);
+}
+
+G_CONST_RETURN gchar *
+gkbd_keyboard_drawing_get_geometry (GkbdKeyboardDrawing * drawing)
+{
+ if (!drawing->xkb || drawing->xkb->names->geometry <= 0)
+ return NULL;
+ else
+ return XGetAtomName (drawing->display,
+ drawing->xkb->names->geometry);
+}
+
+G_CONST_RETURN gchar *
+gkbd_keyboard_drawing_get_symbols (GkbdKeyboardDrawing * drawing)
+{
+ if (!drawing->xkb || drawing->xkb->names->symbols <= 0)
+ return NULL;
+ else
+ return XGetAtomName (drawing->display,
+ drawing->xkb->names->symbols);
+}
+
+G_CONST_RETURN gchar *
+gkbd_keyboard_drawing_get_types (GkbdKeyboardDrawing * drawing)
+{
+ if (!drawing->xkb || drawing->xkb->names->types <= 0)
+ return NULL;
+ else
+ return XGetAtomName (drawing->display,
+ drawing->xkb->names->types);
+}
+
+G_CONST_RETURN gchar *
+gkbd_keyboard_drawing_get_compat (GkbdKeyboardDrawing * drawing)
+{
+ if (!drawing->xkb || drawing->xkb->names->compat <= 0)
+ return NULL;
+ else
+ return XGetAtomName (drawing->display,
+ drawing->xkb->names->compat);
+}
+
+void
+gkbd_keyboard_drawing_set_track_modifiers (GkbdKeyboardDrawing * drawing,
+ gboolean enable)
+{
+ if (enable) {
+ XkbStateRec state;
+ drawing->track_modifiers = 1;
+ memset (&state, 0, sizeof (state));
+ XkbGetState (drawing->display, XkbUseCoreKbd, &state);
+ gkbd_keyboard_drawing_set_mods (drawing,
+ state.compat_state);
+ } else
+ drawing->track_modifiers = 0;
+}
+
+void
+gkbd_keyboard_drawing_set_track_config (GkbdKeyboardDrawing * drawing,
+ gboolean enable)
+{
+ if (enable)
+ drawing->track_config = 1;
+ else
+ drawing->track_config = 0;
+}
+
+void
+gkbd_keyboard_drawing_set_groups_levels (GkbdKeyboardDrawing * drawing,
+ GkbdKeyboardDrawingGroupLevel *
+ groupLevels[])
+{
+#ifdef KBDRAW_DEBUG
+ printf ("set_group_levels [topLeft]: %d %d \n",
+ groupLevels[GKBD_KEYBOARD_DRAWING_POS_TOPLEFT]->group,
+ groupLevels[GKBD_KEYBOARD_DRAWING_POS_TOPLEFT]->level);
+ printf ("set_group_levels [topRight]: %d %d \n",
+ groupLevels[GKBD_KEYBOARD_DRAWING_POS_TOPRIGHT]->group,
+ groupLevels[GKBD_KEYBOARD_DRAWING_POS_TOPRIGHT]->level);
+ printf ("set_group_levels [bottomLeft]: %d %d \n",
+ groupLevels[GKBD_KEYBOARD_DRAWING_POS_BOTTOMLEFT]->group,
+ groupLevels[GKBD_KEYBOARD_DRAWING_POS_BOTTOMLEFT]->level);
+ printf ("set_group_levels [bottomRight]: %d %d \n",
+ groupLevels[GKBD_KEYBOARD_DRAWING_POS_BOTTOMRIGHT]->group,
+ groupLevels[GKBD_KEYBOARD_DRAWING_POS_BOTTOMRIGHT]->level);
+#endif
+ drawing->groupLevels = groupLevels;
+
+ gtk_widget_queue_draw (GTK_WIDGET (drawing));
+}
diff --git a/libgnomekbd/gkbd-keyboard-drawing.h b/libgnomekbd/gkbd-keyboard-drawing.h
new file mode 100644
index 0000000..c13c43d
--- /dev/null
+++ b/libgnomekbd/gkbd-keyboard-drawing.h
@@ -0,0 +1,189 @@
+/* $Id$ */
+/*
+ * keyboard-drawing.h: header file for a gtk+ widget that is a drawing of
+ * the keyboard of the default display
+ *
+ * Copyright (c) 2003 Noah Levitt
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef GKBD_KEYBOARD_DRAWING_H
+#define GKBD_KEYBOARD_DRAWING_H 1
+
+#include <gtk/gtk.h>
+#include <X11/XKBlib.h>
+#include <X11/extensions/XKBgeom.h>
+
+G_BEGIN_DECLS
+#define GKBD_KEYBOARD_DRAWING(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), gkbd_keyboard_drawing_get_type (), \
+ GkbdKeyboardDrawing))
+#define GKBD_KEYBOARD_DRAWING_CLASS(clazz) (G_TYPE_CHECK_CLASS_CAST ((clazz), gkbd_keyboard_drawing_get_type () \
+ GkbdKeyboardDrawingClass))
+#define GKBD_IS_KEYBOARD_DRAWING(obj) G_TYPE_CHECK_INSTANCE_TYPE ((obj), gkbd_keyboard_drawing_get_type ())
+typedef struct _GkbdKeyboardDrawing GkbdKeyboardDrawing;
+typedef struct _GkbdKeyboardDrawingClass GkbdKeyboardDrawingClass;
+
+typedef struct _GkbdKeyboardDrawingItem GkbdKeyboardDrawingItem;
+typedef struct _GkbdKeyboardDrawingKey GkbdKeyboardDrawingKey;
+typedef struct _GkbdKeyboardDrawingDoodad GkbdKeyboardDrawingDoodad;
+typedef struct _GkbdKeyboardDrawingGroupLevel
+ GkbdKeyboardDrawingGroupLevel;
+
+typedef enum {
+ GKBD_KEYBOARD_DRAWING_ITEM_TYPE_KEY,
+ GKBD_KEYBOARD_DRAWING_ITEM_TYPE_DOODAD
+} GkbdKeyboardDrawingItemType;
+
+typedef enum {
+ GKBD_KEYBOARD_DRAWING_POS_TOPLEFT,
+ GKBD_KEYBOARD_DRAWING_POS_TOPRIGHT,
+ GKBD_KEYBOARD_DRAWING_POS_BOTTOMLEFT,
+ GKBD_KEYBOARD_DRAWING_POS_BOTTOMRIGHT,
+ GKBD_KEYBOARD_DRAWING_POS_TOTAL,
+ GKBD_KEYBOARD_DRAWING_POS_FIRST =
+ GKBD_KEYBOARD_DRAWING_POS_TOPLEFT,
+ GKBD_KEYBOARD_DRAWING_POS_LAST =
+ GKBD_KEYBOARD_DRAWING_POS_BOTTOMRIGHT,
+} GkbdKeyboardDrawingGroupLevelPosition;
+
+/* units are in xkb form */
+struct _GkbdKeyboardDrawingItem {
+ /*< private > */
+
+ GkbdKeyboardDrawingItemType type;
+ gint origin_x;
+ gint origin_y;
+ gint angle;
+ guint priority;
+};
+
+/* units are in xkb form */
+struct _GkbdKeyboardDrawingKey {
+ /*< private > */
+
+ GkbdKeyboardDrawingItemType type;
+ gint origin_x;
+ gint origin_y;
+ gint angle;
+ guint priority;
+
+ XkbKeyRec *xkbkey;
+ gboolean pressed;
+ guint keycode;
+};
+
+/* units are in xkb form */
+struct _GkbdKeyboardDrawingDoodad {
+ /*< private > */
+
+ GkbdKeyboardDrawingItemType type;
+ gint origin_x;
+ gint origin_y;
+ gint angle;
+ guint priority;
+
+ XkbDoodadRec *doodad;
+ gboolean on; /* for indicator doodads */
+};
+
+struct _GkbdKeyboardDrawingGroupLevel {
+ gint group;
+ gint level;
+};
+
+struct _GkbdKeyboardDrawing {
+ /*< private > */
+
+ GtkDrawingArea parent;
+
+ GdkPixmap *pixmap;
+ XkbDescRec *xkb;
+ gboolean xkbOnDisplay;
+
+ gint angle; /* current angle pango is set to draw at, in tenths of a degree */
+ PangoLayout *layout;
+ PangoFontDescription *font_desc;
+
+ gint scale_numerator;
+ gint scale_denominator;
+
+ GkbdKeyboardDrawingKey *keys;
+
+ /* list of stuff to draw in priority order */
+ GList *keyboard_items;
+
+ GdkColor *colors;
+
+ guint timeout;
+
+ GkbdKeyboardDrawingGroupLevel **groupLevels;
+
+ guint mods;
+
+ Display *display;
+ gint screen_num;
+
+ gint xkb_event_type;
+
+ GkbdKeyboardDrawingDoodad **physical_indicators;
+ gint physical_indicators_size;
+
+ guint track_config:1;
+ guint track_modifiers:1;
+};
+
+struct _GkbdKeyboardDrawingClass {
+ GtkDrawingAreaClass parent_class;
+
+ /* we send this signal when the user presses a key that "doesn't exist"
+ * according to the keyboard geometry; it probably means their xkb
+ * configuration is incorrect */
+ void (*bad_keycode) (GkbdKeyboardDrawing * drawing, guint keycode);
+};
+
+GType gkbd_keyboard_drawing_get_type (void);
+GtkWidget *gkbd_keyboard_drawing_new (void);
+
+GdkPixbuf *gkbd_keyboard_drawing_get_pixbuf (GkbdKeyboardDrawing *
+ kbdrawing);
+gboolean gkbd_keyboard_drawing_set_keyboard (GkbdKeyboardDrawing *
+ kbdrawing,
+ XkbComponentNamesRec * names);
+
+G_CONST_RETURN gchar
+ * gkbd_keyboard_drawing_get_keycodes (GkbdKeyboardDrawing * kbdrawing);
+G_CONST_RETURN gchar
+ * gkbd_keyboard_drawing_get_geometry (GkbdKeyboardDrawing * kbdrawing);
+G_CONST_RETURN gchar
+ * gkbd_keyboard_drawing_get_symbols (GkbdKeyboardDrawing * kbdrawing);
+G_CONST_RETURN gchar *gkbd_keyboard_drawing_get_types (GkbdKeyboardDrawing
+ * kbdrawing);
+G_CONST_RETURN gchar *gkbd_keyboard_drawing_get_compat (GkbdKeyboardDrawing
+ * kbdrawing);
+
+void gkbd_keyboard_drawing_set_track_modifiers (GkbdKeyboardDrawing *
+ kbdrawing,
+ gboolean enable);
+void gkbd_keyboard_drawing_set_track_config (GkbdKeyboardDrawing *
+ kbdrawing, gboolean enable);
+
+void gkbd_keyboard_drawing_set_groups_levels (GkbdKeyboardDrawing *
+ kbdrawing,
+ GkbdKeyboardDrawingGroupLevel
+ * groupLevels[]);
+
+G_END_DECLS
+#endif /* #ifndef GKBD_KEYBOARD_DRAWING_H */
diff --git a/libgnomekbd/gkbd-util.c b/libgnomekbd/gkbd-util.c
new file mode 100644
index 0000000..dbc164b
--- /dev/null
+++ b/libgnomekbd/gkbd-util.c
@@ -0,0 +1,148 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include <gkbd-util.h>
+
+#include <time.h>
+
+#include <glib/gi18n.h>
+
+#include <libxklavier/xklavier.h>
+
+#include <gconf/gconf-client.h>
+
+#include <gkbd-config-private.h>
+
+static void
+gkbd_log_appender (const char file[], const char function[],
+ int level, const char format[], va_list args)
+{
+ time_t now = time (NULL);
+ g_log (NULL, G_LOG_LEVEL_DEBUG, "[%08ld,%03d,%s:%s/] \t",
+ (long) now, level, file, function);
+ g_logv (NULL, G_LOG_LEVEL_DEBUG, format, args);
+}
+
+void
+gkbd_install_glib_log_appender (void)
+{
+ xkl_set_log_appender (gkbd_log_appender);
+}
+
+#define GKBD_PREVIEW_CONFIG_KEY_PREFIX GKBD_CONFIG_KEY_PREFIX "/preview"
+
+const gchar GKBD_PREVIEW_CONFIG_DIR[] = GKBD_PREVIEW_CONFIG_KEY_PREFIX;
+const gchar GKBD_PREVIEW_CONFIG_KEY_X[] =
+ GKBD_PREVIEW_CONFIG_KEY_PREFIX "/x";
+const gchar GKBD_PREVIEW_CONFIG_KEY_Y[] =
+ GKBD_PREVIEW_CONFIG_KEY_PREFIX "/y";
+const gchar GKBD_PREVIEW_CONFIG_KEY_WIDTH[] =
+ GKBD_PREVIEW_CONFIG_KEY_PREFIX "/width";
+const gchar GKBD_PREVIEW_CONFIG_KEY_HEIGHT[] =
+ GKBD_PREVIEW_CONFIG_KEY_PREFIX "/height";
+
+GdkRectangle *
+gkbd_preview_load_position (void)
+{
+ GError *gerror = NULL;
+ GdkRectangle *rv = NULL;
+ gint x, y, w, h;
+ GConfClient *conf_client = gconf_client_get_default ();
+
+ if (conf_client == NULL)
+ return NULL;
+
+ x = gconf_client_get_int (conf_client,
+ GKBD_PREVIEW_CONFIG_KEY_X, &gerror);
+ if (gerror != NULL) {
+ xkl_debug (0, "Error getting the preview x: %s\n",
+ gerror->message);
+ g_error_free (gerror);
+ g_object_unref (G_OBJECT (conf_client));
+ return NULL;
+ }
+
+ y = gconf_client_get_int (conf_client,
+ GKBD_PREVIEW_CONFIG_KEY_Y, &gerror);
+ if (gerror != NULL) {
+ xkl_debug (0, "Error getting the preview y: %s\n",
+ gerror->message);
+ g_error_free (gerror);
+ g_object_unref (G_OBJECT (conf_client));
+ return NULL;
+ }
+
+ w = gconf_client_get_int (conf_client,
+ GKBD_PREVIEW_CONFIG_KEY_WIDTH, &gerror);
+ if (gerror != NULL) {
+ xkl_debug (0, "Error getting the preview width: %s\n",
+ gerror->message);
+ g_error_free (gerror);
+ g_object_unref (G_OBJECT (conf_client));
+ return NULL;
+ }
+
+ h = gconf_client_get_int (conf_client,
+ GKBD_PREVIEW_CONFIG_KEY_HEIGHT, &gerror);
+ if (gerror != NULL) {
+ xkl_debug (0, "Error getting the preview height: %s\n",
+ gerror->message);
+ g_error_free (gerror);
+ g_object_unref (G_OBJECT (conf_client));
+ return NULL;
+ }
+
+ g_object_unref (G_OBJECT (conf_client));
+
+ // default values should be just ignored
+ if (x == -1 || y == -1 || w == -1 || h == -1)
+ return NULL;
+
+ rv = g_new (GdkRectangle, 1);
+ rv->x = x;
+ rv->y = y;
+ rv->width = w;
+ rv->height = h;
+ return rv;
+}
+
+void
+gkbd_preview_save_position (GdkRectangle * rect)
+{
+ GConfClient *conf_client = gconf_client_get_default ();
+ GConfChangeSet *cs;
+ GError *gerror = NULL;
+
+ cs = gconf_change_set_new ();
+
+ gconf_change_set_set_int (cs, GKBD_PREVIEW_CONFIG_KEY_X, rect->x);
+ gconf_change_set_set_int (cs, GKBD_PREVIEW_CONFIG_KEY_Y, rect->y);
+ gconf_change_set_set_int (cs, GKBD_PREVIEW_CONFIG_KEY_WIDTH,
+ rect->width);
+ gconf_change_set_set_int (cs, GKBD_PREVIEW_CONFIG_KEY_HEIGHT,
+ rect->height);
+
+ gconf_client_commit_change_set (conf_client, cs, TRUE, &gerror);
+ if (gerror != NULL) {
+ g_warning ("Error saving preview configuration: %s\n",
+ gerror->message);
+ g_error_free (gerror);
+ }
+ gconf_change_set_unref (cs);
+ g_object_unref (G_OBJECT (conf_client));
+}
diff --git a/libgnomekbd/gkbd-util.h b/libgnomekbd/gkbd-util.h
new file mode 100644
index 0000000..3aca8c9
--- /dev/null
+++ b/libgnomekbd/gkbd-util.h
@@ -0,0 +1,30 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __GKBD_UTIL_H__
+#define __GKBD_UTIL_H__
+
+#include <glib.h>
+#include <gdk/gdk.h>
+
+extern void gkbd_install_glib_log_appender (void);
+
+extern GdkRectangle *gkbd_preview_load_position (void);
+
+extern void gkbd_preview_save_position (GdkRectangle * rect);
+
+
+#endif