Description: TODO: Put a short summary on the line above and replace this paragraph with a longer explanation of this change. Complete the meta-information with other relevant fields (see below for details). To make it easier, the information below has been extracted from the changelog. Adjust it or drop it. . unity-greeter (0.2.9-0ubuntu1.4) precise; urgency=medium . * debian/patches/post-login-messages.patch: - Require user to acknowledge messages received after authentication is complete, for example if their password is about to expire. (LP: #1304866) Author: Robert Ancell Bug-Ubuntu: https://bugs.launchpad.net/bugs/1304866 --- The information above should follow the Patch Tagging Guidelines, please checkout http://dep.debian.net/deps/dep3/ to learn about the format. Here are templates for supplementary fields that you might want to add: Origin: , Bug: Bug-Debian: http://bugs.debian.org/ Bug-Ubuntu: https://launchpad.net/bugs/ Forwarded: Reviewed-By: Last-Update: --- unity-greeter-0.2.9.orig/po/es.po +++ unity-greeter-0.2.9/po/es.po @@ -122,5 +122,20 @@ msgstr "Iniciando sesión…" msgid "Login" msgstr "Iniciar sesión" +msgid "Language selection" +msgstr "Selección de idioma" + +msgid "User defined (Language Support)" +msgstr "Definido por el usuario (Soporte de idiomas)" + +msgid "Spanish" +msgstr "Español" + +msgid "Valencian" +msgstr "Valenciano" + +msgid "English" +msgstr "Inglés" + #~ msgid "Other..." #~ msgstr "Otros…" --- unity-greeter-0.2.9.orig/po/ca@valencia.po +++ unity-greeter-0.2.9/po/ca@valencia.po @@ -119,3 +119,18 @@ msgstr "" #: ../src/user-list.vala:503 msgid "Login" msgstr "" + +msgid "Language selection" +msgstr "Selecció d'idioma" + +msgid "User defined (Language Support)" +msgstr "Definit per l'usuari (Suport d'idioma)" + +msgid "English" +msgstr "Anglés" + +msgid "Spanish" +msgstr "Espanyol" + +msgid "Valencian" +msgstr "Valencià" --- unity-greeter-0.2.9.orig/po/ca.po +++ unity-greeter-0.2.9/po/ca.po @@ -119,3 +119,18 @@ msgstr "" #: ../src/user-list.vala:503 msgid "Login" msgstr "" + +msgid "Language selection" +msgstr "Selecció d'idioma" + +msgid "User defined (Language Support)" +msgstr "Definit per l'usuari (Suport d'idioma)" + +msgid "English" +msgstr "Anglés" + +msgid "Spanish" +msgstr "Espanyol" + +msgid "Valencian" +msgstr "Valencià" --- unity-greeter-0.2.9.orig/src/menubar.vala +++ unity-greeter-0.2.9/src/menubar.vala @@ -67,6 +67,7 @@ public class MenuBar : Gtk.MenuBar { public Background? background {get; construct; default = null;} public bool high_contrast {get; private set; default = false;} + public string user_language{get; private set; default = "";} public Gtk.Window? keyboard_window {get; private set; default = null;} public Gtk.AccelGroup? accel_group {get; construct;} @@ -228,6 +229,69 @@ public class MenuBar : Gtk.MenuBar return a11y_item; } +private Gtk.Widget make_language_selector () + { + var selector_item = new Gtk.MenuItem (); + var hbox = new Gtk.HBox (false, 3); + hbox.show (); + selector_item.add (hbox); + var label= new Gtk.Label(_("Language selection")); + label.show(); + hbox.add(label); + selector_item.show (); + + selector_item.submenu = new Gtk.Menu (); + Gtk.RadioMenuItem? default_item = null; + Gtk.RadioMenuItem? last_item = null; + + var selected = new Gtk.RadioMenuItem.with_label (last_item == null ? null : last_item.get_group (), _("User defined (Language Support)")); + selected.show (); + selector_item.submenu.append (selected); + last_item = selected; + + selected = new Gtk.RadioMenuItem.with_label (last_item == null ? null : last_item.get_group (), _("Spanish")); + selected.show (); + selector_item.submenu.append (selected); + last_item = selected; + selected.toggled.connect (spanish_toggled_cb); + + selected = new Gtk.RadioMenuItem.with_label (last_item == null ? null : last_item.get_group (), _("Valencian")); + selected.show (); + selector_item.submenu.append (selected); + last_item = selected; + selected.toggled.connect (valencian_toggled_cb); + + selected = new Gtk.RadioMenuItem.with_label (last_item == null ? null : last_item.get_group (), _("English")); + selected.show (); + selector_item.submenu.append (selected); + last_item = selected; + selected.toggled.connect (english_toggled_cb); + + return selector_item; + } + + private void spanish_toggled_cb(Gtk.CheckMenuItem item) + { + if(!item.active) + return; + user_language="es_ES"; + } + + private void valencian_toggled_cb(Gtk.CheckMenuItem item) + { + if(!item.active) + return; + user_language="ca_ES@valencia"; + } + + private void english_toggled_cb(Gtk.CheckMenuItem item) + { + if(!item.active) + return; + user_language="en"; + } + + private void layout_toggled_cb (Gtk.CheckMenuItem item) { if (!item.active) @@ -303,6 +367,10 @@ public class MenuBar : Gtk.MenuBar { var keyboard_item = make_keyboard_indicator (); insert (keyboard_item, (int) get_children ().length () - 1); + + var language_selector=make_language_selector(); + insert (language_selector, (int) get_children ().length () - 1); + } else if (indicator_name == "ug-accessibility") { --- unity-greeter-0.2.9.orig/src/unity-greeter.vala +++ unity-greeter-0.2.9/src/unity-greeter.vala @@ -426,6 +426,8 @@ public class UnityGreeter try { + if (main_window.menubar.user_language!="") + greeter.set_language(main_window.menubar.user_language); greeter.start_session_sync (user_list.session); } catch (Error e) --- /dev/null +++ unity-greeter-0.2.9/src/unity-greeter.vala.orig @@ -0,0 +1,1025 @@ +/* -*- Mode: Vala; indent-tabs-mode: nil; tab-width: 4 -*- + * + * Copyright (C) 2011 Canonical Ltd + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 3 as + * published by the Free Software Foundation. + * + * 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 . + * + * Authored by: Robert Ancell + */ + +public const int grid_size = 40; + +public class UnityGreeter +{ + static bool show_version = false; + public static bool test_mode = false; + public static const OptionEntry[] options = + { + { "version", 'v', 0, OptionArg.NONE, ref show_version, + /* Help string for command line --version flag */ + N_("Show release version"), null}, + { "test-mode", 0, 0, OptionArg.NONE, ref test_mode, + /* Help string for command line --test-mode flag */ + N_("Run in test mode"), null}, + { null } + }; + + private static Timer log_timer; + + private string state_file; + private KeyFile state; + + private static Cairo.XlibSurface background_surface; + + private SettingsDaemon settings_daemon; + + private MainWindow main_window; + public UserList user_list; + + private LightDM.Greeter greeter; + private bool prompted = false; + private bool unacknowledged_messages = false; + private bool clear_messages = false; + + private List active_prompts; + + /* User to authenticate against */ + private string ?authenticate_user = null; + + private const TestEntry[] test_entries = + { + { "has-password", "Has Password", "*", "uk;us", false, false, null }, + { "different-prompt", "Different Prompt", "*", "uk;us", false, false, null }, + { "no-password", "No Password", "*", "uk;us", false, false, null }, + { "change-password", "Change Password", "*", "uk;us", false, false, null }, + { "auth-error", "Auth Error", "*", "uk;us", false, false, null }, + { "two-factor", "Two Factor", "*", "uk;us", false, false, null }, + { "two-prompts", "Two Prompts", "*", "uk;us", false, false, null }, + { "info-prompt", "Info Prompt", "*", "uk;us", false, false, null }, + { "long-info-prompt", "Long Info Prompt", "*", "uk;us", false, false, null }, + { "wide-info-prompt", "Wide Info Prompt", "*", "uk;us", false, false, null }, + { "multi-info-prompt", "Multi Info Prompt", "*", "uk;us", false, false, null }, + { "very-very-long-name", "Long name (far too long to fit)", "*", "uk;us", false, false, null }, + { "long-name-and-messages", "Long name and messages", "*", "uk;us", false, true, null }, + { "active", "Active Account", "*", "uk;us", true, false, null }, + { "has-messages", "Has Messages", "*", "uk;us", false, true, null }, + { "gnome", "GNOME", "*", "uk;us", false, false, "gnome-shell" }, + { "locked", "Locked Account", "*", "uk;us", false, false, null }, + { "color-background", "Color Background", "#dd4814", "uk;us", false, false, null }, + { "white-background", "White Background", "#ffffff", "uk;us", false, false, null }, + { "black-background", "Black Background", "#000000", "uk;us", false, false, null }, + { "no-background", "No Background", null, "uk;us", false, false, null }, + { "unicode", "가나다라마", "*", "uk;us", false, false, null }, + { "system-layout", "System Layout", "*", null, false, false, null }, + { "four-layouts", "Four Layouts", "*", "de\tdvorak;ca;gb;fr\toss", false, false, null }, + { "hy-layout", "Layout Is 'hy'", "*", "am\teastern-alt", false, false, null }, // inherits parent layout's short_desc + { "no-response", "No Response", "*", null, false, false, null }, + { "messages-after-login", "Messages After Login", "*", null, false, false, null }, + { "", "", null, null, false, false, null } + }; + private List test_backgrounds; + private int n_test_entries = 0; + private string? test_username = null; + private bool test_prompted_sso = false; + private string test_two_prompts_first = null; + private bool test_request_new_password = false; + private string? test_new_password = null; + private bool test_is_authenticated = false; + private Canberra.Context canberra_context; + + public UnityGreeter () + { + greeter = new LightDM.Greeter (); + greeter.show_message.connect (show_message_cb); + greeter.show_prompt.connect (show_prompt_cb); + greeter.autologin_timer_expired.connect (() => { greeter.authenticate_autologin (); }); + greeter.authentication_complete.connect (authentication_complete_cb); + var connected = false; + try + { + connected = greeter.connect_sync (); + } + catch (Error e) + { + warning ("Failed to connect to LightDM daemon"); + } + if (!connected && !test_mode) + Posix.exit (Posix.EXIT_FAILURE); + + if (!test_mode) + { + settings_daemon = new SettingsDaemon (); + settings_daemon.start (); + } + + var state_dir = Path.build_filename (Environment.get_user_cache_dir (), "unity-greeter"); + DirUtils.create_with_parents (state_dir, 0775); + + state_file = Path.build_filename (state_dir, "state"); + state = new KeyFile (); + try + { + state.load_from_file (state_file, KeyFileFlags.NONE); + } + catch (Error e) + { + if (!(e is FileError.NOENT)) + warning ("Failed to load state from %s: %s\n", state_file, e.message); + } + var last_user = ""; + try + { + last_user = state.get_value ("greeter", "last-user"); + } + catch (Error e) {} + + main_window = new MainWindow (); + user_list = main_window.user_list; + + if (test_mode) + { + test_backgrounds = new List (); + try + { + var dir = Dir.open ("/usr/share/backgrounds/"); + while (true) + { + var bg = dir.read_name (); + if (bg == null) + break; + test_backgrounds.append ("/usr/share/backgrounds/" + bg); + } + } + catch (FileError e) + { + } + + while (add_test_entry ()); + user_list.offer_guest = true; + + main_window.key_press_event.connect (key_press_cb); + + if (last_user != null) + user_list.set_active_entry (last_user); + } + else + { + user_list.default_session = greeter.default_session_hint; + user_list.always_show_manual = greeter.show_manual_login_hint; + if (!greeter.hide_users_hint) + { + var users = LightDM.UserList.get_instance (); + users.user_added.connect (user_added_cb); + users.user_changed.connect (user_added_cb); + users.user_removed.connect (user_removed_cb); + foreach (var user in users.users) + user_added_cb (user); + } + + if (greeter.has_guest_account_hint) + { + debug ("Adding guest account entry"); + user_list.offer_guest = true; + } + + if (greeter.select_user_hint != null) + user_list.set_active_entry (greeter.select_user_hint); + else if (last_user != null) + user_list.set_active_entry (last_user); + } + + user_list.user_selected.connect (user_selected_cb); + user_list.respond_to_prompt.connect (respond_to_prompt_cb); + user_list.start_session.connect (start_session_cb); + user_selected_cb (user_list.selected); + + start_fake_wm (); + Gdk.threads_add_idle (ready_cb); + } + + private bool key_press_cb (Gdk.EventKey event) + { + if ((event.state & Gdk.CONTROL_MASK) == 0) + return false; + + switch (event.keyval) + { + case Gdk.KEY_plus: + add_test_entry (); + break; + case Gdk.KEY_minus: + remove_test_entry (); + break; + case Gdk.KEY_0: + while (remove_test_entry ()); + user_list.offer_guest = false; + break; + case Gdk.KEY_equal: + while (add_test_entry ()); + user_list.offer_guest = true; + break; + case Gdk.KEY_g: + user_list.offer_guest = false; + break; + case Gdk.KEY_G: + user_list.offer_guest = true; + break; + case Gdk.KEY_m: + user_list.always_show_manual = false; + break; + case Gdk.KEY_M: + user_list.always_show_manual = true; + break; + } + + return false; + } + + private bool add_test_entry () + { + var e = test_entries[n_test_entries]; + if (e.username == "") + return false; + + var background = e.background; + if (background == "*") + { + var background_index = 0; + for (var i = 0; i < n_test_entries; i++) + { + if (test_entries[i].background == "*") + background_index++; + } + if (test_backgrounds.length () > 0) + background = test_backgrounds.nth_data (background_index % test_backgrounds.length ()); + } + user_list.add_entry (e.username, e.real_name, background, make_layout_list (e.layouts), e.is_active, e.has_messages, e.session); + n_test_entries++; + + return true; + } + + private bool remove_test_entry () + { + if (n_test_entries == 0) + return false; + + user_list.remove_entry (test_entries[n_test_entries - 1].username); + n_test_entries--; + + return true; + } + + public static void add_style_class (Gtk.Widget widget) + { + /* Add style context class lightdm-user-list */ + var ctx = widget.get_style_context (); + ctx.add_class ("lightdm"); + } + + private List make_layout_list (string names) + { + var names_split = names.split (";"); + + var layouts = new List (); + foreach (var name in names_split) + { + var layout = get_layout_by_name (name); + if (layout != null) + layouts.append (layout); + } + + return layouts; + } + + public static LightDM.Layout? get_layout_by_name (string name) + { + foreach (var layout in LightDM.get_layouts ()) + { + if (layout.name == name) + return layout; + } + return null; + } + + private bool ready_cb () + { + debug ("starting system-ready sound"); + + /* Launch canberra */ + Canberra.Context.create (out canberra_context); + + if (UGSettings.get_boolean (UGSettings.KEY_PLAY_READY_SOUND)) + canberra_context.play (0, + Canberra.PROP_CANBERRA_XDG_THEME_NAME, + "ubuntu", + Canberra.PROP_EVENT_ID, + "system-ready"); + + return false; + } + + private void user_added_cb (LightDM.User user) + { + debug ("Adding/updating user %s (%s)", user.name, user.real_name); + + var label = user.real_name; + if (user.real_name == "") + label = user.name; + + var layouts = new List (); + foreach (var name in user.get_layouts ()) + { + var layout = get_layout_by_name (name); + if (layout != null) + layouts.append (layout); + } + + user_list.add_entry (user.name, label, user.background, layouts, user.logged_in, user.has_messages, user.session); + } + + private void user_removed_cb (LightDM.User user) + { + debug ("Removing user %s", user.name); + user_list.remove_entry (user.name); + } + + public void show () + { + debug ("Showing main window"); + main_window.show (); + main_window.get_window ().focus (Gdk.CURRENT_TIME); + } + + private void show_message_cb (string text, LightDM.MessageType type) + { + unacknowledged_messages = true; + if (clear_messages) + { + user_list.clear_messages (); + clear_messages = false; + } + user_list.show_message (text, type == LightDM.MessageType.ERROR); + } + + private void show_prompt_cb (string text, LightDM.PromptType type) + { + active_prompts.append (new Prompt (text, type)); + if (active_prompts.length () == 1) + set_prompt (text, type); + } + + private void set_prompt (string text, LightDM.PromptType type) + { + if (clear_messages) + { + user_list.clear_messages (); + clear_messages = false; + } + + /* Notify the greeter on what user has been logged */ + if (user_list.selected == "*other" && user_list.manual_username == null) + { + if (test_mode) + user_list.manual_username = test_username; + else + user_list.manual_username = greeter.authentication_user; + } + + prompted = true; + if (text == "Password: ") + text = _("Password:"); + if (text == "login:") + text = _("Username:"); + user_list.show_prompt (text, type == LightDM.PromptType.SECRET); + + /* Clear messages on the next prompt */ + clear_messages = true; + } + + private void background_loaded_cb (ParamSpec pspec) + { + if (user_list.background.alpha == 1.0) + { + user_list.background.notify["alpha"].disconnect (background_loaded_cb); + start_session (); + } + } + + private void start_session () + { + /* Set the background */ + var c = new Cairo.Context (background_surface); + user_list.background.draw_full (c, Background.DrawFlags.NONE); + c = null; + refresh_background (Gdk.Screen.get_default (), background_surface); + + try + { + greeter.start_session_sync (user_list.session); + } + catch (Error e) + { + warning ("Failed to start session: %s", e.message); + } + } + + private void authentication_complete_cb () + { + active_prompts = new List (); + + bool is_authenticated; + if (test_mode) + is_authenticated = test_is_authenticated; + else + is_authenticated = greeter.is_authenticated; + + if (is_authenticated) + { + /* Login immediately if prompted and user has acknowledged all messages */ + if (prompted && !unacknowledged_messages) + { + user_list.login_complete (); + if (!test_mode) + { + if (user_list.background.alpha == 1.0) + start_session (); + else + user_list.background.notify["alpha"].connect (background_loaded_cb); + } + else + { + /* Set the background */ + var c = new Cairo.Context (background_surface); + user_list.background.draw_full (c, Background.DrawFlags.NONE); + c = null; + refresh_background (Gdk.Screen.get_default (), background_surface); + + debug ("Successfully logged in! Quitting..."); + Gtk.main_quit (); + } + } + else + { + prompted = true; + user_list.show_authenticated (); + } + } + else + { + if (prompted) + { + /* Show an error if one wasn't provided */ + if (clear_messages) + user_list.clear_messages (); + if (!user_list.have_messages ()) + user_list.show_message (_("Invalid password, please try again"), true); + + /* Restart authentication */ + start_authentication (); + } + else + { + /* Show an error if one wasn't provided */ + if (!user_list.have_messages ()) + user_list.show_message (_("Failed to authenticate"), true); + + /* Stop authentication */ + user_list.show_authenticated (false); + } + } + } + + private void user_selected_cb (string? username) + { + state.set_value ("greeter", "last-user", username); + var data = state.to_data (); + try + { + FileUtils.set_contents (state_file, data); + } + catch (Error e) + { + debug ("Failed to write state: %s", e.message); + } + + user_list.clear_messages (); + start_authentication (); + } + + private void start_authentication () + { + prompted = false; + unacknowledged_messages = false; + active_prompts = new List (); + + /* Reset manual username */ + user_list.manual_username = null; + + clear_messages = false; + + if (test_mode) + { + test_username = null; + test_is_authenticated = false; + test_prompted_sso = false; + test_two_prompts_first = null; + test_request_new_password = false; + test_new_password = null; + + switch (user_list.selected) + { + case "*other": + if (authenticate_user != null) + { + test_username = authenticate_user; + authenticate_user = null; + show_prompt_cb (_("Password:"), LightDM.PromptType.SECRET); + } + else + show_prompt_cb (_("Username:"), LightDM.PromptType.QUESTION); + break; + case "*guest": + test_is_authenticated = true; + authentication_complete_cb (); + break; + case "different-prompt": + show_prompt_cb ("Secret word", LightDM.PromptType.SECRET); + break; + case "no-password": + test_is_authenticated = true; + authentication_complete_cb (); + break; + case "auth-error": + show_message_cb ("Authentication Error", LightDM.MessageType.ERROR); + test_is_authenticated = false; + authentication_complete_cb (); + break; + case "info-prompt": + show_message_cb ("Welcome to Unity Greeter", LightDM.MessageType.INFO); + show_prompt_cb (_("Password:"), LightDM.PromptType.SECRET); + break; + case "long-info-prompt": + show_message_cb ("Welcome to Unity Greeter\n\nWe like to annoy you with long messages.\nLike this one\n\nThis is the last line of a multiple line message.", LightDM.MessageType.INFO); + show_prompt_cb (_("Password:"), LightDM.PromptType.SECRET); + break; + case "wide-info-prompt": + show_message_cb ("Welcome to Unity Greeter, the greeteriest greeter that ever did appear in these fine lands", LightDM.MessageType.INFO); + show_prompt_cb (_("Password:"), LightDM.PromptType.SECRET); + break; + case "multi-info-prompt": + show_message_cb ("Welcome to Unity Greeter", LightDM.MessageType.INFO); + show_message_cb ("This is an error", LightDM.MessageType.ERROR); + show_message_cb ("You should have seen three messages", LightDM.MessageType.INFO); + show_prompt_cb (_("Password:"), LightDM.PromptType.SECRET); + break; + case "two-prompts": + show_prompt_cb (_("Favorite Color (blue):"), LightDM.PromptType.QUESTION); + show_prompt_cb (_("Password:"), LightDM.PromptType.SECRET); + break; + default: + show_prompt_cb (_("Password:"), LightDM.PromptType.SECRET); + break; + } + } + else + { + if (user_list.selected == "*other") + greeter.authenticate (); + else if (user_list.selected == "*guest") + greeter.authenticate_as_guest (); + else + greeter.authenticate (user_list.selected); + } + } + + private void respond_to_prompt_cb (string text) + { + unacknowledged_messages = false; + + /* Prompt complete */ + active_prompts.remove_link (active_prompts.first ()); + Prompt? next_prompt = null; + if (active_prompts.length () > 0) + { + next_prompt = active_prompts.nth_data (0); + active_prompts.remove (next_prompt); + } + + if (test_mode) + { + debug ("response %s", text); + switch (user_list.selected) + { + case "*other": + if (test_username == null) + { + debug ("username=%s", text); + test_username = text; + show_prompt_cb (_("Password:"), LightDM.PromptType.SECRET); + } + else + { + test_is_authenticated = text == "password"; + authentication_complete_cb (); + } + break; + case "two-factor": + if (!test_prompted_sso) + { + if (text == "password") + { + debug ("prompt otp"); + test_prompted_sso = true; + show_prompt_cb ("OTP:", LightDM.PromptType.QUESTION); + } + else + { + test_is_authenticated = false; + authentication_complete_cb (); + } + } + else + { + test_is_authenticated = text == "otp"; + authentication_complete_cb (); + } + break; + case "two-prompts": + if (test_two_prompts_first == null) + test_two_prompts_first = text; + else + { + test_is_authenticated = test_two_prompts_first == "blue" && text == "password"; + authentication_complete_cb (); + } + break; + case "change-password": + if (test_new_password != null) + { + test_is_authenticated = text == test_new_password; + authentication_complete_cb (); + } + else if (test_request_new_password) + { + test_new_password = text; + show_prompt_cb ("Retype new UNIX password: ", LightDM.PromptType.SECRET); + } + else + { + if (text != "password") + { + test_is_authenticated = false; + authentication_complete_cb (); + } + else + { + test_request_new_password = true; + show_message_cb ("You are required to change your password immediately (root enforced)", LightDM.MessageType.ERROR); + show_prompt_cb ("Enter new UNIX password: ", LightDM.PromptType.SECRET); + } + } + break; + case "no-response": + break; + case "locked": + test_is_authenticated = false; + show_message_cb ("Account is locked", LightDM.MessageType.ERROR); + authentication_complete_cb (); + break; + case "messages-after-login": + test_is_authenticated = text == "password"; + if (test_is_authenticated) + show_message_cb ("Congratulations on logging in!", LightDM.MessageType.INFO); + authentication_complete_cb (); + break; + default: + test_is_authenticated = text == "password"; + authentication_complete_cb (); + break; + } + } + else + greeter.respond (text); + + /* Move onto next prompt if there is one */ + if (next_prompt != null) + { + clear_messages = false; + set_prompt (next_prompt.text, next_prompt.type); + } + } + + private void start_session_cb () + { + var is_authenticated = false; + if (test_mode) + is_authenticated = test_is_authenticated; + else + is_authenticated = greeter.is_authenticated; + + /* Finish authentication (again) or restart it */ + if (is_authenticated) + { + unacknowledged_messages = false; + authentication_complete_cb (); + } + else + { + user_list.clear_messages (); + start_authentication (); + } + } + + private Gdk.FilterReturn focus_upon_map (Gdk.XEvent gxevent, Gdk.Event event) + { + var xevent = (X.Event*)gxevent; + if (xevent.type == X.EventType.MapNotify) + { + var display = Gdk.x11_lookup_xdisplay (xevent.xmap.display); + var xwin = xevent.xmap.window; + var win = Gdk.X11Window.foreign_new_for_display (display, xwin); + if (win != null) + { + /* Check to see if this window is our onboard window, since we don't want to focus it. */ + X.Window keyboard_xid = 0; + if (main_window.menubar.keyboard_window != null) + keyboard_xid = Gdk.X11Window.get_xid (main_window.menubar.keyboard_window.get_window ()); + + if (xwin != keyboard_xid && win.get_type_hint() != Gdk.WindowTypeHint.NOTIFICATION) + { + win.focus (Gdk.CURRENT_TIME); + + /* Make sure to keep keyboard above */ + if (main_window.menubar.keyboard_window != null) + main_window.menubar.keyboard_window.get_window ().raise (); + } + } + } + else if (xevent.type == X.EventType.UnmapNotify) + { + // Since we aren't keeping track of focus (for example, we don't + // track the Z stack of windows) like a normal WM would, when we + // decide here where to return focus after another window unmaps, + // we don't have much to go on. X will tell us if we should take + // focus back. (I could not find an obvious way to determine this, + // but checking if the X input focus is RevertTo.None seems + // reliable.) + + X.Window xwin; + int revert_to; + xevent.xunmap.display.get_input_focus (out xwin, out revert_to); + + if (revert_to == X.RevertTo.None) + { + main_window.get_window ().focus (Gdk.CURRENT_TIME); + + /* Make sure to keep keyboard above */ + if (main_window.menubar.keyboard_window != null) + main_window.menubar.keyboard_window.get_window ().raise (); + } + } + return Gdk.FilterReturn.CONTINUE; + } + + private void start_fake_wm () + { + /* We want new windows (e.g. the shutdown dialog) to gain focus. + We don't really need anything more than that (don't need alt-tab + since any dialog should be "modal" or at least dealt with before + continuing even if not actually marked as modal) */ + var root = Gdk.get_default_root_window (); + root.set_events (root.get_events () | Gdk.EventMask.SUBSTRUCTURE_MASK); + root.add_filter (focus_upon_map); + } + + private static Cairo.XlibSurface? create_root_surface (Gdk.Screen screen) + { + var visual = screen.get_system_visual (); + + unowned X.Display display = Gdk.X11Display.get_xdisplay (screen.get_display ()); + + var pixmap = X.CreatePixmap (display, + Gdk.X11Window.get_xid (screen.get_root_window ()), + screen.width (), + screen.height (), + visual.get_depth ()); + + /* Convert into a Cairo surface */ + var surface = new Cairo.XlibSurface (display, + pixmap, + Gdk.X11Visual.get_xvisual (visual), + screen.width (), screen.height ()); + + return surface; + } + + private void refresh_background (Gdk.Screen screen, Cairo.XlibSurface surface) + { + Gdk.flush (); + + unowned X.Display display = Gdk.X11Display.get_xdisplay (screen.get_display ()); + + /* Ensure Cairo has actually finished its drawing */ + surface.flush (); + /* Use this pixmap for the background */ + X.SetWindowBackgroundPixmap (display, + Gdk.X11Window.get_xid (screen.get_root_window ()), + surface.get_drawable ()); + + X.ClearWindow (display, Gdk.X11Window.get_xid (screen.get_root_window ())); + } + + private static void log_cb (string? log_domain, LogLevelFlags log_level, string message) + { + string prefix; + switch (log_level & LogLevelFlags.LEVEL_MASK) + { + case LogLevelFlags.LEVEL_ERROR: + prefix = "ERROR:"; + break; + case LogLevelFlags.LEVEL_CRITICAL: + prefix = "CRITICAL:"; + break; + case LogLevelFlags.LEVEL_WARNING: + prefix = "WARNING:"; + break; + case LogLevelFlags.LEVEL_MESSAGE: + prefix = "MESSAGE:"; + break; + case LogLevelFlags.LEVEL_INFO: + prefix = "INFO:"; + break; + case LogLevelFlags.LEVEL_DEBUG: + prefix = "DEBUG:"; + break; + default: + prefix = "LOG:"; + break; + } + + stderr.printf ("[%+.2fs] %s %s\n", log_timer.elapsed (), prefix, message); + } + + public static int main (string[] args) + { + /* Disable the stupid global menubar */ + Environment.unset_variable ("UBUNTU_MENUPROXY"); + + /* Initialize i18n */ + Intl.setlocale (LocaleCategory.ALL, ""); + Intl.bindtextdomain (Config.GETTEXT_PACKAGE, Config.LOCALEDIR); + Intl.bind_textdomain_codeset (Config.GETTEXT_PACKAGE, "UTF-8"); + Intl.textdomain (Config.GETTEXT_PACKAGE); + + /* Set up the accessibility stack, in case the user needs it for screen reading etc. */ + Environment.set_variable ("GTK_MODULES", "atk-bridge", false); + + Pid atspi_pid = 0; + + try + { + string[] argv; + + Shell.parse_argv ("/usr/lib/at-spi2-core/at-spi-bus-launcher --launch-immediately", out argv); + Process.spawn_async (null, + argv, + null, + SpawnFlags.SEARCH_PATH, + null, + out atspi_pid); + } + catch (Error e) + { + warning ("Error starting the at-spi registry: %s", e.message); + } + + Gtk.init (ref args); + + log_timer = new Timer (); + Log.set_default_handler (log_cb); + + debug ("Starting unity-greeter %s UID=%d LANG=%s", Config.VERSION, (int) Posix.getuid (), Environment.get_variable ("LANG")); + + /* Set the cursor to not be the crap default */ + debug ("Setting cursor"); + Gdk.get_default_root_window ().set_cursor (new Gdk.Cursor (Gdk.CursorType.LEFT_PTR)); + + /* Prepare to set the background */ + debug ("Creating background surface"); + background_surface = create_root_surface (Gdk.Screen.get_default ()); + + debug ("Loading command line options"); + var c = new OptionContext (/* Arguments and description for --help text */ + _("- Unity Greeter")); + c.add_main_entries (options, Config.GETTEXT_PACKAGE); + c.add_group (Gtk.get_option_group (true)); + try + { + c.parse (ref args); + } + catch (Error e) + { + stderr.printf ("%s\n", e.message); + stderr.printf (/* Text printed out when an unknown command-line argument provided */ + _("Run '%s --help' to see a full list of available command line options."), args[0]); + stderr.printf ("\n"); + return Posix.EXIT_FAILURE; + } + if (show_version) + { + /* Note, not translated so can be easily parsed */ + stderr.printf ("unity-greeter %s\n", Config.VERSION); + return Posix.EXIT_SUCCESS; + } + + if (test_mode) + debug ("Running in test mode"); + + /* Set GTK+ settings */ + debug ("Setting GTK+ settings"); + var settings = Gtk.Settings.get_default (); + var value = UGSettings.get_string (UGSettings.KEY_THEME_NAME); + if (value != "") + settings.set ("gtk-theme-name", value, null); + value = UGSettings.get_string (UGSettings.KEY_ICON_THEME_NAME); + if (value != "") + settings.set ("gtk-icon-theme-name", value, null); + value = UGSettings.get_string (UGSettings.KEY_FONT_NAME); + if (value != "") + settings.set ("gtk-font-name", value, null); + var double_value = UGSettings.get_double (UGSettings.KEY_XFT_DPI); + if (double_value != 0.0) + settings.set ("gtk-xft-dpi", (int) (1024 * double_value), null); + var boolean_value = UGSettings.get_boolean (UGSettings.KEY_XFT_ANTIALIAS); + settings.set ("gtk-xft-antialias", boolean_value, null); + value = UGSettings.get_string (UGSettings.KEY_XFT_HINTSTYLE); + if (value != "") + settings.set ("gtk-xft-hintstyle", value, null); + value = UGSettings.get_string (UGSettings.KEY_XFT_RGBA); + if (value != "") + settings.set ("gtk-xft-rgba", value, null); + + debug ("Creating Unity Greeter"); + var greeter = new UnityGreeter (); + + debug ("Showing greeter"); + greeter.show (); + + /* Launch the unity_support_test tool as an async process to cache + its result */ + var exec = new string[1]; + exec[0] = "/usr/lib/nux/unity_support_test"; + try { + Process.spawn_async (null, exec, null, SpawnFlags.SEARCH_PATH, null, null); + } catch (SpawnError e) { + warning ("Failed to spawn unity-support-test tool for pre-caching: %s", e.message); + } + + debug ("Starting main loop"); + Gtk.main (); + + if (atspi_pid != 0) + { + Posix.kill (atspi_pid, Posix.SIGKILL); + int status; + Posix.waitpid (atspi_pid, out status, 0); + atspi_pid = 0; + } + + return Posix.EXIT_SUCCESS; + } +} + +private class Prompt +{ + public string text; + public LightDM.PromptType type; + + public Prompt (string text, LightDM.PromptType type) + { + this.text = text; + this.type = type; + } +} + +private struct TestEntry +{ + string username; + string real_name; + string? background; + string? layouts; + bool is_active; + bool has_messages; + string? session; +}