[caribou: 12/22] libcaribou: Ported XKB helper to Vala.



commit f72b4505ac6a46e03b106ea0b294e4fb2b67f535
Author: Eitan Isaacson <eitan monotonous org>
Date:   Tue Apr 26 15:28:40 2011 -0700

    libcaribou: Ported XKB helper to Vala.

 .gitignore                            |    6 +
 configure.ac                          |    5 +-
 libcaribou/Makefile.am                |  111 ++++------
 libcaribou/caribou-marshal.list       |    2 -
 libcaribou/caribou-virtual-keyboard.c |  392 ---------------------------------
 libcaribou/caribou-virtual-keyboard.h |   59 -----
 libcaribou/caribou.h                  |   19 --
 libcaribou/external-libs.vapi         |  234 ++++++++++++++++++++
 libcaribou/libxklavier.vapi           |  182 +++++++++++++++
 libcaribou/xadapter.vala              |  213 ++++++++++++++++++
 10 files changed, 678 insertions(+), 545 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index f770bfb..cb3be79 100644
--- a/.gitignore
+++ b/.gitignore
@@ -36,5 +36,11 @@ libcaribou/.libs/
 libcaribou/Caribou-1.0.gir
 libcaribou/Caribou-1.0.typelib
 *.lo
+*.o
 libcaribou/libcaribou.la
