aboutsummaryrefslogtreecommitdiff
path: root/lib/main.vala
diff options
context:
space:
mode:
Diffstat (limited to 'lib/main.vala')
-rw-r--r--lib/main.vala483
1 files changed, 432 insertions, 51 deletions
diff --git a/lib/main.vala b/lib/main.vala
index 91466f8c..66147b18 100644
--- a/lib/main.vala
+++ b/lib/main.vala
@@ -19,6 +19,7 @@
[DBus (name = "com.canonical.indicator.keyboard")]
public class Indicator.Keyboard.Service : Object {
+ private static Service service;
private static IBus.Bus? ibus;
private bool force;
@@ -29,6 +30,7 @@ public class Indicator.Keyboard.Service : Object {
private Settings indicator_settings;
private Settings source_settings;
private Settings per_window_settings;
+ private SList<Act.User> users;
private Bamf.Matcher? matcher;
private Gee.HashMap<string, uint>? window_sources;
@@ -39,6 +41,10 @@ public class Indicator.Keyboard.Service : Object {
private MenuModel? menu_model;
private Menu? sources_menu;
+ private Greeter? greeter;
+ private string? greeter_user;
+ private uint lightdm_current;
+
[DBus (visible = false)]
public Service (ref unowned string[] args) {
force = "--force" in args;
@@ -51,6 +57,18 @@ public class Indicator.Keyboard.Service : Object {
Gdk.init (ref args);
}
+ if (is_login_user ()) {
+ var name = Environment.get_variable ("UNITY_GREETER_DBUS_NAME");
+
+ if (name != null) {
+ Bus.watch_name (BusType.SESSION,
+ (!) name,
+ BusNameWatcherFlags.NONE,
+ handle_name_appeared,
+ handle_name_vanished);
+ }
+ }
+
indicator_settings = new Settings ("com.canonical.indicator.keyboard");
indicator_settings.changed["visible"].connect (handle_changed_visible);
@@ -67,6 +85,11 @@ public class Indicator.Keyboard.Service : Object {
}
[DBus (visible = false)]
+ private static bool is_login_user () {
+ return Environment.get_user_name () == "lightdm";
+ }
+
+ [DBus (visible = false)]
private static IBus.Bus get_ibus () {
if (ibus == null) {
IBus.init ();
@@ -77,6 +100,22 @@ public class Indicator.Keyboard.Service : Object {
}
[DBus (visible = false)]
+ public void up () {
+ if (loop == null) {
+ loop = new MainLoop ();
+ ((!) loop).run ();
+ }
+ }
+
+ [DBus (visible = false)]
+ public void down () {
+ if (loop != null) {
+ ((!) loop).quit ();
+ loop = null;
+ }
+ }
+
+ [DBus (visible = false)]
private void acquire_bus_name () {
Bus.own_name (BusType.SESSION,
"com.canonical.indicator.keyboard",
@@ -84,71 +123,348 @@ public class Indicator.Keyboard.Service : Object {
handle_bus_acquired,
null,
handle_name_lost);
-
- loop = new MainLoop ();
- ((!) loop).run ();
}
[DBus (visible = false)]
- private void migrate_keyboard_layouts () {
- if (!indicator_settings.get_boolean ("migrated")) {
- var builder = new VariantBuilder (new VariantType ("a(ss)"));
- var length = 0;
+ private void update_greeter_user () {
+ if (greeter_user == null && greeter != null) {
+ try {
+ greeter_user = ((!) greeter).get_active_entry ();
+ } catch (IOError error) {
+ warning ("error: %s", error.message);
+ }
+ }
- var layout_settings = new Settings ("org.gnome.libgnomekbd.keyboard");
- var layouts = layout_settings.get_strv ("layouts");
+ string? source = null;
- foreach (var layout in layouts) {
- var source = layout;
+ if (greeter_user != null) {
+ var manager = Act.UserManager.get_default ();
- source = source.replace (" ", "+");
- source = source.replace ("\t", "+");
+ if (manager.is_loaded) {
+ Act.User? user = manager.get_user ((!) greeter_user);
- builder.add ("(ss)", "xkb", source);
- length++;
- }
+ if (user != null && ((!) user).is_loaded) {
+ VariantIter outer;
+ VariantIter inner;
+
+ var sources = ((!) user).input_sources;
+ sources.get ("aa{ss}", out outer);
- var engines = get_ibus ().list_active_engines ();
+ while (outer.next ("a{ss}", out inner)) {
+ unowned string key;
+ unowned string value;
- foreach (var engine in engines) {
- if (length == 0 || engine.name.has_prefix ("xkb")) {
- var source = "us";
- string? layout = engine.get_layout ();
- string? variant = engine.get_layout_variant ();
+ while (inner.next ("{&s&s}", out key, out value)) {
+ if (key == "xkb") {
+ source = value;
+ break;
+ }
+ }
- if (layout != null && ((!) layout).length == 0) {
- layout = null;
+ if (source != null) {
+ break;
+ }
}
- if (variant != null && ((!) variant).length == 0) {
- variant = null;
+ if (source == null) {
+ var layouts = ((!) user).xkeyboard_layouts;
+
+ if (layouts.length <= 0) {
+ var user_list = LightDM.UserList.get_instance ();
+ LightDM.User? light_user = user_list.get_user_by_name ((!) greeter_user);
+
+ if (light_user != null) {
+ layouts = ((!) light_user).get_layouts ();
+ }
+ }
+
+ if (layouts.length > 0) {
+ source = layouts[0];
+ source = ((!) source).replace (" ", "+");
+ source = ((!) source).replace ("\t", "+");
+ }
}
+ }
+ }
+ }
+
+ if (source == null) {
+ LightDM.Layout? layout = LightDM.get_layout ();
+
+ if (layout != null) {
+ source = ((!) layout).name;
+
+ if (source != null) {
+ source = ((!) source).replace (" ", "+");
+ source = ((!) source).replace ("\t", "+");
+ }
+ }
+ }
+
+ if (source != null) {
+ var array = source_settings.get_value ("sources");
+
+ for (int i = 0; i < array.n_children (); i++) {
+ unowned string type;
+ unowned string name;
- if (layout != null && variant != null) {
- source = @"$((!) layout)+$((!) variant)";
- } else if (layout != null) {
- source = (!) layout;
+ array.get_child (i, "(&s&s)", out type, out name);
+
+ if (type == "xkb" && name == (!) source) {
+ source_settings.set_uint ("current", i);
+ break;
+ }
+ }
+ }
+ }
+
+ [DBus (visible = false)]
+ private void handle_entry_selected (string entry_name) {
+ if (greeter_user == null || entry_name != (!) greeter_user) {
+ greeter_user = entry_name;
+
+ update_greeter_user ();
+ }
+ }
+
+ [DBus (visible = false)]
+ private void migrate_keyboard_layouts () {
+ if (is_login_user ()) {
+ lightdm_current = source_settings.get_uint ("current");
+
+ var manager = Act.UserManager.get_default ();
+
+ if (manager.is_loaded) {
+ users = manager.list_users ();
+
+ foreach (var user in users) {
+ if (user.is_loaded) {
+ migrate_input_sources ();
+ } else {
+ user.notify["is-loaded"].connect ((pspec) => {
+ if (user.is_loaded) {
+ migrate_input_sources ();
+ }
+ });
}
+ }
+ } else {
+ manager.notify["is-loaded"].connect ((pspec) => {
+ if (manager.is_loaded) {
+ users = manager.list_users ();
+
+ foreach (var user in users) {
+ if (user.is_loaded) {
+ migrate_input_sources ();
+ } else {
+ user.notify["is-loaded"].connect ((pspec) => {
+ if (user.is_loaded) {
+ migrate_input_sources ();
+ }
+ });
+ }
+ }
+ }
+ });
+ }
+
+ var user_list = LightDM.UserList.get_instance ();
+
+ user_list.user_added.connect ((user) => { migrate_input_sources (); });
+ user_list.user_changed.connect ((user) => { migrate_input_sources (); });
+ user_list.user_removed.connect ((user) => { migrate_input_sources (); });
+
+ /* Force the loading of the user list. */
+ user_list.get_user_by_name ("");
+ } else {
+ if (!indicator_settings.get_boolean ("migrated")) {
+ var builder = new VariantBuilder (new VariantType ("a(ss)"));
+ var length = 0;
+
+ var layout_settings = new Settings ("org.gnome.libgnomekbd.keyboard");
+ var layouts = layout_settings.get_strv ("layouts");
+
+ foreach (var layout in layouts) {
+ var source = layout;
+ source = source.replace (" ", "+");
+ source = source.replace ("\t", "+");
builder.add ("(ss)", "xkb", source);
length++;
}
- if (!engine.name.has_prefix ("xkb")) {
- builder.add ("(ss)", "ibus", engine.name);
- length++;
+ var engines = get_ibus ().list_active_engines ();
+
+ foreach (var engine in engines) {
+ if (length == 0 || engine.name.has_prefix ("xkb")) {
+ var source = "us";
+ string? layout = engine.get_layout ();
+ string? variant = engine.get_layout_variant ();
+
+ if (layout != null && ((!) layout).length == 0) {
+ layout = null;
+ }
+
+ if (variant != null && ((!) variant).length == 0) {
+ variant = null;
+ }
+
+ if (layout != null && variant != null) {
+ source = @"$((!) layout)+$((!) variant)";
+ } else if (layout != null) {
+ source = (!) layout;
+ }
+
+ builder.add ("(ss)", "xkb", source);
+ length++;
+ }
+
+ if (!engine.name.has_prefix ("xkb")) {
+ builder.add ("(ss)", "ibus", engine.name);
+ length++;
+ }
+ }
+
+ source_settings.set_value ("sources", builder.end ());
+ indicator_settings.set_boolean ("migrated", true);
+ }
+ }
+ }
+
+ [DBus (visible = false)]
+ private void migrate_input_sources () {
+ var list = new Gee.LinkedList<string> ();
+ var added = new Gee.HashSet<string> ();
+
+ foreach (var user in users) {
+ if (user.is_loaded) {
+ var done = false;
+
+ VariantIter outer;
+ VariantIter inner;
+
+ var sources = user.input_sources;
+ sources.get ("aa{ss}", out outer);
+
+ while (outer.next ("a{ss}", out inner)) {
+ unowned string key;
+ unowned string source;
+
+ while (inner.next ("{&s&s}", out key, out source)) {
+ if (key == "xkb") {
+ done = true;
+
+ if (!added.contains (source)) {
+ list.add (source);
+ added.add (source);
+ }
+ }
+ }
+ }
+
+ if (!done) {
+ var layouts = user.xkeyboard_layouts;
+ foreach (var layout in layouts) {
+ done = true;
+
+ var source = layout;
+ source = source.replace (" ", "+");
+ source = source.replace ("\t", "+");
+
+ if (!added.contains (source)) {
+ list.add (source);
+ added.add (source);
+ }
+ }
+ }
+
+ if (!done) {
+ var user_list = LightDM.UserList.get_instance ();
+ LightDM.User? light_user = user_list.get_user_by_name (user.user_name);
+
+ if (light_user != null) {
+ var layouts = ((!) light_user).get_layouts ();
+ foreach (var layout in layouts) {
+ done = true;
+
+ var source = layout;
+ source = source.replace (" ", "+");
+ source = source.replace ("\t", "+");
+
+ if (!added.contains (source)) {
+ list.add (source);
+ added.add (source);
+ }
+ }
+ }
}
}
+ }
+
+ LightDM.Layout? layout = LightDM.get_layout ();
+
+ if (layout != null) {
+ string? source = ((!) layout).name;
+
+ if (source != null) {
+ source = ((!) source).replace (" ", "+");
+ source = ((!) source).replace ("\t", "+");
+
+ if (!added.contains ((!) source)) {
+ list.add ((!) source);
+ added.add ((!) source);
+ }
+ }
+ }
+
+ var builder = new VariantBuilder (new VariantType ("a(ss)"));
+
+ foreach (var name in list) {
+ builder.add ("(ss)", "xkb", name);
+ }
+
+ if (lightdm_current < list.size) {
+ source_settings.set_uint ("current", lightdm_current);
+ } else {
+ source_settings.set_uint ("current", list.size - 1);
+ }
+
+ source_settings.set_value ("sources", builder.end ());
+
+ update_greeter_user ();
+ }
- source_settings.set_value ("sources", builder.end ());
+ [DBus (visible = false)]
+ private void update_login_layout () {
+ if (is_login_user ()) {
+ unowned List<LightDM.Layout> layouts = LightDM.get_layouts ();
+ var current = source_settings.get_uint ("current");
+
+ if (current < get_sources ().length) {
+ var source = get_sources ()[current];
+ string? name = null;
+
+ if (source.layout != null && source.variant != null) {
+ name = @"$((!) source.layout)\t$((!) source.variant)";
+ } else if (source.layout != null) {
+ name = source.layout;
+ }
- indicator_settings.set_boolean ("migrated", true);
+ if (name != null) {
+ foreach (var layout in layouts) {
+ if (layout.name == (!) name) {
+ LightDM.set_layout (layout);
+ break;
+ }
+ }
+ }
+ }
}
}
[DBus (visible = false)]
private void update_window_sources () {
- if (use_bamf) {
+ if (use_bamf && !is_login_user ()) {
var group_per_window = per_window_settings.get_boolean ("group-per-window");
if (group_per_window != (window_sources != null)) {
@@ -220,16 +536,27 @@ public class Indicator.Keyboard.Service : Object {
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;
+ var sources = get_sources ();
+
+ Icon? icon = null;
+ string? name = null;
+
+ if (current < sources.length) {
+ icon = sources[current].icon;
+ name = sources[current].name;
+ }
+ var builder = new VariantBuilder (new VariantType ("a{sv}"));
+ builder.add ("{sv}", "visible", new Variant.boolean (visible));
+ if (name != null) {
+ var description = _ ("%s input source").printf ((!) name);
+ builder.add ("{sv}", "accessible-desc", new Variant.string (description));
+ }
if (icon != null) {
- state = new Variant.parsed ("{ 'visible' : <%b>, 'icon' : %v }", visible, ((!) icon).serialize ());
- } else {
- state = new Variant.parsed ("{ 'visible' : <%b> }", visible);
+ builder.add ("{sv}", "icon", ((!) icon).serialize ());
}
- get_indicator_action ().set_state (state);
+ get_indicator_action ().set_state (builder.end ());
}
[DBus (visible = false)]
@@ -244,13 +571,40 @@ public class Indicator.Keyboard.Service : Object {
}
[DBus (visible = false)]
+ private void handle_middle_click (Variant? parameter) {
+ handle_scroll_wheel (new Variant.int32 (-1));
+ }
+
+ [DBus (visible = false)]
+ private void handle_scroll_wheel (Variant? parameter) {
+ if (parameter != null) {
+ var sources = source_settings.get_value ("sources");
+ var current = source_settings.get_uint ("current");
+ var length = (int) sources.n_children ();
+
+ if (length > 0) {
+ var offset = parameter.get_int32 () % length;
+ source_settings.set_uint ("current", (current + (length - offset)) % length);
+ }
+ }
+ }
+
+ [DBus (visible = false)]
protected virtual SimpleActionGroup create_action_group (Action root_action) {
var group = new SimpleActionGroup ();
group.insert (root_action);
group.insert (source_settings.create_action ("current"));
- var action = new SimpleAction ("map", null);
+ var action = new SimpleAction ("next", null);
+ action.activate.connect (handle_middle_click);
+ group.insert (action);
+
+ action = new SimpleAction ("scroll", VariantType.INT32);
+ action.activate.connect (handle_scroll_wheel);
+ group.insert (action);
+
+ action = new SimpleAction ("map", null);
action.activate.connect (handle_activate_map);
group.insert (action);
@@ -318,14 +672,18 @@ public class Indicator.Keyboard.Service : Object {
submenu.append_section (null, section_menu);
- var section = new Menu ();
- section.append (_ ("Character Map"), "indicator.map");
- section.append (_ ("Keyboard Layout Chart"), "indicator.chart");
- section.append (_ ("Text Entry Settings..."), "indicator.settings");
- submenu.append_section (null, section);
+ if (!is_login_user ()) {
+ var section = new Menu ();
+ section.append (_ ("Character Map"), "indicator.map");
+ section.append (_ ("Keyboard Layout Chart"), "indicator.chart");
+ section.append (_ ("Text Entry Settings..."), "indicator.settings");
+ submenu.append_section (null, section);
+ }
var indicator = new MenuItem.submenu ("x", submenu);
indicator.set_attribute ("x-canonical-type", "s", "com.canonical.indicator.root");
+ indicator.set_attribute ("x-canonical-secondary-action", "s", "indicator.next");
+ indicator.set_attribute ("x-canonical-scroll-action", "s", "indicator.scroll");
indicator.set_detailed_action ("indicator.indicator");
menu.append_item (indicator);
@@ -349,6 +707,7 @@ public class Indicator.Keyboard.Service : Object {
[DBus (visible = false)]
private void handle_changed_current (string key) {
update_indicator_action ();
+ update_login_layout ();
}
[DBus (visible = false)]
@@ -357,6 +716,7 @@ public class Indicator.Keyboard.Service : Object {
update_sources_menu ();
update_indicator_action ();
+ update_login_layout ();
}
[DBus (visible = false)]
@@ -411,6 +771,21 @@ public class Indicator.Keyboard.Service : Object {
}
[DBus (visible = false)]
+ private void handle_name_appeared (DBusConnection connection, string name, string name_owner) {
+ try {
+ greeter = Bus.get_proxy_sync (BusType.SESSION, name, "/list");
+ ((!) greeter).entry_selected.connect (handle_entry_selected);
+ } catch (IOError error) {
+ warning ("error: %s", error.message);
+ }
+ }
+
+ [DBus (visible = false)]
+ private void handle_name_vanished (DBusConnection connection, string name) {
+ greeter = null;
+ }
+
+ [DBus (visible = false)]
private void handle_bus_acquired (DBusConnection connection, string name) {
try {
connection.export_action_group ("/com/canonical/indicator/keyboard", get_action_group ());
@@ -422,13 +797,19 @@ public class Indicator.Keyboard.Service : Object {
[DBus (visible = false)]
private void handle_name_lost (DBusConnection? connection, string name) {
- ((!) loop).quit ();
- loop = null;
+ down ();
}
[DBus (visible = false)]
public static int main (string[] args) {
- new Service (ref args);
+ Service.service = new Service (ref args);
+
+ Posix.signal (Posix.SIGTERM, (code) => {
+ Service.service.down ();
+ });
+
+ Service.service.up ();
+
return 0;
}
}