[caribou: 14/22] libcaribou: Implemented CaribouKeyboardModel.



commit 6294dab42aec83a4e9edd314544903a67152b7fb
Author: Eitan Isaacson <eitan monotonous org>
Date:   Wed Apr 27 20:32:35 2011 -0700

    libcaribou: Implemented CaribouKeyboardModel.

 configure.ac                      |    3 +-
 libcaribou/Makefile.am            |   13 +++-
 libcaribou/group-model.vala       |   50 +++++++++++++++
 libcaribou/json-deserializer.vala |  126 +++++++++++++++++++++++++++++++++++++
 libcaribou/key-model.vala         |   71 +++++++++++++++++++++
 libcaribou/keyboard-model.vala    |   49 ++++++++++++++
 libcaribou/keyboard-service.vala  |   35 ++++++++++
 libcaribou/level-model.vala       |   41 ++++++++++++
 libcaribou/row-model.vala         |   22 +++++++
 libcaribou/util.vala              |   13 ++++
 10 files changed, 420 insertions(+), 3 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 7cdd299..8108c43 100644
--- a/configure.ac
+++ b/configure.ac
@@ -44,7 +44,8 @@ PKG_CHECK_MODULES(LIBCARIBOU, [
   gdk-3.0 >= $GDK_REQUIRED,
   xtst,
   x11,
-  libxklavier
+  libxklavier,
+  json-glib-1.0
   ])
 AC_SUBST(LIBCARIBOU_CFLAGS)
 AC_SUBST(LIBCARIBOU_LIBS)
diff --git a/libcaribou/Makefile.am b/libcaribou/Makefile.am
index ca2b6b7..90cc34b 100644
--- a/libcaribou/Makefile.am
+++ b/libcaribou/Makefile.am
@@ -9,7 +9,8 @@ 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 \
+	--pkg x11 --pkg json-glib-1.0 --pkg gdk-3.0 --pkg gio-2.0 \
+	--pkg libxklavier --pkg external-libs  --pkg gdk-x11-3.0 \
 	--internal-vapi caribou-internals-1.0.vapi \
 	--library caribou-1.0 --gir Caribou-1.0.gir \
 	$(VALAFLAGS)
@@ -29,7 +30,15 @@ libcaribou_la_LIBADD = \
 	$(LIBCARIBOU_LIBS)
 
 libcaribou_la_SOURCES = \
-	xadapter.vala
+	xadapter.vala \
+	keyboard-model.vala \
+	keyboard-service.vala \
+	group-model.vala \
+	level-model.vala \
+	row-model.vala \
+	key-model.vala \
+	util.vala \
+	json-deserializer.vala
 
 EXTRA_DIST = \
 	external-libs.vapi \