+libcaribou/*.[ch]
+caribou-1.0.vapi
+caribou-internals-1.0.vapi
+caribou-internals.h
+*.stamp
 
diff --git a/configure.ac b/configure.ac
index d41d3e3..7cdd299 100644
--- a/configure.ac
+++ b/configure.ac
@@ -14,7 +14,6 @@ AM_MAINTAINER_MODE([enable])
 # to configure or passing V=1 to make
 AM_SILENT_RULES([yes])
 
-
 AM_PATH_GLIB_2_0(2.27.5,,,gobject)
 if test "$GLIB_LIBS" = ""; then
    AC_MSG_ERROR(GLIB 2.27.5 or later is required to build libcaribou)
@@ -37,6 +36,10 @@ PKG_CHECK_MODULES(CARIBOU, [
 AC_SUBST(CARIBOU_CFLAGS)
 AC_SUBST(CARIBOU_LIBS)
 
+AM_PROG_VALAC([0.9.3])
+AC_SUBST(VALAC)
+AC_SUBST(VALAFLAGS)
+
 PKG_CHECK_MODULES(LIBCARIBOU, [
   gdk-3.0 >= $GDK_REQUIRED,
   xtst,
diff --git a/libcaribou/Makefile.am b/libcaribou/Makefile.am
index c7f7a0a..ca2b6b7 100644
--- a/libcaribou/Makefile.am
+++ b/libcaribou/Makefile.am
@@ -1,93 +1,60 @@
-INCLUDES =                              \
-        -DG_LOG_DOMAIN=\"libcaribou\"   \
-        -I$(top_srcdir)                 \
-        $(LIBCARIBOU_CFLAGS)
-
-
-MARSHAL_GENERATED = caribou-marshal.c caribou-marshal.h
-MKENUMS_GENERATED = caribou-enum-types.c caribou-enum-types.h
-
-caribou-marshal.h: caribou-marshal.list
-	$(AM_V_GEN) ( $(GLIB_GENMARSHAL) --prefix=caribou_marshal $(srcdir)/caribou-marshal.list --header > caribou-marshal.tmp \
-	&& mv caribou-marshal.tmp caribou-marshal.h ) \
-	|| ( rm -f caribou-marshal.tmp && exit 1 )
-
-caribou-marshal.c: caribou-marshal.h
-	$(AM_V_GEN) ( (echo '#include "caribou-marshal.h"'; $(GLIB_GENMARSHAL) --prefix=caribou_marshal $(srcdir)/caribou-marshal.list --body) > caribou-marshal.tmp \
-	&& mv caribou-marshal.tmp caribou-marshal.c ) \
-	|| ( rm -f caribou-marshal.tmp && exit 1 )
-
-caribou-enum-types.h: $(caribou_headers)
-	$(AM_V_GEN) ( cd $(srcdir) && $(GLIB_MKENUMS) --template caribou-enum-types.h.tmpl \
-		$(caribou_headers) ) > caribou-enum-types.h.tmp \
-	&& mv caribou-enum-types.h.tmp caribou-enum-types.h \
-	|| rm -f caribou-enum-type.h.tmp
+lib_LTLIBRARIES = libcaribou.la
 
-caribou-enum-types.c: $(libcaribouinclude_HEADERS)
-	$(AM_V_GEN) ( cd $(srcdir) && $(GLIB_MKENUMS) --template caribou-enum-types.c.tmpl \
-		$(caribou_headers) ) > caribou-enum-types.c.tmp \
-	&& mv caribou-enum-types.c.tmp caribou-enum-types.c \
-	|| rm -f caribou-enum-type.c.tmp
+INCLUDES = \
+	-DG_LOG_DOMAIN=\"caribou\" \
+	-I$(top_srcdir) \
+	$(LIBCARIBOU_CFLAGS)
 
-BUILT_SOURCES = $(MARSHAL_GENERATED) $(MKENUMS_GENERATED)
+libcaribou_la_VALAFLAGS = \
+	-H caribou.h --vapi caribou-1.0.vapi \
+	-h caribou-internals.h \
+	--vapidir=. \
+	--pkg x11 --pkg libxklavier --pkg external-libs --pkg gdk-3.0 --pkg gdk-x11-3.0 \
+	--internal-vapi caribou-internals-1.0.vapi \
+	--library caribou-1.0 --gir Caribou-1.0.gir \
+	$(VALAFLAGS)
 
-CLEANFILES = $(MARSHAL_GENERATED) $(MKENUMS_GENERATED)
+libcaribou_la_CPPFLAGS = \
+	$(INCLUDES)
 
 libcaribouincludedir = $(includedir)/libcaribou
 
-caribou_headers =		  \
-	caribou.h		      \
-	caribou-virtual-keyboard.h
-
-libcaribouinclude_HEADERS =	\
-	$(caribou_headers)	 \
-	caribou-enum-types.h
+caribouinclude_headers = \
+	caribou.h
 
-lib_LTLIBRARIES = libcaribou.la
+libcaribouinclude_HEADERS = \
+	$(caribou_headers)
 
 libcaribou_la_LIBADD = \
 	$(LIBCARIBOU_LIBS)
 
-libcaribou_la_SOURCES =		\
-	$(BUILT_SOURCES)	    \
-	caribou-virtual-keyboard.c
+libcaribou_la_SOURCES = \
+	xadapter.vala
+
+EXTRA_DIST = \
+	external-libs.vapi \
+	libxklavier.vapi
 
 #
 # Introspection support
 #
-include $(INTROSPECTION_MAKEFILE)
-INTROSPECTION_GIRS =
-INTROSPECTION_SCANNER_ARGS = --add-include-path=.
-INTROSPECTION_COMPILER_ARGS = --includedir=.
 
 if HAVE_INTROSPECTION
-
-gi_caribou_files = \
-	$(filter-out caribou.h caribou-enum-types.% caribou-marshal.h,\
-	   $(caribou_headers) $(filter-out %.h, $(libcaribou_la_SOURCES)))
-# gi_built_caribou_files = caribou-enum-types.h
-
-Caribou-1.0.gir: libcaribou.la
-Caribou_1_0_gir_INCLUDES = Gdk-3.0
-Caribou_1_0_gir_CFLAGS = $(INCLUDES)
-Caribou_1_0_gir_LIBS = libcaribou.la
-Caribou_1_0_gir_EXPORT_PACKAGES = libcaribou
-Caribou_1_0_gir_SCANNERFLAGS = --c-include "libcaribou/caribou.h"
-Caribou_1_0_gir_FILES = \
-	$(addprefix $(srcdir)/, $(gi_caribou_files)) \
-	$(foreach f,$(gi_built_caribou_files), \
-	   $(if $(shell test -f $(addprefix $(srcdir)/,$(f)) && echo yes), \
-	      $(addprefix $(srcdir)/,$(f)), \
-	      $(f)))
-
-INTROSPECTION_GIRS += Caribou-1.0.gir
-
 girdir = $(datadir)/gir-1.0
-gir_DATA = $(INTROSPECTION_GIRS)
+gir_DATA = Caribou-1.0.gir
+
+typelibdir = $(libdir)/girepository-1.0
+typelib_DATA = Caribou-1.0.typelib
 
-typelibsdir = $(libdir)/girepository-1.0
-typelibs_DATA = $(INTROSPECTION_GIRS:.gir=.typelib)
+Caribou-1.0.typelib: Caribou-1.0.gir
+	@INTROSPECTION_COMPILER@ --shared-library=libcaribou -o $@ $^
+endif
 
-CLEANFILES += $(gir_DATA) $(typelibs_DATA)
+Caribou-1.0.gir caribou-internals-1.0.vapi caribou-1.0.vapi: libcaribou.la
 
-endif
\ No newline at end of file
+CLEANFILES = \
+	caribou-1.0.vapi \
+	caribou-internals-1.0.vapi \
+	Caribou-1.0.typelib \
+	Caribou-1.0.gir \
+	*.[ch]
\ No newline at end of file
diff --git a/libcaribou/external-libs.vapi b/libcaribou/external-libs.vapi
new file mode 100644
index 0000000..6a87d33
--- /dev/null
+++ b/libcaribou/external-libs.vapi
@@ -0,0 +1,234 @@
+using X;
+
+[CCode (cprefix = "", lower_case_cprefix = "",
+        cheader_filename = "X11/extensions/XTest.h")]
+namespace XTest {
+    [CCode (cname = "XTestFakeKeyEvent")]
+    public int fake_key_event (Display dpy, uchar keycode, bool key_press,
+                               ulong delay);
+}
+
+[CCode (cprefix = "", lower_case_cprefix = "", cheader_filename = "X11/Xlib.h")]
+namespace X {
+    [CCode (cname = "XKeycodeToKeysym")]
+    public int keycode_to_keysym (Display dpy, uchar keycode, int index);
+
+}
+
+[CCode (cprefix = "", lower_case_cprefix = "", cheader_filename = "X11/XKBlib.h")]
+namespace Xkb {
+
+    [CCode (cname = "XkbGetKeyboard")]
+    public Desc get_keyboard (X.Display dpy, uint which, uint device_spec);
+
+    [CCode (cname = "XkbSetMap")]
+    public void set_map (X.Display dpy, uint which, Desc xkb);
+
+    [CCode (cname = "XkbFreeKeyboard")]
+    public void free_keyboard (Desc xkb, uint which, bool free_all);
+
+    [CCode (cname = "XkbGetState")]
+    public void get_state (X.Display dpy, uint device_spec, out State state);
+
+    [CCode (cname = "XkbSelectEvents")]
+    public void select_events (X.Display dpy, uint device_spec, ulong bits_to_change,
+        ulong values_for_bits);
+
+    [CCode (cname = "XkbLatchModifiers")]
+    public void latch_modifiers (X.Display dpy, uint device_spec, uint affect,
+                                 uint values);
+
+    [Compact]
+    [CCode (cname = "XkbAnyEvent", free_function = "")]
+    public struct AnyEvent {
+        int xkb_type;
+    }
+
+    [Compact]
+    [CCode (cname = "XkbStateNotifyEvent", free_function = "")]
+    public struct StateNotifyEvent {
+        uint changed;
+        int group;
+        uint mods;
+    }
+
+    [Compact]
+    [CCode (cname = "XkbEvent", free_function = "")]
+    public struct Event {
+        int type;
+        AnyEvent any;
+        StateNotifyEvent state;
+    }
+
+    [Compact]
+    [CCode (cname = "XkbStateRec", free_function = "")]
+    public struct State {
+        uchar   group;
+        uchar   locked_group;
+        ushort  base_group;
+        ushort  latched_group;
+        uchar   mods;
+        uchar   base_mods;
+        uchar   latched_mods;
+        uchar   locked_mods;
+        uchar   compat_state;
+        uchar   grab_mods;
+        uchar   compat_grab_mods;
+        uchar   lookup_mods;
+        uchar   compat_lookup_mods;
+        ushort  ptr_buttons;
+    }
+
+    [Compact]
+    [CCode (cname = "XkbDescRec", free_function = "")]
+    public class Desc {
+        public X.Display dpy;
+        public ushort flags;
+        public ushort device_spec;
+        public char min_key_code;
+        public char max_key_code;   
+        public Controls          ctrls;
+        public ServerMap         server;
+        public ClientMap         map;
+        public Indicator         indicators;
+        public Names             names;
+        public CompatMap         compat;
+        public Geometry          geom;
+    }
+
+    [Compact]
+    [CCode (cname = "XkbControlsRec", free_function = "")]
+    public class Controls {
+    }
+
+    [Compact]
+    [CCode (cname = "XkbServerMapRec", free_function = "")]
+    public class ServerMap {
+    }
+
+    [Compact]
+    [CCode (cname = "XkbKeyTypeRec", free_function = "")]
+    public struct KeyType {
+    }
+
+    [CCode (cname = "XkbSymMapRec", free_function = "")]
+    public struct SymMap {
+        uchar    kt_index[4];
+        uchar    group_info;
+        uchar    width;
+        ushort   offset;
+    }
+
+    [Compact]
+    [CCode (cname = "XkbClientMapRec", free_function = "")]
+    public class ClientMap {
+        public uchar            size_types;
+        public uchar            num_types;
+        public KeyType[]        types;
+
+        public ushort           size_syms;
+        public ushort           num_syms;
+        public uint[]           syms;
+        public SymMap[]         key_sym_map;
+
+        public uchar[]          modmap;
+    }
+
+    [Compact]
+    [CCode (cname = "XkbIndicatorRec", free_function = "")]
+    public class Indicator {
+    }
+
+    [Compact]
+    [CCode (cname = "XkbNamesRec", free_function = "")]
+    public class Names {
+    }
+
+    [Compact]
+    [CCode (cname = "XkbCompatMapRec", free_function = "")]
+    public class CompatMap {
+    }
+
+    [Compact]
+    [CCode (cname = "XkbGeometryRec", free_function = "")]
+    public class Geometry {
+    }
+
+    [CCode (cname = "XkbUseCoreKbd")]
+    public int UseCoreKbd;
+    [CCode (cname = "XkbUseCorePtr")]
+    public int UseCorePtr;
+    [CCode (cname = "XkbDfltXIClass")]
+    public int DfltXIClass;
+    [CCode (cname = "XkbDfltXIId")]
+    public int DfltXIId;
+    [CCode (cname = "XkbAllXIClasses")]
+    public int AllXIClasses;
+    [CCode (cname = "XkbAllXIIds")]
+    public int AllXIIds;
+    [CCode (cname = "XkbXINone")]
+    public int XINone;
+
+    [CCode (cname = "XkbGBN_TypesMask")]
+    public int GBN_TypesMask;
+    [CCode (cname = "XkbGBN_CompatMapMask")]
+    public int GBN_CompatMapMask;
+    [CCode (cname = "XkbGBN_ClientSymbolsMask")]
+    public int GBN_ClientSymbolsMask;
+    [CCode (cname = "XkbGBN_ServerSymbolsMask")]
+    public int GBN_ServerSymbolsMask;
+    [CCode (cname = "XkbGBN_SymbolsMask")]
+    public int GBN_SymbolsMask;
+    [CCode (cname = "XkbGBN_IndicatorMapMask")]
+    public int GBN_IndicatorMapMask;
+    [CCode (cname = "XkbGBN_KeyNamesMask")]
+    public int GBN_KeyNamesMask;
+    [CCode (cname = "XkbGBN_GeometryMask")]
+    public int GBN_GeometryMask;
+    [CCode (cname = "XkbGBN_OtherNamesMask")]
+    public int GBN_OtherNamesMask;
+    [CCode (cname = "XkbGBN_AllComponentsMask")]
+    public int GBN_AllComponentsMask;
+
+    [CCode (cname = "XkbOneLevelIndex")]
+    public int OneLevelIndex;
+
+    [CCode (cname = "XkbNewKeyboardNotifyMask")]
+    public int NewKeyboardNotifyMask;
+    [CCode (cname = "XkbMapNotifyMask")]
+    public int MapNotifyMask;
+    [CCode (cname = "XkbStateNotifyMask")]
+    public int StateNotifyMask;
+    [CCode (cname = "XkbControlsNotifyMask")]
+    public int ControlsNotifyMask;
+    [CCode (cname = "XkbIndicatorStateNotifyMask")]
+    public int IndicatorStateNotifyMask;
+    [CCode (cname = "XkbIndicatorMapNotifyMask")]
+    public int IndicatorMapNotifyMask;
+    [CCode (cname = "XkbNamesNotifyMask")]
+    public int NamesNotifyMask;
+    [CCode (cname = "XkbCompatMapNotifyMask")]
+    public int CompatMapNotifyMask;
+    [CCode (cname = "XkbBellNotifyMask")]
+    public int BellNotifyMask;
+    [CCode (cname = "XkbActionMessageMask")]
+    public int ActionMessageMask;
+    [CCode (cname = "XkbAccessXNotifyMask")]
+    public int AccessXNotifyMask;
+    [CCode (cname = "XkbExtensionDeviceNotifyMask")]
+    public int ExtensionDeviceNotifyMask;
+    [CCode (cname = "XkbAllEventsMask")]
+    public int AllEventsMask;
+
+   [CCode (cname = "XkbStateNotify")]
+    public int StateNotify;
+
+   [CCode (cname = "XkbGroupStateMask")]
+    public int GroupStateMask;
+
+   [CCode (cname = "XkbModifierStateMask")]
+    public int ModifierStateMask;
+
+  [CCode (cname = "XkbAllMapComponentsMask")]
+    public int AllMapComponentsMask;
+}
\ No newline at end of file
diff --git a/libcaribou/libxklavier.vapi b/libcaribou/libxklavier.vapi
new file mode 100644
index 0000000..7d31572
--- /dev/null
+++ b/libcaribou/libxklavier.vapi
@@ -0,0 +1,182 @@
+/* libxklavier.vapi generated by vapigen, do not modify. */
+
+[CCode (cprefix = "Xkl", lower_case_cprefix = "xkl_")]
+namespace Xkl {
+	[CCode (cheader_filename = "libxklavier/xklavier.h")]
+	public class ConfigItem : GLib.Object {
+		[CCode (array_length = false)]
+		public weak char[] description;
+		[CCode (array_length = false)]
+		public weak char[] name;
+		[CCode (array_length = false)]
+		public weak char[] short_description;
+		[CCode (has_construct_function = false)]
+		public ConfigItem ();
+	}
+	[CCode (cheader_filename = "libxklavier/xklavier.h")]
+	public class ConfigRec : GLib.Object {
+		public string[] layouts;
+		public weak string model;
+		public string[] options;
+		public string[] variants;
+		[CCode (has_construct_function = false)]
+		public ConfigRec ();
+		public bool activate (Xkl.Engine engine);
+		public bool equals (Xkl.ConfigRec data2);
+		public bool get_from_backup (Xkl.Engine engine);
+		public bool get_from_root_window_property (X.Atom rules_atom_name, string rules_file_out, Xkl.Engine engine);
+		public bool get_from_server (Xkl.Engine engine);
+		public void reset ();
+		public bool set_to_root_window_property (X.Atom rules_atom_name, string rules_file, Xkl.Engine engine);
+		public static bool write_to_file (Xkl.Engine engine, string file_name, Xkl.ConfigRec data, bool binary);
+	}
+	[CCode (cheader_filename = "libxklavier/xklavier.h")]
+	public class ConfigRegistry : GLib.Object {
+		[CCode (has_construct_function = false)]
+		protected ConfigRegistry ();
+		public bool find_layout (Xkl.ConfigItem item);
+		public bool find_model (Xkl.ConfigItem item);
+		public bool find_option (string option_group_name, Xkl.ConfigItem item);
+		public bool find_option_group (Xkl.ConfigItem item);
+		public bool find_variant (string layout_name, Xkl.ConfigItem item);
+		public void foreach_country (Xkl.ConfigItemProcessFunc func, void* data);
+		public void foreach_country_variant (string country_code, Xkl.TwoConfigItemsProcessFunc func, void* data);
+		public void foreach_language (Xkl.ConfigItemProcessFunc func, void* data);
+		public void foreach_language_variant (string language_code, Xkl.TwoConfigItemsProcessFunc func, void* data);
+		public void foreach_layout (Xkl.ConfigItemProcessFunc func, void* data);
+		public void foreach_layout_variant (string layout_name, Xkl.ConfigItemProcessFunc func, void* data);
+		public void foreach_model (Xkl.ConfigItemProcessFunc func, void* data);
+		public void foreach_option (string option_group_name, Xkl.ConfigItemProcessFunc func, void* data);
+		public void foreach_option_group (Xkl.ConfigItemProcessFunc func, void* data);
+		public static unowned Xkl.ConfigRegistry get_instance (Xkl.Engine engine);
+		public bool load (bool if_extras_needed);
+		public void search_by_pattern (string pattern, Xkl.TwoConfigItemsProcessFunc func, void* data);
+		[NoAccessorMethod]
+		public Xkl.Engine engine { owned get; construct; }
+	}
+	[CCode (cheader_filename = "libxklavier/xklavier.h")]
+	public class Engine : GLib.Object {
+		[CCode (has_construct_function = false)]
+		protected Engine ();
+		public static void INT__LONG_LONG (GLib.Closure closure, GLib.Value return_value, uint n_param_values, GLib.Value param_values, void* invocation_hint, void* marshal_data);
+		public static void VOID__FLAGS_INT_BOOLEAN (GLib.Closure closure, GLib.Value return_value, uint n_param_values, GLib.Value param_values, void* invocation_hint, void* marshal_data);
+		public void allow_one_switch_to_secondary_group ();
+		public bool backup_names_prop ();
+		[NoWrapper]
+		public virtual void config_notify ();
+		public void delete_state (X.Window win);
+		public int filter_events (X.Event evt);
+		public unowned string get_backend_name ();
+		public unowned Xkl.State get_current_state ();
+		public X.Window get_current_window ();
+		public int get_current_window_group ();
+		public int get_default_group ();
+		public uint get_features ();
+		public unowned string get_groups_names ();
+		public bool get_indicators_handling ();
+		public unowned string get_indicators_names ();
+		public static unowned Xkl.Engine get_instance (X.Display display);
+		public uint get_max_num_groups ();
+		public int get_next_group ();
+		public uint get_num_groups ();
+		public int get_prev_group ();
+		public uint get_secondary_groups_mask ();
+		public bool get_state (X.Window win, Xkl.State state_out);
+		public unowned string get_window_title (X.Window win);
+		public bool grab_key (int keycode, uint modifiers);
+		public bool is_group_per_toplevel_window ();
+		public bool is_window_from_same_toplevel_window (X.Window win1, X.Window win2);
+		public bool is_window_transparent (X.Window win);
+		public void lock_group (int group);
+		public int pause_listen ();
+		public int resume_listen ();
+		public void save_state (X.Window win, Xkl.State state);
+		public void set_default_group (int group);
+		public void set_group_per_toplevel_window (bool is_global);
+		public void set_indicators_handling (bool whether_handle);
+		public void set_secondary_groups_mask (uint mask);
+		public void set_window_transparent (X.Window win, bool transparent);
+		public int start_listen (uint flags);
+		[NoWrapper]
+		public virtual void state_notify (Xkl.EngineStateChange change_type, int group, bool restore);
+		public int stop_listen (uint flags);
+		public bool ungrab_key (int keycode, uint modifiers);
+		[NoAccessorMethod]
+		public string backendName { owned get; }
+		public uint default_group { get; }
+		[NoAccessorMethod]
+		public void* display { get; construct; }
+		public Xkl.EngineFeatures features { get; }
+		public bool indicators_handling { get; }
+		public uint max_num_groups { get; }
+		public uint num_groups { get; }
+		public uint secondary_groups_mask { get; }
+		public virtual signal void X_config_changed ();
+		public virtual signal void X_new_device ();
+		public virtual signal void X_state_changed (int p0, int p1, bool p2);
+		public virtual signal int new_toplevel_window (long p0, long p1);
+	}
+	[Compact]
+	[CCode (cheader_filename = "libxklavier/xklavier.h")]
+	public class State {
+		public int32 group;
+		public uint32 indicators;
+	}
+	[CCode (cprefix = "XKLF_", cheader_filename = "libxklavier/xklavier.h")]
+	[Flags]
+	public enum EngineFeatures {
+		CAN_TOGGLE_INDICATORS,
+		CAN_OUTPUT_CONFIG_AS_ASCII,
+		CAN_OUTPUT_CONFIG_AS_BINARY,
+		MULTIPLE_LAYOUTS_SUPPORTED,
+		REQUIRES_MANUAL_LAYOUT_MANAGEMENT,
+		DEVICE_DISCOVERY
+	}
+	[CCode (cprefix = "XKLL_", cheader_filename = "libxklavier/xklavier.h")]
+	public enum EngineListenModes {
+		MANAGE_WINDOW_STATES,
+		TRACK_KEYBOARD_STATE,
+		MANAGE_LAYOUTS
+	}
+	[CCode (cprefix = "", cheader_filename = "libxklavier/xklavier.h")]
+	public enum EngineStateChange {
+		GROUP_CHANGED,
+		INDICATORS_CHANGED
+	}
+	[CCode (cheader_filename = "libxklavier/xklavier.h")]
+	public delegate void ConfigItemProcessFunc (Xkl.ConfigRegistry config, Xkl.ConfigItem item);
+	[CCode (cheader_filename = "libxklavier/xklavier.h", has_target = false)]
+	public delegate void LogAppender (char[] file, char[] function, int level, char[] format, void* args);
+	[CCode (cheader_filename = "libxklavier/xklavier.h")]
+	public delegate void TwoConfigItemsProcessFunc (Xkl.ConfigRegistry config, Xkl.ConfigItem item, Xkl.ConfigItem subitem);
+	[CCode (cheader_filename = "libxklavier/xklavier.h")]
+	public const int MAX_CI_DESC_LENGTH;
+	[CCode (cheader_filename = "libxklavier/xklavier.h")]
+	public const int MAX_CI_NAME_LENGTH;
+	[CCode (cheader_filename = "libxklavier/xklavier.h")]
+	public const int MAX_CI_SHORT_DESC_LENGTH;
+	[CCode (cheader_filename = "libxklavier/xklavier.h")]
+	public const string XCI_PROP_ALLOW_MULTIPLE_SELECTION;
+	[CCode (cheader_filename = "libxklavier/xklavier.h")]
+	public const string XCI_PROP_COUNTRY_LIST;
+	[CCode (cheader_filename = "libxklavier/xklavier.h")]
+	public const string XCI_PROP_EXTRA_ITEM;
+	[CCode (cheader_filename = "libxklavier/xklavier.h")]
+	public const string XCI_PROP_LANGUAGE_LIST;
+	[CCode (cheader_filename = "libxklavier/xklavier.h")]
+	public const string XCI_PROP_VENDOR;
+	[CCode (cheader_filename = "libxklavier/xklavier.h")]
+	public static void default_log_appender (char[] file, char[] function, int level, char[] format, void* args);
+	[CCode (cheader_filename = "libxklavier/xklavier.h")]
+	public static unowned string get_country_name (string code);
+	[CCode (cheader_filename = "libxklavier/xklavier.h")]
+	public static unowned string get_language_name (string code);
+	[CCode (cheader_filename = "libxklavier/xklavier.h")]
+	public static unowned string get_last_error ();
+	[CCode (cheader_filename = "libxklavier/xklavier.h")]
+	public static bool restore_names_prop (Xkl.Engine engine);
+	[CCode (cheader_filename = "libxklavier/xklavier.h")]
+	public static void set_debug_level (int level);
+	[CCode (cheader_filename = "libxklavier/xklavier.h")]
+	public static void set_log_appender (Xkl.LogAppender fun);
+}
diff --git a/libcaribou/xadapter.vala b/libcaribou/xadapter.vala
new file mode 100644
index 0000000..d240f08
--- /dev/null
+++ b/libcaribou/xadapter.vala
@@ -0,0 +1,213 @@
+using Xkl;
+using Gdk;
+using Xkb;
+using XTest;
+using X;
+
+namespace Caribou {
+    public class XAdapter : Object {
+
+        /* Signals */
+        public signal void modifiers_changed (uint modifiers);
+        public signal void group_changed (uint gid, string group, string variant);
+
+        /* Private properties */
+        private static XAdapter instance;
+        X.Display xdisplay;
+        Xkb.Desc xkbdesc;
+        Xkl.Engine xkl_engine;
+        uint reserved_keysym;
+        uchar reserved_keycode;
+        uchar modifiers;
+        uchar group;
+
+        construct {
+            Xkb.State state;
+
+            this.xdisplay = new X.Display ();
+            this.xkbdesc = Xkb.get_keyboard (this.xdisplay,
+                                             Xkb.GBN_AllComponentsMask,
+                                             Xkb.UseCoreKbd);
+            this.xkl_engine = Xkl.Engine.get_instance (this.xdisplay);
+
+            Xkb.get_state (this.xdisplay, Xkb.UseCoreKbd, out state);
+
+            this.group = state.group;
+            this.modifiers = state.mods;
+
+            this.reserved_keycode = 0;
+
+            Xkb.select_events (
+                this.xdisplay, Xkb.UseCoreKbd,
+                Xkb.StateNotifyMask | Xkb.AccessXNotifyMask,
+                Xkb.StateNotifyMask | Xkb.AccessXNotifyMask);
+
+            ((Gdk.Window) null).add_filter (x_event_filter); // Did I blow your mind?
+        }
+
+        ~XAdapter () {
+            Xkb.free_keyboard(this.xkbdesc, Xkb.GBN_AllComponentsMask, true);
+        }
+
+        public static XAdapter get_default() {
+            if (instance == null)
+                instance = new XAdapter ();
+            return instance;
+        }
+
+        private Gdk.FilterReturn x_event_filter (Gdk.XEvent xevent, Gdk.Event event) {
+            void* pointer = &xevent;
+            Xkb.Event *xev = (Xkb.Event *) pointer;
+                        
+            if (xev.any.xkb_type == Xkb.StateNotify) {
+                Xkb.StateNotifyEvent *sevent = &xev.state;
+                if ((sevent.changed & Xkb.GroupStateMask) != 0) {
+                    Xkl.ConfigRec config_rec = new Xkl.ConfigRec ();
+                    config_rec.get_from_server (this.xkl_engine);
+                    group_changed (sevent.group, config_rec.layouts[sevent.group],
+                        config_rec.variants[sevent.group]);
+                    this.group = (uchar) sevent.group;
+                } else if ((sevent.changed & Xkb.ModifierStateMask) != 0) {
+                    this.modifiers = (uchar) sevent.mods;
+                }
+            }
+
+            return Gdk.FilterReturn.CONTINUE;
+        }
+
+        private uchar get_reserved_keycode () {
+            uchar i;
+            unowned Xkb.Desc xkbdesc = this.xkbdesc;
+
+            for (i = xkbdesc.max_key_code; i >= xkbdesc.min_key_code; --i) {
+                if (xkbdesc.map.key_sym_map[i].kt_index[0] == Xkb.OneLevelIndex) {
+                    if (X.keycode_to_keysym (this.xdisplay, i, 0) != 0) {
+                        Gdk.error_trap_push ();
+                        this.xdisplay.grab_key (i, 0,
+                                    Gdk.x11_get_default_root_xwindow (), true,
+                                    X.GrabMode.Sync, X.GrabMode.Sync);
+                        this.xdisplay.flush ();
+                        this.xdisplay.ungrab_key (
+                            i, 0, Gdk.x11_get_default_root_xwindow ());
+                        if (Gdk.error_trap_pop () == 0)
+                            return i;
+                    }
+                }
+            }
+
+            return (uchar) this.xdisplay.keysym_to_keycode (0x0023); // XK_numbersign
+        }
+
+        private void replace_keycode (uint keysym) {
+            if (this.reserved_keycode == 0) {
+                this.reserved_keycode = get_reserved_keycode ();
+                this.reserved_keysym = X.keycode_to_keysym (this.xdisplay,
+                                                            this.reserved_keycode, 0);
+            }
+
+            this.xdisplay.flush ();
+            uint offset = this.xkbdesc.map.key_sym_map[this.reserved_keycode].offset;
+
+            this.xkbdesc.map.syms[offset] = keysym;
+
+            Xkb.set_map (this.xdisplay, Xkb.AllMapComponentsMask, this.xkbdesc);
+            /**
+             *  FIXME: the use of XkbChangeMap, and the reuse of the priv->xkb_desc
+             *  structure, would be far preferable. HOWEVER it does not seem to work
+             *  using XFree 4.3.
+             **/
+
+            this.xdisplay.flush ();
+
+            if (keysym != this.reserved_keysym)
+                GLib.Timeout.add (500, reset_reserved);
+        }
+
+        private bool reset_reserved () {
+            replace_keycode (this.reserved_keysym);
+            return false;
+        }
+
+        private uchar keycode_for_keyval (uint keyval, out uint modmask) {
+            Gdk.Keymap kmap= Gdk.Keymap.get_default ();
+            Gdk.KeymapKey[] kmk;
+            uchar keycode = 0;
+
+            if (kmap.get_entries_for_keyval (keyval, out kmk)) {
+                Gdk.KeymapKey best_match = kmk[0];
+                foreach (KeymapKey km in kmk)
+                    if (km.group == this.group)
+                        best_match = km;
+                
+                keycode = (uchar) best_match.keycode;
+                modmask = (best_match.level == 1) ? Gdk.ModifierType.SHIFT_MASK : 0;
+            } else {
+                replace_keycode (keyval);
+                keycode = this.reserved_keycode;
+            }
+
+            return keycode;
+        }
+
+        public void keyval_press (uint keyval) {
+            uint mask;
+            uchar keycode = keycode_for_keyval (keyval, out mask);
+
+            if (mask != 0)
+                mod_latch (mask);
+
+            XTest.fake_key_event (this.xdisplay, keycode, true, X.CURRENT_TIME);
+            this.xdisplay.flush ();
+        }
+
+        public void keyval_release (uint keyval) {
+            uchar keycode = keycode_for_keyval (keyval, null);
+            
+            XTest.fake_key_event (this.xdisplay, keycode, false, X.CURRENT_TIME);
+            this.xdisplay.flush ();
+        }
+
+        public void mod_latch (uint mask) {
+            Xkb.latch_modifiers (this.xdisplay, Xkb.UseCoreKbd, mask, mask);
+            this.xdisplay.flush ();
+        }
+
+        public void mod_unlatch (uint mask) {
+            Xkb.latch_modifiers (this.xdisplay, Xkb.UseCoreKbd, mask, 0);
+            this.xdisplay.flush ();
+        }
+
+        public uint get_current_group (out string group_name,
+                                       out string variant_name) {
+            Xkl.ConfigRec config_rec = new Xkl.ConfigRec ();
+            config_rec.get_from_server (this.xkl_engine);
+            group_name = config_rec.layouts[this.group];
+            variant_name = config_rec.variants[this.group];
+
+            return this.group;
+        }
+
+        public void get_groups (out string[] group_names,
+                                out string[] variant_names) {
+            int i;
+            Xkl.ConfigRec config_rec = new Xkl.ConfigRec ();
+            config_rec.get_from_server (this.xkl_engine);
+
+            for (i=0; i<4; i++)
+                if (config_rec.layouts[i] == null)
+                    break;
+
+            group_names = new string[i];
+            variant_names = new string[i];
+
+            for (; i>=0; i--) {
+                group_names[i] = config_rec.layouts[i];
+                variant_names[i] = config_rec.variants[i];
+            }
+        }
+
+        public void me () {
+            stdout.printf("%p\n", this.xkl_engine);
+        }
+    }
+}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]