diff options
author | Sergey V. Udaltsov <svu@src.gnome.org> | 2006-09-27 20:27:09 +0000 |
---|---|---|
committer | Sergey V. Udaltsov <svu@src.gnome.org> | 2006-09-27 20:27:09 +0000 |
commit | 7699e660c678df45a7d0ce2edaec1611e210d583 (patch) | |
tree | a1e92bed7f668a851e276ec79a9bca846d70a2a1 /libgnomekbd | |
download | libgnomekbd-7699e660c678df45a7d0ce2edaec1611e210d583.tar.gz |
Initial revision
Diffstat (limited to 'libgnomekbd')
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 |