diff options
author | Allan LeSage <allan.lesage@canonical.com> | 2013-11-21 10:37:31 -0600 |
---|---|---|
committer | Allan LeSage <allan.lesage@canonical.com> | 2013-11-21 10:37:31 -0600 |
commit | bf2aab363e93263b1615f1811524fb22b14bf34b (patch) | |
tree | 406500af69bd6555eb4e4dc63e3711bd341bb6b4 /lib | |
parent | f10353bc4208a48339cdc1e0656361b16636a3e2 (diff) | |
parent | f90c7c21d0e82779356eaa8ae471703cda45d7cc (diff) | |
download | ayatana-indicator-keyboard-bf2aab363e93263b1615f1811524fb22b14bf34b.tar.gz ayatana-indicator-keyboard-bf2aab363e93263b1615f1811524fb22b14bf34b.tar.bz2 ayatana-indicator-keyboard-bf2aab363e93263b1615f1811524fb22b14bf34b.zip |
Merge trunk, resolving Makefile conflict.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Makefile.am | 72 | ||||
-rw-r--r-- | lib/greeter.vala | 26 | ||||
-rw-r--r-- | lib/main.vala | 483 |
3 files changed, 497 insertions, 84 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am index 2e257df0..72f5f949 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -2,41 +2,47 @@ libexec_PROGRAMS = indicator-keyboard-service AM_CFLAGS = -w -DGNOME_DESKTOP_USE_UNSTABLE_API AM_LDFLAGS = -lm -AM_VALAFLAGS = --enable-experimental-non-null \ - --metadatadir $(top_srcdir)/deps \ +AM_VALAFLAGS = --metadatadir $(top_srcdir)/deps \ --vapidir $(top_srcdir)/deps -indicator_keyboard_service_SOURCES = main.vala \ - source.vala \ - common.vala -indicator_keyboard_service_VALAFLAGS = $(AM_VALAFLAGS) \ - --pkg gee-1.0 \ - --pkg posix \ - --pkg pangocairo \ - --pkg gtk+-3.0 \ - --pkg GDesktopEnums-3.0 \ - --pkg gnome-desktop-3.0 \ - --pkg Xkl-1.0 \ - --pkg Gkbd-3.0 \ - --pkg ibus-1.0 \ +indicator_keyboard_service_SOURCES = main.vala \ + source.vala \ + common.vala \ + greeter.vala +indicator_keyboard_service_VALAFLAGS = $(AM_VALAFLAGS) \ + --pkg gee-1.0 \ + --pkg posix \ + --pkg pangocairo \ + --pkg gtk+-3.0 \ + --pkg GDesktopEnums-3.0 \ + --pkg gnome-desktop-3.0 \ + --pkg Xkl-1.0 \ + --pkg Gkbd-3.0 \ + --pkg ibus-1.0 \ + --pkg accountsservice \ + --pkg liblightdm-gobject-1 \ --pkg libbamf3 -indicator_keyboard_service_CFLAGS = $(AM_CFLAGS) \ - $(GEE_CFLAGS) \ - $(PANGOCAIRO_CFLAGS) \ - $(GTK_CFLAGS) \ - $(GNOME_DESKTOP_CFLAGS) \ - $(LIBXKLAVIER_CFLAGS) \ - $(LIBGNOMEKBD_CFLAGS) \ - $(IBUS_CFLAGS) \ - $(BAMF_CFLAGS) \ +indicator_keyboard_service_CFLAGS = $(AM_CFLAGS) \ + $(GEE_CFLAGS) \ + $(PANGOCAIRO_CFLAGS) \ + $(GTK_CFLAGS) \ + $(GNOME_DESKTOP_CFLAGS) \ + $(LIBXKLAVIER_CFLAGS) \ + $(LIBGNOMEKBD_CFLAGS) \ + $(IBUS_CFLAGS) \ + $(ACCOUNTSSERVICE_CFLAGS) \ + $(LIGHTDM_CFLAGS) \ + $(BAMF_CFLAGS) \ $(COVERAGE_CFLAGS) -indicator_keyboard_service_LDFLAGS = $(AM_LDFLAGS) \ - $(GEE_LIBS) \ - $(PANGOCAIRO_LIBS) \ - $(GTK_LIBS) \ - $(GNOME_DESKTOP_LIBS) \ - $(LIBXKLAVIER_LIBS) \ - $(LIBGNOMEKBD_LIBS) \ - $(IBUS_LIBS) \ - $(BAMF_LIBS) \ +indicator_keyboard_service_LDFLAGS = $(AM_LDFLAGS) \ + $(GEE_LIBS) \ + $(PANGOCAIRO_LIBS) \ + $(GTK_LIBS) \ + $(GNOME_DESKTOP_LIBS) \ + $(LIBXKLAVIER_LIBS) \ + $(LIBGNOMEKBD_LIBS) \ + $(IBUS_LIBS) \ + $(ACCOUNTSSERVICE_LIBS) \ + $(LIGHTDM_LIBS) \ + $(BAMF_LIBS) \ $(COVERAGE_LDFLAGS) diff --git a/lib/greeter.vala b/lib/greeter.vala new file mode 100644 index 00000000..c378bbd5 --- /dev/null +++ b/lib/greeter.vala @@ -0,0 +1,26 @@ +/* + * 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> + */ + +[DBus (name="com.canonical.UnityGreeter.List")] +public interface Greeter : Object { + + public abstract string get_active_entry () throws IOError; + public abstract void set_active_entry (string entry_name) throws IOError; + + public signal void entry_selected (string entry_name); +} 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; } } |