[caribou] Port daemon from Python to Vala



commit 1b7a0c6c7b855e6204830656a699483898329bc1
Author: Daiki Ueno <ueno unixuser org>
Date:   Mon Nov 12 13:06:06 2012 +0900

    Port daemon from Python to Vala
    
    This eliminates the need of the shell script wrapper.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=688218

 Makefile.am                |    2 +-
 bin/Makefile.am            |    2 +-
 bin/caribou.in             |   41 ---------
 caribou/Makefile.am        |    3 +-
 caribou/daemon/Makefile.am |    7 --
 caribou/daemon/__init__.py |    1 -
 caribou/daemon/main.py     |  123 ---------------------------
 configure.ac               |    8 +-
 daemon/Makefile.am         |   23 +++++
 daemon/daemon.vala         |  196 ++++++++++++++++++++++++++++++++++++++++++++
 10 files changed, 227 insertions(+), 179 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index 07a7a55..c23aab2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,6 +1,6 @@
 ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS}
 
-SUBDIRS = caribou bin data po libcaribou modules tools vapi
+SUBDIRS = caribou bin data po libcaribou modules tools vapi daemon
 
 if HAVE_VALADOC
 SUBDIRS += docs
diff --git a/bin/Makefile.am b/bin/Makefile.am
index b001b10..2b1839a 100644
--- a/bin/Makefile.am
+++ b/bin/Makefile.am
@@ -1,4 +1,4 @@
-bin_SCRIPTS = caribou caribou-preferences
+bin_SCRIPTS = caribou-preferences
 libexec_SCRIPTS = antler-keyboard
 
 DISTCLEANFILES = $(bin_SCRIPTS) $(libexec_SCRIPTS)
diff --git a/caribou/Makefile.am b/caribou/Makefile.am
index cdb7045..2d7fd50 100644
--- a/caribou/Makefile.am
+++ b/caribou/Makefile.am
@@ -6,8 +6,7 @@ caribou_PYTHON = \
 
 SUBDIRS = \
         antler/ \
-        settings/ \
-       daemon/
+        settings/
 
 DISTCLEANFILES = i18n.py
 
diff --git a/configure.ac b/configure.ac
index be48c44..228d094 100644
--- a/configure.ac
+++ b/configure.ac
@@ -32,7 +32,10 @@ VALADOC_REQUIRED=0.3.1
 PKG_CHECK_MODULES(CARIBOU, [
   pygobject-3.0 >= $PYGOBJECT_REQUIRED,
   gtk+-3.0      >= $GTK_REQUIRED,
-  clutter-1.0   >= $CLUTTER_REQUIRED
+  clutter-1.0   >= $CLUTTER_REQUIRED,
+  gdk-3.0       >= $GDK_REQUIRED,
+  x11,
+  atspi-2
   ])
 AC_SUBST(CARIBOU_CFLAGS)
 AC_SUBST(CARIBOU_LIBS)
@@ -132,9 +135,7 @@ caribou/Makefile
 caribou/i18n.py
 caribou/antler/Makefile
 caribou/settings/Makefile
-caribou/daemon/Makefile
 bin/Makefile
-bin/caribou
 bin/caribou-preferences
 bin/antler-keyboard
 data/Makefile
@@ -151,4 +152,5 @@ modules/gtk2/Makefile
 tools/Makefile
 docs/Makefile
 vapi/Makefile
