aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/main.vala17
-rwxr-xr-xdebian/rules2
-rw-r--r--lib/Makefile.am1
-rw-r--r--lib/common.vala16
-rw-r--r--lib/main.vala617
-rw-r--r--lib/source.vala441
-rw-r--r--po/indicator-keyboard.pot8
-rw-r--r--tests/main.vala27
8 files changed, 629 insertions, 500 deletions
diff --git a/data/main.vala b/data/main.vala
index 6457c61f..8077f093 100644
--- a/data/main.vala
+++ b/data/main.vala
@@ -91,15 +91,14 @@ int main (string[] args) {
info.get_layout_info (name, null, out short_name, null, null);
- if (short_name != null) {
- var abbreviation = get_abbreviation ((!) short_name);
-
- if (abbreviation.get_char () != '\0') {
- if (!occurrences.has_key (abbreviation)) {
- occurrences[abbreviation] = 1;
- } else {
- occurrences[abbreviation] = occurrences[abbreviation] + 1;
- }
+ var abbreviation = abbreviate (short_name);
+ var has_abbreviation = abbreviation != null && ((!) abbreviation).get_char () != '\0';
+
+ if (has_abbreviation) {
+ if (!occurrences.has_key ((!) abbreviation)) {
+ occurrences[(!) abbreviation] = 1;
+ } else {
+ occurrences[(!) abbreviation] = occurrences[(!) abbreviation] + 1;
}
}
});
diff --git a/debian/rules b/debian/rules
index d2bfba7b..a69660c0 100755
--- a/debian/rules
+++ b/debian/rules
@@ -17,3 +17,5 @@ override_dh_install:
find debian/indicator-keyboard/usr/lib -name *.a -delete
dh_install --fail-missing
+override_dh_auto_test:
+ dh_auto_test || ( cat tests/test-suite.log )
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 169a2de0..cdf41ba2 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -7,6 +7,7 @@ AM_VALAFLAGS = --enable-experimental-non-null \
--vapidir $(top_srcdir)/deps
indicator_keyboard_service_SOURCES = main.vala \
+ source.vala \
common.vala
indicator_keyboard_service_VALAFLAGS = $(AM_VALAFLAGS) \
--pkg gee-1.0 \
diff --git a/lib/common.vala b/lib/common.vala
index 4d8b9add..9824bc26 100644
--- a/lib/common.vala
+++ b/lib/common.vala
@@ -16,18 +16,22 @@
* Authors: William Hua <william.hua@canonical.com>
*/
-string get_abbreviation (string name) {
+string? abbreviate (string? name) {
var index = 0;
unichar first;
unichar second;
- if (name.get_next_char (ref index, out first)) {
- if (name.get_next_char (ref index, out second)) {
- return @"$((!) first.toupper ().to_string ())$((!) second.to_string ())";
+ if (name != null) {
+ if (((!) name).get_next_char (ref index, out first)) {
+ if (((!) name).get_next_char (ref index, out second)) {
+ return @"$((!) first.toupper ().to_string ())$((!) second.to_string ())";
+ } else {
+ return first.toupper ().to_string ();
+ }
} else {
- return (!) first.toupper ().to_string ();
+ return "";
}
} else {
- return "";
+ return null;
}
}
diff --git a/lib/main.vala b/lib/main.vala
index 5fb251dd..91466f8c 100644
--- a/lib/main.vala
+++ b/lib/main.vala
@@ -19,78 +19,79 @@
[DBus (name = "com.canonical.indicator.keyboard")]
public class Indicator.Keyboard.Service : Object {
+ private static IBus.Bus? ibus;
+
+ private bool force;
private bool use_gtk;
private bool use_bamf;
+
private MainLoop? loop;
private Settings indicator_settings;
private Settings source_settings;
private Settings per_window_settings;
- private Gnome.XkbInfo xkb_info;
- private IBus.Bus? ibus;
private Bamf.Matcher? matcher;
private Gee.HashMap<string, uint>? window_sources;
+ private Source[]? sources;
+
private SimpleActionGroup? action_group;
private SimpleAction? indicator_action;
private MenuModel? menu_model;
private Menu? sources_menu;
- private Icon?[]? icons;
- private string[]? icon_strings;
- private int[]? icon_string_uniques;
- private uint[]? icon_string_subscripts;
-
[DBus (visible = false)]
public Service (ref unowned string[] args) {
- Bus.own_name (BusType.SESSION,
- "com.canonical.indicator.keyboard",
- BusNameOwnerFlags.ALLOW_REPLACEMENT | ("--force" in args ? BusNameOwnerFlags.REPLACE : 0),
- this.handle_bus_acquired,
- null,
- this.handle_name_lost);
-
- this.use_gtk = "--use-gtk" in args;
- this.use_bamf = "--use-bamf" in args;
+ force = "--force" in args;
+ use_gtk = "--use-gtk" in args;
+ use_bamf = "--use-bamf" in args;
- if (this.use_gtk) {
- this.use_gtk = Gtk.init_check (ref args);
+ if (use_gtk) {
+ use_gtk = Gtk.init_check (ref args);
} else {
Gdk.init (ref args);
}
- this.indicator_settings = new Settings ("com.canonical.indicator.keyboard");
- this.indicator_settings.changed["visible"].connect (this.handle_changed_visible);
-
- this.source_settings = new Settings ("org.gnome.desktop.input-sources");
- this.source_settings.changed["current"].connect (this.handle_changed_current);
- this.source_settings.changed["sources"].connect (this.handle_changed_sources);
+ indicator_settings = new Settings ("com.canonical.indicator.keyboard");
+ indicator_settings.changed["visible"].connect (handle_changed_visible);
- this.per_window_settings = new Settings ("org.gnome.libgnomekbd.desktop");
- this.per_window_settings.changed["group-per-window"].connect (this.handle_changed_group_per_window);
+ source_settings = new Settings ("org.gnome.desktop.input-sources");
+ source_settings.changed["current"].connect (handle_changed_current);
+ source_settings.changed["sources"].connect (handle_changed_sources);
- this.xkb_info = new Gnome.XkbInfo ();
+ per_window_settings = new Settings ("org.gnome.libgnomekbd.desktop");
+ per_window_settings.changed["group-per-window"].connect (handle_changed_group_per_window);
migrate_keyboard_layouts ();
-
update_window_sources ();
-
- this.loop = new MainLoop ();
- ((!) this.loop).run ();
+ acquire_bus_name ();
}
[DBus (visible = false)]
- private IBus.Bus get_ibus () {
- if (this.ibus == null) {
+ private static IBus.Bus get_ibus () {
+ if (ibus == null) {
IBus.init ();
- this.ibus = new IBus.Bus ();
+ ibus = new IBus.Bus ();
}
- return (!) this.ibus;
+ return (!) ibus;
+ }
+
+ [DBus (visible = false)]
+ private void acquire_bus_name () {
+ Bus.own_name (BusType.SESSION,
+ "com.canonical.indicator.keyboard",
+ BusNameOwnerFlags.ALLOW_REPLACEMENT | (force ? BusNameOwnerFlags.REPLACE : 0),
+ handle_bus_acquired,
+ null,
+ handle_name_lost);
+
+ loop = new MainLoop ();
+ ((!) loop).run ();
}
[DBus (visible = false)]
private void migrate_keyboard_layouts () {
- if (!this.indicator_settings.get_boolean ("migrated")) {
+ if (!indicator_settings.get_boolean ("migrated")) {
var builder = new VariantBuilder (new VariantType ("a(ss)"));
var length = 0;
@@ -139,26 +140,26 @@ public class Indicator.Keyboard.Service : Object {
}
}
- this.source_settings.set_value ("sources", builder.end ());
+ source_settings.set_value ("sources", builder.end ());
- this.indicator_settings.set_boolean ("migrated", true);
+ indicator_settings.set_boolean ("migrated", true);
}
}
[DBus (visible = false)]
private void update_window_sources () {
- if (this.use_bamf) {
- var group_per_window = this.per_window_settings.get_boolean ("group-per-window");
+ if (use_bamf) {
+ var group_per_window = per_window_settings.get_boolean ("group-per-window");
- if (group_per_window != (this.window_sources != null)) {
+ if (group_per_window != (window_sources != null)) {
if (group_per_window) {
- this.window_sources = new Gee.HashMap<string, uint> ();
- this.matcher = Bamf.Matcher.get_default ();
- ((!) this.matcher).active_window_changed.connect (this.handle_active_window_changed);
+ window_sources = new Gee.HashMap<string, uint> ();
+ matcher = Bamf.Matcher.get_default ();
+ ((!) matcher).active_window_changed.connect (handle_active_window_changed);
} else {
- ((!) this.matcher).active_window_changed.disconnect (this.handle_active_window_changed);
- this.matcher = null;
- this.window_sources = null;
+ ((!) matcher).active_window_changed.disconnect (handle_active_window_changed);
+ matcher = null;
+ window_sources = null;
}
}
}
@@ -172,312 +173,74 @@ public class Indicator.Keyboard.Service : Object {
[DBus (visible = false)]
private void handle_active_window_changed (Bamf.View? old_view, Bamf.View? new_view) {
if (old_view != null) {
- ((!) this.window_sources)[((!) old_view).path] = this.source_settings.get_uint ("current");
+ ((!) window_sources)[((!) old_view).path] = source_settings.get_uint ("current");
}
if (new_view != null) {
- if (!((!) this.window_sources).has_key (((!) new_view).path)) {
- var default_group = this.per_window_settings.get_int ("default-group");
+ if (!((!) window_sources).has_key (((!) new_view).path)) {
+ var default_group = per_window_settings.get_int ("default-group");
if (default_group >= 0) {
- this.source_settings.set_uint ("current", (uint) default_group);
+ source_settings.set_uint ("current", (uint) default_group);
}
} else {
- this.source_settings.set_uint ("current", ((!) this.window_sources)[((!) new_view).path]);
- }
- }
- }
-
- [DBus (visible = false)]
- private Gtk.StyleContext? get_style_context () {
- Gtk.StyleContext? context = null;
-
- if (this.use_gtk) {
- Gdk.Screen? screen = Gdk.Screen.get_default ();
-
- if (screen != null) {
- context = new Gtk.StyleContext ();
- ((!) context).set_screen ((!) screen);
-
- var path = new Gtk.WidgetPath ();
- path.append_type (typeof (Gtk.MenuItem));
- ((!) context).set_path (path);
- }
- }
-
- return context;
- }
-
- [DBus (visible = false)]
- protected virtual Icon? create_icon (string? text, uint subscript) {
- Icon? icon = null;
-
- var style = get_style_context ();
-
- if (style != null) {
- const int W = 22;
- const int H = 22;
- const int w = 20;
- const int h = 20;
- const double R = 2.0;
- const double TEXT_SIZE = 12.0;
- const double SUBSCRIPT_SIZE = 8.0;
-
- Pango.FontDescription description;
- var colour = ((!) style).get_color (Gtk.StateFlags.NORMAL);
- colour = { 0.5, 0.5, 0.5, 1.0 };
- ((!) style).get (Gtk.StateFlags.NORMAL, Gtk.STYLE_PROPERTY_FONT, out description);
-
- var surface = new Cairo.ImageSurface (Cairo.Format.ARGB32, W, H);
- var context = new Cairo.Context (surface);
-
- context.translate (0.5 * (W - w), 0.5 * (H - h));
-
- context.new_sub_path ();
- context.arc (R, R, R, Math.PI, -0.5 * Math.PI);
- context.arc (w - R, R, R, -0.5 * Math.PI, 0);
- context.arc (w - R, h - R, R, 0, 0.5 * Math.PI);
- context.arc (R, h - R, R, 0.5 * Math.PI, Math.PI);
- context.close_path ();
-
- context.set_source_rgba (colour.red, colour.green, colour.blue, colour.alpha);
- context.fill ();
- context.set_operator (Cairo.Operator.CLEAR);
-
- if (text != null) {
- var text_layout = Pango.cairo_create_layout (context);
- text_layout.set_alignment (Pango.Alignment.CENTER);
- description.set_absolute_size (Pango.units_from_double (TEXT_SIZE));
- text_layout.set_font_description (description);
- text_layout.set_text ((!) text, -1);
- Pango.cairo_update_layout (context, text_layout);
- int text_width;
- int text_height;
- text_layout.get_pixel_size (out text_width, out text_height);
-
- if (subscript > 0) {
- var subscript_layout = Pango.cairo_create_layout (context);
- subscript_layout.set_alignment (Pango.Alignment.CENTER);
- description.set_absolute_size (Pango.units_from_double (SUBSCRIPT_SIZE));
- subscript_layout.set_font_description (description);
- subscript_layout.set_text (@"$subscript", -1);
- Pango.cairo_update_layout (context, subscript_layout);
- int subscript_width;
- int subscript_height;
- subscript_layout.get_pixel_size (out subscript_width, out subscript_height);
-
- context.save ();
- context.translate ((w - (text_width + subscript_width)) / 2, (h - text_height) / 2);
- Pango.cairo_layout_path (context, text_layout);
- context.fill ();
- context.restore ();
-
- context.save ();
- context.translate ((w + (text_width - subscript_width)) / 2, (h + text_height) / 2 - subscript_height);
- Pango.cairo_layout_path (context, subscript_layout);
- context.fill ();
- context.restore ();
- } else {
- context.save ();
- context.translate ((w - text_width) / 2, (h - text_height) / 2);
- Pango.cairo_layout_path (context, text_layout);
- context.fill ();
- context.restore ();
- }
- }
-
- var buffer = new ByteArray ();
-
- surface.write_to_png_stream ((data) => {
- buffer.append (data);
- return Cairo.Status.SUCCESS;
- });
-
- icon = new BytesIcon (ByteArray.free_to_bytes ((owned) buffer));
- }
-
- return icon;
- }
-
- [DBus (visible = false)]
- private string get_icon_string (uint index) {
- string? icon_string = null;
-
- if (this.icon_strings == null) {
- var array = this.source_settings.get_value ("sources");
- this.icon_strings = new string[array.n_children ()];
- }
-
- if (index < ((!) this.icon_strings).length) {
- icon_string = this.icon_strings[index];
-
- if (icon_string == null) {
- var array = this.source_settings.get_value ("sources");
-
- string type;
- string name;
-
- array.get_child (index, "(ss)", out type, out name);
-
- if (type == "xkb") {
- string? short_name;
-
- this.xkb_info.get_layout_info (name, null, out short_name, null, null);
-
- if (short_name != null) {
- this.icon_strings[index] = get_abbreviation ((!) short_name);
- icon_string = this.icon_strings[index];
- }
- }
+ source_settings.set_uint ("current", ((!) window_sources)[((!) new_view).path]);
}
}
-
- if (icon_string == null) {
- icon_string = "";
- }
-
- return (!) icon_string;
}
[DBus (visible = false)]
- private bool is_icon_string_unique (uint index) {
- bool icon_string_unique = true;
-
- if (this.icon_string_uniques == null) {
- var array = this.source_settings.get_value ("sources");
- this.icon_string_uniques = new int[array.n_children ()];
+ private Source[] get_sources () {
+ if (sources == null) {
+ var array = source_settings.get_value ("sources");
- for (var i = 0; i < ((!) this.icon_string_uniques).length; i++) {
- this.icon_string_uniques[i] = -1;
- }
- }
+ sources = new Source[array.n_children ()];
- if (index < ((!) this.icon_string_uniques).length) {
- if (this.icon_string_uniques[index] == -1) {
- this.icon_string_uniques[index] = 1;
+ for (var i = 0; i < ((!) sources).length; i++) {
+ sources[i] = new Source(array.get_child_value (i), use_gtk);
+ sources[i].show_subscript = false;
+ sources[i].subscript = 1;
- var icon_string = get_icon_string (index);
+ for (var j = (int) i - 1; j >= 0; j--) {
+ if ((!) sources[j].short_name == (!) sources[i].short_name) {
+ sources[i].subscript = sources[j].subscript + 1;
+ sources[i].show_subscript = true;
+ sources[j].show_subscript = true;
- for (var i = 0; i < ((!) this.icon_string_uniques).length && this.icon_string_uniques[index] == 1; i++) {
- if (i != index && get_icon_string (i) == icon_string) {
- this.icon_string_uniques[index] = 0;
+ break;
}
}
}
-
- icon_string_unique = this.icon_string_uniques[index] != 0;
}
- return icon_string_unique;
+ return (!) sources;
}
[DBus (visible = false)]
- private uint get_icon_string_subscript (uint index) {
- uint icon_string_subscript = 0;
-
- if (this.icon_string_subscripts == null) {
- var array = this.source_settings.get_value ("sources");
- this.icon_string_subscripts = new uint[array.n_children ()];
- }
-
- if (index < ((!) this.icon_string_subscripts).length) {
- icon_string_subscript = this.icon_string_subscripts[index];
-
- if (icon_string_subscript == 0) {
- this.icon_string_subscripts[index] = 1;
-
- for (var i = (int) index - 1; i >= 0 && this.icon_string_subscripts[index] == 1; i--) {
- if (get_icon_string (i) == get_icon_string (index)) {
- this.icon_string_subscripts[index] = get_icon_string_subscript (i) + 1;
- }
- }
+ private void update_indicator_action () {
+ var visible = indicator_settings.get_boolean ("visible");
+ var current = source_settings.get_uint ("current");
+ var icon = get_sources ()[current].icon;
+ Variant state;
- icon_string_subscript = this.icon_string_subscripts[index];
- }
+ if (icon != null) {
+ state = new Variant.parsed ("{ 'visible' : <%b>, 'icon' : %v }", visible, ((!) icon).serialize ());
+ } else {
+ state = new Variant.parsed ("{ 'visible' : <%b> }", visible);
}
- return icon_string_subscript;
+ get_indicator_action ().set_state (state);
}
[DBus (visible = false)]
- private Icon? get_icon (uint index) {
- Icon? icon = null;
-
- if (this.icons == null) {
- var array = this.source_settings.get_value ("sources");
- this.icons = new Icon?[array.n_children ()];
- }
-
- if (index < ((!) this.icons).length) {
- icon = this.icons[index];
-
- if (icon == null) {
- var array = this.source_settings.get_value ("sources");
-
- string type;
- string name;
-
- array.get_child (index, "(ss)", out type, out name);
-
- if (type == "xkb") {
- var icon_string = get_icon_string (index);
- var icon_unique = is_icon_string_unique (index);
- var icon_subscript = get_icon_string_subscript (index);
-
- if (icon_string.get_char () != '\0') {
- string icon_name;
-
- if (icon_unique) {
- icon_name = @"indicator-keyboard-$((!) icon_string)";
- } else {
- icon_name = @"indicator-keyboard-$((!) icon_string)-$icon_subscript";
- }
-
- if (this.use_gtk) {
- var icon_theme = Gtk.IconTheme.get_default ();
- Gtk.IconInfo? icon_info = icon_theme.lookup_icon (icon_name, 22, 0);
-
- if (icon_info != null) {
- try {
- this.icons[index] = Icon.new_for_string (((!) icon_info).get_filename ());
- } catch (Error error) {
- this.icons[index] = null;
- }
- }
- } else {
- this.icons[index] = new ThemedIcon (icon_name);
- }
- }
-
- if (this.icons[index] == null) {
- if (icon_unique) {
- this.icons[index] = create_icon (icon_string, 0);
- } else {
- this.icons[index] = create_icon (icon_string, icon_subscript);
- }
- }
- } else if (type == "ibus") {
- var names = new string[2];
- names[0] = name;
-
- var engines = get_ibus ().get_engines_by_names (names);
-
- if (engines.length > 0) {
- var engine = engines[0];
-
- try {
- this.icons[index] = Icon.new_for_string (engine.get_icon ());
- } catch (Error error) {
- warning ("error: %s", error.message);
- }
- }
- }
-
- icon = this.icons[index];
- }
+ private SimpleAction get_indicator_action () {
+ if (indicator_action == null) {
+ var state = new Variant.parsed ("{ 'visible' : <false> }");
+ indicator_action = new SimpleAction.stateful ("indicator", null, state);
+ update_indicator_action ();
}
- return icon;
+ return (!) indicator_action;
}
[DBus (visible = false)]
@@ -485,57 +248,66 @@ public class Indicator.Keyboard.Service : Object {
var group = new SimpleActionGroup ();
group.insert (root_action);
- group.insert (this.source_settings.create_action ("current"));
+ group.insert (source_settings.create_action ("current"));
var action = new SimpleAction ("map", null);
- action.activate.connect (this.handle_activate_map);
+ action.activate.connect (handle_activate_map);
group.insert (action);
action = new SimpleAction ("chart", null);
- action.activate.connect (this.handle_activate_chart);
+ action.activate.connect (handle_activate_chart);
group.insert (action);
action = new SimpleAction ("settings", null);
- action.activate.connect (this.handle_activate_settings);
+ action.activate.connect (handle_activate_settings);
group.insert (action);
return group;
}
[DBus (visible = false)]
- private void update_indicator_action () {
- var visible = this.indicator_settings.get_boolean ("visible");
- var current = this.source_settings.get_uint ("current");
- var icon = get_icon (current);
- Variant state;
-
- if (icon != null) {
- state = new Variant.parsed ("{ 'visible' : <%b>, 'icon' : %v }", visible, ((!) icon).serialize ());
- } else {
- state = new Variant.parsed ("{ 'visible' : <%b> }", visible);
+ public SimpleActionGroup get_action_group () {
+ if (action_group == null) {
+ action_group = create_action_group (get_indicator_action ());
}
- get_indicator_action ().set_state (state);
+ return (!) action_group;
}
[DBus (visible = false)]
- private SimpleAction get_indicator_action () {
- if (this.indicator_action == null) {
- var state = new Variant.parsed ("{ 'visible' : <false> }");
- this.indicator_action = new SimpleAction.stateful ("indicator", null, state);
- update_indicator_action ();
- }
+ private void update_sources_menu () {
+ if (sources_menu != null) {
+ var menu = get_sources_menu ();
+
+ while (menu.get_n_items () > 0)
+ menu.remove (0);
+
+ var sources = get_sources ();
- return (!) this.indicator_action;
+ for (var i = 0; i < sources.length; i++) {
+ var item = new MenuItem (sources[i].name, "indicator.current");
+ item.set_attribute (Menu.ATTRIBUTE_TARGET, "u", i);
+
+ var icon = sources[i].icon;
+ if (icon != null) {
+ item.set_icon ((!) icon);
+ }
+
+ menu.append_item (item);
+ }
+ } else {
+ get_sources_menu ();
+ }
}
[DBus (visible = false)]
- public SimpleActionGroup get_action_group () {
- if (this.action_group == null) {
- this.action_group = create_action_group (get_indicator_action ());
+ private Menu get_sources_menu () {
+ if (sources_menu == null) {
+ sources_menu = new Menu ();
+ update_sources_menu ();
}
- return (!) this.action_group;
+ return (!) sources_menu;
}
[DBus (visible = false)]
@@ -561,107 +333,12 @@ public class Indicator.Keyboard.Service : Object {
}
[DBus (visible = false)]
- private string get_display_name (string layout) {
- string? language = Xkl.get_language_name (layout);
- string? country = Xkl.get_country_name (layout);
- var has_language = language != null && ((!) language).get_char () != '\0';
- var has_country = country != null && ((!) country).get_char () != '\0';
-
- if (has_language && has_country) {
- return @"$((!) language) ($((!) country))";
- } else if (has_language) {
- return (!) language;
- } else if (has_country) {
- return (!) country;
- } else {
- return "";
- }
- }
-
- [DBus (visible = false)]
- private void update_sources_menu () {
- if (this.sources_menu != null) {
- var menu = get_sources_menu ();
-
- while (menu.get_n_items () > 0)
- menu.remove (0);
-
- VariantIter iter;
- string type;
- string name;
-
- this.source_settings.get ("sources", "a(ss)", out iter);
-
- for (var i = 0; iter.next ("(ss)", out type, out name); i++) {
- if (type == "xkb") {
- string? display_name;
- string? layout_name;
-
- this.xkb_info.get_layout_info (name, out display_name, null, out layout_name, null);
-
- if (display_name != null) {
- name = (!) display_name;
- } else if (layout_name != null) {
- name = get_display_name ((!) layout_name);
- }
- }
- else if (type == "ibus") {
- var names = new string[2];
- names[0] = name;
-
- var engines = get_ibus ().get_engines_by_names (names);
-
- if (engines.length > 0) {
- var engine = engines[0];
- string? language = engine.get_language ();
- string? display_name = engine.get_longname ();
-
- if (language != null) {
- language = Xkl.get_language_name ((!) language);
- }
-
- if (language != null && display_name != null) {
- name = @"$((!) language) ($((!) display_name))";
- } else if (language != null) {
- name = (!) language;
- } else if (display_name != null) {
- name = (!) display_name;
- }
- }
- }
-
- var menu_item = new MenuItem (name, "indicator.current");
- menu_item.set_attribute (Menu.ATTRIBUTE_TARGET, "u", i);
-
- var icon = get_icon (i);
- if (icon != null) {
- menu_item.set_icon ((!) icon);
- }
-
- menu.append_item (menu_item);
- }
- } else {
- get_sources_menu ();
- }
- }
-
- [DBus (visible = false)]
- private Menu get_sources_menu () {
- if (this.sources_menu == null) {
- this.sources_menu = new Menu ();
- update_sources_menu ();
- }
-
- return (!) this.sources_menu;
- }
-
- [DBus (visible = false)]
public MenuModel get_menu_model () {
- if (this.menu_model == null) {
- this.menu_model = create_menu_model (get_sources_menu ());
+ if (menu_model == null) {
+ menu_model = create_menu_model (get_sources_menu ());
}
- return (!) this.menu_model;
+ return (!) menu_model;
}
[DBus (visible = false)]
@@ -676,10 +353,7 @@ public class Indicator.Keyboard.Service : Object {
[DBus (visible = false)]
private void handle_changed_sources (string key) {
- this.icon_string_subscripts = null;
- this.icon_string_uniques = null;
- this.icon_strings = null;
- this.icons = null;
+ sources = null;
update_sources_menu ();
update_indicator_action ();
@@ -696,42 +370,29 @@ public class Indicator.Keyboard.Service : Object {
[DBus (visible = false)]
private void handle_activate_chart (Variant? parameter) {
- var layout = "us";
+ string? layout = "us";
string? variant = null;
- var current = this.source_settings.get_uint ("current");
- var array = this.source_settings.get_value ("sources");
-
- if (current < array.n_children ()) {
- string type;
- string name;
-
- array.get_child (current, "(ss)", out type, out name);
-
- if (type == "xkb") {
- this.xkb_info.get_layout_info (name, null, null, out layout, out variant);
- } else if (type == "ibus") {
- var names = new string[2];
- names[0] = name;
+ var sources = get_sources ();
+ var current = source_settings.get_uint ("current");
- var engines = get_ibus ().get_engines_by_names (names);
-
- if (engines.length > 0) {
- var engine = engines[0];
-
- layout = engine.get_layout ();
- variant = engine.get_layout_variant ();
- }
- }
+ if (current < sources.length) {
+ layout = sources[current].layout;
+ variant = sources[current].variant;
}
+ var has_layout = layout != null && ((!) layout).get_char () != '\0';
+ var has_variant = variant != null && ((!) variant).get_char () != '\0';
+
try {
string command;
- if (variant != null && ((!) variant).get_char () != '\0') {
- command = @"gkbd-keyboard-display -l \"$layout\t$((!) variant)\"";
+ if (has_layout && has_variant) {
+ command = @"gkbd-keyboard-display -l \"$((!) layout)\t$((!) variant)\"";
+ } else if (has_layout) {
+ command = @"gkbd-keyboard-display -l $((!) layout)";
} else {
- command = @"gkbd-keyboard-display -l $layout";
+ command = @"gkbd-keyboard-display -l us";
}
Process.spawn_command_line_async (command);
@@ -761,8 +422,8 @@ public class Indicator.Keyboard.Service : Object {
[DBus (visible = false)]
private void handle_name_lost (DBusConnection? connection, string name) {
- ((!) this.loop).quit ();
- this.loop = null;
+ ((!) loop).quit ();
+ loop = null;
}
[DBus (visible = false)]
diff --git a/lib/source.vala b/lib/source.vala
new file mode 100644
index 00000000..3e38a86e
--- /dev/null
+++ b/lib/source.vala
@@ -0,0 +1,441 @@
+/*
+ * Copyright 2013 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: William Hua <william.hua@canonical.com>
+ */
+
+public class Indicator.Keyboard.Source : Object {
+
+ private static Gnome.XkbInfo? xkb_info;
+ private static IBus.Bus? bus;
+
+ private string? xkb;
+ private string? ibus;
+
+ private string? _name;
+ private string? _short_name;
+ private string? _layout;
+ private string? _variant;
+ private Icon? _icon;
+ private uint _subscript;
+ private bool _show_subscript;
+ private bool _use_gtk;
+
+ public string? name {
+ get { if (_name == null) { _name = _get_name (); } return _name; }
+ }
+
+ public string? short_name {
+ get { if (_short_name == null) { _short_name = _get_short_name (); } return _short_name; }
+ }
+
+ public string? layout {
+ get { if (_layout == null) { _layout = _get_layout (); } return _layout; }
+ }
+
+ public string? variant {
+ get { if (_variant == null) { _variant = _get_variant (); } return _variant; }
+ }
+
+ public Icon? icon {
+ get { if (_icon == null) { _icon = _get_icon (); } return _icon; }
+ private set { _icon = value; }
+ }
+
+ public uint subscript {
+ get { return _subscript; }
+ set { _subscript = value; icon = null; }
+ }
+
+ public bool show_subscript {
+ get { return _show_subscript; }
+ set { _show_subscript = value; icon = null; }
+ }
+
+ public bool use_gtk {
+ get { return _use_gtk; }
+ construct set { _use_gtk = value; icon = null; }
+ }
+
+ public Source (Variant variant, bool use_gtk = false) {
+ Object (use_gtk: use_gtk);
+
+ if (variant.is_of_type (new VariantType ("(ss)"))) {
+ unowned string type;
+ unowned string name;
+
+ variant.get ("(&s&s)", out type, out name);
+
+ if (type == "xkb") {
+ xkb = name;
+ } else if (type == "ibus") {
+ ibus = name;
+ }
+ } else if (variant.is_of_type (new VariantType ("a{ss}"))) {
+ VariantIter iter;
+ unowned string key;
+ unowned string value;
+
+ variant.get ("a{ss}", out iter);
+
+ while (iter.next ("{&s&s}", out key, out value)) {
+ if (key == "xkb") {
+ xkb = value;
+ } else if (key == "ibus") {
+ ibus = value;
+ }
+ }
+ }
+ }
+
+ private static Gnome.XkbInfo get_xkb_info () {
+ if (xkb_info == null) {
+ xkb_info = new Gnome.XkbInfo ();
+ }
+
+ return (!) xkb_info;
+ }
+
+ private static IBus.Bus get_bus () {
+ if (bus == null) {
+ IBus.init ();
+ bus = new IBus.Bus ();
+ }
+
+ return (!) bus;
+ }
+
+ private IBus.EngineDesc? get_engine () {
+ IBus.EngineDesc? engine = null;
+
+ if (ibus != null) {
+ var names = new string[2];
+ names[0] = (!) ibus;
+
+ var engines = get_bus ().get_engines_by_names (names);
+
+ if (engines.length > 0) {
+ engine = engines[0];
+ }
+ }
+
+ return engine;
+ }
+
+ protected virtual string? _get_name () {
+ string? name = null;
+
+ var engine = get_engine ();
+
+ if (engine != null) {
+ string? language = ((!) engine).get_language ();
+ string? display_name = ((!) engine).get_longname ();
+ var has_language = language != null && ((!) language).get_char () != '\0';
+ var has_display_name = display_name != null && ((!) display_name).get_char () != '\0';
+
+ if (has_language) {
+ language = Xkl.get_language_name ((!) language);
+ has_language = language != null && ((!) language).get_char () != '\0';
+ }
+
+ if (has_language && has_display_name) {
+ name = @"$((!) language) ($((!) display_name))";
+ } else if (has_language) {
+ name = language;
+ } else if (has_display_name) {
+ name = display_name;
+ }
+ }
+
+ var has_name = name != null && ((!) name).get_char () != '\0';
+
+ if (!has_name && xkb != null) {
+ string? display_name = null;
+ string? layout = null;
+
+ get_xkb_info ().get_layout_info ((!) xkb, out display_name, null, out layout, null);
+
+ var has_display_name = display_name != null && ((!) display_name).get_char () != '\0';
+ var has_layout = layout != null && ((!) layout).get_char () != '\0';
+
+ if (has_display_name) {
+ name = display_name;
+ } else if (has_layout) {
+ string? language = Xkl.get_language_name ((!) layout);
+ string? country = Xkl.get_country_name ((!) layout);
+ var has_language = language != null && ((!) language).get_char () != '\0';
+ var has_country = country != null && ((!) country).get_char () != '\0';
+
+ if (has_language && has_country) {
+ name = @"$((!) language) ($((!) country))";
+ } else if (has_language) {
+ name = language;
+ } else if (has_country) {
+ name = country;
+ }
+ }
+ }
+
+ if (name == null || ((!) name).get_char () == '\0') {
+ if (ibus != null) {
+ name = ibus;
+ } else if (xkb != null) {
+ name = xkb;
+ }
+ }
+
+ return name;
+ }
+
+ protected virtual string? _get_short_name () {
+ string? short_name = null;
+
+ if (xkb != null) {
+ get_xkb_info ().get_layout_info ((!) xkb, null, out short_name, null, null);
+ }
+
+ var has_short_name = short_name != null && ((!) short_name).get_char () != '\0';
+
+ if (!has_short_name) {
+ var engine = get_engine ();
+
+ if (engine != null) {
+ short_name = ((!) engine).get_name ();
+ }
+ }
+
+ if (short_name == null || ((!) short_name).get_char () == '\0') {
+ if (ibus != null) {
+ short_name = ibus;
+ } else if (xkb != null) {
+ short_name = xkb;
+ }
+ }
+
+ return abbreviate (short_name);
+ }
+
+ protected virtual string? _get_layout () {
+ string? layout = null;
+
+ if (xkb != null) {
+ get_xkb_info ().get_layout_info ((!) xkb, null, null, out layout, null);
+ }
+
+ var has_layout = layout != null && ((!) layout).get_char () != '\0';
+
+ if (!has_layout) {
+ var engine = get_engine ();
+
+ if (engine != null) {
+ layout = ((!) engine).get_layout ();
+ }
+ }
+
+ if (layout == null || ((!) layout).get_char () == '\0') {
+ layout = xkb;
+ }
+
+ return layout;
+ }
+
+ protected virtual string? _get_variant () {
+ string? variant = null;
+
+ if (xkb != null) {
+ get_xkb_info ().get_layout_info ((!) xkb, null, null, null, out variant);
+ }
+
+ var has_variant = variant != null && ((!) variant).get_char () != '\0';
+
+ if (!has_variant) {
+ var engine = get_engine ();
+
+ if (engine != null) {
+ variant = ((!) engine).get_layout_variant ();
+ }
+ }
+
+ if (variant == null || ((!) variant).get_char () == '\0') {
+ variant = null;
+ }
+
+ return variant;
+ }
+
+ private Gtk.StyleContext? get_style_context () {
+ Gtk.StyleContext? context = null;
+
+ if (_use_gtk) {
+ Gdk.Screen? screen = Gdk.Screen.get_default ();
+
+ if (screen != null) {
+ context = new Gtk.StyleContext ();
+ ((!) context).set_screen ((!) screen);
+
+ var path = new Gtk.WidgetPath ();
+ path.append_type (typeof (Gtk.MenuItem));
+ ((!) context).set_path (path);
+ }
+ }
+
+ return context;
+ }
+
+ protected virtual Icon? create_icon () {
+ Icon? icon = null;
+
+ var style = get_style_context ();
+
+ if (style != null) {
+ const int W = 22;
+ const int H = 22;
+ const int w = 20;
+ const int h = 20;
+ const double R = 2.0;
+ const double TEXT_SIZE = 12.0;
+ const double SUBSCRIPT_SIZE = 8.0;
+
+ Pango.FontDescription description;
+ var colour = ((!) style).get_color (Gtk.StateFlags.NORMAL);
+ colour = { 0.5, 0.5, 0.5, 1.0 };
+ ((!) style).get (Gtk.StateFlags.NORMAL, Gtk.STYLE_PROPERTY_FONT, out description);
+
+ var surface = new Cairo.ImageSurface (Cairo.Format.ARGB32, W, H);
+ var context = new Cairo.Context (surface);
+
+ context.translate (0.5 * (W - w), 0.5 * (H - h));
+
+ context.new_sub_path ();
+ context.arc (R, R, R, Math.PI, -0.5 * Math.PI);
+ context.arc (w - R, R, R, -0.5 * Math.PI, 0);
+ context.arc (w - R, h - R, R, 0, 0.5 * Math.PI);
+ context.arc (R, h - R, R, 0.5 * Math.PI, Math.PI);
+ context.close_path ();
+
+ context.set_source_rgba (colour.red, colour.green, colour.blue, colour.alpha);
+ context.fill ();
+ context.set_operator (Cairo.Operator.CLEAR);
+
+ if (short_name != null) {
+ var text_layout = Pango.cairo_create_layout (context);
+ text_layout.set_alignment (Pango.Alignment.CENTER);
+ description.set_absolute_size (Pango.units_from_double (TEXT_SIZE));
+ text_layout.set_font_description (description);
+ text_layout.set_text ((!) short_name, -1);
+ Pango.cairo_update_layout (context, text_layout);
+ int text_width;
+ int text_height;
+ text_layout.get_pixel_size (out text_width, out text_height);
+
+ if (_show_subscript) {
+ var subscript_layout = Pango.cairo_create_layout (context);
+ subscript_layout.set_alignment (Pango.Alignment.CENTER);
+ description.set_absolute_size (Pango.units_from_double (SUBSCRIPT_SIZE));
+ subscript_layout.set_font_description (description);
+ subscript_layout.set_text (@"$_subscript", -1);
+ Pango.cairo_update_layout (context, subscript_layout);
+ int subscript_width;
+ int subscript_height;
+ subscript_layout.get_pixel_size (out subscript_width, out subscript_height);
+
+ context.save ();
+ context.translate ((w - (text_width + subscript_width)) / 2, (h - text_height) / 2);
+ Pango.cairo_layout_path (context, text_layout);
+ context.fill ();
+ context.restore ();
+
+ context.save ();
+ context.translate ((w + (text_width - subscript_width)) / 2, (h + text_height) / 2 - subscript_height);
+ Pango.cairo_layout_path (context, subscript_layout);
+ context.fill ();
+ context.restore ();
+ } else {
+ context.save ();
+ context.translate ((w - text_width) / 2, (h - text_height) / 2);
+ Pango.cairo_layout_path (context, text_layout);
+ context.fill ();
+ context.restore ();
+ }
+ }
+
+ var buffer = new ByteArray ();
+
+ surface.write_to_png_stream ((data) => {
+ buffer.append (data);
+ return Cairo.Status.SUCCESS;
+ });
+
+ icon = new BytesIcon (ByteArray.free_to_bytes ((owned) buffer));
+ }
+
+ return icon;
+ }
+
+ private Icon? _get_icon () {
+ Icon? icon = null;
+
+ var engine = get_engine ();
+
+ if (engine != null) {
+ string? icon_name = ((!) engine).get_icon ();
+ var has_icon_name = icon_name != null && ((!) icon_name).get_char () != '\0';
+
+ if (has_icon_name) {
+ try {
+ icon = Icon.new_for_string ((!) icon_name);
+ } catch (Error error) {
+ warning ("error: %s", error.message);
+ }
+ }
+ }
+
+ if (icon == null && short_name != null) {
+ string icon_name;
+
+ if (_show_subscript) {
+ icon_name = @"indicator-keyboard-$((!) short_name)-$_subscript";
+ } else {
+ icon_name = @"indicator-keyboard-$((!) short_name)";
+ }
+
+ if (_use_gtk) {
+ var icon_theme = Gtk.IconTheme.get_default ();
+ Gtk.IconInfo? icon_info = icon_theme.lookup_icon (icon_name, 22, 0);
+
+ if (icon_info != null) {
+ string? file_name = ((!) icon_info).get_filename ();
+ var has_file_name = file_name != null && ((!) file_name).get_char () != '\0';
+
+ if (has_file_name) {
+ try {
+ icon = Icon.new_for_string ((!) file_name);
+ } catch (Error error) {
+ warning ("error: %s", error.message);
+ }
+ }
+ }
+ } else {
+ icon = new ThemedIcon (icon_name);
+ }
+ }
+
+ if (icon == null) {
+ icon = create_icon ();
+ }
+
+ return icon;
+ }
+}
diff --git a/po/indicator-keyboard.pot b/po/indicator-keyboard.pot
index a96fdd39..171c3021 100644
--- a/po/indicator-keyboard.pot
+++ b/po/indicator-keyboard.pot
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2013-07-18 18:00-0400\n"
+"POT-Creation-Date: 2013-08-07 15:03-0400\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -17,14 +17,14 @@ msgstr ""
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
-#: ../lib/main.c:2297 ../lib/main.vala:532
+#: ../lib/main.c:1405 ../lib/main.vala:322
msgid "Character Map"
msgstr ""
-#: ../lib/main.c:2299 ../lib/main.vala:533
+#: ../lib/main.c:1407 ../lib/main.vala:323
msgid "Keyboard Layout Chart"
msgstr ""
-#: ../lib/main.c:2301 ../lib/main.vala:534
+#: ../lib/main.c:1409 ../lib/main.vala:324
msgid "Text Entry Settings..."
msgstr ""
diff --git a/tests/main.vala b/tests/main.vala
index 36a915c7..d9d52733 100644
--- a/tests/main.vala
+++ b/tests/main.vala
@@ -31,12 +31,12 @@ public class Service : Object {
}
public void execute (string command) {
- this._command = command;
+ _command = command;
- var pspec = this.get_class ().find_property ("command");
+ var pspec = get_class ().find_property ("command");
if (pspec != null) {
- this.notify["command"] ((!) pspec);
+ notify["command"] ((!) pspec);
}
}
}
@@ -165,11 +165,13 @@ static void test_activate_input_source (void *data) {
var state = action_group.get_action_state ("current");
var current = state.get_uint32 ();
+ stderr.printf ("current = %u\n", current);
assert (current == 2);
try {
string output;
Process.spawn_command_line_sync ("gsettings get org.gnome.desktop.input-sources current", out output);
+ stderr.printf ("output = \"%s\"\n", output);
assert (strcmp (output, "uint32 2\n") == 0);
} catch (SpawnError error) {
Test.message ("error: %s", error.message);
@@ -202,6 +204,7 @@ static void test_activate_character_map (void *data) {
Source.remove (source);
((!) fixture.service).disconnect (signal_name);
+ stderr.printf ("fixture.service.command = \"%s\"\n", (!) ((!) fixture.service).command);
assert (strcmp ((!) ((!) fixture.service).command, "'gucharmap '") == 0);
}
@@ -240,6 +243,7 @@ static void test_activate_keyboard_layout_chart (void *data) {
Source.remove (source);
((!) fixture.service).disconnect (signal_name);
+ stderr.printf ("fixture.service.command = \"%s\"\n", (!) ((!) fixture.service).command);
assert (strcmp ((!) ((!) fixture.service).command, "'gkbd-keyboard-display -l ca\teng'") == 0);
}
@@ -267,6 +271,7 @@ static void test_activate_text_entry_settings (void *data) {
Source.remove (source);
((!) fixture.service).disconnect (signal_name);
+ stderr.printf ("fixture.service.command = \"%s\"\n", (!) ((!) fixture.service).command);
assert (strcmp ((!) ((!) fixture.service).command, "'gnome-control-center region layouts'") == 0);
}
@@ -323,6 +328,7 @@ static void test_migration (void *data) {
try {
string sources;
Process.spawn_command_line_sync ("gsettings get org.gnome.desktop.input-sources sources", out sources);
+ stderr.printf ("sources = \"%s\"\n", sources);
assert (strcmp (sources, "[('xkb', 'us'), ('xkb', 'ca+eng'), ('xkb', 'epo')]\n") == 0);
} catch (SpawnError error) {
Test.message ("error: %s", error.message);
@@ -384,6 +390,7 @@ static void test_no_migration (void *data) {
try {
string sources;
Process.spawn_command_line_sync ("gsettings get org.gnome.desktop.input-sources sources", out sources);
+ stderr.printf ("sources = \"%s\"\n", sources);
assert (strcmp (sources, "[('xkb', 'us')]\n") == 0);
} catch (SpawnError error) {
Test.message ("error: %s", error.message);
@@ -429,6 +436,7 @@ static void test_update_visible (void *data) {
var state = action_group.get_action_state ("indicator");
assert (state.lookup ("visible", "b", out visible));
+ stderr.printf ("visible = %s\n", visible ? "true" : "false");
assert (visible);
loop = new MainLoop (null, false);
@@ -452,6 +460,7 @@ static void test_update_visible (void *data) {
state = action_group.get_action_state ("indicator");
assert (state.lookup ("visible", "b", out visible));
+ stderr.printf ("visible = %s\n", visible ? "true" : "false");
assert (!visible);
loop = new MainLoop (null, false);
@@ -475,6 +484,7 @@ static void test_update_visible (void *data) {
state = action_group.get_action_state ("indicator");
assert (state.lookup ("visible", "b", out visible));
+ stderr.printf ("visible = %s\n", visible ? "true" : "false");
assert (visible);
}
@@ -524,11 +534,13 @@ static void test_update_input_source (void *data) {
var state = action_group.get_action_state ("current");
var current = state.get_uint32 ();
+ stderr.printf ("current = %u\n", current);
assert (current == 1);
try {
string output;
Process.spawn_command_line_sync ("gsettings get org.gnome.desktop.input-sources current", out output);
+ stderr.printf ("output = \"%s\"\n", output);
assert (strcmp (output, "uint32 1\n") == 0);
} catch (SpawnError error) {
Test.message ("error: %s", error.message);
@@ -557,11 +569,13 @@ static void test_update_input_source (void *data) {
state = action_group.get_action_state ("current");
current = state.get_uint32 ();
+ stderr.printf ("current = %u\n", current);
assert (current == 0);
try {
string output;
Process.spawn_command_line_sync ("gsettings get org.gnome.desktop.input-sources current", out output);
+ stderr.printf ("output = \"%s\"\n", output);
assert (strcmp (output, "uint32 0\n") == 0);
} catch (SpawnError error) {
Test.message ("error: %s", error.message);
@@ -633,8 +647,10 @@ static void test_update_input_sources (void *data) {
string label;
+ stderr.printf ("section.get_n_items () = %d\n", section.get_n_items ());
assert (section.get_n_items () == 1);
section.get_item_attribute (0, Menu.ATTRIBUTE_LABEL, "s", out label);
+ stderr.printf ("label = \"%s\"\n", label);
assert (strcmp (label, "English (US)") == 0);
loop = new MainLoop (null, false);
@@ -658,14 +674,19 @@ static void test_update_input_sources (void *data) {
Source.remove (source);
section.disconnect (signal_name);
+ stderr.printf ("section.get_n_items () = %d\n", section.get_n_items ());
assert (section.get_n_items () == 4);
section.get_item_attribute (0, Menu.ATTRIBUTE_LABEL, "s", out label);
+ stderr.printf ("label = \"%s\"\n", label);
assert (strcmp (label, "English (US)") == 0);
section.get_item_attribute (1, Menu.ATTRIBUTE_LABEL, "s", out label);
+ stderr.printf ("label = \"%s\"\n", label);
assert (strcmp (label, "English (Canada)") == 0);
section.get_item_attribute (2, Menu.ATTRIBUTE_LABEL, "s", out label);
+ stderr.printf ("label = \"%s\"\n", label);
assert (strcmp (label, "Esperanto") == 0);
section.get_item_attribute (3, Menu.ATTRIBUTE_LABEL, "s", out label);
+ stderr.printf ("label = \"%s\"\n", label);
assert (label.ascii_casecmp ("Pinyin") == 0);
}