Compare commits
	
		
			48 Commits
		
	
	
		
			eekboard-0
			...
			eekboard-0
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| f562e8c212 | |||
| 8ff00226e2 | |||
| c72c75083c | |||
| 862a54eac3 | |||
| 12bc18e1ba | |||
| f045bd0d50 | |||
| dfe06468ed | |||
| 3fda8da1a5 | |||
| d0a5715f8c | |||
| 6b83bb8503 | |||
| 69f1dba96a | |||
| dcbdd7ff63 | |||
| 9b28a011e7 | |||
| 350598dc55 | |||
| ae9df021c2 | |||
| d7cb78ecf5 | |||
| ef2e9acf1e | |||
| 7f52069e41 | |||
| 9a5c0d9cdc | |||
| 551fb17e02 | |||
| b5b9864033 | |||
| a2d2ef3a5e | |||
| b09a586357 | |||
| 70f3bc5308 | |||
| 8bc7b754bc | |||
| 3d5160455a | |||
| 983cc22761 | |||
| 6d80e4cacb | |||
| 1c5a271177 | |||
| e4891ccf6b | |||
| 48bfc7485f | |||
| 2e297ab1ef | |||
| 828fc553b4 | |||
| 08e1a6c69a | |||
| 039ea44520 | |||
| 65c1abbe27 | |||
| 0ab5a0f114 | |||
| 94219bd31e | |||
| 7c2457e659 | |||
| a156453301 | |||
| c2e53ec9a9 | |||
| 687b2a83b4 | |||
| a1f7d628bb | |||
| 789ee66836 | |||
| 9ec42b66f3 | |||
| b2b44a0810 | |||
| 59076afcb5 | |||
| 5ab24250bc | 
							
								
								
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -34,6 +34,8 @@ eek/eek-special-keysym-labels.h
 | 
			
		||||
eek/eek-unicode-keysym-labels.h
 | 
			
		||||
eek/eek-keyname-keysym-labels.h
 | 
			
		||||
eek/*.pc
 | 
			
		||||
eek/*.gir
 | 
			
		||||
eek/*.typelib
 | 
			
		||||
tests/eek-simple-test
 | 
			
		||||
tests/eek-xkb-test
 | 
			
		||||
src/eekboard
 | 
			
		||||
@ -51,4 +53,4 @@ po/*.gmo
 | 
			
		||||
po/Makefile.in.in
 | 
			
		||||
po/POTFILES
 | 
			
		||||
po/stamp-it
 | 
			
		||||
 | 
			
		||||
bindings/vala/*.vapi
 | 
			
		||||
 | 
			
		||||
@ -18,4 +18,5 @@
 | 
			
		||||
 | 
			
		||||
ACLOCAL_AMFLAGS = -I m4
 | 
			
		||||
SUBDIRS = eek src tests bindings docs po
 | 
			
		||||
DISTCHECK_CONFIGURE_FLAGS = --enable-introspection
 | 
			
		||||
DISTCHECK_CONFIGURE_FLAGS = --enable-gtk-doc --enable-introspection
 | 
			
		||||
EXTRA_DIST = eekboard-sample.conf
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										13
									
								
								TODO
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								TODO
									
									
									
									
									
								
							@ -1,19 +1,14 @@
 | 
			
		||||
- packaging
 | 
			
		||||
-- GIR
 | 
			
		||||
-- .spec
 | 
			
		||||
-- debian
 | 
			
		||||
-- add more tests
 | 
			
		||||
 | 
			
		||||
- eekboard
 | 
			
		||||
-- a11y
 | 
			
		||||
-- display current configuration
 | 
			
		||||
-- add command line options
 | 
			
		||||
-- notify user if there is no focused window
 | 
			
		||||
-- rewrite in Vala
 | 
			
		||||
 | 
			
		||||
- libeek
 | 
			
		||||
-- matchbox-keyboard layout engine
 | 
			
		||||
-- CSS based themes
 | 
			
		||||
-- Caribou layout engine (XML)
 | 
			
		||||
-- matchbox-keyboard layout engine (XML)
 | 
			
		||||
-- delay initialization of XKB and XKL layouts
 | 
			
		||||
-- add eek_keyboard_find_by_position(), that takes account of section
 | 
			
		||||
   rotation, in addition to eek_container_find_by_position()
 | 
			
		||||
-- add mechanism to change appearances (colors?) of UI widgets
 | 
			
		||||
   depending on modifier states
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,7 @@ which gnome-autogen.sh || {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ACLOCAL_FLAGS="$ACLOCAL_FLAGS -I m4"
 | 
			
		||||
REQUIRED_AUTOMAKE_VERSION=1.8
 | 
			
		||||
REQUIRED_AUTOMAKE_VERSION=1.10
 | 
			
		||||
REQUIRED_AUTOCONF_VERSION=2.60
 | 
			
		||||
 | 
			
		||||
. gnome-autogen.sh
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										96
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										96
									
								
								configure.ac
									
									
									
									
									
								
							@ -16,7 +16,7 @@
 | 
			
		||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
			
		||||
# 02110-1301 USA
 | 
			
		||||
 | 
			
		||||
AC_INIT([eekboard], [0.0.3], [ueno@unixuser.org])
 | 
			
		||||
AC_INIT([eekboard], [0.0.6], [ueno@unixuser.org])
 | 
			
		||||
AC_CONFIG_SRCDIR([configure.ac])
 | 
			
		||||
AC_PREREQ(2.63)
 | 
			
		||||
AM_INIT_AUTOMAKE
 | 
			
		||||
@ -25,6 +25,50 @@ AC_CONFIG_MACRO_DIR([m4])
 | 
			
		||||
LT_INIT
 | 
			
		||||
IT_PROG_INTLTOOL([0.35.0])
 | 
			
		||||
 | 
			
		||||
AC_MSG_CHECKING([which gtk+ version to compile against])
 | 
			
		||||
AC_ARG_WITH([gtk],
 | 
			
		||||
  [AS_HELP_STRING([--with-gtk=2.0|3.0],[which gtk+ version to compile against (default: 2.0)])],
 | 
			
		||||
  [case "$with_gtk" in
 | 
			
		||||
     2.0|3.0) ;;
 | 
			
		||||
     *) AC_MSG_ERROR([invalid gtk version specified]) ;;
 | 
			
		||||
   esac],
 | 
			
		||||
  [with_gtk=2.0])
 | 
			
		||||
AC_MSG_RESULT([$with_gtk])
 | 
			
		||||
 | 
			
		||||
case "$with_gtk" in
 | 
			
		||||
  2.0) GTK_API_VERSION=2.0
 | 
			
		||||
       GTK_REQUIRED=2.14.0
 | 
			
		||||
       EEK_API_VERSION=0.1
 | 
			
		||||
       EEK_API_MAJOR_VERSION=0
 | 
			
		||||
       EEK_API_MINOR_VERSION=1
 | 
			
		||||
       EEK_API_PC_VERSION=0.1
 | 
			
		||||
       EEK_LIBRARY_SUFFIX="-$EEK_API_VERSION"
 | 
			
		||||
       ;;
 | 
			
		||||
  3.0) GTK_API_VERSION=3.0
 | 
			
		||||
       GTK_REQUIRED=2.91.0
 | 
			
		||||
#       EEK_API_VERSION=0.90
 | 
			
		||||
#       EEK_API_MAJOR_VERSION=0
 | 
			
		||||
#       EEK_API_MINOR_VERSION=90
 | 
			
		||||
#       EEK_API_PC_VERSION=0.90
 | 
			
		||||
       EEK_API_VERSION=0.1
 | 
			
		||||
       EEK_API_MAJOR_VERSION=0
 | 
			
		||||
       EEK_API_MINOR_VERSION=1
 | 
			
		||||
       EEK_API_PC_VERSION=0.1
 | 
			
		||||
       EEK_LIBRARY_SUFFIX="-$EEK_API_VERSION"
 | 
			
		||||
       ;;
 | 
			
		||||
esac
 | 
			
		||||
 | 
			
		||||
AC_SUBST([GTK_API_VERSION])
 | 
			
		||||
AC_SUBST([EEK_API_VERSION])
 | 
			
		||||
AC_SUBST([EEK_API_MAJOR_VERSION])
 | 
			
		||||
AC_SUBST([EEK_API_MINOR_VERSION])
 | 
			
		||||
AC_SUBST([EEK_API_PC_VERSION])
 | 
			
		||||
AC_SUBST([EEK_LIBRARY_SUFFIX])
 | 
			
		||||
AC_SUBST([EEK_LIBRARY_SUFFIX_U],[AS_TR_SH([$EEK_LIBRARY_SUFFIX])])
 | 
			
		||||
 | 
			
		||||
AM_CONDITIONAL([HAVE_GTK_2],[test "$with_gtk" = "2.0"])
 | 
			
		||||
AM_CONDITIONAL([HAVE_GTK_3],[test "$with_gtk" = "3.0"])
 | 
			
		||||
 | 
			
		||||
PKG_CHECK_MODULES([GLIB2], [glib-2.0], ,
 | 
			
		||||
  [AC_MSG_ERROR([GLib2 not found])])
 | 
			
		||||
PKG_CHECK_MODULES([GOBJECT2], [gobject-2.0], ,
 | 
			
		||||
@ -33,14 +77,38 @@ PKG_CHECK_MODULES([CAIRO], [cairo], ,
 | 
			
		||||
  [AC_MSG_ERROR([Cairo not found])])
 | 
			
		||||
PKG_CHECK_MODULES([PANGO], [pango], ,
 | 
			
		||||
  [AC_MSG_ERROR([Pango not found])])
 | 
			
		||||
PKG_CHECK_MODULES([GTK2], [gtk+-2.0 gdk-2.0], ,
 | 
			
		||||
  [AC_MSG_ERROR([GTK2 not found])])
 | 
			
		||||
PKG_CHECK_MODULES([GTK], [
 | 
			
		||||
  gtk+-$GTK_API_VERSION >= $GTK_REQUIRED
 | 
			
		||||
  gdk-$GTK_API_VERSION >= $GTK_REQUIRED], ,
 | 
			
		||||
  [AC_MSG_ERROR([GTK not found])])
 | 
			
		||||
PKG_CHECK_MODULES([GCONF2], [gconf-2.0], ,
 | 
			
		||||
  [AC_MSG_ERROR([GConf not found])])
 | 
			
		||||
PKG_CHECK_MODULES([XKB], [x11], ,
 | 
			
		||||
  [AC_MSG_ERROR([XKB support not found])])
 | 
			
		||||
PKG_CHECK_MODULES([LIBXKLAVIER], [libxklavier x11], ,
 | 
			
		||||
  [AC_MSG_ERROR([Libxklavier not found])])
 | 
			
		||||
PKG_CHECK_MODULES([LIBFAKEKEY], [libfakekey], ,
 | 
			
		||||
  [AC_MSG_ERROR([libfakekey not found])])
 | 
			
		||||
PKG_CHECK_MODULES([CSPI], [cspi-1.0], ,
 | 
			
		||||
  [AC_MSG_ERROR([AT-SPI C not found])])
 | 
			
		||||
 | 
			
		||||
PKG_CHECK_MODULES([NOTIFY], [libnotify], ,
 | 
			
		||||
  [AC_MSG_ERROR([libnotify not found])])
 | 
			
		||||
 | 
			
		||||
dnl libnotify >= 0.7.0 omitted the feature to attach notification to widget.
 | 
			
		||||
need_libnotify_attach_workaround=0
 | 
			
		||||
save_CFLAGS="$CFLAGS"
 | 
			
		||||
CFLAGS="$NOTIFY_CFLAGS"
 | 
			
		||||
save_LIBS="$LIBS"
 | 
			
		||||
LIBS="$NOTIFY_LIBS"
 | 
			
		||||
AC_TRY_LINK([#include <libnotify/notification.h>],
 | 
			
		||||
  [notify_notification_new (NULL, NULL, NULL);], ,
 | 
			
		||||
  [need_libnotify_attach_workaround=1])
 | 
			
		||||
CFLAGS="$save_CFLAGS"
 | 
			
		||||
LIBS="$save_LIBS"
 | 
			
		||||
AC_DEFINE_UNQUOTED([NEED_LIBNOTIFY_ATTACH_WORKAROUND],
 | 
			
		||||
  $need_libnotify_attach_workaround,
 | 
			
		||||
  [Define if notify_notification_new work around is needed])
 | 
			
		||||
 | 
			
		||||
AC_MSG_CHECKING([whether you enable Vala language support])
 | 
			
		||||
AC_ARG_ENABLE(vala,
 | 
			
		||||
@ -69,24 +137,20 @@ if test x$enable_clutter = xyes; then
 | 
			
		||||
  PKG_CHECK_MODULES([CLUTTER], [clutter-1.0], ,
 | 
			
		||||
    [AC_MSG_ERROR([Clutter not found -- install it or add --disable-clutter])])
 | 
			
		||||
  AC_DEFINE([HAVE_CLUTTER], [1], [Define if Clutter is found])
 | 
			
		||||
  PKG_CHECK_MODULES([CLUTTER_GTK], [clutter-gtk-0.90],
 | 
			
		||||
    [enable_clutter_gtk=yes])
 | 
			
		||||
  if test x$enable_clutter_gtk = xno; then
 | 
			
		||||
    PKG_CHECK_MODULES([CLUTTER_GTK], [clutter-gtk-0.10],
 | 
			
		||||
      [enable_clutter_gtk=yes])
 | 
			
		||||
  fi
 | 
			
		||||
  if test x$enable_clutter_gtk = xyes; then
 | 
			
		||||
    AC_DEFINE([HAVE_CLUTTER_GTK], [1], [Define if Clutter-Gtk is found])
 | 
			
		||||
  fi
 | 
			
		||||
  have_clutter_gtk=0
 | 
			
		||||
  need_swap_event_workaround=0
 | 
			
		||||
  PKG_CHECK_MODULES([CLUTTER_GTK], [clutter-gtk-1.0], [have_clutter_gtk=1],
 | 
			
		||||
    [PKG_CHECK_MODULES([CLUTTER_GTK], [clutter-gtk-0.10 clutter-x11-1.0],
 | 
			
		||||
      [have_clutter_gtk=1; need_swap_event_workaround=1])])
 | 
			
		||||
  AC_DEFINE_UNQUOTED([HAVE_CLUTTER_GTK], $have_clutter_gtk,
 | 
			
		||||
    [Define if Clutter-Gtk is found])
 | 
			
		||||
  AC_DEFINE_UNQUOTED([NEED_SWAP_EVENT_WORKAROUND], $need_swap_event_workaround,
 | 
			
		||||
    [Define if GLX_INTEL_swap_event work around is needed])
 | 
			
		||||
fi
 | 
			
		||||
AM_CONDITIONAL(HAVE_CLUTTER, [test x$enable_clutter = xyes])
 | 
			
		||||
AM_CONDITIONAL(HAVE_CLUTTER_GTK, [test x$enable_clutter_gtk = xyes])
 | 
			
		||||
 | 
			
		||||
GTK_DOC_CHECK([1.14],[--flavour no-tmpl])
 | 
			
		||||
 | 
			
		||||
EEK_API_VERSION=0.1
 | 
			
		||||
AC_SUBST(EEK_API_VERSION)
 | 
			
		||||
 | 
			
		||||
dnl to re-generate eek/*-keysym-labels.txt
 | 
			
		||||
AC_CHECK_PROGS([PYTHON], [python])
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -8,7 +8,7 @@
 | 
			
		||||
  <bookinfo>
 | 
			
		||||
    <title>libeek Reference Manual</title>
 | 
			
		||||
    <releaseinfo>
 | 
			
		||||
      for libeek 0.0.3.
 | 
			
		||||
      for libeek 0.0.5.
 | 
			
		||||
    </releaseinfo>
 | 
			
		||||
    <copyright>
 | 
			
		||||
      <year>2010</year>
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										200
									
								
								eek/Makefile.am
									
									
									
									
									
								
							
							
						
						
									
										200
									
								
								eek/Makefile.am
									
									
									
									
									
								
							@ -27,97 +27,97 @@ lib_LTLIBRARIES += libeek-clutter.la
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
libeek_la_SOURCES = \
 | 
			
		||||
	eek-layout.c \
 | 
			
		||||
	eek-layout.h \
 | 
			
		||||
	eek-element.c \
 | 
			
		||||
	eek-element.h \
 | 
			
		||||
	eek-container.c \
 | 
			
		||||
	eek-container.h \
 | 
			
		||||
	eek-keyboard.c \
 | 
			
		||||
	eek-keyboard.h \
 | 
			
		||||
	eek-section.c \
 | 
			
		||||
	eek-section.h \
 | 
			
		||||
	eek-key.c \
 | 
			
		||||
	eek-key.h \
 | 
			
		||||
	eek-types.h \
 | 
			
		||||
	eek-types.c \
 | 
			
		||||
	eek-keysym.h \
 | 
			
		||||
	eek-keysym.c \
 | 
			
		||||
	eek-special-keysym-labels.h \
 | 
			
		||||
	eek-unicode-keysym-labels.h \
 | 
			
		||||
	eek-keyname-keysym-labels.h
 | 
			
		||||
	$(srcdir)/eek-layout.c \
 | 
			
		||||
	$(srcdir)/eek-layout.h \
 | 
			
		||||
	$(srcdir)/eek-element.c \
 | 
			
		||||
	$(srcdir)/eek-element.h \
 | 
			
		||||
	$(srcdir)/eek-container.c \
 | 
			
		||||
	$(srcdir)/eek-container.h \
 | 
			
		||||
	$(srcdir)/eek-keyboard.c \
 | 
			
		||||
	$(srcdir)/eek-keyboard.h \
 | 
			
		||||
	$(srcdir)/eek-section.c \
 | 
			
		||||
	$(srcdir)/eek-section.h \
 | 
			
		||||
	$(srcdir)/eek-key.c \
 | 
			
		||||
	$(srcdir)/eek-key.h \
 | 
			
		||||
	$(srcdir)/eek-types.h \
 | 
			
		||||
	$(srcdir)/eek-types.c \
 | 
			
		||||
	$(srcdir)/eek-keysym.h \
 | 
			
		||||
	$(srcdir)/eek-keysym.c \
 | 
			
		||||
	$(srcdir)/eek-special-keysym-labels.h \
 | 
			
		||||
	$(srcdir)/eek-unicode-keysym-labels.h \
 | 
			
		||||
	$(srcdir)/eek-keyname-keysym-labels.h
 | 
			
		||||
libeek_la_CFLAGS = $(GOBJECT2_CFLAGS)
 | 
			
		||||
libeek_la_LIBADD = $(GOBJECT2_LIBS)
 | 
			
		||||
libeek_la_LIBADD = $(GOBJECT2_LIBS) -lm
 | 
			
		||||
 | 
			
		||||
if HAVE_CLUTTER
 | 
			
		||||
libeek_clutter_la_SOURCES = \
 | 
			
		||||
	eek-clutter-keyboard.c \
 | 
			
		||||
	eek-clutter-keyboard.h \
 | 
			
		||||
	eek-clutter-section.c \
 | 
			
		||||
	eek-clutter-section.h \
 | 
			
		||||
	eek-clutter-key.c \
 | 
			
		||||
	eek-clutter-key.h \
 | 
			
		||||
	eek-clutter-key-actor.c \
 | 
			
		||||
	eek-clutter-key-actor.h \
 | 
			
		||||
	eek-clutter-drawing-context.c \
 | 
			
		||||
	eek-clutter-drawing-context.h \
 | 
			
		||||
	eek-drawing.h \
 | 
			
		||||
	eek-drawing.c \
 | 
			
		||||
	eek-clutter.h
 | 
			
		||||
	$(srcdir)/eek-clutter-keyboard.c \
 | 
			
		||||
	$(srcdir)/eek-clutter-keyboard.h \
 | 
			
		||||
	$(srcdir)/eek-clutter-section.c \
 | 
			
		||||
	$(srcdir)/eek-clutter-section.h \
 | 
			
		||||
	$(srcdir)/eek-clutter-key.c \
 | 
			
		||||
	$(srcdir)/eek-clutter-key.h \
 | 
			
		||||
	$(srcdir)/eek-clutter-key-actor.c \
 | 
			
		||||
	$(srcdir)/eek-clutter-key-actor.h \
 | 
			
		||||
	$(srcdir)/eek-clutter-drawing-context.c \
 | 
			
		||||
	$(srcdir)/eek-clutter-drawing-context.h \
 | 
			
		||||
	$(srcdir)/eek-drawing.h \
 | 
			
		||||
	$(srcdir)/eek-drawing.c \
 | 
			
		||||
	$(srcdir)/eek-clutter.h
 | 
			
		||||
 | 
			
		||||
libeek_clutter_la_CFLAGS = $(CLUTTER_CFLAGS) $(CAIRO_LIBS) $(PANGO_LIBS)
 | 
			
		||||
libeek_clutter_la_LIBADD = libeek.la $(CLUTTER_LIBS) $(CAIRO_LIBS) $(PANGO_LIBS)
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
libeek_gtk_la_SOURCES = \
 | 
			
		||||
	eek-gtk-keyboard.c \
 | 
			
		||||
	eek-gtk-keyboard.h \
 | 
			
		||||
	eek-drawing.h \
 | 
			
		||||
	eek-drawing.c \
 | 
			
		||||
	eek-gtk.h
 | 
			
		||||
	$(srcdir)/eek-gtk-keyboard.c \
 | 
			
		||||
	$(srcdir)/eek-gtk-keyboard.h \
 | 
			
		||||
	$(srcdir)/eek-drawing.h \
 | 
			
		||||
	$(srcdir)/eek-drawing.c \
 | 
			
		||||
	$(srcdir)/eek-gtk.h
 | 
			
		||||
 | 
			
		||||
libeek_gtk_la_CFLAGS = $(GTK2_CFLAGS) $(CAIRO_LIBS) $(PANGO_LIBS)
 | 
			
		||||
libeek_gtk_la_LIBADD = libeek.la $(GTK2_LIBS) $(CAIRO_LIBS) $(PANGO_LIBS)
 | 
			
		||||
libeek_gtk_la_CFLAGS = $(GTK_CFLAGS) $(CAIRO_LIBS) $(PANGO_LIBS)
 | 
			
		||||
libeek_gtk_la_LIBADD = libeek.la $(GTK_LIBS) $(CAIRO_LIBS) $(PANGO_LIBS)
 | 
			
		||||
 | 
			
		||||
libeek_xkb_la_SOURCES = \
 | 
			
		||||
	eek-xkb-layout.h \
 | 
			
		||||
	eek-xkb-layout.c
 | 
			
		||||
	$(srcdir)/eek-xkb-layout.h \
 | 
			
		||||
	$(srcdir)/eek-xkb-layout.c
 | 
			
		||||
 | 
			
		||||
libeek_xkb_la_CFLAGS = $(GTK2_CFLAGS) $(XKB_CFLAGS)
 | 
			
		||||
libeek_xkb_la_LIBADD = libeek.la $(GTK2_LIBS) $(XKB_LIBS)
 | 
			
		||||
libeek_xkb_la_CFLAGS = $(XKB_CFLAGS) $(GTK_CFLAGS)
 | 
			
		||||
libeek_xkb_la_LIBADD = libeek.la $(XKB_LIBS) $(GTK_LIBS)
 | 
			
		||||
 | 
			
		||||
libeek_xkl_la_SOURCES = \
 | 
			
		||||
	eek-xkl-layout.h \
 | 
			
		||||
	eek-xkl-layout.c
 | 
			
		||||
	$(srcdir)/eek-xkl-layout.h \
 | 
			
		||||
	$(srcdir)/eek-xkl-layout.c
 | 
			
		||||
 | 
			
		||||
libeek_xkl_la_CFLAGS = $(GTK2_CFLAGS) $(LIBXKLAVIER_CFLAGS)
 | 
			
		||||
libeek_xkl_la_LIBADD = libeek-xkb.la $(GTK2_LIBS) $(LIBXKLAVIER_LIBS)
 | 
			
		||||
libeek_xkl_la_CFLAGS = $(LIBXKLAVIER_CFLAGS) $(GTK_CFLAGS)
 | 
			
		||||
libeek_xkl_la_LIBADD = libeek-xkb.la $(LIBXKLAVIER_LIBS) $(GTK_LIBS)
 | 
			
		||||
 | 
			
		||||
eekdir = $(includedir)/eek-$(EEK_API_VERSION)/eek
 | 
			
		||||
eek_HEADERS = \
 | 
			
		||||
	$(top_srcdir)/eek/eek-element.h \
 | 
			
		||||
	$(top_srcdir)/eek/eek-container.h \
 | 
			
		||||
	$(top_srcdir)/eek/eek-keyboard.h \
 | 
			
		||||
	$(top_srcdir)/eek/eek-section.h \
 | 
			
		||||
	$(top_srcdir)/eek/eek-key.h \
 | 
			
		||||
	$(top_srcdir)/eek/eek-layout.h \
 | 
			
		||||
	$(top_srcdir)/eek/eek-keysym.h \
 | 
			
		||||
	$(top_srcdir)/eek/eek-types.h \
 | 
			
		||||
	$(top_srcdir)/eek/eek-gtk-keyboard.h \
 | 
			
		||||
	$(top_srcdir)/eek/eek-xkb-layout.h \
 | 
			
		||||
	$(top_srcdir)/eek/eek-xkl-layout.h \
 | 
			
		||||
	$(top_srcdir)/eek/eek.h \
 | 
			
		||||
	$(top_srcdir)/eek/eek-gtk.h \
 | 
			
		||||
	$(top_srcdir)/eek/eek-xkb.h \
 | 
			
		||||
	$(top_srcdir)/eek/eek-xkl.h
 | 
			
		||||
	$(srcdir)/eek-element.h \
 | 
			
		||||
	$(srcdir)/eek-container.h \
 | 
			
		||||
	$(srcdir)/eek-keyboard.h \
 | 
			
		||||
	$(srcdir)/eek-section.h \
 | 
			
		||||
	$(srcdir)/eek-key.h \
 | 
			
		||||
	$(srcdir)/eek-layout.h \
 | 
			
		||||
	$(srcdir)/eek-keysym.h \
 | 
			
		||||
	$(srcdir)/eek-types.h \
 | 
			
		||||
	$(srcdir)/eek-gtk-keyboard.h \
 | 
			
		||||
	$(srcdir)/eek-xkb-layout.h \
 | 
			
		||||
	$(srcdir)/eek-xkl-layout.h \
 | 
			
		||||
	$(srcdir)/eek.h \
 | 
			
		||||
	$(srcdir)/eek-gtk.h \
 | 
			
		||||
	$(srcdir)/eek-xkb.h \
 | 
			
		||||
	$(srcdir)/eek-xkl.h
 | 
			
		||||
 | 
			
		||||
if HAVE_CLUTTER
 | 
			
		||||
eek_HEADERS += \
 | 
			
		||||
	$(top_srcdir)/eek/eek-clutter-keyboard.h \
 | 
			
		||||
	$(top_srcdir)/eek/eek-clutter-section.h \
 | 
			
		||||
	$(top_srcdir)/eek/eek-clutter-key.h \
 | 
			
		||||
	$(top_srcdir)/eek/eek-clutter-drawing-context.h \
 | 
			
		||||
	$(top_srcdir)/eek/eek-clutter.h
 | 
			
		||||
	$(srcdir)/eek-clutter-keyboard.h \
 | 
			
		||||
	$(srcdir)/eek-clutter-section.h \
 | 
			
		||||
	$(srcdir)/eek-clutter-key.h \
 | 
			
		||||
	$(srcdir)/eek-clutter-drawing-context.h \
 | 
			
		||||
	$(srcdir)/eek-clutter.h
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
eek-keysym.c: eek-special-keysym-labels.h eek-unicode-keysym-labels.h eek-keyname-keysym-labels.h
 | 
			
		||||
@ -153,53 +153,53 @@ CLEANFILES =
 | 
			
		||||
 | 
			
		||||
-include $(INTROSPECTION_MAKEFILE)
 | 
			
		||||
INTROSPECTION_GIRS =
 | 
			
		||||
INTROSPECTION_SCANNER_ARGS = --add-include-path=$(srcdir)
 | 
			
		||||
INTROSPECTION_SCANNER_ARGS = --add-include-path=$(builddir)
 | 
			
		||||
INTROSPECTION_COMPILER_ARGS = --includedir=$(srcdir)
 | 
			
		||||
 | 
			
		||||
if HAVE_INTROSPECTION
 | 
			
		||||
 | 
			
		||||
Eek-0.1.gir: libeek.la
 | 
			
		||||
Eek_0_1_gir_SCANNERFLAGS = --strip-prefix=Eek --pkg=glib-2.0
 | 
			
		||||
Eek_0_1_gir_INCLUDES = GLib-2.0 GObject-2.0
 | 
			
		||||
Eek_0_1_gir_CFLAGS = $(libeek_la_CFLAGS)
 | 
			
		||||
Eek_0_1_gir_LIBS = libeek.la
 | 
			
		||||
Eek_0_1_gir_FILES = $(libeek_la_SOURCES)
 | 
			
		||||
Eek@EEK_LIBRARY_SUFFIX@.gir: libeek.la
 | 
			
		||||
Eek@EEK_LIBRARY_SUFFIX_U@_gir_SCANNERFLAGS = --strip-prefix=Eek --pkg=glib-2.0
 | 
			
		||||
Eek@EEK_LIBRARY_SUFFIX_U@_gir_INCLUDES = GLib-2.0 GObject-2.0
 | 
			
		||||
Eek@EEK_LIBRARY_SUFFIX_U@_gir_CFLAGS = $(libeek_la_CFLAGS)
 | 
			
		||||
Eek@EEK_LIBRARY_SUFFIX_U@_gir_LIBS = libeek.la
 | 
			
		||||
Eek@EEK_LIBRARY_SUFFIX_U@_gir_FILES = $(libeek_la_SOURCES)
 | 
			
		||||
 | 
			
		||||
EekGtk-0.1.gir: libeek-gtk.la Eek-0.1.gir
 | 
			
		||||
EekGtk_0_1_gir_INCLUDES = GObject-2.0 Gtk-2.0 Eek-0.1
 | 
			
		||||
EekGtk_0_1_gir_CFLAGS = $(libeek_gtk_la_CFLAGS)
 | 
			
		||||
EekGtk_0_1_gir_LIBS = libeek-gtk.la
 | 
			
		||||
EekGtk_0_1_gir_FILES = $(libeek_gtk_la_SOURCES)
 | 
			
		||||
EekGtk@EEK_LIBRARY_SUFFIX@.gir: libeek-gtk.la Eek@EEK_LIBRARY_SUFFIX@.gir
 | 
			
		||||
EekGtk@EEK_LIBRARY_SUFFIX_U@_gir_INCLUDES = GObject-2.0 Gtk-@GTK_API_VERSION@ Eek@EEK_LIBRARY_SUFFIX@
 | 
			
		||||
EekGtk@EEK_LIBRARY_SUFFIX_U@_gir_CFLAGS = $(libeek_gtk_la_CFLAGS)
 | 
			
		||||
EekGtk@EEK_LIBRARY_SUFFIX_U@_gir_LIBS = libeek-gtk.la
 | 
			
		||||
EekGtk@EEK_LIBRARY_SUFFIX_U@_gir_FILES = $(libeek_gtk_la_SOURCES)
 | 
			
		||||
 | 
			
		||||
if HAVE_CLUTTER
 | 
			
		||||
EekClutter-0.1.gir: libeek-clutter.la Eek-0.1.gir
 | 
			
		||||
EekClutter_0_1_gir_INCLUDES = GObject-2.0 Clutter-1.0 Eek-0.1
 | 
			
		||||
EekClutter_0_1_gir_CFLAGS = $(libeek_clutter_la_CFLAGS)
 | 
			
		||||
EekClutter_0_1_gir_LIBS = libeek-clutter.la
 | 
			
		||||
EekClutter_0_1_gir_FILES = $(libeek_clutter_la_SOURCES)
 | 
			
		||||
EekClutter@EEK_LIBRARY_SUFFIX@.gir: libeek-clutter.la Eek@EEK_LIBRARY_SUFFIX@.gir
 | 
			
		||||
EekClutter@EEK_LIBRARY_SUFFIX_U@_gir_INCLUDES = GObject-2.0 Clutter-1.0 Eek@EEK_LIBRARY_SUFFIX@
 | 
			
		||||
EekClutter@EEK_LIBRARY_SUFFIX_U@_gir_CFLAGS = $(libeek_clutter_la_CFLAGS)
 | 
			
		||||
EekClutter@EEK_LIBRARY_SUFFIX_U@_gir_LIBS = libeek-clutter.la
 | 
			
		||||
EekClutter@EEK_LIBRARY_SUFFIX_U@_gir_FILES = $(libeek_clutter_la_SOURCES)
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
EekXkb-0.1.gir: libeek-xkb.la Eek-0.1.gir
 | 
			
		||||
EekXkb_0_1_gir_INCLUDES = GObject-2.0 Eek-0.1
 | 
			
		||||
EekXkb_0_1_gir_CFLAGS = $(libeek_xkb_la_CFLAGS)
 | 
			
		||||
EekXkb_0_1_gir_LIBS = libeek-xkb.la
 | 
			
		||||
EekXkb_0_1_gir_FILES = $(libeek_xkb_la_SOURCES)
 | 
			
		||||
EekXkb@EEK_LIBRARY_SUFFIX@.gir: libeek-xkb.la Eek@EEK_LIBRARY_SUFFIX@.gir
 | 
			
		||||
EekXkb@EEK_LIBRARY_SUFFIX_U@_gir_INCLUDES = GObject-2.0 Eek@EEK_LIBRARY_SUFFIX@
 | 
			
		||||
EekXkb@EEK_LIBRARY_SUFFIX_U@_gir_CFLAGS = $(libeek_xkb_la_CFLAGS)
 | 
			
		||||
EekXkb@EEK_LIBRARY_SUFFIX_U@_gir_LIBS = libeek-xkb.la
 | 
			
		||||
EekXkb@EEK_LIBRARY_SUFFIX_U@_gir_FILES = $(libeek_xkb_la_SOURCES)
 | 
			
		||||
 | 
			
		||||
EekXkl-0.1.gir: libeek-xkl.la EekXkb-0.1.gir
 | 
			
		||||
EekXkl_0_1_gir_INCLUDES = GObject-2.0 EekXkb-0.1
 | 
			
		||||
EekXkl_0_1_gir_CFLAGS = $(libeek_xkl_la_CFLAGS)
 | 
			
		||||
EekXkl_0_1_gir_LIBS = libeek-xkl.la
 | 
			
		||||
EekXkl_0_1_gir_FILES = $(libeek_xkl_la_SOURCES)
 | 
			
		||||
EekXkl@EEK_LIBRARY_SUFFIX@.gir: libeek-xkl.la EekXkb@EEK_LIBRARY_SUFFIX@.gir
 | 
			
		||||
EekXkl@EEK_LIBRARY_SUFFIX_U@_gir_INCLUDES = GObject-2.0 EekXkb@EEK_LIBRARY_SUFFIX@
 | 
			
		||||
EekXkl@EEK_LIBRARY_SUFFIX_U@_gir_CFLAGS = $(libeek_xkl_la_CFLAGS)
 | 
			
		||||
EekXkl@EEK_LIBRARY_SUFFIX_U@_gir_LIBS = libeek-xkl.la
 | 
			
		||||
EekXkl@EEK_LIBRARY_SUFFIX_U@_gir_FILES = $(libeek_xkl_la_SOURCES)
 | 
			
		||||
 | 
			
		||||
INTROSPECTION_GIRS += \
 | 
			
		||||
	Eek-0.1.gir \
 | 
			
		||||
	EekGtk-0.1.gir \
 | 
			
		||||
	EekXkb-0.1.gir \
 | 
			
		||||
	EekXkl-0.1.gir
 | 
			
		||||
	Eek@EEK_LIBRARY_SUFFIX@.gir \
 | 
			
		||||
	EekGtk@EEK_LIBRARY_SUFFIX@.gir \
 | 
			
		||||
	EekXkb@EEK_LIBRARY_SUFFIX@.gir \
 | 
			
		||||
	EekXkl@EEK_LIBRARY_SUFFIX@.gir
 | 
			
		||||
 | 
			
		||||
if HAVE_CLUTTER
 | 
			
		||||
INTROSPECTION_GIRS += \
 | 
			
		||||
	EekClutter-0.1.gir
 | 
			
		||||
	EekClutter@EEK_LIBRARY_SUFFIX@.gir
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
girdir = $(datadir)/gir-1.0
 | 
			
		||||
 | 
			
		||||
@ -52,6 +52,7 @@ struct _EekClutterKeyActorPrivate
 | 
			
		||||
    EekClutterDrawingContext *context;
 | 
			
		||||
    EekKey *key;
 | 
			
		||||
    ClutterActor *texture;
 | 
			
		||||
    gboolean is_pressed;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static ClutterActor *get_texture          (EekClutterKeyActor *actor);
 | 
			
		||||
@ -103,28 +104,6 @@ eek_clutter_key_actor_real_paint (ClutterActor *self)
 | 
			
		||||
    g_object_unref (layout);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* FIXME: This is a workaround for the bug
 | 
			
		||||
 * http://bugzilla.openedhand.com/show_bug.cgi?id=2137 A developer
 | 
			
		||||
 * says this is not a right way to solve the original problem.
 | 
			
		||||
 */
 | 
			
		||||