diff --git a/libcaribou/group-model.vala b/libcaribou/group-model.vala
new file mode 100644
index 0000000..564dbd8
--- /dev/null
+++ b/libcaribou/group-model.vala
@@ -0,0 +1,50 @@
+using GLib;
+
+namespace Caribou {
+    public class GroupModel : GLib.Object {
+        public string active_level { get; private set; }
+
+        public string group;
+        public string variant;
+        private string default_level;
+        private HashTable<string, LevelModel> levels;
+
+        public GroupModel (string group, string variant) {
+            this.group = group;
+            this.variant = variant;
+            levels = new HashTable<string, LevelModel> (str_hash, str_equal);
+            active_level = default_level;
+        }
+
+        public static string create_group_name (string group, string variant) {
+            if (variant != "")
+                return @"$(group)_$(variant)";
+            else
+                return group;
+        }
+
+        public void add_level (string lname, LevelModel level) {
+            levels.insert (lname, level);
+            level.level_toggled.connect(on_level_toggled);
+            if (level.mode == "default") {
+                default_level = lname;
+                active_level = lname;
+            }
+        }
+
+        public string[] get_levels () {
+            return Util.list_to_array (levels.get_keys ());
+        }
+
+        public LevelModel get_level (string level_name) {
+            return levels.lookup(level_name);
+        }
+
+        private void on_level_toggled (string new_level) {
+            if (new_level == "default")
+                active_level = default_level;
+            else
+                active_level = new_level;
+        }
+    }
+}
\ No newline at end of file
diff --git a/libcaribou/json-deserializer.vala b/libcaribou/json-deserializer.vala
new file mode 100644
index 0000000..e136042
--- /dev/null
+++ b/libcaribou/json-deserializer.vala
@@ -0,0 +1,126 @@
+namespace Caribou {
+
+    private class JsonDeserializer : Object {
+
+        public static bool get_layout_file_inner (string data_dir,
+                                                  string group,
+                                                  string variant,
+                                                  out File fp) {
+            string[] files = {@"$(group)_$(variant).json", @"$(group).json"};
+
+            foreach (string fn in files) {
+                string layout_fn = GLib.Path.build_filename (data_dir, fn);
+                fp = GLib.File.new_for_path (layout_fn);
+                if (fp.query_exists ())
+                    return true;
+            }
+
+            return false;
+        }
+
+        public static GLib.File get_layout_file (string group,
+                                                 string variant) throws IOError {
+            Settings caribou_settings = new Settings ("org.gnome.caribou");
+            string kb_type = caribou_settings.get_string("keyboard-type");
+
+            List<string> dirs = new List<string> ();
+            string custom_dir = Environment.get_variable("CARIBOU_LAYOUTS_DIR");
+
+            if (custom_dir != null)
+                dirs.append (Path.build_filename (custom_dir, "layouts", kb_type));
+
+            dirs.append (Path.build_filename (Environment.get_user_data_dir (),
+                                              "caribou", "layouts", kb_type));
+
+            foreach (string data_dir in Environment.get_system_data_dirs ()) {
+                dirs.append (Path.build_filename (
+                                 data_dir, "caribou", "layouts", kb_type));
+            }
+
+            foreach (string data_dir in dirs) {
+                File fp;
+                if (get_layout_file_inner (data_dir, group, variant, out fp))
+                    return fp;
+            }
+
+            throw new IOError.NOT_FOUND (
+                "Could not find layout file for %s %s", group, variant);                       }
+
+        public static void load_group (GroupModel group) {
+            Json.Parser parser = new Json.Parser ();
+
+            try {
+                GLib.File f = get_layout_file (group.group, group.variant);
+                parser.load_from_stream (f.read (), (Cancellable) null);
+                create_levels_from_json (group, parser.get_root ());
+            } catch (GLib.Error e) {
+                stdout.printf ("Failed to load JSON: %s\n", e.message);
+                return;
+            }
+        }
+
+        public static void create_levels_from_json (GroupModel group,
+                                                    Json.Node root) {
+            Json.Object obj = root.get_object ();
+
+            if (root.get_node_type () != Json.NodeType.OBJECT)
+                return;
+
+            foreach (string levelname in obj.get_members ()) {
+                unowned Json.Object json_level = obj.get_object_member (levelname);
+                string mode = "";
+
+                if (json_level.has_member ("mode"))
+                    mode = json_level.get_string_member ("mode");
+
+                Json.Array json_rows = json_level.get_array_member ("rows");
+                LevelModel level = new LevelModel(mode, json_rows.get_length ());
+
+                group.add_level(levelname, level);
+
+                load_rows (level, json_rows);
+            }
+        }
+
+        public static void load_rows (LevelModel level, Json.Array json_rows) {
+            uint i,j;
+
+            for (i=0;i<level.n_rows;i++) {
+                Json.Array json_keys = json_rows.get_array_element (i);
+                uint nkeys = json_keys.get_length ();
+                for (j=0;j<nkeys;j++) {
+                    Json.Object json_key = json_keys.get_object_element (j);
+                    level.add_key (i, load_key (json_key));
+                }
+            }
+
+        }
+
+        public static KeyModel load_key (Json.Object json_key) {
+            KeyModel key = new KeyModel (json_key.get_string_member ("name"));
+
+            if (json_key.has_member ("toggle"))
+                key.toggle = json_key.get_string_member ("toggle");
+
+            if (json_key.has_member ("margin_left"))
+                key.margin_left = json_key.get_double_member ("margin_left");
+
+            if (json_key.has_member ("width"))
+                key.width = json_key.get_double_member ("width");
+
+            if (json_key.has_member ("extended_names")) {
+                Json.Array json_keys = json_key.get_array_member ("extended_names");
+                uint nkeys = json_keys.get_length ();
+                uint i;
+
+                key.add_subkey(key.name);
+
+                for (i=0;i<nkeys;i++)
+                    key.add_subkey(json_keys.get_string_element (i));
+            }
+
+            return key;
+        }
+        
+    }
+}
\ No newline at end of file
diff --git a/libcaribou/key-model.vala b/libcaribou/key-model.vala
new file mode 100644
index 0000000..90f3625
--- /dev/null
+++ b/libcaribou/key-model.vala
@@ -0,0 +1,71 @@
+using GLib;
+
+namespace Caribou {
+    public class KeyModel : GLib.Object {
+        public double margin_left { get; set; default = 0.0; }
+        public double width { get; set; default = 1.0; }
+        public string toggle { get; set; default = ""; }
+
+        public bool show_subkeys { get; private set; default = false; }
+        public string name { get; private set; }
+        public uint keyval { get; private set; }
+
+        private uint hold_tid;
+        private XAdapter xadapter;
+        private List<KeyModel> _extended_keys;
+
+        public signal void key_pressed ();
+        public signal void key_released ();
+        public signal void key_clicked ();
+        public signal void key_hold_end ();
+        public signal void key_hold ();
+
+        public KeyModel (string name) {
+            this.name = name;
+            xadapter = XAdapter.get_default();
+            keyval = Gdk.keyval_from_name (name);
+        }
+
+        public void add_subkey (string name) {
+            KeyModel key = new KeyModel (name);
+            key.key_clicked.connect(on_subkey_clicked);
+            _extended_keys.append (key);
+        }
+
+        private void on_subkey_clicked () {
+            show_subkeys = false;
+        }
+
+        public void press () {
+            hold_tid = GLib.Timeout.add(1000, on_key_held);
+            key_pressed();
+        }
+
+        public void release () {
+            key_released();
+            if (hold_tid != 0) {
+                GLib.Source.remove (hold_tid);
+                hold_tid = 0;
+                key_clicked();
+                if (keyval != 0) {
+                    xadapter.keyval_press(keyval);
+                    xadapter.keyval_release(keyval);
+                }
+            } else {
+                key_hold_end ();
+            }
+        }
+
+        private bool on_key_held () {
+            hold_tid = 0;
+            if (_extended_keys.length () != 0)
+                show_subkeys = true;
+            key_hold ();
+            return false;
+        }
+
+        public unowned List<KeyModel> get_extended_keys () {
+            return _extended_keys;
+        }
+    }
+}
\ No newline at end of file
diff --git a/libcaribou/keyboard-model.vala b/libcaribou/keyboard-model.vala
new file mode 100644
index 0000000..b9d96f4
--- /dev/null
+++ b/libcaribou/keyboard-model.vala
@@ -0,0 +1,49 @@
+using Bus;
+
+namespace Caribou {
+    public class KeyboardModel : Object {
+        public string active_group { get; private set; default = ""; }
+
+        XAdapter xadapter;
+        HashTable<string, GroupModel> groups;
+
+        construct {
+            uint grpid;
+            string group, variant;
+            string[] grps, variants;
+            int i;
+
+            groups = new HashTable<string, GroupModel> (str_hash, str_equal);
+
+            xadapter = XAdapter.get_default ();
+            xadapter.group_changed.connect (on_group_changed);
+
+            grpid = xadapter.get_current_group (out group, out variant);
+            on_group_changed (grpid, group, variant);
+
+            xadapter.get_groups (out grps, out variants);
+
+            for (i=0;i<grps.length;i++)
+                populate_group (grps[i], variants[i]);
+        }
+
+        private void populate_group (string group, string variant) {
+            GroupModel grp = new GroupModel (group, variant);
+            groups.insert (GroupModel.create_group_name (group, variant), grp);
+            JsonDeserializer.load_group (grp);
+        }
+
+        public string[] get_groups () {
+            return Util.list_to_array (groups.get_keys ());
+        }
+
+        public GroupModel get_group (string group_name) {
+            return groups.lookup(group_name);
+        }
+
+        private void on_group_changed (uint grpid, string group, string variant) {
+            active_group = group;
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/libcaribou/keyboard-service.vala b/libcaribou/keyboard-service.vala
new file mode 100644
index 0000000..ee0035f
--- /dev/null
+++ b/libcaribou/keyboard-service.vala
@@ -0,0 +1,35 @@
+namespace Caribou {
+    [DBus(name = "org.gnome.Caribou.Keyboard")]
+    public abstract class KeyboardService : Object {
+        public string name { get; private set; default = "CaribouKeyboard"; }
+
+        public abstract void set_cursor_location(int x, int y, int w, int h);
+        public abstract void set_entry_location(int x, int y, int w, int h);
+        public abstract void show();
+        public abstract void hide();
+
+        protected void register_keyboard (string name) {
+            this.name = name;
+            string dbus_name = @"org.gnome.Caribou.$name";
+            Bus.own_name (BusType.SESSION, dbus_name, BusNameOwnerFlags.NONE,
+                          on_bus_aquired, on_name_aquired, on_name_lost);
+        }
+
+        private void on_name_aquired (DBusConnection conn, string name) {
+        }
+
+        private void on_name_lost (DBusConnection conn, string name) {
+            stderr.printf ("Could not aquire %s\n", name);
+        }
+
+        private void on_bus_aquired (DBusConnection conn) {
+            try {
+                string path = @"/org/gnome/Caribou/$name";
+                conn.register_object (path, this);
+            } catch (IOError e) {
+                stderr.printf ("Could not register service: %s\n", e.message);
+            }
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/libcaribou/level-model.vala b/libcaribou/level-model.vala
new file mode 100644
index 0000000..14e8ea8
--- /dev/null
+++ b/libcaribou/level-model.vala
@@ -0,0 +1,41 @@
+using GLib;
+
+namespace Caribou {
+    public class LevelModel : GLib.Object {
+        public signal void level_toggled (string new_level);
+
+        public string mode { get; private set; default = ""; }
+        public int n_rows {
+            get {
+                return _rows.length;
+            }
+        }
+
+        private RowModel[] _rows;
+
+        public LevelModel (string mode, uint nrows) {
+            uint i;
+            this.mode = mode;
+            _rows = new RowModel[nrows];
+            for (i=0;i<nrows;i++)
+                _rows[i] = new RowModel ();
+        }
+
+        public void add_key (uint rownum, KeyModel key) {
+            key.key_clicked.connect (on_key_clicked);
+            _rows[rownum].add_key (key);
+        }
+
+        public RowModel[] get_rows () {
+            return _rows;
+        }
+
+        private void on_key_clicked (KeyModel key) {
+            if (key.toggle != "")
+                level_toggled (key.toggle);
+            else
+                level_toggled ("default");
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/libcaribou/row-model.vala b/libcaribou/row-model.vala
new file mode 100644
index 0000000..de4456c
--- /dev/null
+++ b/libcaribou/row-model.vala
@@ -0,0 +1,22 @@
+namespace Caribou {
+    public class RowModel : GLib.Object {
+
+        List<KeyModel> keys;
+
+        public RowModel () {
+            keys = new List<KeyModel> ();
+        }
+
+        public void add_key (KeyModel key) {
+            keys.append (key);
+        }
+
+        public KeyModel get_key (uint index) {
+            return keys.nth (index).data;
+        }
+
+        public unowned List<weak KeyModel> get_keys () {
+            return keys;
+        }
+    }
+}
diff --git a/libcaribou/util.vala b/libcaribou/util.vala
new file mode 100644
index 0000000..c4625ae
--- /dev/null
+++ b/libcaribou/util.vala
@@ -0,0 +1,13 @@
+namespace Caribou {
+    class Util {
+        public static string[] list_to_array (List<string> list) {
+            string[] rv = new string[list.length()];
+            int i = 0;
+            foreach (string v in list) {
+                rv[i] = v;
+                i++;
+            }
+            return rv;
+        }
+    }
+}
\ No newline at end of file



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