/* -*- 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
{
if (main_window.menubar.user_language!="")
greeter.set_language(main_window.menubar.user_language);
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;
}