static void
 | 
			
		||||
eek_clutter_key_actor_real_get_preferred_width (ClutterActor *self,
 | 
			
		||||
                                                gfloat        for_height,
 | 
			
		||||
                                                gfloat       *min_width_p,
 | 
			
		||||
                                                gfloat       *natural_width_p)
 | 
			
		||||
{
 | 
			
		||||
    PangoLayout *layout;
 | 
			
		||||
 | 
			
		||||
    /* Draw the label on the key - just to validate the glyph cache. */
 | 
			
		||||
    layout = clutter_actor_create_pango_layout (self, NULL);
 | 
			
		||||
    draw_key_on_layout (EEK_CLUTTER_KEY_ACTOR(self), layout);
 | 
			
		||||
    cogl_pango_ensure_glyph_cache_for_layout (layout);
 | 
			
		||||
    g_object_unref (layout);
 | 
			
		||||
 | 
			
		||||
    CLUTTER_ACTOR_CLASS (eek_clutter_key_actor_parent_class)->
 | 
			
		||||
        get_preferred_width (self, for_height, min_width_p, natural_width_p);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
eek_clutter_key_actor_real_pressed (EekClutterKeyActor *self)
 | 
			
		||||
{
 | 
			
		||||
@ -181,12 +160,6 @@ eek_clutter_key_actor_class_init (EekClutterKeyActorClass *klass)
 | 
			
		||||
                              sizeof (EekClutterKeyActorPrivate));
 | 
			
		||||
 | 
			
		||||
    actor_class->paint = eek_clutter_key_actor_real_paint;
 | 
			
		||||
    /* FIXME: This is a workaround for the bug
 | 
			
		||||
     * http://bugzilla.openedhand.com/show_bug.cgi?id=2137 A developer
 | 
			
		||||
     * says this is not a right way to solve the original problem.
 | 
			
		||||
     */
 | 
			
		||||
    actor_class->get_preferred_width =
 | 
			
		||||
        eek_clutter_key_actor_real_get_preferred_width;
 | 
			
		||||
 | 
			
		||||
    gobject_class->dispose = eek_clutter_key_actor_dispose;
 | 
			
		||||
 | 
			
		||||
@ -223,8 +196,11 @@ on_button_press_event (ClutterActor *actor,
 | 
			
		||||
    EekClutterKeyActorPrivate *priv =
 | 
			
		||||
        EEK_CLUTTER_KEY_ACTOR_GET_PRIVATE(actor);
 | 
			
		||||
 | 
			
		||||
    /* priv->key will send back PRESSED event of actor. */
 | 
			
		||||
    g_signal_emit_by_name (priv->key, "pressed");
 | 
			
		||||
    if (!priv->is_pressed) {
 | 
			
		||||
        priv->is_pressed = TRUE;
 | 
			
		||||
        /* priv->key will send back PRESSED event of actor. */
 | 
			
		||||
        g_signal_emit_by_name (priv->key, "pressed");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@ -235,8 +211,27 @@ on_button_release_event (ClutterActor *actor,
 | 
			
		||||
    EekClutterKeyActorPrivate *priv =
 | 
			
		||||
        EEK_CLUTTER_KEY_ACTOR_GET_PRIVATE(actor);
 | 
			
		||||
 | 
			
		||||
    /* priv->key will send back RELEASED event of actor. */
 | 
			
		||||
    g_signal_emit_by_name (priv->key, "released");
 | 
			
		||||
    if (priv->is_pressed) {
 | 
			
		||||
        priv->is_pressed = FALSE;
 | 
			
		||||
        /* priv->key will send back RELEASED event of actor. */
 | 
			
		||||
        g_signal_emit_by_name (priv->key, "released");
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
on_leave_event (ClutterActor *actor,
 | 
			
		||||
                ClutterEvent *event,
 | 
			
		||||
                gpointer      user_data)
 | 
			
		||||
{
 | 
			
		||||
    EekClutterKeyActorPrivate *priv =
 | 
			
		||||
        EEK_CLUTTER_KEY_ACTOR_GET_PRIVATE(actor);
 | 
			
		||||
 | 
			
		||||
    if (priv->is_pressed) {
 | 
			
		||||
        priv->is_pressed = FALSE;
 | 
			
		||||
        /* priv->key will send back RELEASED event of actor. */
 | 
			
		||||
        g_signal_emit_by_name (priv->key, "released");
 | 
			
		||||
    }
 | 
			
		||||
    return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@ -247,12 +242,15 @@ eek_clutter_key_actor_init (EekClutterKeyActor *self)
 | 
			
		||||
    priv = self->priv = EEK_CLUTTER_KEY_ACTOR_GET_PRIVATE(self);
 | 
			
		||||
    priv->key = NULL;
 | 
			
		||||
    priv->texture = NULL;
 | 
			
		||||
    
 | 
			
		||||
 | 
			
		||||
    clutter_actor_set_reactive (CLUTTER_ACTOR(self), TRUE);
 | 
			
		||||
 | 
			
		||||
    g_signal_connect (self, "button-press-event",
 | 
			
		||||
                      G_CALLBACK (on_button_press_event), NULL);
 | 
			
		||||
    g_signal_connect (self, "button-release-event",
 | 
			
		||||
                      G_CALLBACK (on_button_release_event), NULL);
 | 
			
		||||
    g_signal_connect (self, "leave-event",
 | 
			
		||||
                      G_CALLBACK (on_leave_event), NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ClutterActor *
 | 
			
		||||
 | 
			
		||||
@ -231,23 +231,16 @@ eek_container_find (EekContainer  *container,
 | 
			
		||||
                                                     user_data);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct _FbpData
 | 
			
		||||
{
 | 
			
		||||
    EekKey *key;
 | 
			
		||||
    gint x, y;
 | 
			
		||||
};
 | 
			
		||||
typedef struct _FbpData FbpData;
 | 
			
		||||
 | 
			
		||||
static gint
 | 
			
		||||
compare_element_by_position (EekElement *element, gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    EekBounds bounds;
 | 
			
		||||
    FbpData *data = user_data;
 | 
			
		||||
    EekPoint *point = user_data;
 | 
			
		||||
 | 
			
		||||
    eek_element_get_bounds (element, &bounds);
 | 
			
		||||
    if (bounds.x <= data->x && bounds.y <= data->y &&
 | 
			
		||||
        data->x <= (bounds.x + bounds.width) &&
 | 
			
		||||
        data->y <= (bounds.y + bounds.height))
 | 
			
		||||
    if (bounds.x <= point->x && bounds.y <= point->y &&
 | 
			
		||||
        point->x <= (bounds.x + bounds.width) &&
 | 
			
		||||
        point->y <= (bounds.y + bounds.height))
 | 
			
		||||
        return 0;
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
@ -258,13 +251,13 @@ eek_container_find_by_position (EekContainer *container,
 | 
			
		||||
                                gdouble       y)
 | 
			
		||||
{
 | 
			
		||||
    EekBounds bounds;
 | 
			
		||||
    FbpData data;
 | 
			
		||||
    EekPoint point;
 | 
			
		||||
 | 
			
		||||
    g_return_val_if_fail (EEK_IS_CONTAINER(container), NULL);
 | 
			
		||||
    eek_element_get_bounds (EEK_ELEMENT(container), &bounds);
 | 
			
		||||
    data.x = x - bounds.x;
 | 
			
		||||
    data.y = y - bounds.y;
 | 
			
		||||
    point.x = x - bounds.x;
 | 
			
		||||
    point.y = y - bounds.y;
 | 
			
		||||
    return eek_container_find (container,
 | 
			
		||||
                               compare_element_by_position,
 | 
			
		||||
                               &data);
 | 
			
		||||
                               &point);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -351,3 +351,45 @@ eek_element_get_absolute_position (EekElement *element,
 | 
			
		||||
    *x = ax;
 | 
			
		||||
    *y = ay;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * eek_element_set_position:
 | 
			
		||||
 * @element: an #EekElement
 | 
			
		||||
 * @x: X coordinate of top left corner
 | 
			
		||||
 * @y: Y coordinate of top left corner
 | 
			
		||||
 *
 | 
			
		||||
 * Set the relative position of @element.
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
eek_element_set_position (EekElement *element,
 | 
			
		||||
                          gdouble     x,
 | 
			
		||||
                          gdouble     y)
 | 
			
		||||
{
 | 
			
		||||
    EekBounds bounds;
 | 
			
		||||
 | 
			
		||||
    eek_element_get_bounds (element, &bounds);
 | 
			
		||||
    bounds.x = x;
 | 
			
		||||
    bounds.y = y;
 | 
			
		||||
    eek_element_set_bounds (element, &bounds);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * eek_element_set_size:
 | 
			
		||||
 * @element: an #EekElement
 | 
			
		||||
 * @width: width of @element
 | 
			
		||||
 * @height: height of @element
 | 
			
		||||
 *
 | 
			
		||||
 * Set the size of @element.
 | 
			
		||||
 */
 | 
			
		||||
void
 | 
			
		||||
eek_element_set_size (EekElement  *element,
 | 
			
		||||
                      gdouble      width,
 | 
			
		||||
                      gdouble      height)
 | 
			
		||||
{
 | 
			
		||||
    EekBounds bounds;
 | 
			
		||||
 | 
			
		||||
    eek_element_get_bounds (element, &bounds);
 | 
			
		||||
    bounds.width = width;
 | 
			
		||||
    bounds.height = height;
 | 
			
		||||
    eek_element_set_bounds (element, &bounds);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -81,6 +81,13 @@ void                  eek_element_set_bounds            (EekElement  *element,
 | 
			
		||||
void                  eek_element_get_bounds            (EekElement  *element,
 | 
			
		||||
                                                         EekBounds   *bounds);
 | 
			
		||||
 | 
			
		||||
void                  eek_element_set_position          (EekElement  *element,
 | 
			
		||||
                                                         gdouble      x,
 | 
			
		||||
                                                         gdouble      y);
 | 
			
		||||
void                  eek_element_set_size              (EekElement  *element,
 | 
			
		||||
                                                         gdouble      width,
 | 
			
		||||
                                                         gdouble      height);
 | 
			
		||||
 | 
			
		||||
void                  eek_element_get_absolute_position (EekElement  *element,
 | 
			
		||||
                                                         gdouble     *x,
 | 
			
		||||
                                                         gdouble     *y);
 | 
			
		||||
 | 
			
		||||
@ -25,6 +25,6 @@ Name: libeek-gtk
 | 
			
		||||
Description: A Library to Create Keyboard-like UI (GTK Support)
 | 
			
		||||
URL: http://ueno.github.com/eekboard/
 | 
			
		||||
Version: @VERSION@
 | 
			
		||||
Requires: eek-@EEK_API_VERSION@ gtk+-2.0
 | 
			
		||||
Requires: eek-@EEK_API_VERSION@ gtk+-@GTK_API_VERSION@
 | 
			
		||||
Libs: -L${libdir} -leek-gtk
 | 
			
		||||
Cflags: -I${includedir}/eek-@EEK_API_VERSION@
 | 
			
		||||
 | 
			
		||||
@ -41,27 +41,32 @@ G_DEFINE_TYPE (EekGtkKeyboard, eek_gtk_keyboard, EEK_TYPE_KEYBOARD);
 | 
			
		||||
#define EEK_GTK_KEYBOARD_GET_PRIVATE(obj)                                  \
 | 
			
		||||
    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EEK_TYPE_GTK_KEYBOARD, EekGtkKeyboardPrivate))
 | 
			
		||||
 | 
			
		||||
#define SCALE 1.5
 | 
			
		||||
enum {
 | 
			
		||||
    KEY_SURFACE_NORMAL = 0,
 | 
			
		||||
    KEY_SURFACE_LARGE,
 | 
			
		||||
    KEY_SURFACE_LAST
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static const gdouble key_surface_scale[KEY_SURFACE_LAST] = {
 | 
			
		||||
    1.0,
 | 
			
		||||
    1.5
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct _EekGtkKeyboardPrivate
 | 
			
		||||
{
 | 
			
		||||
    GtkWidget *widget;
 | 
			
		||||
 | 
			
		||||
    /* pixmap of entire keyboard (for expose event) */
 | 
			
		||||
    GdkPixmap *pixmap;
 | 
			
		||||
 | 
			
		||||
    /* mapping from outline pointer to pixmap */
 | 
			
		||||
    GHashTable *outline_textures;
 | 
			
		||||
 | 
			
		||||
    /* mapping from outline pointer to large pixmap */
 | 
			
		||||
    GHashTable *large_outline_textures;
 | 
			
		||||
    cairo_surface_t *keyboard_surface;
 | 
			
		||||
    GHashTable *key_surfaces;
 | 
			
		||||
 | 
			
		||||
    PangoFontDescription *fonts[EEK_KEYSYM_CATEGORY_LAST];
 | 
			
		||||
 | 
			
		||||
    gdouble scale;
 | 
			
		||||
 | 
			
		||||
    EekKey *key;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void prepare_keyboard_pixmap (EekGtkKeyboard *keyboard);
 | 
			
		||||
static void prepare_keyboard_surface (EekGtkKeyboard *keyboard);
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
eek_gtk_keyboard_real_set_keysym_index (EekKeyboard *self,
 | 
			
		||||
@ -77,18 +82,26 @@ eek_gtk_keyboard_real_set_keysym_index (EekKeyboard *self,
 | 
			
		||||
        EekGtkKeyboard *keyboard = EEK_GTK_KEYBOARD(self);
 | 
			
		||||
        EekGtkKeyboardPrivate *priv =
 | 
			
		||||
            EEK_GTK_KEYBOARD_GET_PRIVATE(keyboard);
 | 
			
		||||
        GtkStyle *style;
 | 
			
		||||
        GtkStateType state;
 | 
			
		||||
        GtkAllocation allocation;
 | 
			
		||||
        cairo_t *cr;
 | 
			
		||||
 | 
			
		||||
        prepare_keyboard_pixmap (keyboard);
 | 
			
		||||
        state = gtk_widget_get_state (GTK_WIDGET (priv->widget));
 | 
			
		||||
        gtk_widget_get_allocation (GTK_WIDGET (priv->widget), &allocation);
 | 
			
		||||
        gdk_draw_drawable (gtk_widget_get_window (priv->widget),
 | 
			
		||||
                           gtk_widget_get_style (priv->widget)->fg_gc[state],
 | 
			
		||||
                           priv->pixmap,
 | 
			
		||||
                           0, 0,
 | 
			
		||||
                           0, 0,
 | 
			
		||||
                           allocation.width, allocation.height);
 | 
			
		||||
        if (!priv->widget || !gtk_widget_get_realized (priv->widget))
 | 
			
		||||
            return;
 | 
			
		||||
 | 
			
		||||
        prepare_keyboard_surface (keyboard);
 | 
			
		||||
        gtk_widget_get_allocation (priv->widget, &allocation);
 | 
			
		||||
 | 
			
		||||
        cr = gdk_cairo_create (GDK_DRAWABLE (gtk_widget_get_window (priv->widget)));
 | 
			
		||||
        style = gtk_widget_get_style (priv->widget);
 | 
			
		||||
        state = gtk_widget_get_state (priv->widget);
 | 
			
		||||
        gdk_cairo_set_source_color (cr, &style->fg[state]);
 | 
			
		||||
 | 
			
		||||
        cairo_set_source_surface (cr, priv->keyboard_surface, 0, 0);
 | 
			
		||||
        cairo_rectangle (cr, 0, 0, allocation.width, allocation.height);
 | 
			
		||||
        cairo_fill (cr);
 | 
			
		||||
        cairo_destroy (cr);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -110,8 +123,7 @@ eek_gtk_keyboard_finalize (GObject *object)
 | 
			
		||||
    EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(object);
 | 
			
		||||
    gint i;
 | 
			
		||||
 | 
			
		||||
    g_hash_table_unref (priv->outline_textures);
 | 
			
		||||
    g_hash_table_unref (priv->large_outline_textures);
 | 
			
		||||
    g_hash_table_unref (priv->key_surfaces);
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < EEK_KEYSYM_CATEGORY_LAST; i++)
 | 
			
		||||
        pango_font_description_free (priv->fonts[i]);
 | 
			
		||||
@ -132,6 +144,17 @@ eek_gtk_keyboard_class_init (EekGtkKeyboardClass *klass)
 | 
			
		||||
    gobject_class->finalize = eek_gtk_keyboard_finalize;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
key_surface_free (gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    cairo_surface_t **key_surfaces = user_data;
 | 
			
		||||
    gint i;
 | 
			
		||||
 | 
			
		||||
    for (i = 0; i < KEY_SURFACE_LAST; i++)
 | 
			
		||||
        cairo_surface_destroy (key_surfaces[i]);
 | 
			
		||||
    g_slice_free1 (sizeof (cairo_surface_t *) * KEY_SURFACE_LAST, key_surfaces);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
eek_gtk_keyboard_init (EekGtkKeyboard *self)
 | 
			
		||||
{
 | 
			
		||||
@ -139,19 +162,15 @@ eek_gtk_keyboard_init (EekGtkKeyboard *self)
 | 
			
		||||
 | 
			
		||||
    priv = self->priv = EEK_GTK_KEYBOARD_GET_PRIVATE(self);
 | 
			
		||||
    priv->widget = NULL;
 | 
			
		||||
    priv->pixmap = NULL;
 | 
			
		||||
    priv->outline_textures =
 | 
			
		||||
    priv->keyboard_surface = NULL;
 | 
			
		||||
    priv->key_surfaces =
 | 
			
		||||
        g_hash_table_new_full (g_direct_hash,
 | 
			
		||||
                               g_direct_equal,
 | 
			
		||||
                               NULL,
 | 
			
		||||
                               g_object_unref);
 | 
			
		||||
    priv->large_outline_textures =
 | 
			
		||||
        g_hash_table_new_full (g_direct_hash,
 | 
			
		||||
                               g_direct_equal,
 | 
			
		||||
                               NULL,
 | 
			
		||||
                               g_object_unref);
 | 
			
		||||
                               key_surface_free);
 | 
			
		||||
    memset (priv->fonts, 0, sizeof priv->fonts);
 | 
			
		||||
    priv->scale = 1.0;
 | 
			
		||||
    priv->key = NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@ -173,6 +192,9 @@ struct _DrawingContext
 | 
			
		||||
};
 | 
			
		||||
typedef struct _DrawingContext DrawingContext;
 | 
			
		||||
 | 
			
		||||
static void on_key_pressed (EekKey *key, gpointer user_data);
 | 
			
		||||
static void on_key_released (EekKey *key, gpointer user_data);
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
prepare_keyboard_pixmap_key_callback (EekElement *element,
 | 
			
		||||
                                      gpointer    user_data)
 | 
			
		||||
@ -183,31 +205,44 @@ prepare_keyboard_pixmap_key_callback (EekElement *element,
 | 
			
		||||
    EekKey *key = EEK_KEY(element);
 | 
			
		||||
    EekBounds bounds;
 | 
			
		||||
    EekOutline *outline;
 | 
			
		||||
    GdkPixmap *texture;
 | 
			
		||||
    cairo_surface_t **key_surfaces;
 | 
			
		||||
 | 
			
		||||
    eek_element_get_bounds (element, &bounds);
 | 
			
		||||
 | 
			
		||||
    outline = eek_key_get_outline (key);
 | 
			
		||||
    texture = g_hash_table_lookup (priv->outline_textures, outline);
 | 
			
		||||
    if (!texture) {
 | 
			
		||||
        cairo_t *cr;
 | 
			
		||||
    g_signal_connect (key, "pressed", G_CALLBACK(on_key_pressed),
 | 
			
		||||
                      context->keyboard);
 | 
			
		||||
    g_signal_connect (key, "released", G_CALLBACK(on_key_released),
 | 
			
		||||
                      context->keyboard);
 | 
			
		||||
 | 
			
		||||
        texture =
 | 
			
		||||
            gdk_pixmap_new (gtk_widget_get_window (GTK_WIDGET (priv->widget)),
 | 
			
		||||
                            bounds.width, bounds.height, -1);
 | 
			
		||||
        cr = gdk_cairo_create (GDK_DRAWABLE (texture));
 | 
			
		||||
        gdk_cairo_set_source_color (cr, context->bg);
 | 
			
		||||
        cairo_rectangle (cr, 0, 0, bounds.width, bounds.height);
 | 
			
		||||
        gdk_cairo_set_source_color (cr, context->fg);
 | 
			
		||||
        eek_draw_outline (cr, outline);
 | 
			
		||||
        cairo_destroy (cr);
 | 
			
		||||
        g_hash_table_insert (priv->outline_textures, outline, texture);
 | 
			
		||||
    outline = eek_key_get_outline (key);
 | 
			
		||||
    key_surfaces = g_hash_table_lookup (priv->key_surfaces, outline);
 | 
			
		||||
    if (!key_surfaces) {
 | 
			
		||||
        cairo_t *cr;
 | 
			
		||||
        gint i;
 | 
			
		||||
 | 
			
		||||
        key_surfaces = g_slice_alloc (sizeof (cairo_surface_t *) *
 | 
			
		||||
                                      KEY_SURFACE_LAST);
 | 
			
		||||
        for (i = 0; i < KEY_SURFACE_LAST; i++) {
 | 
			
		||||
            gdouble scale = key_surface_scale[i];
 | 
			
		||||
            key_surfaces[i] = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
 | 
			
		||||
                                                          bounds.width * scale,
 | 
			
		||||
                                                          bounds.height * scale);
 | 
			
		||||
            cr = cairo_create (key_surfaces[i]);
 | 
			
		||||
            cairo_scale (cr, priv->scale * scale, priv->scale * scale);
 | 
			
		||||
            gdk_cairo_set_source_color (cr, context->bg);
 | 
			
		||||
            cairo_rectangle (cr, 0, 0, bounds.width, bounds.height);
 | 
			
		||||
            gdk_cairo_set_source_color (cr, context->fg);
 | 
			
		||||
            eek_draw_outline (cr, outline);
 | 
			
		||||
            cairo_destroy (cr);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        g_hash_table_insert (priv->key_surfaces, outline, key_surfaces);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    cairo_save (context->cr);
 | 
			
		||||
    cairo_translate (context->cr, bounds.x, bounds.y);
 | 
			
		||||
 | 
			
		||||
    gdk_cairo_set_source_pixmap (context->cr, texture, 0, 0);
 | 
			
		||||
    cairo_translate (context->cr, bounds.x, bounds.y);
 | 
			
		||||
    cairo_set_source_surface (context->cr, key_surfaces[0], 0, 0);
 | 
			
		||||
    cairo_rectangle (context->cr, 0, 0, bounds.width, bounds.height);
 | 
			
		||||
    cairo_fill (context->cr);
 | 
			
		||||
 | 
			
		||||
@ -240,48 +275,119 @@ prepare_keyboard_pixmap_section_callback (EekElement *element,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
drawing_context_init (DrawingContext *context, EekGtkKeyboard *keyboard)
 | 
			
		||||
drawing_context_init (DrawingContext *context,
 | 
			
		||||
                      cairo_t        *cr,
 | 
			
		||||
                      EekGtkKeyboard *keyboard)
 | 
			
		||||
{
 | 
			
		||||
    EekGtkKeyboardPrivate *priv = keyboard->priv;
 | 
			
		||||
    GtkStyle *style;
 | 
			
		||||
    GtkStateType state;
 | 
			
		||||
 | 
			
		||||
    state = gtk_widget_get_state (GTK_WIDGET (priv->widget));
 | 
			
		||||
    context->cr = cr;
 | 
			
		||||
    context->keyboard = keyboard;
 | 
			
		||||
    context->fg = >k_widget_get_style (GTK_WIDGET (priv->widget))->fg[state];
 | 
			
		||||
    context->bg = >k_widget_get_style (GTK_WIDGET (priv->widget))->bg[state];
 | 
			
		||||
    
 | 
			
		||||
    style = gtk_widget_get_style (priv->widget);
 | 
			
		||||
    state = gtk_widget_get_state (priv->widget);
 | 
			
		||||
    context->fg = &style->fg[state];
 | 
			
		||||
    context->bg = &style->bg[state];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
prepare_keyboard_pixmap (EekGtkKeyboard *keyboard)
 | 
			
		||||
prepare_keyboard_surface (EekGtkKeyboard *keyboard)
 | 
			
		||||
{
 | 
			
		||||
    EekGtkKeyboardPrivate *priv = keyboard->priv;
 | 
			
		||||
    GtkAllocation allocation;
 | 
			
		||||
    GtkStyle *style;
 | 
			
		||||
    GtkStateType state;
 | 
			
		||||
    DrawingContext context;
 | 
			
		||||
    cairo_t *cr;
 | 
			
		||||
 | 
			
		||||
    gtk_widget_get_allocation (GTK_WIDGET (priv->widget), &allocation);
 | 
			
		||||
    priv->pixmap =
 | 
			
		||||
        gdk_pixmap_new (gtk_widget_get_window (GTK_WIDGET (priv->widget)),
 | 
			
		||||
                        allocation.width, allocation.height, -1);
 | 
			
		||||
    gtk_widget_get_allocation (priv->widget, &allocation);
 | 
			
		||||
    priv->keyboard_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
 | 
			
		||||
                                                         allocation.width,
 | 
			
		||||
                                                         allocation.height);
 | 
			
		||||
 | 
			
		||||
    /* blank background */
 | 
			
		||||
    state = gtk_widget_get_state (GTK_WIDGET (priv->widget));
 | 
			
		||||
    gdk_draw_rectangle
 | 
			
		||||
        (priv->pixmap,
 | 
			
		||||
         gtk_widget_get_style (GTK_WIDGET(priv->widget))->base_gc[state],
 | 
			
		||||
         TRUE,
 | 
			
		||||
         0, 0, allocation.width, allocation.height);
 | 
			
		||||
    cr = cairo_create (priv->keyboard_surface);
 | 
			
		||||
    cairo_scale (cr, priv->scale, priv->scale);
 | 
			
		||||
 | 
			
		||||
    style = gtk_widget_get_style (priv->widget);
 | 
			
		||||
    state = gtk_widget_get_state (priv->widget);
 | 
			
		||||
    gdk_cairo_set_source_color (cr, &style->base[state]);
 | 
			
		||||
 | 
			
		||||
    cairo_rectangle (cr, 0, 0, allocation.width, allocation.height);
 | 
			
		||||
    cairo_fill (cr);
 | 
			
		||||
 | 
			
		||||
    /* draw sections on the canvas */
 | 
			
		||||
    drawing_context_init (&context, keyboard);
 | 
			
		||||
    context.cr = gdk_cairo_create (GDK_DRAWABLE (priv->pixmap));
 | 
			
		||||
    cairo_scale (context.cr, priv->scale, priv->scale);
 | 
			
		||||
    drawing_context_init (&context, cr, keyboard);
 | 
			
		||||
    eek_container_foreach_child (EEK_CONTAINER(keyboard),
 | 
			
		||||
                                 prepare_keyboard_pixmap_section_callback,
 | 
			
		||||
                                 &context);
 | 
			
		||||
    cairo_destroy (context.cr);
 | 
			
		||||
    cairo_destroy (cr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
redraw_keyboard (cairo_t        *cr,
 | 
			
		||||
                 EekGtkKeyboard *keyboard,
 | 
			
		||||
                 gint            x,
 | 
			
		||||
                 gint            y,
 | 
			
		||||
                 gint            width,
 | 
			
		||||
                 gint            height)
 | 
			
		||||
{
 | 
			
		||||
    EekGtkKeyboardPrivate *priv =
 | 
			
		||||
        EEK_GTK_KEYBOARD_GET_PRIVATE(keyboard);
 | 
			
		||||
    GtkStyle *style;
 | 
			
		||||
    GtkStateType state;
 | 
			
		||||
 | 
			
		||||
    style = gtk_widget_get_style (priv->widget);
 | 
			
		||||
    state = gtk_widget_get_state (priv->widget);
 | 
			
		||||
 | 
			
		||||
    if (!priv->keyboard_surface) {
 | 
			
		||||
        PangoFontDescription *base_font;
 | 
			
		||||
        PangoContext *context;
 | 
			
		||||
        PangoLayout *layout;
 | 
			
		||||
 | 
			
		||||
        /* compute font sizes which fit in each key shape */
 | 
			
		||||
        context = gtk_widget_get_pango_context (priv->widget);
 | 
			
		||||
        layout = pango_layout_new (context);
 | 
			
		||||
        base_font = style->font_desc;
 | 
			
		||||
        pango_layout_set_font_description (layout, base_font);
 | 
			
		||||
        eek_get_fonts (EEK_KEYBOARD(keyboard), layout, priv->fonts);
 | 
			
		||||
        g_object_unref (layout);
 | 
			
		||||
 | 
			
		||||
        prepare_keyboard_surface (keyboard);
 | 
			
		||||
    }
 | 
			
		||||
    g_return_val_if_fail (priv->keyboard_surface, FALSE);
 | 
			
		||||
 | 
			
		||||
    gdk_cairo_set_source_color (cr, &style->fg[state]);
 | 
			
		||||
 | 
			
		||||
    cairo_set_source_surface (cr,
 | 
			
		||||
                              priv->keyboard_surface,
 | 
			
		||||
                              x, y);
 | 
			
		||||
    cairo_rectangle (cr, x, y, width, height);
 | 
			
		||||
    cairo_fill (cr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if GTK_CHECK_VERSION (2, 91, 2)
 | 
			
		||||
static gboolean
 | 
			
		||||
on_draw (GtkWidget *widget,
 | 
			
		||||
         cairo_t   *cr,
 | 
			
		||||
         gpointer   user_data)
 | 
			
		||||
{
 | 
			
		||||
    EekGtkKeyboard *keyboard = user_data;
 | 
			
		||||
    EekGtkKeyboardPrivate *priv =
 | 
			
		||||
        EEK_GTK_KEYBOARD_GET_PRIVATE(keyboard);
 | 
			
		||||
    GtkAllocation allocation;
 | 
			
		||||
 | 
			
		||||
    g_return_val_if_fail (widget == priv->widget, FALSE);
 | 
			
		||||
 | 
			
		||||
    gtk_widget_get_allocation (priv->widget, &allocation);
 | 
			
		||||
 | 
			
		||||
    redraw_keyboard (cr, keyboard, 0, 0, allocation.width, allocation.height);
 | 
			
		||||
 | 
			
		||||
    return TRUE;
 | 
			
		||||
}
 | 
			
		||||
#else
 | 
			
		||||
static gboolean
 | 
			
		||||
on_expose_event (GtkWidget      *widget,
 | 
			
		||||
                 GdkEventExpose *event,
 | 
			
		||||
@ -290,160 +396,179 @@ on_expose_event (GtkWidget      *widget,
 | 
			
		||||
    EekGtkKeyboard *keyboard = user_data;
 | 
			
		||||
    EekGtkKeyboardPrivate *priv =
 | 
			
		||||
        EEK_GTK_KEYBOARD_GET_PRIVATE(keyboard);
 | 
			
		||||
    GtkStateType state = gtk_widget_get_state (widget);
 | 
			
		||||
    cairo_t *cr;
 | 
			
		||||
 | 
			
		||||
    if (!priv->pixmap) {
 | 
			
		||||
        /* compute font sizes which fit in each key shape */
 | 
			
		||||
        PangoFontDescription *base_font;
 | 
			
		||||
        PangoContext *context;
 | 
			
		||||
        PangoLayout *layout;
 | 
			
		||||
    g_return_val_if_fail (widget == priv->widget, FALSE);
 | 
			
		||||
    
 | 
			
		||||
    cr = gdk_cairo_create (GDK_DRAWABLE (gtk_widget_get_window (priv->widget)));
 | 
			
		||||
    redraw_keyboard (cr, keyboard,
 | 
			
		||||
                     event->area.x, event->area.y,
 | 
			
		||||
                     event->area.width, event->area.height);
 | 
			
		||||
    cairo_destroy (cr);
 | 
			
		||||
 | 
			
		||||
        context = gtk_widget_get_pango_context (priv->widget);
 | 
			
		||||
        layout = pango_layout_new (context);
 | 
			
		||||
        base_font = gtk_widget_get_style (priv->widget)->font_desc;
 | 
			
		||||
        pango_layout_set_font_description (layout, base_font);
 | 
			
		||||
        eek_get_fonts (EEK_KEYBOARD(keyboard), layout, priv->fonts);
 | 
			
		||||
        g_object_unref (layout);
 | 
			
		||||
 | 
			
		||||
        prepare_keyboard_pixmap (keyboard);
 | 
			
		||||
    }
 | 
			
		||||
    g_return_val_if_fail (priv->pixmap, FALSE);
 | 
			
		||||
 | 
			
		||||
    gdk_draw_drawable (gtk_widget_get_window (widget),
 | 
			
		||||
                       gtk_widget_get_style (widget)->fg_gc[state],
 | 
			
		||||
                       priv->pixmap,
 | 
			
		||||
                       event->area.x, event->area.y,
 | 
			
		||||
                       event->area.x, event->area.y,
 | 
			
		||||
                       event->area.width, event->area.height);
 | 
			
		||||
    return TRUE;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
key_enlarge (EekGtkKeyboard *keyboard, EekKey *key)
 | 
			
		||||
redraw_key (cairo_t        *cr,
 | 
			
		||||
            EekKey         *key,
 | 
			
		||||
            gint            key_surface_type,
 | 
			
		||||
            EekGtkKeyboard *keyboard)
 | 
			
		||||
{
 | 
			
		||||
    EekGtkKeyboardPrivate *priv =
 | 
			
		||||
        EEK_GTK_KEYBOARD_GET_PRIVATE(keyboard);
 | 
			
		||||
    EekBounds bounds;
 | 
			
		||||
    EekOutline *outline;
 | 
			
		||||
    gdouble ax, ay;
 | 
			
		||||
    GdkPixmap *pixmap, *texture;
 | 
			
		||||
    DrawingContext context;
 | 
			
		||||
    gdouble x, y;
 | 
			
		||||
    int width, height;
 | 
			
		||||
    GtkStyle *style;
 | 
			
		||||
    GtkStateType state;
 | 
			
		||||
    cairo_t *cr;
 | 
			
		||||
    cairo_surface_t **key_surfaces, *large_surface;
 | 
			
		||||
 | 
			
		||||
    drawing_context_init (&context, keyboard);
 | 
			
		||||
 | 
			
		||||
    eek_element_get_bounds (EEK_ELEMENT(key), &bounds);
 | 
			
		||||
    eek_element_get_absolute_position (EEK_ELEMENT(key), &ax, &ay);
 | 
			
		||||
    g_return_if_fail (priv->keyboard_surface);
 | 
			
		||||
 | 
			
		||||
    outline = eek_key_get_outline (key);
 | 
			
		||||
    texture = g_hash_table_lookup (priv->large_outline_textures, outline);
 | 
			
		||||
    if (!texture) {
 | 
			
		||||
        texture =
 | 
			
		||||
            gdk_pixmap_new (gtk_widget_get_window (GTK_WIDGET (priv->widget)),
 | 
			
		||||
                            bounds.width * SCALE, bounds.height * SCALE, -1);
 | 
			
		||||
        cr = gdk_cairo_create (GDK_DRAWABLE (texture));
 | 
			
		||||
        cairo_scale (cr, SCALE, SCALE);
 | 
			
		||||
        gdk_cairo_set_source_color (cr, context.bg);
 | 
			
		||||
        cairo_rectangle (cr, 0, 0, bounds.width, bounds.height);
 | 
			
		||||
        gdk_cairo_set_source_color (cr, context.fg);
 | 
			
		||||
        eek_draw_outline (cr, outline);
 | 
			
		||||
        cairo_destroy (cr);
 | 
			
		||||
        g_hash_table_insert (priv->large_outline_textures, outline, texture);
 | 
			
		||||
    key_surfaces = g_hash_table_lookup (priv->key_surfaces, outline);
 | 
			
		||||
    g_return_if_fail (key_surfaces);
 | 
			
		||||
 | 
			
		||||
    large_surface = key_surfaces[KEY_SURFACE_LARGE];
 | 
			
		||||
    width = cairo_image_surface_get_width (large_surface);
 | 
			
		||||
    height = cairo_image_surface_get_height (large_surface);
 | 
			
		||||
 | 
			
		||||
    eek_element_get_bounds (EEK_ELEMENT(key), &bounds);
 | 
			
		||||
    eek_element_get_absolute_position (EEK_ELEMENT(key), &x, &y);
 | 
			
		||||
 | 
			
		||||
    x -= (width - bounds.width) / 2;
 | 
			
		||||
    y -= (height - bounds.height) / 2;
 | 
			
		||||
 | 
			
		||||
    style = gtk_widget_get_style (priv->widget);
 | 
			
		||||
    state = gtk_widget_get_state (priv->widget);
 | 
			
		||||
    gdk_cairo_set_source_color (cr, &style->fg[state]);
 | 
			
		||||
 | 
			
		||||
    switch (key_surface_type) {
 | 
			
		||||
    case KEY_SURFACE_NORMAL:
 | 
			
		||||
        cairo_set_source_surface (cr, priv->keyboard_surface, 0, 0);
 | 
			
		||||
        cairo_scale (cr, priv->scale, priv->scale);
 | 
			
		||||
        cairo_rectangle (cr, x, y, width, height);
 | 
			
		||||
        cairo_fill (cr);
 | 
			
		||||
        break;
 | 
			
		||||
 | 
			
		||||
    case KEY_SURFACE_LARGE:
 | 
			
		||||
        cairo_scale (cr, priv->scale, priv->scale);
 | 
			
		||||
        cairo_set_source_surface (cr, large_surface, x, y);
 | 
			
		||||
        cairo_rectangle (cr, x, y, width, height);
 | 
			
		||||
        cairo_fill (cr);
 | 
			
		||||
 | 
			
		||||
        cairo_move_to (cr, x, y);
 | 
			
		||||
        gdk_cairo_set_source_color (cr, &style->fg[state]);
 | 
			
		||||
 | 
			
		||||
        cairo_scale (cr,
 | 
			
		||||
                     key_surface_scale[KEY_SURFACE_LARGE],
 | 
			
		||||
                     key_surface_scale[KEY_SURFACE_LARGE]);
 | 
			
		||||
        eek_draw_key_label (cr, key, priv->fonts);
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pixmap =
 | 
			
		||||
        gdk_pixmap_new (gtk_widget_get_window (GTK_WIDGET (priv->widget)),
 | 
			
		||||
                        bounds.width * SCALE * priv->scale,
 | 
			
		||||
                        bounds.height * SCALE * priv->scale, -1);
 | 
			
		||||
    cr = gdk_cairo_create (GDK_DRAWABLE (pixmap));
 | 
			
		||||
    cairo_scale (cr, priv->scale, priv->scale);
 | 
			
		||||
    gdk_cairo_set_source_pixmap (cr, texture, 0, 0);
 | 
			
		||||
    cairo_rectangle (cr, 0, 0, bounds.width * SCALE, bounds.height * SCALE);
 | 
			
		||||
    cairo_fill (cr);
 | 
			
		||||
 | 
			
		||||
    cairo_move_to (cr, 0, 0);
 | 
			
		||||
    cairo_scale (cr, SCALE, SCALE);
 | 
			
		||||
    gdk_cairo_set_source_color (cr, context.fg);
 | 
			
		||||
    eek_draw_key_label (cr, key, priv->fonts);
 | 
			
		||||
    cairo_destroy (cr);
 | 
			
		||||
 | 
			
		||||
    state = gtk_widget_get_state (GTK_WIDGET (priv->widget));
 | 
			
		||||
    gdk_draw_drawable (gtk_widget_get_window (priv->widget),
 | 
			
		||||
                       gtk_widget_get_style (priv->widget)->fg_gc[state],
 | 
			
		||||
                       pixmap,
 | 
			
		||||
                       0, 0,
 | 
			
		||||
                       (ax - (bounds.width * SCALE - bounds.width) / 2) *
 | 
			
		||||
                       priv->scale,
 | 
			
		||||
                       (ay - (bounds.height * SCALE - bounds.height) / 2) *
 | 
			
		||||
                       priv->scale,
 | 
			
		||||
                       bounds.width * SCALE * priv->scale,
 | 
			
		||||
                       bounds.height * SCALE * priv->scale);
 | 
			
		||||
    g_object_unref (pixmap);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
key_shrink (EekGtkKeyboard *keyboard, EekKey *key)
 | 
			
		||||
on_key_pressed (EekKey *key, gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    EekGtkKeyboardPrivate *priv =
 | 
			
		||||
        EEK_GTK_KEYBOARD_GET_PRIVATE(keyboard);
 | 
			
		||||
    EekBounds bounds;
 | 
			
		||||
    gdouble ax, ay;
 | 
			
		||||
    GtkStateType state;
 | 
			
		||||
    EekGtkKeyboard *keyboard = user_data;
 | 
			
		||||
    EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(keyboard);
 | 
			
		||||
    cairo_t *cr;
 | 
			
		||||
 | 
			
		||||
    g_return_if_fail (priv->pixmap);
 | 
			
		||||
    eek_element_get_bounds (EEK_ELEMENT(key), &bounds);
 | 
			
		||||
    eek_element_get_absolute_position (EEK_ELEMENT(key), &ax, &ay);
 | 
			
		||||
    state = gtk_widget_get_state (GTK_WIDGET (priv->widget));
 | 
			
		||||
    cr = gdk_cairo_create (GDK_DRAWABLE (gtk_widget_get_window (priv->widget)));
 | 
			
		||||
    redraw_key (cr, key, KEY_SURFACE_LARGE, keyboard);
 | 
			
		||||
    cairo_destroy (cr);
 | 
			
		||||
 | 
			
		||||
    ax -= (bounds.width * SCALE - bounds.width) / 2;
 | 
			
		||||
    ay -= (bounds.height * SCALE - bounds.height) / 2;
 | 
			
		||||
    priv->key = key;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
    gdk_draw_drawable (gtk_widget_get_window (priv->widget),
 | 
			
		||||
                       gtk_widget_get_style (priv->widget)->fg_gc[state],
 | 
			
		||||
                       priv->pixmap,
 | 
			
		||||
                       ax * priv->scale, ay * priv->scale,
 | 
			
		||||
                       ax * priv->scale, ay * priv->scale,
 | 
			
		||||
                       bounds.width * SCALE * priv->scale,
 | 
			
		||||
                       bounds.height * SCALE * priv->scale);
 | 
			
		||||
static void
 | 
			
		||||
on_key_released (EekKey *key, gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    EekGtkKeyboard *keyboard = user_data;
 | 
			
		||||
    EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(keyboard);
 | 
			
		||||
    cairo_t *cr;
 | 
			
		||||
 | 
			
		||||
    cr = gdk_cairo_create (GDK_DRAWABLE (gtk_widget_get_window (priv->widget)));
 | 
			
		||||
    if (priv->key) {
 | 
			
		||||
        redraw_key (cr, priv->key, KEY_SURFACE_NORMAL, keyboard);
 | 
			
		||||
        priv->key = NULL;
 | 
			
		||||
    }
 | 
			
		||||
    redraw_key (cr, key, KEY_SURFACE_NORMAL, keyboard);
 | 
			
		||||
    cairo_destroy (cr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
press_key (EekGtkKeyboard *keyboard, EekKey *key)
 | 
			
		||||
{
 | 
			
		||||
    EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(keyboard);
 | 
			
		||||
    if (priv->key != key)
 | 
			
		||||
        g_signal_emit_by_name (key, "pressed", keyboard);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
release_key (EekGtkKeyboard *keyboard)
 | 
			
		||||
{
 | 
			
		||||
    EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(keyboard);
 | 
			
		||||
 | 
			
		||||
    if (priv->key)
 | 
			
		||||
        g_signal_emit_by_name (priv->key, "released", keyboard);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
on_key_event (GtkWidget   *widget,
 | 
			
		||||
              GdkEventKey *event,
 | 
			
		||||
              gpointer     user_data)
 | 
			
		||||
{
 | 
			
		||||
    EekGtkKeyboard *keyboard = user_data;
 | 
			
		||||
    EekKey *key;
 | 
			
		||||
 | 
			
		||||
    key = eek_keyboard_find_key_by_keycode (EEK_KEYBOARD(keyboard),
 | 
			
		||||
                                            event->hardware_keycode);
 | 
			
		||||
    if (!key)
 | 
			
		||||
        return FALSE;
 | 
			
		||||
    switch (event->type) {
 | 
			
		||||
    case GDK_KEY_PRESS:
 | 
			
		||||
        press_key (keyboard, key);
 | 
			
		||||
        return TRUE;
 | 
			
		||||
    case GDK_KEY_RELEASE:
 | 
			
		||||
        release_key (keyboard);
 | 
			
		||||
        return TRUE;
 | 
			
		||||
    default:
 | 
			
		||||
        return FALSE;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
on_button_event (GtkWidget      *widget,
 | 
			
		||||
                     GdkEventButton *event,
 | 
			
		||||
                     gpointer        user_data)
 | 
			
		||||
                 GdkEventButton *event,
 | 
			
		||||
                 gpointer        user_data)
 | 
			
		||||
{
 | 
			
		||||
    EekElement *keyboard = user_data, *section, *key;
 | 
			
		||||
    EekGtkKeyboard *keyboard = EEK_GTK_KEYBOARD(user_data);
 | 
			
		||||
    EekGtkKeyboardPrivate *priv = EEK_GTK_KEYBOARD_GET_PRIVATE(keyboard);
 | 
			
		||||
    EekBounds bounds;
 | 
			
		||||
    EekKey *key;
 | 
			
		||||
    gdouble x, y;
 | 
			
		||||
 | 
			
		||||
    x = (gdouble)event->x / priv->scale;
 | 
			
		||||
    y = (gdouble)event->y / priv->scale;
 | 
			
		||||
    section = eek_container_find_by_position (EEK_CONTAINER(keyboard), x, y);
 | 
			
		||||
    if (section) {
 | 
			
		||||
        eek_element_get_bounds (keyboard, &bounds);
 | 
			
		||||
        x -= bounds.x;
 | 
			
		||||
        y -= bounds.y;
 | 
			
		||||
        key = eek_container_find_by_position (EEK_CONTAINER(section),
 | 
			
		||||
                                              x,
 | 
			
		||||
                                              y);
 | 
			
		||||
        if (key)
 | 
			
		||||
            switch (event->type) {
 | 
			
		||||
            case GDK_BUTTON_PRESS:
 | 
			
		||||
                key_enlarge (EEK_GTK_KEYBOARD(keyboard), EEK_KEY(key));
 | 
			
		||||
                g_signal_emit_by_name (keyboard, "key-pressed", key);
 | 
			
		||||
                return TRUE;
 | 
			
		||||
            case GDK_BUTTON_RELEASE:
 | 
			
		||||
                key_shrink (EEK_GTK_KEYBOARD(keyboard), EEK_KEY(key));
 | 
			
		||||
                g_signal_emit_by_name (keyboard, "key-released", key);
 | 
			
		||||
                return TRUE;
 | 
			
		||||
            default:
 | 
			
		||||
                return FALSE;
 | 
			
		||||
            }
 | 
			
		||||
    }
 | 
			
		||||
    key = eek_keyboard_find_key_by_position (EEK_KEYBOARD(keyboard), x, y);
 | 
			
		||||
    if (key)
 | 
			
		||||
        switch (event->type) {
 | 
			
		||||
        case GDK_BUTTON_PRESS:
 | 
			
		||||
            press_key (EEK_GTK_KEYBOARD(keyboard), key);
 | 
			
		||||
            return TRUE;
 | 
			
		||||
        case GDK_BUTTON_RELEASE:
 | 
			
		||||
            release_key (EEK_GTK_KEYBOARD(keyboard));
 | 
			
		||||
            return TRUE;
 | 
			
		||||
        default:
 | 
			
		||||
            return FALSE;
 | 
			
		||||
        }
 | 
			
		||||
    return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_size_allocate (GtkWidget     *widget,
 | 
			
		||||
                  GtkAllocation *allocation,
 | 
			
		||||
@ -453,12 +578,10 @@ on_size_allocate (GtkWidget     *widget,
 | 
			
		||||
    EekGtkKeyboardPrivate *priv =
 | 
			
		||||
        EEK_GTK_KEYBOARD_GET_PRIVATE(keyboard);
 | 
			
		||||
    EekBounds bounds;
 | 
			
		||||
    GdkPixmap *pixmap;
 | 
			
		||||
 | 
			
		||||
    if (priv->pixmap) {
 | 
			
		||||
        pixmap = priv->pixmap;
 | 
			
		||||
        priv->pixmap = NULL;
 | 
			
		||||
        g_object_unref (pixmap);
 | 
			
		||||
    if (priv->keyboard_surface) {
 | 
			
		||||
        cairo_surface_destroy (priv->keyboard_surface);
 | 
			
		||||
        priv->keyboard_surface = NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    eek_element_get_bounds (EEK_ELEMENT(keyboard), &bounds);
 | 
			
		||||
@ -466,6 +589,7 @@ on_size_allocate (GtkWidget     *widget,
 | 
			
		||||
        allocation->width / bounds.width :
 | 
			
		||||
        allocation->height / bounds.height;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GtkWidget *
 | 
			
		||||
eek_gtk_keyboard_get_widget (EekGtkKeyboard *keyboard)
 | 
			
		||||
{
 | 
			
		||||
@ -480,12 +604,22 @@ eek_gtk_keyboard_get_widget (EekGtkKeyboard *keyboard)
 | 
			
		||||
        gtk_widget_set_events (priv->widget,
 | 
			
		||||
                               GDK_EXPOSURE_MASK |
 | 
			
		||||
                               GDK_KEY_PRESS_MASK |
 | 
			
		||||
                               GDK_KEY_RELEASE_MASK |
 | 
			
		||||
                               GDK_BUTTON_PRESS_MASK |
 | 
			
		||||
                               GDK_BUTTON_RELEASE_MASK);
 | 
			
		||||
#if GTK_CHECK_VERSION (2, 91, 2)
 | 
			
		||||
        g_signal_connect (priv->widget, "draw",
 | 
			
		||||
                          G_CALLBACK (on_draw), keyboard);
 | 
			
		||||
#else
 | 
			
		||||
        g_signal_connect (priv->widget, "expose_event",
 | 
			
		||||
                          G_CALLBACK (on_expose_event), keyboard);
 | 
			
		||||
#endif
 | 
			
		||||
        g_signal_connect (priv->widget, "size-allocate",
 | 
			
		||||
                          G_CALLBACK (on_size_allocate), keyboard);
 | 
			
		||||
        g_signal_connect (priv->widget, "key-press-event",
 | 
			
		||||
                          G_CALLBACK (on_key_event), keyboard);
 | 
			
		||||
        g_signal_connect (priv->widget, "key-release-event",
 | 
			
		||||
                          G_CALLBACK (on_key_event), keyboard);
 | 
			
		||||
        g_signal_connect (priv->widget, "button-press-event",
 | 
			
		||||
                          G_CALLBACK (on_button_event), keyboard);
 | 
			
		||||
        g_signal_connect (priv->widget, "button-release-event",
 | 
			
		||||
 | 
			
		||||
@ -20,6 +20,7 @@
 | 
			
		||||
#ifndef EEK_GTK_KEYBOARD_H
 | 
			
		||||
#define EEK_GTK_KEYBOARD_H 1
 | 
			
		||||
 | 
			
		||||
#include <glib.h>
 | 
			
		||||
#include <gtk/gtk.h>
 | 
			
		||||
#include "eek-keyboard.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -226,13 +226,17 @@ eek_key_real_get_keysym_index (EekKey *self,
 | 
			
		||||
static void
 | 
			
		||||
eek_key_real_pressed (EekKey *key)
 | 
			
		||||
{
 | 
			
		||||
#if DEBUG
 | 
			
		||||
    g_debug ("pressed %X", eek_key_get_keycode (key));
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
eek_key_real_released (EekKey *key)
 | 
			
		||||
{
 | 
			
		||||
#if DEBUG
 | 
			
		||||
    g_debug ("released %X", eek_key_get_keycode (key));
 | 
			
		||||
#endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
 | 
			
		||||
@ -484,3 +484,70 @@ eek_keyboard_find_key_by_keycode (EekKeyboard *keyboard,
 | 
			
		||||
    return EEK_KEYBOARD_GET_CLASS(keyboard)->find_key_by_keycode (keyboard,
 | 
			
		||||
                                                                  keycode);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct _FkbpData {
 | 
			
		||||
    gdouble x;
 | 
			
		||||
    gdouble y;
 | 
			
		||||
    EekKey *key;
 | 
			
		||||
};
 | 
			
		||||
typedef struct _FkbpData FkbpData;
 | 
			
		||||
 | 
			
		||||
static gint
 | 
			
		||||
compare_section_by_position (EekElement *element, gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    EekSection *section = EEK_SECTION(element);
 | 
			
		||||
    EekPoint *point = user_data;
 | 
			
		||||
    gint angle;
 | 
			
		||||
    EekBounds bounds;
 | 
			
		||||
    EekPoint rotated;
 | 
			
		||||
 | 
			
		||||
    eek_element_get_bounds (element, &bounds);
 | 
			
		||||
    rotated.x = point->x - bounds.x;
 | 
			
		||||
    rotated.y = point->y - bounds.y;
 | 
			
		||||
    angle = eek_section_get_angle (section);
 | 
			
		||||
    eek_point_rotate (&rotated, -angle);
 | 
			
		||||
 | 
			
		||||
    if (0 <= rotated.x && 0 <= rotated.y &&
 | 
			
		||||
        rotated.x <= bounds.width &&
 | 
			
		||||
        rotated.y <= bounds.height)
 | 
			
		||||
        return 0;
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
fkbp_foreach_child_callback (EekElement *element,
 | 
			
		||||
                             gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    FkbpData *data = user_data;
 | 
			
		||||
    EekPoint point;
 | 
			
		||||
 | 
			
		||||
    if (!data->key) {
 | 
			
		||||
        point.x = data->x;
 | 
			
		||||
        point.y = data->y;
 | 
			
		||||
        if (compare_section_by_position (element, &point) == 0) {
 | 
			
		||||
            data->key = eek_section_find_key_by_position (EEK_SECTION(element),
 | 
			
		||||
                                                          point.x,
 | 
			
		||||
                                                          point.y);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
EekKey *
 | 
			
		||||
eek_keyboard_find_key_by_position (EekKeyboard *keyboard,
 | 
			
		||||
                                   gdouble      x,
 | 
			
		||||
                                   gdouble      y)
 | 
			
		||||
{
 | 
			
		||||
    FkbpData data;
 | 
			
		||||
    EekSection *section;
 | 
			
		||||
    EekBounds bounds;
 | 
			
		||||
 | 
			
		||||
    eek_element_get_bounds (EEK_ELEMENT(keyboard), &bounds);
 | 
			
		||||
    data.x = x - bounds.x;
 | 
			
		||||
    data.y = y - bounds.y;
 | 
			
		||||
    data.key = NULL;
 | 
			
		||||
    /* eek_container_find() cannot be used here since sections may overlap. */
 | 
			
		||||
    eek_container_foreach_child (EEK_CONTAINER(keyboard),
 | 
			
		||||
                                 fkbp_foreach_child_callback,
 | 
			
		||||
                                 &data);
 | 
			
		||||
    return data.key;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -83,22 +83,25 @@ struct _EekKeyboardClass
 | 
			
		||||
    gpointer pdummy[24];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
GType       eek_keyboard_get_type            (void) G_GNUC_CONST;
 | 
			
		||||
GType       eek_keyboard_get_type             (void) G_GNUC_CONST;
 | 
			
		||||
 | 
			
		||||
void        eek_keyboard_set_keysym_index    (EekKeyboard *keyboard,
 | 
			
		||||
                                              gint         group,
 | 
			
		||||
                                              gint         level);
 | 
			
		||||
void        eek_keyboard_get_keysym_index    (EekKeyboard *keyboard,
 | 
			
		||||
                                              gint        *group,
 | 
			
		||||
                                              gint        *level);
 | 
			
		||||
void        eek_keyboard_set_keysym_index     (EekKeyboard *keyboard,
 | 
			
		||||
                                               gint         group,
 | 
			
		||||
                                               gint         level);
 | 
			
		||||
void        eek_keyboard_get_keysym_index     (EekKeyboard *keyboard,
 | 
			
		||||
                                               gint        *group,
 | 
			
		||||
                                               gint        *level);
 | 
			
		||||
 | 
			
		||||
EekSection *eek_keyboard_create_section      (EekKeyboard *keyboard);
 | 
			
		||||
EekSection *eek_keyboard_create_section       (EekKeyboard *keyboard);
 | 
			
		||||
 | 
			
		||||
void        eek_keyboard_set_layout          (EekKeyboard *keyboard,
 | 
			
		||||
                                              EekLayout   *layout);
 | 
			
		||||
void        eek_keyboard_realize             (EekKeyboard *keyboard);
 | 
			
		||||
EekKey     *eek_keyboard_find_key_by_keycode (EekKeyboard *keyboard,
 | 
			
		||||
                                              guint        keycode);
 | 
			
		||||
void        eek_keyboard_set_layout           (EekKeyboard *keyboard,
 | 
			
		||||
                                               EekLayout   *layout);
 | 
			
		||||
void        eek_keyboard_realize              (EekKeyboard *keyboard);
 | 
			
		||||
EekKey     *eek_keyboard_find_key_by_keycode  (EekKeyboard *keyboard,
 | 
			
		||||
                                               guint        keycode);
 | 
			
		||||
EekKey     *eek_keyboard_find_key_by_position (EekKeyboard *keyboard,
 | 
			
		||||
                                               gdouble      x,
 | 
			
		||||
                                               gdouble      y);
 | 
			
		||||
 | 
			
		||||
G_END_DECLS
 | 
			
		||||
#endif  /* EEK_KEYBOARD_H */
 | 
			
		||||
 | 
			
		||||
@ -438,3 +438,26 @@ eek_section_find_key_by_keycode (EekSection *section,
 | 
			
		||||
    return EEK_SECTION_GET_CLASS(section)->find_key_by_keycode (section,
 | 
			
		||||
                                                                keycode);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
EekKey *
 | 
			
		||||
eek_section_find_key_by_position (EekSection *section,
 | 
			
		||||
                                  gdouble     x,
 | 
			
		||||
                                  gdouble     y)
 | 
			
		||||
{
 | 
			
		||||
    gint angle;
 | 
			
		||||
    EekBounds bounds;
 | 
			
		||||
    EekPoint point;
 | 
			
		||||
    EekElement *key;
 | 
			
		||||
 | 
			
		||||
    eek_element_get_bounds (EEK_ELEMENT(section), &bounds);
 | 
			
		||||
    point.x = x - bounds.x;
 | 
			
		||||
    point.y = y - bounds.y;
 | 
			
		||||
    angle = eek_section_get_angle (section);
 | 
			
		||||
    eek_point_rotate (&point, -angle);
 | 
			
		||||
    key = eek_container_find_by_position (EEK_CONTAINER(section),
 | 
			
		||||
                                          point.x + bounds.x,
 | 
			
		||||
                                          point.y + bounds.y);
 | 
			
		||||
    if (!key)
 | 
			
		||||
        return NULL;
 | 
			
		||||
    return EEK_KEY(key);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -86,27 +86,30 @@ struct _EekSectionClass
 | 
			
		||||
    gpointer pdummy[24];
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
GType   eek_section_get_type            (void) G_GNUC_CONST;
 | 
			
		||||
GType   eek_section_get_type             (void) G_GNUC_CONST;
 | 
			
		||||
 | 
			
		||||
void    eek_section_set_angle           (EekSection     *section,
 | 
			
		||||
                                         gint            angle);
 | 
			
		||||
gint    eek_section_get_angle           (EekSection     *section);
 | 
			
		||||
void    eek_section_set_angle            (EekSection     *section,
 | 
			
		||||
                                          gint            angle);
 | 
			
		||||
gint    eek_section_get_angle            (EekSection     *section);
 | 
			
		||||
 | 
			
		||||
gint    eek_section_get_n_rows          (EekSection     *section);
 | 
			
		||||
void    eek_section_add_row             (EekSection     *section,
 | 
			
		||||
                                         gint            num_columns,
 | 
			
		||||
                                         EekOrientation  orientation);
 | 
			
		||||
void    eek_section_get_row             (EekSection     *section,
 | 
			
		||||
                                         gint            index,
 | 
			
		||||
                                         gint           *num_columns,
 | 
			
		||||
                                         EekOrientation *orientation);
 | 
			
		||||
gint    eek_section_get_n_rows           (EekSection     *section);
 | 
			
		||||
void    eek_section_add_row              (EekSection     *section,
 | 
			
		||||
                                          gint            num_columns,
 | 
			
		||||
                                          EekOrientation  orientation);
 | 
			
		||||
void    eek_section_get_row              (EekSection     *section,
 | 
			
		||||
                                          gint            index,
 | 
			
		||||
                                          gint           *num_columns,
 | 
			
		||||
                                          EekOrientation *orientation);
 | 
			
		||||
 | 
			
		||||
EekKey *eek_section_create_key          (EekSection     *section,
 | 
			
		||||
                                         gint            column,
 | 
			
		||||
                                         gint            row);
 | 
			
		||||
EekKey *eek_section_create_key           (EekSection     *section,
 | 
			
		||||
                                          gint            column,
 | 
			
		||||
                                          gint            row);
 | 
			
		||||
 | 
			
		||||
EekKey *eek_section_find_key_by_keycode (EekSection     *section,
 | 
			
		||||
                                         guint           keycode);
 | 
			
		||||
EekKey *eek_section_find_key_by_keycode  (EekSection     *section,
 | 
			
		||||
                                          guint           keycode);
 | 
			
		||||
EekKey *eek_section_find_key_by_position (EekSection     *section,
 | 
			
		||||
                                          gdouble         x,
 | 
			
		||||
                                          gdouble         y);
 | 
			
		||||
 | 
			
		||||
G_END_DECLS
 | 
			
		||||
#endif  /* EEK_SECTION_H */
 | 
			
		||||
 | 
			
		||||
@ -28,6 +28,7 @@
 | 
			
		||||
#endif  /* HAVE_CONFIG_H */
 | 
			
		||||
 | 
			
		||||
#include "eek-types.h"
 | 
			
		||||
#include <math.h>
 | 
			
		||||
 | 
			
		||||
/* EekKeysymMatrix */
 | 
			
		||||
static EekKeysymMatrix *
 | 
			
		||||
@ -81,6 +82,18 @@ eek_point_get_type (void)
 | 
			
		||||
    return our_type;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
eek_point_rotate (EekPoint *point, gint angle)
 | 
			
		||||
{
 | 
			
		||||
    gdouble r, phi;
 | 
			
		||||
 | 
			
		||||
    phi = atan2 (point->y, point->x);
 | 
			
		||||
    r = sqrt (point->x * point->x + point->y * point->y);
 | 
			
		||||
    phi += angle * M_PI / 180;
 | 
			
		||||
    point->x = r * cos (phi);
 | 
			
		||||
    point->y = r * sin (phi);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* EekBounds */
 | 
			
		||||
static EekBounds *
 | 
			
		||||
eek_bounds_copy (const EekBounds *bounds)
 | 
			
		||||
 | 
			
		||||
@ -24,6 +24,12 @@
 | 
			
		||||
 | 
			
		||||
G_BEGIN_DECLS
 | 
			
		||||
 | 
			
		||||
#define EEK_TYPE_KEYSYM_MATRIX (eek_keysym_matrix_get_type ())
 | 
			
		||||
#define EEK_TYPE_POINT (eek_point_get_type ())
 | 
			
		||||
#define EEK_TYPE_BOUNDS (eek_bounds_get_type ())
 | 
			
		||||
#define EEK_TYPE_OUTLINE (eek_outline_get_type ())
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * EekOrientation:
 | 
			
		||||
 * @EEK_ORIENTATION_VERTICAL: the elements will be arranged vertically
 | 
			
		||||
@ -45,6 +51,11 @@ typedef struct _EekKey EekKey;
 | 
			
		||||
typedef struct _EekSection EekSection;
 | 
			
		||||
typedef struct _EekKeyboard EekKeyboard;
 | 
			
		||||
 | 
			
		||||
typedef struct _EekKeysymMatrix EekKeysymMatrix;
 | 
			
		||||
typedef struct _EekPoint EekPoint;
 | 
			
		||||
typedef struct _EekBounds EekBounds;
 | 
			
		||||
typedef struct _EekOutline EekOutline;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * EekKeysymMatrix:
 | 
			
		||||
 * @data: array of keysyms
 | 
			
		||||
@ -59,9 +70,7 @@ struct _EekKeysymMatrix
 | 
			
		||||
    gint num_groups;
 | 
			
		||||
    gint num_levels;
 | 
			
		||||
};
 | 
			
		||||
typedef struct _EekKeysymMatrix EekKeysymMatrix;
 | 
			
		||||
 | 
			
		||||
#define EEK_TYPE_KEYSYM_MATRIX (eek_keysym_matrix_get_type ())
 | 
			
		||||
GType eek_keysym_matrix_get_type (void) G_GNUC_CONST;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@ -76,10 +85,10 @@ struct _EekPoint
 | 
			
		||||
    gdouble x;
 | 
			
		||||
    gdouble y;
 | 
			
		||||
};
 | 
			
		||||
typedef struct _EekPoint EekPoint;
 | 
			
		||||
 | 
			
		||||
#define EEK_TYPE_POINT (eek_point_get_type ())
 | 
			
		||||
GType eek_point_get_type (void) G_GNUC_CONST;
 | 
			
		||||
void  eek_point_rotate   (EekPoint *point,
 | 
			
		||||
                          gint      angle);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * EekBounds:
 | 
			
		||||
@ -88,18 +97,17 @@ GType eek_point_get_type (void) G_GNUC_CONST;
 | 
			
		||||
 * @width: width of the box
 | 
			
		||||
 * @height: height of the box
 | 
			
		||||
 *
 | 
			
		||||
 * 2D bounding box
 | 
			
		||||
 * The rectangle containing an element's bounding box.
 | 
			
		||||
 */
 | 
			
		||||
struct _EekBounds
 | 
			
		||||
{
 | 
			
		||||
    /*< public >*/
 | 
			
		||||
    gdouble x;
 | 
			
		||||
    gdouble y;
 | 
			
		||||
    gdouble width;
 | 
			
		||||
    gdouble height;
 | 
			
		||||
};
 | 
			
		||||
typedef struct _EekBounds EekBounds;
 | 
			
		||||
 | 
			
		||||
#define EEK_TYPE_BOUNDS (eek_bounds_get_type ())
 | 
			
		||||
GType eek_bounds_get_type (void) G_GNUC_CONST;
 | 
			
		||||
 | 
			
		||||
G_INLINE_FUNC gdouble
 | 
			
		||||
@ -122,9 +130,7 @@ struct _EekOutline
 | 
			
		||||
    EekPoint *points;
 | 
			
		||||
    gint num_points;
 | 
			
		||||
};
 | 
			
		||||
typedef struct _EekOutline EekOutline;
 | 
			
		||||
 | 
			
		||||
#define EEK_TYPE_OUTLINE (eek_outline_get_type ())
 | 
			
		||||
GType eek_outline_get_type (void) G_GNUC_CONST;
 | 
			
		||||
 | 
			
		||||
G_END_DECLS
 | 
			
		||||
 | 
			
		||||
@ -25,6 +25,6 @@ Name: libeek-xkb
 | 
			
		||||
Description: A Library to Create Keyboard-like UI (XKB Support)
 | 
			
		||||
URL: http://ueno.github.com/eekboard/
 | 
			
		||||
Version: @VERSION@
 | 
			
		||||
Requires: eek-@EEK_API_VERSION@ gtk+-x11-2.0
 | 
			
		||||
Requires: eek-@EEK_API_VERSION@ gtk+-x11-@GTK_API_VERSION@
 | 
			
		||||
Libs: -L${libdir} -leek-xkb
 | 
			
		||||
Cflags: -I${includedir}/eek-@EEK_API_VERSION@
 | 
			
		||||
 | 
			
		||||
@ -31,6 +31,7 @@
 | 
			
		||||
#include <X11/XKBlib.h>
 | 
			
		||||
#include <X11/extensions/XKBgeom.h>
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdarg.h>
 | 
			
		||||
 | 
			
		||||
#ifdef HAVE_CONFIG_H
 | 
			
		||||
#include "config.h"
 | 
			
		||||
@ -613,38 +614,64 @@ eek_xkb_layout_set_names (EekXkbLayout *layout, XkbComponentNamesRec *names)
 | 
			
		||||
/**
 | 
			
		||||
 * eek_xkb_layout_set_names_full:
 | 
			
		||||
 * @layout: an #EekXkbLayout
 | 
			
		||||
 * @keymap: keymap component name
 | 
			
		||||
 * @keycodes: keycodes component name
 | 
			
		||||
 * @types: types component name
 | 
			
		||||
 * @compat: compat component name
 | 
			
		||||
 * @symbols: symbols component name
 | 
			
		||||
 * @geometry: geometry component name
 | 
			
		||||
 * @Varargs: pairs of component name and value, terminated by NULL.
 | 
			
		||||
 *
 | 
			
		||||
 * Set the XKB component names to @layout.  This function is merely a
 | 
			
		||||
 * wrapper around eek_xkb_layout_set_names() to avoid passing a
 | 
			
		||||
 * pointer of XkbComponentNamesRec, which is not currently available
 | 
			
		||||
 * in the gobject-introspection repository.
 | 
			
		||||
 *
 | 
			
		||||
 * Available component names are: keymap, keycodes, types, compat,
 | 
			
		||||
 * symbols, geometry.
 | 
			
		||||
 *
 | 
			
		||||
 * Returns: %TRUE if the component name is successfully set, %FALSE otherwise
 | 
			
		||||
 * Since: 0.0.2
 | 
			
		||||
 */
 | 
			
		||||
gboolean
 | 
			
		||||
eek_xkb_layout_set_names_full (EekXkbLayout *layout,
 | 
			
		||||
                               const gchar  *keymap,
 | 
			
		||||
                               const gchar  *keycodes,
 | 
			
		||||
                               const gchar  *types,
 | 
			
		||||
                               const gchar  *compat,
 | 
			
		||||
                               const gchar  *symbols,
 | 
			
		||||
                               const gchar  *geometry)
 | 
			
		||||
                               ...)
 | 
			
		||||
{
 | 
			
		||||
    va_list var_args;
 | 
			
		||||
    va_start (var_args, layout);
 | 
			
		||||
    eek_xkb_layout_set_names_full_valist (layout, var_args);
 | 
			
		||||
    va_end (var_args);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * eek_xkb_layout_set_names_full_valist:
 | 
			
		||||
 * @layout: an #EekXkbLayout
 | 
			
		||||
 * @var_args: <type>va_list</type> of pairs of component name and value.
 | 
			
		||||
 *
 | 
			
		||||
 * See eek_xkb_layout_set_names_full(), this version takes a
 | 
			
		||||
 * <type>va_list</type> for language bindings to use.
 | 
			
		||||
 *
 | 
			
		||||
 * Since: 0.0.5
 | 
			
		||||
 */
 | 
			
		||||
gboolean
 | 
			
		||||
eek_xkb_layout_set_names_full_valist (EekXkbLayout *layout,
 | 
			
		||||
                                      va_list       var_args)
 | 
			
		||||
{
 | 
			
		||||
    XkbComponentNamesRec names;
 | 
			
		||||
    gchar *name, *value;
 | 
			
		||||
 | 
			
		||||
    names.keymap = (char *)keymap;
 | 
			
		||||
    names.keycodes = (char *)keycodes;
 | 
			
		||||
    names.types = (char *)types;
 | 
			
		||||
    names.compat = (char *)compat;
 | 
			
		||||
    names.symbols = (char *)symbols;
 | 
			
		||||
    names.geometry = (char *)geometry;
 | 
			
		||||
    memset (&names, 0, sizeof names);
 | 
			
		||||
    name = va_arg (var_args, gchar *);
 | 
			
		||||
    while (name) {
 | 
			
		||||
        value = va_arg (var_args, gchar *);
 | 
			
		||||
        if (g_strcmp0 (name, "keymap") == 0)
 | 
			
		||||
            names.keymap = (char *)value;
 | 
			
		||||
        else if (g_strcmp0 (name, "keycodes") == 0)
 | 
			
		||||
            names.keycodes = (char *)value;
 | 
			
		||||
        else if (g_strcmp0 (name, "types") == 0)
 | 
			
		||||
            names.types = (char *)value;
 | 
			
		||||
        else if (g_strcmp0 (name, "compat") == 0)
 | 
			
		||||
            names.compat = (char *)value;
 | 
			
		||||
        else if (g_strcmp0 (name, "symbols") == 0)
 | 
			
		||||
            names.symbols = (char *)value;
 | 
			
		||||
        else if (g_strcmp0 (name, "geometry") == 0)
 | 
			
		||||
            names.geometry = (char *)value;
 | 
			
		||||
        name = va_arg (var_args, gchar *);
 | 
			
		||||
    }
 | 
			
		||||
    return eek_xkb_layout_set_names (layout, &names);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -63,12 +63,10 @@ gboolean              eek_xkb_layout_set_names (EekXkbLayout         *layout,
 | 
			
		||||
 | 
			
		||||
gboolean              eek_xkb_layout_set_names_full
 | 
			
		||||
                                               (EekXkbLayout         *layout,
 | 
			
		||||
                                                const gchar          *keymap,
 | 
			
		||||
                                                const gchar          *keycodes,
 | 
			
		||||
                                                const gchar          *types,
 | 
			
		||||
                                                const gchar          *compat,
 | 
			
		||||
                                                const gchar          *symbols,
 | 
			
		||||
                                                const gchar          *geometry);
 | 
			
		||||
                                                ...);
 | 
			
		||||
gboolean              eek_xkb_layout_set_names_full_valist
 | 
			
		||||
                                               (EekXkbLayout         *layout,
 | 
			
		||||
                                                va_list               var_args);
 | 
			
		||||
                                        
 | 
			
		||||
gboolean              eek_xkb_layout_set_keycodes
 | 
			
		||||
                                               (EekXkbLayout         *layout,
 | 
			
		||||
 | 
			
		||||
@ -400,7 +400,11 @@ eek_xkl_layout_set_model (EekXklLayout *layout,
 | 
			
		||||
    
 | 
			
		||||
    g_return_val_if_fail (priv, FALSE);
 | 
			
		||||
    config = xkl_config_rec_new ();
 | 
			
		||||
    config->model = (gchar *)model;
 | 
			
		||||
    /* config->model will be freed on g_object_unref (config) */
 | 
			
		||||
    if (model)
 | 
			
		||||
        config->model = g_strdup (model);
 | 
			
		||||
    else
 | 
			
		||||
        config->model = NULL;
 | 
			
		||||
    success = eek_xkl_layout_set_config (layout, config);
 | 
			
		||||
    g_object_unref (config);
 | 
			
		||||
    return success;
 | 
			
		||||
@ -424,7 +428,11 @@ eek_xkl_layout_set_layouts (EekXklLayout *layout,
 | 
			
		||||
 | 
			
		||||
    g_return_val_if_fail (priv, FALSE);
 | 
			
		||||
    config = xkl_config_rec_new ();
 | 
			
		||||
    config->layouts = layouts;
 | 
			
		||||
    /* config->layouts will be freed on g_object_unref (config) */
 | 
			
		||||
    if (layouts)
 | 
			
		||||
        config->layouts = g_strdupv (layouts);
 | 
			
		||||
    else
 | 
			
		||||
        config->layouts = layouts;
 | 
			
		||||
    success = eek_xkl_layout_set_config (layout, config);
 | 
			
		||||
    g_object_unref (config);
 | 
			
		||||
    return success;
 | 
			
		||||
@ -448,7 +456,11 @@ eek_xkl_layout_set_variants (EekXklLayout *layout,
 | 
			
		||||
 | 
			
		||||
    g_return_val_if_fail (priv, FALSE);
 | 
			
		||||
    config = xkl_config_rec_new ();
 | 
			
		||||
    config->variants = variants;
 | 
			
		||||
    /* config->variants will be freed on g_object_unref (config) */
 | 
			
		||||
    if (variants)
 | 
			
		||||
        config->variants = g_strdupv (variants);
 | 
			
		||||
    else
 | 
			
		||||
        config->variants = NULL;
 | 
			
		||||
    success = eek_xkl_layout_set_config (layout, config);
 | 
			
		||||
    g_object_unref (config);
 | 
			
		||||
    return success;
 | 
			
		||||
@ -472,7 +484,11 @@ eek_xkl_layout_set_options (EekXklLayout *layout,
 | 
			
		||||
 | 
			
		||||
    g_return_val_if_fail (priv, FALSE);
 | 
			
		||||
    config = xkl_config_rec_new ();
 | 
			
		||||
    config->options = options;
 | 
			
		||||
    /* config->options will be freed on g_object_unref (config) */
 | 
			
		||||
    if (options)
 | 
			
		||||
        config->options = options;
 | 
			
		||||
    else
 | 
			
		||||
        config->options = NULL;
 | 
			
		||||
    success = eek_xkl_layout_set_config (layout, config);
 | 
			
		||||
    g_object_unref (config);
 | 
			
		||||
    return success;
 | 
			
		||||
@ -549,7 +565,7 @@ eek_xkl_layout_get_model (EekXklLayout *layout)
 | 
			
		||||
    EekXklLayoutPrivate *priv = EEK_XKL_LAYOUT_GET_PRIVATE (layout);
 | 
			
		||||
 | 
			
		||||
    g_return_val_if_fail (priv, NULL);
 | 
			
		||||
    return priv->config->model;
 | 
			
		||||
    return g_strdup (priv->config->model);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@ -565,7 +581,7 @@ eek_xkl_layout_get_layouts (EekXklLayout *layout)
 | 
			
		||||
    EekXklLayoutPrivate *priv = EEK_XKL_LAYOUT_GET_PRIVATE (layout);
 | 
			
		||||
 | 
			
		||||
    g_return_val_if_fail (priv, NULL);
 | 
			
		||||
    return priv->config->layouts;
 | 
			
		||||
    return g_strdupv (priv->config->layouts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@ -581,7 +597,7 @@ eek_xkl_layout_get_variants (EekXklLayout *layout)
 | 
			
		||||
    EekXklLayoutPrivate *priv = EEK_XKL_LAYOUT_GET_PRIVATE (layout);
 | 
			
		||||
 | 
			
		||||
    g_return_val_if_fail (priv, NULL);
 | 
			
		||||
    return priv->config->variants;
 | 
			
		||||
    return g_strdupv (priv->config->variants);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@ -597,7 +613,7 @@ eek_xkl_layout_get_options (EekXklLayout *layout)
 | 
			
		||||
    EekXklLayoutPrivate *priv = EEK_XKL_LAYOUT_GET_PRIVATE (layout);
 | 
			
		||||
 | 
			
		||||
    g_return_val_if_fail (priv, NULL);
 | 
			
		||||
    return priv->config->options;
 | 
			
		||||
    return g_strdupv (priv->config->options);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static gboolean
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										23
									
								
								eekboard-sample.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								eekboard-sample.conf
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,23 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<eekboard>
 | 
			
		||||
  <config>
 | 
			
		||||
    <name>Thai Kinesis</name>
 | 
			
		||||
    <model>kinesis</model>
 | 
			
		||||
    <layouts>pc+us+th(pat)</layouts>
 | 
			
		||||
  </config>
 | 
			
		||||
  <config>
 | 
			
		||||
    <name>Tifinagh Typematrix</name>
 | 
			
		||||
    <model>tm2030USB-106</model>
 | 
			
		||||
    <layouts>pc+us+ma(tifinagh-extended-phonetic)</layouts>
 | 
			
		||||
  </config>
 | 
			
		||||
  <config>
 | 
			
		||||
    <name>Indic Bengali Microsoft Natural</name>
 | 
			
		||||
    <model>microsoft</model>
 | 
			
		||||
    <layouts>pc+us+in(ben)</layouts>
 | 
			
		||||
  </config>
 | 
			
		||||
  <config>
 | 
			
		||||
    <name>US Generic 104-key PC</name>
 | 
			
		||||
    <model>pc104</model>
 | 
			
		||||
    <layouts>pc+us</layouts>
 | 
			
		||||
  </config>
 | 
			
		||||
</eekboard>
 | 
			
		||||
							
								
								
									
										54
									
								
								po/ja.po
									
									
									
									
									
								
							
							
						
						
									
										54
									
								
								po/ja.po
									
									
									
									
									
								
							@ -6,10 +6,10 @@
 | 
			
		||||
#
 | 
			
		||||
msgid ""
 | 
			
		||||
msgstr ""
 | 
			
		||||
"Project-Id-Version: eekboard 0.0.0\n"
 | 
			
		||||
"Project-Id-Version: eekboard 0.0.3\n"
 | 
			
		||||
"Report-Msgid-Bugs-To: \n"
 | 
			
		||||
"POT-Creation-Date: 2010-06-21 12:42+0900\n"
 | 
			
		||||
"PO-Revision-Date: 2010-06-21 12:45+0900\n"
 | 
			
		||||
"POT-Creation-Date: 2010-06-23 16:52+0900\n"
 | 
			
		||||
"PO-Revision-Date: 2010-06-23 16:55+0900\n"
 | 
			
		||||
"Last-Translator: Daiki Ueno <ueno@unixuser.org>\n"
 | 
			
		||||
"Language-Team: Japanese\n"
 | 
			
		||||
"MIME-Version: 1.0\n"
 | 
			
		||||
@ -17,46 +17,74 @@ msgstr ""
 | 
			
		||||
"Content-Transfer-Encoding: 8bit\n"
 | 
			
		||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
 | 
			
		||||
 | 
			
		||||
#: ../src/eekboard.c:195
 | 
			
		||||
#: ../src/eekboard.c:198
 | 
			
		||||
msgid "_File"
 | 
			
		||||
msgstr "ファイル"
 | 
			
		||||
 | 
			
		||||
#: ../src/eekboard.c:196
 | 
			
		||||
#: ../src/eekboard.c:199
 | 
			
		||||
msgid "_Keyboard"
 | 
			
		||||
msgstr "キーボード"
 | 
			
		||||
 | 
			
		||||
#: ../src/eekboard.c:197
 | 
			
		||||
#: ../src/eekboard.c:200
 | 
			
		||||
msgid "_Help"
 | 
			
		||||
msgstr "ヘルプ"
 | 
			
		||||
 | 
			
		||||
#: ../src/eekboard.c:199
 | 
			
		||||
#: ../src/eekboard.c:202
 | 
			
		||||
msgid "Country"
 | 
			
		||||
msgstr "国"
 | 
			
		||||
 | 
			
		||||
#: ../src/eekboard.c:201
 | 
			
		||||
#: ../src/eekboard.c:204
 | 
			
		||||
msgid "Language"
 | 
			
		||||
msgstr "言語"
 | 
			
		||||
 | 
			
		||||
#: ../src/eekboard.c:203
 | 
			
		||||
#: ../src/eekboard.c:206
 | 
			
		||||
msgid "Model"
 | 
			
		||||
msgstr "モデル"
 | 
			
		||||
 | 
			
		||||
#: ../src/eekboard.c:205
 | 
			
		||||
#: ../src/eekboard.c:208
 | 
			
		||||
msgid "Layout"
 | 
			
		||||
msgstr "レイアウト"
 | 
			
		||||
 | 
			
		||||
#: ../src/eekboard.c:207
 | 
			
		||||
#: ../src/eekboard.c:210
 | 
			
		||||
msgid "Option"
 | 
			
		||||
msgstr "オプション"
 | 
			
		||||
 | 
			
		||||
#: ../src/eekboard.c:214
 | 
			
		||||
#: ../src/eekboard.c:217
 | 
			
		||||
msgid "Monitor Key Typing"
 | 
			
		||||
msgstr "打鍵をモニタ"
 | 
			
		||||
 | 
			
		||||
#: ../src/eekboard.c:232
 | 
			
		||||
msgid "Keyboard model to display"
 | 
			
		||||
msgstr "表示するキーボードのモデル"
 | 
			
		||||
 | 
			
		||||
#: ../src/eekboard.c:234
 | 
			
		||||
msgid "Keyboard layouts to display, separated with commas"
 | 
			
		||||
msgstr "表示するキーボードのレイアウト,カンマ区切り"
 | 
			
		||||
 | 
			
		||||
#: ../src/eekboard.c:236
 | 
			
		||||
msgid "Keyboard layout options to display, separated with commas"
 | 
			
		||||
msgstr "表示するキーボードのオプション,カンマ区切り"
 | 
			
		||||
 | 
			
		||||
#: ../src/eekboard.c:238
 | 
			
		||||
msgid "List keyboard models"
 | 
			
		||||
msgstr "キーボードのモデルを一覧"
 | 
			
		||||
 | 
			
		||||
#: ../src/eekboard.c:240
 | 
			
		||||
msgid "List all available keyboard layouts and variants"
 | 
			
		||||
msgstr "利用可能なキーボードのレイアウトとバリアントを一覧"
 | 
			
		||||
 | 
			
		||||
#: ../src/eekboard.c:242
 | 
			
		||||
msgid "List all available keyboard layout options"
 | 
			
		||||
msgstr "利用可能なキーボードのレイアウトオプションを一覧"
 | 
			
		||||
 | 
			
		||||
#: ../src/eekboard.c:244
 | 
			
		||||
msgid "Display version"
 | 
			
		||||
msgstr "バージョンを表示"
 | 
			
		||||
 | 
			
		||||
#: ../src/eekboard.c:261
 | 
			
		||||
msgid "A virtual keyboard for GNOME"
 | 
			
		||||
msgstr "GNOME 向け仮想キーボード"
 | 
			
		||||
 | 
			
		||||
#: ../src/eekboard.c:236
 | 
			
		||||
#: ../src/eekboard.c:265
 | 
			
		||||
msgid "Eekboard web site"
 | 
			
		||||
msgstr "Eekboard のウェブサイト"
 | 
			
		||||
 | 
			
		||||
@ -22,27 +22,28 @@ eekboard_CFLAGS = \
 | 
			
		||||
	-I$(top_srcdir) \
 | 
			
		||||
	$(GOBJECT2_CFLAGS) \
 | 
			
		||||
	$(GTK2_CFLAGS) \
 | 
			
		||||
	$(GCONF2_CFLAGS) \
 | 
			
		||||
	$(XKB_CFLAGS) \
 | 
			
		||||
	$(LIBXKLAVIER_CFLAGS) \
 | 
			
		||||
	$(LIBFAKEKEY_CFLAGS)
 | 
			
		||||
	$(LIBFAKEKEY_CFLAGS) \
 | 
			
		||||
	$(CSPI_CFLAGS) \
 | 
			
		||||
	$(NOTIFY_CFLAGS)
 | 
			
		||||
 | 
			
		||||
eekboard_LDFLAGS = \
 | 
			
		||||
	$(top_builddir)/eek/libeek.la \
 | 
			
		||||
	$(top_builddir)/eek/libeek-xkl.la \
 | 
			
		||||
	$(top_builddir)/eek/libeek-gtk.la \
 | 
			
		||||
	$(GOBJECT2_LIBS) \
 | 
			
		||||
	$(GTK2_CFLAGS) \
 | 
			
		||||
	$(GTK2_LIBS) \
 | 
			
		||||
	$(GCONF2_LIBS) \
 | 
			
		||||
	$(XKB_LIBS) \
 | 
			
		||||
	$(LIBXKLAVIER_LIBS) \
 | 
			
		||||
	$(LIBFAKEKEY_LIBS)
 | 
			
		||||
	$(LIBFAKEKEY_LIBS) \
 | 
			
		||||
	$(CSPI_LIBS) \
 | 
			
		||||
	$(NOTIFY_LIBS)
 | 
			
		||||
 | 
			
		||||
if HAVE_CLUTTER
 | 
			
		||||
eekboard_CFLAGS += $(CLUTTER_CFLAGS)
 | 
			
		||||
eekboard_LDFLAGS += $(CLUTTER_LIBS)
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
if HAVE_CLUTTER_GTK
 | 
			
		||||
eekboard_CFLAGS += $(CLUTTER_GTK_CFLAGS)
 | 
			
		||||
eekboard_LDFLAGS += $(top_builddir)/eek/libeek-clutter.la $(CLUTTER_GTK_LIBS)
 | 
			
		||||
eekboard_CFLAGS += $(CLUTTER_CFLAGS) $(CLUTTER_GTK_CFLAGS)
 | 
			
		||||
eekboard_LDFLAGS += $(CLUTTER_LIBS) $(top_builddir)/eek/libeek-clutter.la $(CLUTTER_GTK_LIBS)
 | 
			
		||||
endif
 | 
			
		||||
endif
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										815
									
								
								src/eekboard.c
									
									
									
									
									
								
							
							
						
						
									
										815
									
								
								src/eekboard.c
									
									
									
									
									
								
							@ -22,16 +22,19 @@
 | 
			
		||||
 | 
			
		||||
#if HAVE_CLUTTER_GTK
 | 
			
		||||
#include <clutter-gtk/clutter-gtk.h>
 | 
			
		||||
#if NEED_SWAP_EVENT_WORKAROUND
 | 
			
		||||
#include <clutter/x11/clutter-x11.h>
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include <glib/gi18n.h>
 | 
			
		||||
#include <gdk/gdkx.h>
 | 
			
		||||
#include <gtk/gtk.h>
 | 
			
		||||
#include <gconf/gconf-client.h>
 | 
			
		||||
#include <libxklavier/xklavier.h>
 | 
			
		||||
#include <fakekey/fakekey.h>
 | 
			
		||||
#if 0
 | 
			
		||||
#include <atk/atk.h>
 | 
			
		||||
#endif
 | 
			
		||||
#include <cspi/spi.h>
 | 
			
		||||
#include <libnotify/notify.h>
 | 
			
		||||
 | 
			
		||||
#include <string.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
@ -73,16 +76,28 @@
 | 
			
		||||
    "You should have received a copy of the GNU General Public License " \
 | 
			
		||||
    "along with this program.  If not, see <http://www.gnu.org/licenses/>. " \
 | 
			
		||||
 | 
			
		||||
struct _Config {
 | 
			
		||||
    gchar *name;
 | 
			
		||||
    XklConfigRec *rec;
 | 
			
		||||
};
 | 
			
		||||
typedef struct _Config Config;
 | 
			
		||||
 | 
			
		||||
struct _Eekboard {
 | 
			
		||||
    gboolean use_clutter;
 | 
			
		||||
    gboolean need_swap_event_workaround;
 | 
			
		||||
    gboolean accessibility_enabled;
 | 
			
		||||
    Config **config;
 | 
			
		||||
    gint active_config;
 | 
			
		||||
    Display *display;
 | 
			
		||||
    FakeKey *fakekey;
 | 
			
		||||
    GtkWidget *widget;
 | 
			
		||||
    GConfClient *gconfc;
 | 
			
		||||
    Accessible *acc;
 | 
			
		||||
    GtkWidget *widget, *window, *combo;
 | 
			
		||||
    gint width, height;
 | 
			
		||||
    guint key_event_listener;
 | 
			
		||||
    XklEngine *engine;
 | 
			
		||||
    XklConfigRegistry *registry;
 | 
			
		||||
    GtkUIManager *ui_manager;
 | 
			
		||||
    gulong on_key_pressed_id, on_key_released_id;
 | 
			
		||||
 | 
			
		||||
    guint countries_merge_id;
 | 
			
		||||
    GtkActionGroup *countries_action_group;
 | 
			
		||||
@ -136,13 +151,9 @@ static void       on_options_menu   (GtkAction       *action,
 | 
			
		||||
                                     GtkWidget       *window);
 | 
			
		||||
static void       on_about          (GtkAction       *action,
 | 
			
		||||
                                     GtkWidget       *window);
 | 
			
		||||
static void       on_quit           (GtkAction *      action,
 | 
			
		||||
static void       on_quit_from_menu (GtkAction *      action,
 | 
			
		||||
                                     GtkWidget       *window);
 | 
			
		||||
#if 0
 | 
			
		||||
static void       on_monitor_key_event_toggled
 | 
			
		||||
                                    (GtkToggleAction *action,
 | 
			
		||||
                                     GtkWidget       *window);
 | 
			
		||||
#endif
 | 
			
		||||
static void       eekboard_free     (Eekboard        *eekboard);
 | 
			
		||||
static GtkWidget *create_widget     (Eekboard        *eekboard,
 | 
			
		||||
                                     gint             initial_width,
 | 
			
		||||
                                     gint             initial_height);
 | 
			
		||||
@ -161,9 +172,6 @@ static const char ui_description[] =
 | 
			
		||||
    "      <menuitem action='Quit'/>"
 | 
			
		||||
    "    </menu>"
 | 
			
		||||
    "    <menu action='KeyboardMenu'>"
 | 
			
		||||
#if 0
 | 
			
		||||
    "      <menuitem action='MonitorKeyEvent'/>"
 | 
			
		||||
#endif
 | 
			
		||||
    "      <menu action='Country'>"
 | 
			
		||||
    "        <placeholder name='CountriesPH'/>"
 | 
			
		||||
    "      </menu>"
 | 
			
		||||
@ -197,7 +205,7 @@ static const GtkActionEntry action_entry[] = {
 | 
			
		||||
    {"FileMenu", NULL, N_("_File")},
 | 
			
		||||
    {"KeyboardMenu", NULL, N_("_Keyboard")},
 | 
			
		||||
    {"HelpMenu", NULL, N_("_Help")},
 | 
			
		||||
    {"Quit", GTK_STOCK_QUIT, NULL, NULL, NULL, G_CALLBACK (on_quit)},
 | 
			
		||||
    {"Quit", GTK_STOCK_QUIT, NULL, NULL, NULL, G_CALLBACK (on_quit_from_menu)},
 | 
			
		||||
    {"Country", NULL, N_("Country"), NULL, NULL,
 | 
			
		||||
     G_CALLBACK(on_countries_menu)},
 | 
			
		||||
    {"Language", NULL, N_("Language"), NULL, NULL,
 | 
			
		||||
@ -211,12 +219,44 @@ static const GtkActionEntry action_entry[] = {
 | 
			
		||||
    {"About", GTK_STOCK_ABOUT, NULL, NULL, NULL, G_CALLBACK (on_about)}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
static const GtkToggleActionEntry toggle_action_entry[] = {
 | 
			
		||||
    {"MonitorKeyEvent", NULL, N_("Monitor Key Typing"), NULL, NULL,
 | 
			
		||||
     G_CALLBACK(on_monitor_key_event_toggled), FALSE}
 | 
			
		||||
};
 | 
			
		||||
static gchar *opt_model = NULL;
 | 
			
		||||
static gchar *opt_layouts = NULL;
 | 
			
		||||
static gchar *opt_options = NULL;
 | 
			
		||||
static gboolean opt_list_models = FALSE;
 | 
			
		||||
static gboolean opt_list_layouts = FALSE;
 | 
			
		||||
static gboolean opt_list_options = FALSE;
 | 
			
		||||
static gboolean opt_version = FALSE;
 | 
			
		||||
#if HAVE_CLUTTER_GTK
 | 
			
		||||
static gchar *opt_toolkit = NULL;
 | 
			
		||||
#endif
 | 
			
		||||
static gboolean opt_standalone = FALSE;
 | 
			
		||||
static gchar *opt_config = NULL;
 | 
			
		||||
 | 
			
		||||
static const GOptionEntry options[] = {
 | 
			
		||||
    {"model", 'M', 0, G_OPTION_ARG_STRING, &opt_model,
 | 
			
		||||
     N_("Keyboard model to display")},
 | 
			
		||||
    {"layouts", 'L', 0, G_OPTION_ARG_STRING, &opt_layouts,
 | 
			
		||||
     N_("Keyboard layouts to display, separated with commas")},
 | 
			
		||||
    {"options", 'O', 0, G_OPTION_ARG_STRING, &opt_options,
 | 
			
		||||
     N_("Keyboard layout options to display, separated with commas")},
 | 
			
		||||
    {"list-models", '\0', 0, G_OPTION_ARG_NONE, &opt_list_models,
 | 
			
		||||
     N_("List keyboard models")},
 | 
			
		||||
    {"list-layouts", '\0', 0, G_OPTION_ARG_NONE, &opt_list_layouts,
 | 
			
		||||
     N_("List all available keyboard layouts and variants")},
 | 
			
		||||
    {"list-options", 'O', 0, G_OPTION_ARG_NONE, &opt_list_options,
 | 
			
		||||
     N_("List all available keyboard layout options")},
 | 
			
		||||
#if HAVE_CLUTTER_GTK
 | 
			
		||||
    {"toolkit", 't', 0, G_OPTION_ARG_STRING, &opt_toolkit,
 | 
			
		||||
     N_("Toolkit (\"clutter\" or \"gtk\")")},
 | 
			
		||||
#endif
 | 
			
		||||
    {"standalone", 's', 0, G_OPTION_ARG_NONE, &opt_standalone,
 | 
			
		||||
     N_("Start as a standalone application")},
 | 
			
		||||
    {"config", 'c', 0, G_OPTION_ARG_STRING, &opt_config,
 | 
			
		||||
     N_("Specify configuration file")},
 | 
			
		||||
    {"version", 'v', 0, G_OPTION_ARG_NONE, &opt_version,
 | 
			
		||||
     N_("Display version")},
 | 
			
		||||
    {NULL}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_about (GtkAction * action, GtkWidget *window)
 | 
			
		||||
@ -240,44 +280,135 @@ on_about (GtkAction * action, GtkWidget *window)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_quit (GtkAction * action, GtkWidget *window)
 | 
			
		||||
on_destroy (gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    Eekboard *eekboard = g_object_get_data (G_OBJECT(window), "eekboard");
 | 
			
		||||
 | 
			
		||||
    g_object_unref (eekboard->keyboard);
 | 
			
		||||
    g_object_unref (eekboard->layout);
 | 
			
		||||
    g_object_unref (eekboard->registry);
 | 
			
		||||
    g_object_unref (eekboard->engine);
 | 
			
		||||
    g_slice_free (Eekboard, eekboard);
 | 
			
		||||
    gtk_main_quit ();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if 0
 | 
			
		||||
static gint
 | 
			
		||||
key_snoop (AtkKeyEventStruct *event, gpointer func_data)
 | 
			
		||||
static gboolean
 | 
			
		||||
on_quit (gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    return FALSE;
 | 
			
		||||
    Eekboard *eekboard = user_data;
 | 
			
		||||
    /* release the currently hold key */
 | 
			
		||||
    if (eekboard->fakekey)
 | 
			
		||||
        fakekey_release (eekboard->fakekey);
 | 
			
		||||
    eekboard_free (eekboard);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_monitor_key_event_toggled (GtkToggleAction *action,
 | 
			
		||||
                              GtkWidget *window)
 | 
			
		||||
on_quit_from_menu (GtkAction * action, GtkWidget *window)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    Eekboard *eekboard = g_object_get_data (G_OBJECT(window), "eekboard");
 | 
			
		||||
 | 
			
		||||
    if (gtk_toggle_action_get_active (action)) {
 | 
			
		||||
        if (eekboard->key_event_listener == 0)
 | 
			
		||||
            eekboard->key_event_listener =
 | 
			
		||||
                atk_add_key_event_listener (key_snoop, eekboard);
 | 
			
		||||
        g_warning ("failed to enable ATK key event listener");
 | 
			
		||||
    } else
 | 
			
		||||
        if (eekboard->key_event_listener != 0) {
 | 
			
		||||
            atk_remove_key_event_listener (eekboard->key_event_listener);
 | 
			
		||||
            eekboard->key_event_listener = 0;
 | 
			
		||||
        }
 | 
			
		||||
    gtk_main_quit ();
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
set_location (Eekboard   *eekboard,
 | 
			
		||||
              Accessible *acc)
 | 
			
		||||
{
 | 
			
		||||
    AccessibleComponent *component = Accessible_getComponent (acc);
 | 
			
		||||
    long int x, y, width, height;
 | 
			
		||||
 | 
			
		||||
    AccessibleComponent_getExtents (component,
 | 
			
		||||
                                    &x, &y, &width, &height,
 | 
			
		||||
                                    SPI_COORD_TYPE_SCREEN);
 | 
			
		||||
    gtk_window_move (GTK_WINDOW(eekboard->window), x, y + height);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static SPIBoolean
 | 
			
		||||
a11y_focus_listener (const AccessibleEvent *event,
 | 
			
		||||
                     void                  *user_data)
 | 
			
		||||
{
 | 
			
		||||
    Eekboard *eekboard = user_data;
 | 
			
		||||
    Accessible *acc = event->source;
 | 
			
		||||
    AccessibleStateSet *state_set = Accessible_getStateSet (acc);
 | 
			
		||||
    AccessibleRole role = Accessible_getRole (acc);
 | 
			
		||||
 | 
			
		||||
    /* Ignore focus on eekboard itself since eekboard itself has GTK+
 | 
			
		||||
       widgets. */
 | 
			
		||||
    if (gtk_widget_has_focus (eekboard->window))
 | 
			
		||||
        return FALSE;
 | 
			
		||||
 | 
			
		||||
    /* The logic is borrowed from Caribou. */
 | 
			
		||||
    if (AccessibleStateSet_contains (state_set, SPI_STATE_EDITABLE) ||
 | 
			
		||||
        role == SPI_ROLE_TERMINAL) {
 | 
			
		||||
        switch (role) {
 | 
			
		||||
        case SPI_ROLE_TEXT:
 | 
			
		||||
        case SPI_ROLE_PARAGRAPH:
 | 
			
		||||
        case SPI_ROLE_PASSWORD_TEXT:
 | 
			
		||||
        case SPI_ROLE_TERMINAL:
 | 
			
		||||
            if (strncmp (event->type, "focus", 5) == 0 || event->detail1 == 1) {
 | 
			
		||||
                set_location (eekboard, acc);
 | 
			
		||||
                gtk_widget_show (eekboard->window);
 | 
			
		||||
                eekboard->acc = acc;
 | 
			
		||||
            } else if (event->detail1 == 0 && acc == eekboard->acc) {
 | 
			
		||||
                gtk_widget_hide (eekboard->window);
 | 
			
		||||
                eekboard->acc = NULL;
 | 
			
		||||
            }
 | 
			
		||||
        case SPI_ROLE_ENTRY:
 | 
			
		||||
            if (strncmp (event->type, "focus", 5) == 0 || event->detail1 == 1) {
 | 
			
		||||
                set_location (eekboard, acc);
 | 
			
		||||
                gtk_widget_show (eekboard->window);
 | 
			
		||||
                eekboard->acc = acc;
 | 
			
		||||
            } else if (event->detail1 == 0 && acc == eekboard->acc) {
 | 
			
		||||
                gtk_widget_hide (eekboard->window);
 | 
			
		||||
                eekboard->acc = NULL;
 | 
			
		||||
            }
 | 
			
		||||
        default:
 | 
			
		||||
            ;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static SPIBoolean
 | 
			
		||||
a11y_keystroke_listener (const AccessibleKeystroke *stroke,
 | 
			
		||||
                         void                      *user_data)
 | 
			
		||||
{
 | 
			
		||||
    Eekboard *eekboard = user_data;
 | 
			
		||||
    EekKey *key;
 | 
			
		||||
    guint keysym;
 | 
			
		||||
    guint ignored_keysyms[] = {XK_Shift_L,
 | 
			
		||||
                               XK_Shift_R,
 | 
			
		||||
                               XK_ISO_Level3_Shift,
 | 
			
		||||
                               XK_Control_L,
 | 
			
		||||
                               XK_Control_R,
 | 
			
		||||
                               XK_Alt_L,
 | 
			
		||||
                               XK_Alt_R};
 | 
			
		||||
    gint i;
 | 
			
		||||
    
 | 
			
		||||
    key = eek_keyboard_find_key_by_keycode (eekboard->keyboard,
 | 
			
		||||
                                            stroke->keycode);
 | 
			
		||||
    if (!key)
 | 
			
		||||
        return FALSE;
 | 
			
		||||
 | 
			
		||||
    /* XXX: Ignore modifier keys since there is no way to receive
 | 
			
		||||
       SPI_KEY_RELEASED event for them. */
 | 
			
		||||
    keysym = eek_key_get_keysym (key);
 | 
			
		||||
    for (i = 0; i < G_N_ELEMENTS(ignored_keysyms) &&
 | 
			
		||||
             keysym != ignored_keysyms[i]; i++)
 | 
			
		||||
        ;
 | 
			
		||||
    if (i != G_N_ELEMENTS(ignored_keysyms))
 | 
			
		||||
        return FALSE;
 | 
			
		||||
 | 
			
		||||
    if (stroke->type == SPI_KEY_PRESSED) {
 | 
			
		||||
        g_signal_handler_block (eekboard->keyboard,
 | 
			
		||||
                                eekboard->on_key_pressed_id);
 | 
			
		||||
        g_signal_emit_by_name (key, "pressed");
 | 
			
		||||
        g_signal_handler_unblock (eekboard->keyboard,
 | 
			
		||||
                                  eekboard->on_key_pressed_id);
 | 
			
		||||
    } else {
 | 
			
		||||
        g_signal_handler_block (eekboard->keyboard,
 | 
			
		||||
                                eekboard->on_key_released_id);
 | 
			
		||||
        g_signal_emit_by_name (key, "released");
 | 
			
		||||
        g_signal_handler_unblock (eekboard->keyboard,
 | 
			
		||||
                                  eekboard->on_key_released_id);
 | 
			
		||||
    }
 | 
			
		||||
    return TRUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static AccessibleEventListener* focusListener;
 | 
			
		||||
static AccessibleEventListener* keystrokeListener;
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_key_pressed (EekKeyboard *keyboard,
 | 
			
		||||
@ -285,23 +416,41 @@ on_key_pressed (EekKeyboard *keyboard,
 | 
			
		||||
                gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    Eekboard *eekboard = user_data;
 | 
			
		||||
    guint keysym;
 | 
			
		||||
    gint group, level;
 | 
			
		||||
    guint keysym, modifiers = 0;
 | 
			
		||||
 | 
			
		||||
    keysym = eek_key_get_keysym (key);
 | 
			
		||||
    EEKBOARD_NOTE("%s %X", eek_keysym_to_string (keysym), eekboard->modifiers);
 | 
			
		||||
    if (keysym == XK_Shift_L || keysym == XK_Shift_R) {
 | 
			
		||||
        gint group, level;
 | 
			
		||||
 | 
			
		||||
    switch (keysym) {
 | 
			
		||||
    case XK_Shift_L:
 | 
			
		||||
    case XK_Shift_R:
 | 
			
		||||
        eekboard->modifiers ^= ShiftMask;
 | 
			
		||||
        eek_keyboard_get_keysym_index (keyboard, &group, &level);
 | 
			
		||||
        eek_keyboard_set_keysym_index (keyboard, group,
 | 
			
		||||
                                       eekboard->modifiers & ShiftMask ? 1 : 0);
 | 
			
		||||
    } else if (keysym == XK_Control_L || keysym == XK_Control_R) {
 | 
			
		||||
                                       (eekboard->modifiers & Mod5Mask) ? 2 :
 | 
			
		||||
                                       (eekboard->modifiers & ShiftMask) ? 1 :
 | 
			
		||||
                                       0);
 | 
			
		||||
        break;
 | 
			
		||||
    case XK_ISO_Level3_Shift:
 | 
			
		||||
        eekboard->modifiers ^= Mod5Mask;
 | 
			
		||||
        eek_keyboard_get_keysym_index (keyboard, &group, &level);
 | 
			
		||||
        eek_keyboard_set_keysym_index (keyboard, group,
 | 
			
		||||
                                       (eekboard->modifiers & Mod5Mask) ? 2 :
 | 
			
		||||
                                       (eekboard->modifiers & ShiftMask) ? 1 :
 | 
			
		||||
                                       0);
 | 
			
		||||
        break;
 | 
			
		||||
    case XK_Control_L:
 | 
			
		||||
    case XK_Control_R:
 | 
			
		||||
        eekboard->modifiers ^= ControlMask;
 | 
			
		||||
    } else if (keysym == XK_Alt_L || keysym == XK_Alt_R) {
 | 
			
		||||
        break;
 | 
			
		||||
    case XK_Alt_L:
 | 
			
		||||
    case XK_Alt_R:
 | 
			
		||||
        eekboard->modifiers ^= Mod1Mask;
 | 
			
		||||
    } else
 | 
			
		||||
        break;
 | 
			
		||||
    default:
 | 
			
		||||
        fakekey_press_keysym (eekboard->fakekey, keysym, eekboard->modifiers);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
@ -833,14 +982,10 @@ create_menus (Eekboard      *eekboard,
 | 
			
		||||
 | 
			
		||||
    gtk_action_group_add_actions (action_group, action_entry,
 | 
			
		||||
                                  G_N_ELEMENTS (action_entry), window);
 | 
			
		||||
#if 0
 | 
			
		||||
    gtk_action_group_add_toggle_actions (action_group, toggle_action_entry,
 | 
			
		||||
                                         G_N_ELEMENTS (toggle_action_entry),
 | 
			
		||||
                                         window);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    gtk_ui_manager_insert_action_group (eekboard->ui_manager, action_group, 0);
 | 
			
		||||
    gtk_ui_manager_add_ui_from_string (eekboard->ui_manager, ui_description, -1, NULL);
 | 
			
		||||
    g_object_unref (action_group);
 | 
			
		||||
 | 
			
		||||
    eekboard->countries_action_group = gtk_action_group_new ("Countries");
 | 
			
		||||
    gtk_ui_manager_insert_action_group (eekboard->ui_manager,
 | 
			
		||||
@ -882,10 +1027,12 @@ create_widget_gtk (Eekboard *eekboard,
 | 
			
		||||
    eekboard->keyboard = eek_gtk_keyboard_new ();
 | 
			
		||||
    eek_keyboard_set_layout (eekboard->keyboard, eekboard->layout);
 | 
			
		||||
    eek_element_set_bounds (EEK_ELEMENT(eekboard->keyboard), &bounds);
 | 
			
		||||
    g_signal_connect (eekboard->keyboard, "key-pressed",
 | 
			
		||||
                      G_CALLBACK(on_key_pressed), eekboard);
 | 
			
		||||
    g_signal_connect (eekboard->keyboard, "key-released",
 | 
			
		||||
                      G_CALLBACK(on_key_released), eekboard);
 | 
			
		||||
    eekboard->on_key_pressed_id =
 | 
			
		||||
        g_signal_connect (eekboard->keyboard, "key-pressed",
 | 
			
		||||
                          G_CALLBACK(on_key_pressed), eekboard);
 | 
			
		||||
    eekboard->on_key_released_id =
 | 
			
		||||
        g_signal_connect (eekboard->keyboard, "key-released",
 | 
			
		||||
                          G_CALLBACK(on_key_released), eekboard);
 | 
			
		||||
 | 
			
		||||
    eekboard->widget =
 | 
			
		||||
        eek_gtk_keyboard_get_widget (EEK_GTK_KEYBOARD (eekboard->keyboard));
 | 
			
		||||
@ -896,6 +1043,26 @@ create_widget_gtk (Eekboard *eekboard,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if HAVE_CLUTTER_GTK
 | 
			
		||||
#if NEED_SWAP_EVENT_WORKAROUND
 | 
			
		||||
static GdkFilterReturn
 | 
			
		||||
gtk_clutter_filter_func (GdkXEvent *native_event,
 | 
			
		||||
                         GdkEvent  *event,
 | 
			
		||||
                         gpointer   user_data)
 | 
			
		||||
{
 | 
			
		||||
  XEvent *xevent = native_event;
 | 
			
		||||
 | 
			
		||||
  clutter_x11_handle_event (xevent);
 | 
			
		||||
 | 
			
		||||
  return GDK_FILTER_CONTINUE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_gtk_clutter_embed_realize (GtkWidget *widget, gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    gdk_window_add_filter (NULL, gtk_clutter_filter_func, widget);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static GtkWidget *
 | 
			
		||||
create_widget_clutter (Eekboard *eekboard,
 | 
			
		||||
                       gint      initial_width,
 | 
			
		||||
@ -912,12 +1079,19 @@ create_widget_clutter (Eekboard *eekboard,
 | 
			
		||||
    eekboard->keyboard = eek_clutter_keyboard_new ();
 | 
			
		||||
    eek_keyboard_set_layout (eekboard->keyboard, eekboard->layout);
 | 
			
		||||
    eek_element_set_bounds (EEK_ELEMENT(eekboard->keyboard), &bounds);
 | 
			
		||||
    g_signal_connect (eekboard->keyboard, "key-pressed",
 | 
			
		||||
                      G_CALLBACK(on_key_pressed), eekboard);
 | 
			
		||||
    g_signal_connect (eekboard->keyboard, "key-released",
 | 
			
		||||
                      G_CALLBACK(on_key_released), eekboard);
 | 
			
		||||
    eekboard->on_key_pressed_id =
 | 
			
		||||
        g_signal_connect (eekboard->keyboard, "key-pressed",
 | 
			
		||||
                          G_CALLBACK(on_key_pressed), eekboard);
 | 
			
		||||
    eekboard->on_key_released_id =
 | 
			
		||||
        g_signal_connect (eekboard->keyboard, "key-released",
 | 
			
		||||
                          G_CALLBACK(on_key_released), eekboard);
 | 
			
		||||
 | 
			
		||||
    eekboard->widget = gtk_clutter_embed_new ();
 | 
			
		||||
#if NEED_SWAP_EVENT_WORKAROUND
 | 
			
		||||
    if (eekboard->need_swap_event_workaround)
 | 
			
		||||
        g_signal_connect (eekboard->widget, "realize",
 | 
			
		||||
                          G_CALLBACK(on_gtk_clutter_embed_realize), NULL);
 | 
			
		||||
#endif
 | 
			
		||||
    stage = gtk_clutter_embed_get_stage (GTK_CLUTTER_EMBED(eekboard->widget));
 | 
			
		||||
    clutter_stage_set_color (CLUTTER_STAGE(stage), &stage_color);
 | 
			
		||||
    clutter_stage_set_user_resizable (CLUTTER_STAGE (stage), TRUE);
 | 
			
		||||
@ -944,13 +1118,43 @@ create_widget (Eekboard *eekboard,
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
parse_layouts (XklConfigRec *rec, const gchar *_layouts)
 | 
			
		||||
{
 | 
			
		||||
    gchar **layouts, **variants;
 | 
			
		||||
    gint i;
 | 
			
		||||
 | 
			
		||||
    layouts = g_strsplit (_layouts, ",", -1);
 | 
			
		||||
    variants = g_strdupv (layouts);
 | 
			
		||||
    for (i = 0; layouts[i]; i++) {
 | 
			
		||||
        gchar *layout = layouts[i], *variant = variants[i],
 | 
			
		||||
            *variant_start, *variant_end;
 | 
			
		||||
 | 
			
		||||
        variant_start = strchr (layout, '(');
 | 
			
		||||
        variant_end = strrchr (layout, ')');
 | 
			
		||||
        if (variant_start && variant_end) {
 | 
			
		||||
            *variant_start++ = '\0';
 | 
			
		||||
            g_strlcpy (variant, variant_start,
 | 
			
		||||
                       variant_end - variant_start + 1);
 | 
			
		||||
        } else
 | 
			
		||||
            *variant = '\0';
 | 
			
		||||
    }
 | 
			
		||||
    rec->layouts = layouts;
 | 
			
		||||
    rec->variants = variants;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Eekboard *
 | 
			
		||||
eekboard_new (gboolean use_clutter)
 | 
			
		||||
eekboard_new (gboolean use_clutter,
 | 
			
		||||
              gboolean need_swap_event_workaround,
 | 
			
		||||
              gboolean accessibility_enabled)
 | 
			
		||||
{
 | 
			
		||||
    Eekboard *eekboard;
 | 
			
		||||
 | 
			
		||||
    eekboard = g_slice_new0 (Eekboard);
 | 
			
		||||
    eekboard->use_clutter = use_clutter;
 | 
			
		||||
    eekboard->need_swap_event_workaround = need_swap_event_workaround;
 | 
			
		||||
    eekboard->accessibility_enabled = accessibility_enabled;
 | 
			
		||||
    eekboard->active_config = -1;
 | 
			
		||||
    eekboard->display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
 | 
			
		||||
    if (!eekboard->display) {
 | 
			
		||||
        g_slice_free (Eekboard, eekboard);
 | 
			
		||||
@ -971,6 +1175,24 @@ eekboard_new (gboolean use_clutter)
 | 
			
		||||
        g_warning ("Can't create layout");
 | 
			
		||||
        return NULL;
 | 
			
		||||
    }
 | 
			
		||||
    if (opt_model)
 | 
			
		||||
        eek_xkl_layout_set_model (EEK_XKL_LAYOUT(eekboard->layout), opt_model);
 | 
			
		||||
    if (opt_layouts) {
 | 
			
		||||
        XklConfigRec *rec = xkl_config_rec_new ();
 | 
			
		||||
 | 
			
		||||
        parse_layouts (rec, opt_layouts);
 | 
			
		||||
        eek_xkl_layout_set_layouts (EEK_XKL_LAYOUT(eekboard->layout),
 | 
			
		||||
                                    rec->layouts);
 | 
			
		||||
        eek_xkl_layout_set_variants (EEK_XKL_LAYOUT(eekboard->layout),
 | 
			
		||||
                                     rec->variants);
 | 
			
		||||
        g_object_unref (rec);
 | 
			
		||||
    }
 | 
			
		||||
    if (opt_options) {
 | 
			
		||||
        gchar **options;
 | 
			
		||||
        options = g_strsplit (opt_options, ",", -1);
 | 
			
		||||
        eek_xkl_layout_set_options (EEK_XKL_LAYOUT(eekboard->layout), options);
 | 
			
		||||
        g_strfreev (options);
 | 
			
		||||
    }
 | 
			
		||||
    g_signal_connect (eekboard->layout, "changed",
 | 
			
		||||
                      G_CALLBACK(on_changed), eekboard);
 | 
			
		||||
 | 
			
		||||
@ -979,34 +1201,294 @@ eekboard_new (gboolean use_clutter)
 | 
			
		||||
    eekboard->registry = xkl_config_registry_get_instance (eekboard->engine);
 | 
			
		||||
    xkl_config_registry_load (eekboard->registry, FALSE);
 | 
			
		||||
 | 
			
		||||
    create_widget (eekboard, CSW, CSH);
 | 
			
		||||
 | 
			
		||||
    return eekboard;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
eekboard_free (Eekboard *eekboard)
 | 
			
		||||
{
 | 
			
		||||
    if (eekboard->layout)
 | 
			
		||||
        g_object_unref (eekboard->layout);
 | 
			
		||||
#if 0
 | 
			
		||||
    if (eekboard->keyboard)
 | 
			
		||||
        g_object_unref (eekboard->keyboard);
 | 
			
		||||
#endif
 | 
			
		||||
    if (eekboard->registry)
 | 
			
		||||
        g_object_unref (eekboard->registry);
 | 
			
		||||
    if (eekboard->engine)
 | 
			
		||||
        g_object_unref (eekboard->engine);
 | 
			
		||||
    if (eekboard->gconfc)
 | 
			
		||||
        g_object_unref (eekboard->gconfc);
 | 
			
		||||
    if (eekboard->ui_manager)
 | 
			
		||||
        g_object_unref (eekboard->ui_manager);
 | 
			
		||||
    if (eekboard->countries_action_group)
 | 
			
		||||
        g_object_unref (eekboard->countries_action_group);
 | 
			
		||||
    if (eekboard->languages_action_group)
 | 
			
		||||
        g_object_unref (eekboard->languages_action_group);
 | 
			
		||||
    if (eekboard->models_action_group)
 | 
			
		||||
        g_object_unref (eekboard->models_action_group);
 | 
			
		||||
    if (eekboard->layouts_action_group)
 | 
			
		||||
        g_object_unref (eekboard->layouts_action_group);
 | 
			
		||||
    if (eekboard->options_action_group)
 | 
			
		||||
        g_object_unref (eekboard->options_action_group);
 | 
			
		||||
    g_slice_free (Eekboard, eekboard);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
print_layout (XklConfigRegistry   *registry,
 | 
			
		||||
              const XklConfigItem *item,
 | 
			
		||||
              gpointer             user_data)
 | 
			
		||||
{
 | 
			
		||||
    GSList *variants = NULL;
 | 
			
		||||
    xkl_config_registry_foreach_layout_variant (registry,
 | 
			
		||||
                                                item->name,
 | 
			
		||||
                                                collect_variant,
 | 
			
		||||
                                                &variants);
 | 
			
		||||
    if (!variants)
 | 
			
		||||
        printf ("%s: %s\n", item->name, item->description);
 | 
			
		||||
    else {
 | 
			
		||||
        GSList *head;
 | 
			
		||||
        for (head = variants; head; head = head->next) {
 | 
			
		||||
            XklConfigItem *_item = head->data;
 | 
			
		||||
            
 | 
			
		||||
            printf ("%s(%s): %s %s\n",
 | 
			
		||||
                    item->name,
 | 
			
		||||
                    _item->name,
 | 
			
		||||
                    item->description,
 | 
			
		||||
                    _item->description);
 | 
			
		||||
            g_slice_free (XklConfigItem, _item);
 | 
			
		||||
        }
 | 
			
		||||
        g_slist_free (variants);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
print_item (XklConfigRegistry *registry,
 | 
			
		||||
            const XklConfigItem *item,
 | 
			
		||||
            gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    printf ("%s: %s\n", item->name, item->description);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
print_option_group (XklConfigRegistry *registry,
 | 
			
		||||
                    const XklConfigItem *item,
 | 
			
		||||
                    gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    xkl_config_registry_foreach_option (registry,
 | 
			
		||||
                                        item->name,
 | 
			
		||||
                                        print_item,
 | 
			
		||||
                                        NULL);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_notify_never_show (NotifyNotification *notification,
 | 
			
		||||
                      char *action,
 | 
			
		||||
                      gpointer user_data)
 | 
			
		||||
{
 | 
			
		||||
    Eekboard *eekboard = user_data;
 | 
			
		||||
    GError *error;
 | 
			
		||||
 | 
			
		||||
    gconf_client_set_bool (eekboard->gconfc,
 | 
			
		||||
                           "/apps/eekboard/inhibit-startup-notify",
 | 
			
		||||
                           TRUE,
 | 
			
		||||
                           &error);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
on_layout_changed (GtkComboBox *combo,
 | 
			
		||||
                   gpointer     user_data)
 | 
			
		||||
{
 | 
			
		||||
    Eekboard *eekboard = user_data;
 | 
			
		||||
    GtkTreeModel *model;
 | 
			
		||||
    GtkTreeIter iter;
 | 
			
		||||
    gint active;
 | 
			
		||||
 | 
			
		||||
    model = gtk_combo_box_get_model (combo);
 | 
			
		||||
    gtk_combo_box_get_active_iter (combo, &iter);
 | 
			
		||||
    gtk_tree_model_get (model, &iter, 1, &active, -1);
 | 
			
		||||
 | 
			
		||||
    if (eekboard->active_config != active) {
 | 
			
		||||
        XklConfigRec *config, *config_base = eekboard->config[active]->rec;
 | 
			
		||||
 | 
			
		||||
        config = xkl_config_rec_new ();
 | 
			
		||||
        if (config_base->model)
 | 
			
		||||
            config->model = g_strdup (config_base->model);
 | 
			
		||||
        else
 | 
			
		||||
            config->model =
 | 
			
		||||
                eek_xkl_layout_get_model (EEK_XKL_LAYOUT(eekboard->layout));
 | 
			
		||||
 | 
			
		||||
        if (config_base->layouts)
 | 
			
		||||
            config->layouts = g_strdupv (config_base->layouts);
 | 
			
		||||
        else
 | 
			
		||||
            config->layouts =
 | 
			
		||||
                eek_xkl_layout_get_layouts (EEK_XKL_LAYOUT(eekboard->layout));
 | 
			
		||||
 | 
			
		||||
        if (config_base->variants)
 | 
			
		||||
            config->variants = g_strdupv (config_base->variants);
 | 
			
		||||
        else
 | 
			
		||||
            config->variants =
 | 
			
		||||
                eek_xkl_layout_get_variants (EEK_XKL_LAYOUT(eekboard->layout));
 | 
			
		||||
 | 
			
		||||
        if (config_base->options)
 | 
			
		||||
            config->options = g_strdupv (config_base->options);
 | 
			
		||||
        else
 | 
			
		||||
            config->options =
 | 
			
		||||
                eek_xkl_layout_get_options (EEK_XKL_LAYOUT(eekboard->layout));
 | 
			
		||||
 | 
			
		||||
        eek_xkl_layout_set_config (EEK_XKL_LAYOUT(eekboard->layout), config);
 | 
			
		||||
        g_object_unref (config);
 | 
			
		||||
 | 
			
		||||
        eekboard->active_config = active;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct _ConfigContext {
 | 
			
		||||
    GSList *list;
 | 
			
		||||
    GString *text;
 | 
			
		||||
};
 | 
			
		||||
typedef struct _ConfigContext ConfigContext;
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
config_parser_start_element (GMarkupParseContext *pcontext,
 | 
			
		||||
                             const gchar         *element_name,
 | 
			
		||||
                             const gchar        **attribute_names,
 | 
			
		||||
                             const gchar        **attribute_values,
 | 
			
		||||
                             gpointer             user_data,
 | 
			
		||||
                             GError             **error)
 | 
			
		||||
{
 | 
			
		||||
    ConfigContext *context = user_data;
 | 
			
		||||
    if (g_strcmp0 (element_name, "config") == 0) {
 | 
			
		||||
        Config *config = g_slice_new0 (Config);
 | 
			
		||||
        config->rec = xkl_config_rec_new ();
 | 
			
		||||
        context->list = g_slist_prepend (context->list, config);
 | 
			
		||||
    } else
 | 
			
		||||
        context->text = g_string_sized_new (100);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
config_parser_end_element (GMarkupParseContext *pcontext,
 | 
			
		||||
                           const gchar         *element_name,
 | 
			
		||||
                           gpointer             user_data,
 | 
			
		||||
                           GError             **error)
 | 
			
		||||
{
 | 
			
		||||
    ConfigContext *context = user_data;
 | 
			
		||||
    Config *config = context->list->data;
 | 
			
		||||
    gchar *text;
 | 
			
		||||
 | 
			
		||||
    if (g_strcmp0 (element_name, "config") == 0 &&
 | 
			
		||||
        !config->name) {
 | 
			
		||||
        if (error)
 | 
			
		||||
            *error = g_error_new (G_MARKUP_ERROR,
 | 
			
		||||
                                  G_MARKUP_ERROR_INVALID_CONTENT,
 | 
			
		||||
                                  "\"name\" is missing");
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (!context->text)
 | 
			
		||||
        return;
 | 
			
		||||
 | 
			
		||||
    text = g_string_free (context->text, FALSE);
 | 
			
		||||
    context->text = NULL;
 | 
			
		||||
 | 
			
		||||
    if (g_strcmp0 (element_name, "name") == 0)
 | 
			
		||||
        config->name = text;
 | 
			
		||||
    else if (g_strcmp0 (element_name, "model") == 0)
 | 
			
		||||
        config->rec->model = text;
 | 
			
		||||
    else if (g_strcmp0 (element_name, "layouts") == 0)
 | 
			
		||||
        parse_layouts (config->rec, text);
 | 
			
		||||
    else if (g_strcmp0 (element_name, "options") == 0)
 | 
			
		||||
        config->rec->options = g_strsplit (text, ",", -1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
config_parser_text (GMarkupParseContext *pcontext,
 | 
			
		||||
                    const gchar         *text,
 | 
			
		||||
                    gsize                text_len,  
 | 
			
		||||
                    gpointer             user_data,
 | 
			
		||||
                    GError             **error)
 | 
			
		||||
{
 | 
			
		||||
    ConfigContext *context = user_data;
 | 
			
		||||
    if (context->text)
 | 
			
		||||
        context->text = g_string_append_len (context->text, text, text_len);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
GMarkupParser config_parser = {
 | 
			
		||||
    .start_element = config_parser_start_element,
 | 
			
		||||
    .end_element = config_parser_end_element,
 | 
			
		||||
    .text = config_parser_text
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int
 | 
			
		||||
main (int argc, char *argv[])
 | 
			
		||||
{
 | 
			
		||||
    const gchar *env;
 | 
			
		||||
    gboolean use_clutter = USE_CLUTTER;
 | 
			
		||||
    gboolean need_swap_event_workaround = FALSE;
 | 
			
		||||
    gboolean accessibility_enabled = FALSE;
 | 
			
		||||
    Eekboard *eekboard;
 | 
			
		||||
    GtkWidget *widget, *vbox, *menubar, *window;
 | 
			
		||||
    GtkWidget *widget, *vbox, *menubar, *window, *combo = NULL;
 | 
			
		||||
    GOptionContext *context;
 | 
			
		||||
    GConfClient *gconfc;
 | 
			
		||||
    GError *error;
 | 
			
		||||
 | 
			
		||||
    context = g_option_context_new ("eekboard");
 | 
			
		||||
    g_option_context_add_main_entries (context, options, NULL);
 | 
			
		||||
    g_option_context_parse (context, &argc, &argv, NULL);
 | 
			
		||||
    g_option_context_free (context);
 | 
			
		||||
 | 
			
		||||
    if (opt_version) {
 | 
			
		||||
        g_print ("eekboard %s\n", VERSION);
 | 
			
		||||
        exit (0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
#ifdef ENABLE_NLS
 | 
			
		||||
    bindtextdomain (GETTEXT_PACKAGE, EEKBOARD_LOCALEDIR);
 | 
			
		||||
    bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    error = NULL;
 | 
			
		||||
    gconfc = gconf_client_get_default ();
 | 
			
		||||
    if (gconf_client_get_bool (gconfc,
 | 
			
		||||
                               "/desktop/gnome/interface/accessibility",
 | 
			
		||||
                               &error) ||
 | 
			
		||||
        gconf_client_get_bool (gconfc,
 | 
			
		||||
                               "/desktop/gnome/interface/accessibility2",
 | 
			
		||||
                               &error)) {
 | 
			
		||||
        if (SPI_init () == 0)
 | 
			
		||||
            accessibility_enabled = TRUE;
 | 
			
		||||
        else
 | 
			
		||||
            g_warning("AT-SPI initialization failed");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    env = g_getenv ("EEKBOARD_DISABLE_CLUTTER");
 | 
			
		||||
    if (env && g_strcmp0 (env, "1") == 0)
 | 
			
		||||
        use_clutter = FALSE;
 | 
			
		||||
 | 
			
		||||
#if HAVE_CLUTTER_GTK
 | 
			
		||||
    if (opt_toolkit) {
 | 
			
		||||
        if (g_strcmp0 (opt_toolkit, "clutter") == 0)
 | 
			
		||||
            use_clutter = TRUE;
 | 
			
		||||
        else if (g_strcmp0 (opt_toolkit, "gtk") == 0)
 | 
			
		||||
            use_clutter = FALSE;
 | 
			
		||||
        else {
 | 
			
		||||
            g_print ("Invalid toolkit \"%s\"\n", opt_toolkit);
 | 
			
		||||
            exit (0);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (use_clutter &&
 | 
			
		||||
        gtk_clutter_init (&argc, &argv) != CLUTTER_INIT_SUCCESS) {
 | 
			
		||||
        g_warning ("Can't init Clutter-Gtk...fallback to GTK");
 | 
			
		||||
        use_clutter = FALSE;
 | 
			
		||||
    }
 | 
			
		||||
#ifdef NEED_SWAP_EVENT_WORKAROUND
 | 
			
		||||
    if (use_clutter &&
 | 
			
		||||
        clutter_feature_available (CLUTTER_FEATURE_SWAP_EVENTS)) {
 | 
			
		||||
        g_warning ("Enabling GLX_INTEL_swap_event workaround for Clutter-Gtk");
 | 
			
		||||
        need_swap_event_workaround = TRUE;
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
    if (!use_clutter && !gtk_init_check (&argc, &argv)) {
 | 
			
		||||
@ -1014,22 +1496,130 @@ main (int argc, char *argv[])
 | 
			
		||||
        exit (1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
 | 
			
		||||
    eekboard = eekboard_new (use_clutter,
 | 
			
		||||
                             need_swap_event_workaround,
 | 
			
		||||
                             accessibility_enabled);
 | 
			
		||||
    if (opt_list_models) {
 | 
			
		||||
        xkl_config_registry_foreach_model (eekboard->registry,
 | 
			
		||||
                                           print_item,
 | 
			
		||||
                                           NULL);
 | 
			
		||||
        eekboard_free (eekboard);
 | 
			
		||||
        exit (0);
 | 
			
		||||
    }
 | 
			
		||||
    if (opt_list_layouts) {
 | 
			
		||||
        xkl_config_registry_foreach_layout (eekboard->registry,
 | 
			
		||||
                                            print_layout,
 | 
			
		||||
                                            NULL);
 | 
			
		||||
        eekboard_free (eekboard);
 | 
			
		||||
        exit (0);
 | 
			
		||||
    }
 | 
			
		||||
    if (opt_list_options) {
 | 
			
		||||
        xkl_config_registry_foreach_option_group (eekboard->registry,
 | 
			
		||||
                                                  print_option_group,
 | 
			
		||||
                                                  NULL);
 | 
			
		||||
        eekboard_free (eekboard);
 | 
			
		||||
        exit (0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (opt_config) {
 | 
			
		||||
        ConfigContext context;
 | 
			
		||||
        GMarkupParseContext *pcontext;
 | 
			
		||||
        GFile *file;
 | 
			
		||||
        GError *error;
 | 
			
		||||
        GFileInputStream *stream;
 | 
			
		||||
        gchar buf[BUFSIZ];
 | 
			
		||||
        GSList *head;
 | 
			
		||||
        gint i;
 | 
			
		||||
 | 
			
		||||
        memset (&context, 0, sizeof context);
 | 
			
		||||
        file = g_file_new_for_path (opt_config);
 | 
			
		||||
 | 
			
		||||
        error = NULL;
 | 
			
		||||
        stream = g_file_read (file, NULL, &error);
 | 
			
		||||
        if (!stream) {
 | 
			
		||||
            eekboard_free (eekboard);
 | 
			
		||||
            g_print ("Can't read configuration file: %s\n", opt_config);
 | 
			
		||||
            exit (1);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        pcontext = g_markup_parse_context_new (&config_parser,
 | 
			
		||||
                                               0,
 | 
			
		||||
                                               &context,
 | 
			
		||||
                                               NULL);
 | 
			
		||||
        while (1) {
 | 
			
		||||
            gssize len;
 | 
			
		||||
                
 | 
			
		||||
            error = NULL;
 | 
			
		||||
            len = g_input_stream_read (G_INPUT_STREAM(stream),
 | 
			
		||||
                                       buf, sizeof buf, NULL,
 | 
			
		||||
                                       &error);
 | 
			
		||||
            if (len <= 0)
 | 
			
		||||
                break;
 | 
			
		||||
 | 
			
		||||
            error = NULL;
 | 
			
		||||
            if (!g_markup_parse_context_parse (pcontext, buf, len, &error))
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
        g_object_unref (stream);
 | 
			
		||||
 | 
			
		||||
        error = NULL;
 | 
			
		||||
        g_markup_parse_context_end_parse (pcontext, &error);
 | 
			
		||||
        g_markup_parse_context_free (pcontext);
 | 
			
		||||
        g_object_unref (file);
 | 
			
		||||
 | 
			
		||||
        if (context.list) {
 | 
			
		||||
            eekboard->config =
 | 
			
		||||
                g_slice_alloc0 ((g_slist_length (context.list) + 1) *
 | 
			
		||||
                                sizeof (*eekboard->config));
 | 
			
		||||
            for (i = 0, head = context.list; head; head = head->next)
 | 
			
		||||
                eekboard->config[i++] = head->data;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    window = gtk_window_new (opt_standalone ?
 | 
			
		||||
                             GTK_WINDOW_TOPLEVEL :
 | 
			
		||||
                             GTK_WINDOW_POPUP);
 | 
			
		||||
    gtk_widget_set_can_focus (window, FALSE);
 | 
			
		||||
    g_object_set (G_OBJECT(window), "accept_focus", FALSE, NULL);
 | 
			
		||||
    gtk_window_set_title (GTK_WINDOW(window), "Keyboard");
 | 
			
		||||
    g_signal_connect (G_OBJECT (window), "destroy",
 | 
			
		||||
                      G_CALLBACK (gtk_main_quit), NULL);
 | 
			
		||||
                      G_CALLBACK (on_destroy), eekboard);
 | 
			
		||||
 | 
			
		||||
    vbox = gtk_vbox_new (FALSE, 0);
 | 
			
		||||
 | 
			
		||||
    eekboard = eekboard_new (use_clutter);
 | 
			
		||||
    g_object_set_data (G_OBJECT(window), "eekboard", eekboard);
 | 
			
		||||
    widget = create_widget (eekboard, CSW, CSH);
 | 
			
		||||
    
 | 
			
		||||
    create_menus (eekboard, window);
 | 
			
		||||
    menubar = gtk_ui_manager_get_widget (eekboard->ui_manager, "/MainMenu");
 | 
			
		||||
    gtk_box_pack_start (GTK_BOX (vbox), menubar, FALSE, FALSE, 0);
 | 
			
		||||
 | 
			
		||||
    if (opt_standalone) {
 | 
			
		||||
        create_menus (eekboard, window);
 | 
			
		||||
        menubar = gtk_ui_manager_get_widget (eekboard->ui_manager, "/MainMenu");
 | 
			
		||||
        gtk_box_pack_start (GTK_BOX (vbox), menubar, FALSE, FALSE, 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (eekboard->config) {
 | 
			
		||||
        GtkListStore *store;
 | 
			
		||||
        GtkTreeIter iter;
 | 
			
		||||
        GtkCellRenderer *renderer;
 | 
			
		||||
        int i;
 | 
			
		||||
        
 | 
			
		||||
        store = gtk_list_store_new (2, G_TYPE_STRING, G_TYPE_INT);
 | 
			
		||||
        for (i = 0; eekboard->config[i]; i++) {
 | 
			
		||||
            gtk_list_store_append (store, &iter);
 | 
			
		||||
            gtk_list_store_set (store, &iter,
 | 
			
		||||
                                0, eekboard->config[i]->name,
 | 
			
		||||
                                1, i,
 | 
			
		||||
                                -1);
 | 
			
		||||
        }
 | 
			
		||||
        combo = gtk_combo_box_new_with_model (GTK_TREE_MODEL(store));
 | 
			
		||||
        renderer = gtk_cell_renderer_text_new ();
 | 
			
		||||
        gtk_cell_layout_pack_start (GTK_CELL_LAYOUT(combo),
 | 
			
		||||
                                    renderer, TRUE);
 | 
			
		||||
        gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT(combo),
 | 
			
		||||
                                        renderer, "text", 0, NULL);
 | 
			
		||||
        gtk_box_pack_end (GTK_BOX (vbox), combo, FALSE, FALSE, 0);
 | 
			
		||||
        g_signal_connect (combo, "changed", G_CALLBACK(on_layout_changed),
 | 
			
		||||
                          eekboard);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    gtk_container_add (GTK_CONTAINER(vbox), widget);
 | 
			
		||||
    gtk_container_add (GTK_CONTAINER(window), vbox);
 | 
			
		||||
@ -1038,6 +1628,73 @@ main (int argc, char *argv[])
 | 
			
		||||
    gtk_widget_show_all (window);
 | 
			
		||||
    gtk_widget_set_size_request (widget, -1, -1);
 | 
			
		||||
 | 
			
		||||
    notify_init ("eekboard");
 | 
			
		||||
    eekboard->window = window;
 | 
			
		||||
    eekboard->gconfc = gconfc;
 | 
			
		||||
    if (eekboard->accessibility_enabled) {
 | 
			
		||||
        if (!opt_standalone) {
 | 
			
		||||
            NotifyNotification *notification;
 | 
			
		||||
 | 
			
		||||
            error = NULL;
 | 
			
		||||
            if (!gconf_client_get_bool (eekboard->gconfc,
 | 
			
		||||
                                        "/apps/eekboard/inhibit-startup-notify",
 | 
			
		||||
                                        &error)) {
 | 
			
		||||
                notification = notify_notification_new
 | 
			
		||||
                    ("eekboard started in background",
 | 
			
		||||
                     "As GNOME accessibility support enabled, "
 | 
			
		||||
                     "eekboard is starting without a window.\n"
 | 
			
		||||
                     "To make eekboard show up, click on some window with "
 | 
			
		||||
                     "an editable widget.",
 | 
			
		||||
                     "keyboard"
 | 
			
		||||
#if NEED_LIBNOTIFY_ATTACH_WORKAROUND
 | 
			
		||||
                     , NULL
 | 
			
		||||
#endif
 | 
			
		||||
                     );
 | 
			
		||||
                notify_notification_add_action
 | 
			
		||||
                    (notification,
 | 
			
		||||
                     "dont-ask",
 | 
			
		||||
                     "Don't show up",
 | 
			
		||||
                     NOTIFY_ACTION_CALLBACK(on_notify_never_show),
 | 
			
		||||
                     eekboard,
 | 
			
		||||
                     NULL);
 | 
			
		||||
                error = NULL;
 | 
			
		||||
                notify_notification_show (notification, &error);
 | 
			
		||||
            }
 | 
			
		||||
 
 | 
			
		||||
            gtk_widget_hide (window);
 | 
			
		||||
 | 
			
		||||
            focusListener =
 | 
			
		||||
                SPI_createAccessibleEventListener (a11y_focus_listener,
 | 
			
		||||
                                                   eekboard);
 | 
			
		||||
            SPI_registerGlobalEventListener (focusListener,
 | 
			
		||||
                                             "object:state-changed:focused");
 | 
			
		||||
            SPI_registerGlobalEventListener (focusListener,
 | 
			
		||||
                                             "focus:");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /* monitor key events */
 | 
			
		||||
        if (!keystrokeListener) {
 | 
			
		||||
            keystrokeListener =
 | 
			
		||||
                SPI_createAccessibleKeystrokeListener (a11y_keystroke_listener,
 | 
			
		||||
                                                       eekboard);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!SPI_registerAccessibleKeystrokeListener
 | 
			
		||||
            (keystrokeListener,
 | 
			
		||||
             SPI_KEYSET_ALL_KEYS,
 | 
			
		||||
             0,
 | 
			
		||||
             SPI_KEY_PRESSED |
 | 
			
		||||
             SPI_KEY_RELEASED,
 | 
			
		||||
             SPI_KEYLISTENER_NOSYNC))
 | 
			
		||||
            g_warning ("failed to register keystroke listener");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL);
 | 
			
		||||
 | 
			
		||||
    if (combo)
 | 
			
		||||
        gtk_combo_box_set_active (GTK_COMBO_BOX(combo), 0);
 | 
			
		||||
 | 
			
		||||
    gtk_quit_add (0, on_quit, eekboard);
 | 
			
		||||
    gtk_main ();
 | 
			
		||||
 | 
			
		||||
    return 0;
 | 
			
		||||
 | 
			
		||||
@ -16,7 +16,7 @@
 | 
			
		||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
			
		||||
# 02110-1301 USA
 | 
			
		||||
 | 
			
		||||
INCLUDES = -I$(top_srcdir) $(GOBJECT2_CFLAGS) $(GTK2_CFLAGS) $(XKB_CFLAGS)
 | 
			
		||||
INCLUDES = -I$(top_srcdir) $(GOBJECT2_CFLAGS) $(GTK_CFLAGS) $(XKB_CFLAGS)
 | 
			
		||||
 | 
			
		||||
TESTS = eek-simple-test eek-xkb-test
 | 
			
		||||
noinst_PROGRAMS = $(TESTS)
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@
 | 
			
		||||
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
			
		||||
 * 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
#include "eek.h"
 | 
			
		||||
#include "eek/eek.h"
 | 
			
		||||
 | 
			
		||||
static void
 | 
			
		||||
test_create (void)
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@
 | 
			
		||||
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
			
		||||
 * 02110-1301 USA
 | 
			
		||||
 */
 | 
			
		||||
#include "eek-xkb.h"
 | 
			
		||||
#include "eek/eek-xkb.h"
 | 
			
		||||
 | 
			
		||||
/* For gdk_x11_display_get_xdisplay().  See main(). */
 | 
			
		||||
#include <gtk/gtk.h>
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user