+daemon/Makefile
 ])
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
new file mode 100644
index 0000000..13bca11
--- /dev/null
+++ b/daemon/Makefile.am
@@ -0,0 +1,23 @@
+bin_PROGRAMS = caribou
+
+caribou_VALAFLAGS = \
+       --vapidir=$(top_srcdir)/vapi \
+       --pkg config \
+       --pkg gtk+-3.0 \
+       --pkg gdk-x11-3.0 \
+       --pkg atspi-2 \
+       --pkg x11 \
+       --pkg posix \
+       --pkg libxklavier \
+       $(VALAFLAGS)
+
+caribou_CFLAGS = \
+       $(CARIBOU_CFLAGS) \
+       -DLOCALEDIR=\"$(datadir)/locale\"
+
+caribou_LDADD = \
+       $(CARIBOU_LIBS)
+
+caribou_SOURCES = daemon.vala
+
+-include $(top_srcdir)/git.mk
diff --git a/daemon/daemon.vala b/daemon/daemon.vala
new file mode 100644
index 0000000..2f5feee
--- /dev/null
+++ b/daemon/daemon.vala
@@ -0,0 +1,196 @@
+namespace Caribou {
+    // We can't use the name "Keyboard" here since caribou-gtk-module
+    // might register the name first.
+    [DBus (name = "org.gnome.Caribou.Keyboard")]
+    interface _Keyboard : Object {
+        public abstract void set_cursor_location (int x, int y, int w, int h)
+            throws IOError;
+        public abstract void set_entry_location (int x, int y, int w, int h)
+            throws IOError;
+        public abstract void show (uint32 timestamp) throws IOError;
+        public abstract void hide (uint32 timestamp) throws IOError;
+    }
+
+    class Daemon : Object {
+        _Keyboard keyboard;
+        Atspi.Accessible current_acc;
+        unowned Gdk.Display display;
+
+        public Daemon () {
+            display = Gdk.Display.get_default ();
+        }
+
+        void on_get_proxy_ready (GLib.Object? obj, GLib.AsyncResult res) {
+            try {
+                keyboard = Bus.get_proxy.end (res);
+            } catch (Error e) {
+                error ("%s\n".printf (e.message));
+            }
+
+            try {
+                register_event_listeners ();
+            } catch (Error e) {
+                warning ("can't register event listeners: %s", e.message);
+            }
+        }
+
+        uint32 get_timestamp () {
+            return Gdk.X11Display.get_user_time (display);
+        }
+
+        void set_entry_location (Atspi.Accessible acc) throws Error {
+            var text = acc.get_text ();
+            var rect = text.get_character_extents (text.get_caret_offset (),
+                                                   Atspi.CoordType.SCREEN);
+            var component = acc.get_component ();
+            var entry_rect = component.get_extents (Atspi.CoordType.SCREEN);
+            if (rect.x == 0 && rect.y == 0 &&
+                rect.width == 0 && rect.height == 0) {
+                rect = entry_rect;
+            }
+
+            keyboard.set_cursor_location (rect.x, rect.y,
+                                          rect.width, rect.height);
+
+            keyboard.set_entry_location (entry_rect.x, entry_rect.y,
+                                         entry_rect.width, entry_rect.height);
+
+            keyboard.show (get_timestamp ());
+        }
+
+        void on_focus (owned Atspi.Event event) throws Error {
+            var acc = event.source;
+            var source_role = acc.get_role ();
+            if (acc.get_state_set ().contains (Atspi.StateType.EDITABLE) ||
+                source_role == Atspi.Role.TERMINAL) {
+                switch (source_role) {
+                case Atspi.Role.TEXT:
+                case Atspi.Role.PARAGRAPH:
+                case Atspi.Role.PASSWORD_TEXT:
+                case Atspi.Role.TERMINAL:
+                case Atspi.Role.ENTRY:
+                    if (event.type.has_prefix ("focus") || event.detail1 == 1) {
+                        set_entry_location (acc);
+                        current_acc = event.source;
+                        debug ("enter text widget in %s",
+                               event.source.get_application ().name);
+                    } else if (event.detail1 == 0 && acc == current_acc) {
+                        keyboard.hide (get_timestamp ());
+                        current_acc = null;
+                        debug ("leave text widget in %s",
+                               event.source.get_application ().name);
+                    } else {
+                        warning ("unhandled editable widget: %s",
+                                 event.source.name);
+                    }
+                    break;
+                default:
+                    break;
+                }
+            }
+        }
+
+        void on_focus_ignore_error (owned Atspi.Event event) {
+            try {
+                on_focus (event);
+            } catch (Error e) {
+                warning ("error in focus handler: %s", e.message);
+            }
+        }
+
+        void on_text_caret_moved (owned Atspi.Event event) throws Error {
+            if (current_acc == event.source) {
+                var text = current_acc.get_text ();
+                var rect = text.get_character_extents (text.get_caret_offset (),
+                                                       Atspi.CoordType.SCREEN);
+                if (rect.x == 0 && rect.y == 0 &&
+                    rect.width == 0 && rect.height == 0) {
+                    var component = current_acc.get_component ();
+                    rect = component.get_extents (Atspi.CoordType.SCREEN);
+                }
+
+                keyboard.set_cursor_location (rect.x, rect.y,
+                                              rect.width, rect.height);
+                debug ("object:text-caret-moved in %s: %d %s",
+                       event.source.get_application ().name,
+                       event.detail1, event.source.description);
+            }
+        }
+
+        void on_text_caret_moved_ignore_error (owned Atspi.Event event) {
+            try {
+                on_text_caret_moved (event);
+            } catch (Error e) {
+                warning ("error in text caret movement handler: %s", e.message);
+            }
+        }
+
+        void register_event_listeners () throws Error {
+            Atspi.EventListener.register_from_callback (
+                on_focus_ignore_error, "object:state-changed:focused");
+            Atspi.EventListener.register_from_callback (
+                on_focus_ignore_error, "focus:");
+            Atspi.EventListener.register_from_callback (
+                on_text_caret_moved_ignore_error, "object:text-caret-moved");
+        }
+
+        void deregister_event_listeners () throws Error {
+            Atspi.EventListener.deregister_from_callback (
+                on_focus_ignore_error, "object:state-changed:focused");
+            Atspi.EventListener.deregister_from_callback (
+                on_focus_ignore_error, "focus:");
+            Atspi.EventListener.deregister_from_callback (
+                on_text_caret_moved_ignore_error, "object:text-caret-moved");
+        }
+
+        public void run () {
+            Bus.get_proxy.begin<_Keyboard> (BusType.SESSION,
+                                            "org.gnome.Caribou.Keyboard",
+                                            "/org/gnome/Caribou/Keyboard",
+                                            0,
+                                            null,
+                                            on_get_proxy_ready);
+            Gtk.main ();
+        }
+
+        public void quit () {
+            if (keyboard != null) {
+                try {
+                    keyboard.hide (get_timestamp ());
+                } catch (IOError e) {
+                    warning ("can't hide keyboard: %s", e.message);
+                }
+
+                try {
+                    deregister_event_listeners ();
+                } catch (Error e) {
+                    warning ("can't deregister event listeners: %s", e.message);
+                }
+                keyboard = null;
+            }
+
+            if (Gtk.main_level () > 0)
+                Gtk.main_quit ();
+        }
+    }
+}
+
+static int main (string[] args) {
+    Gtk.init (ref args);
+
+    Intl.setlocale (LocaleCategory.ALL, "");
+    Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Config.LOCALEDIR);
+    Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8");
+    Intl.textdomain (Config.GETTEXT_PACKAGE);
+
+    Atspi.init ();
+
+    var daemon = new Caribou.Daemon ();
+    Unix.signal_add (Posix.SIGINT, () => {
+            daemon.quit ();
+            return false;
+        });
+    daemon.run ();
+
+    return 0;
+}


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