summaryrefslogtreecommitdiffstats
path: root/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0')
-rw-r--r--src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/Makefile.kmk61
-rw-r--r--src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/config.h90
-rw-r--r--src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/greeter.c1442
-rw-r--r--src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/language.c416
-rw-r--r--src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/layout.c344
-rw-r--r--src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/power.c211
-rw-r--r--src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/session.c388
-rw-r--r--src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/system.c42
-rw-r--r--src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/user.c1655
9 files changed, 4649 insertions, 0 deletions
diff --git a/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/Makefile.kmk b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/Makefile.kmk
new file mode 100644
index 00000000..dfae0972
--- /dev/null
+++ b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/Makefile.kmk
@@ -0,0 +1,61 @@
+# $Id: Makefile.kmk $
+## @file
+# Makefile for liblighdm-gobject 1.5.0
+#
+
+#
+# Copyright (C) 2013-2023 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# 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, in 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 <https://www.gnu.org/licenses>.
+#
+# SPDX-License-Identifier: GPL-3.0-only
+#
+
+SUB_DEPTH = ../../../../../..
+include $(KBUILD_PATH)/subheader.kmk
+
+# The greeter module.
+LIBRARIES += VBox-liblightdm-gobject
+
+VBox-liblightdm-gobject_TEMPLATE = VBoxGuestR3Lib
+VBox-liblightdm-gobject_SDKS = VBoxGlib20WithIo
+VBox-liblightdm-gobject_INCS = \
+ /usr/include/glib-2.0 \
+ /usr/lib/i386-linux-gnu/glib-2.0/include \
+ /usr/lib/x86_64-linux-gnu/glib-2.0/include \
+ /usr/include/gio-unix-2.0
+ifdef VBOX_WITH_AUTOMATIC_DEFS_QUOTING
+ VBox-liblightdm-gobject_DEFS = \
+ CONFIG_DIR="/etc/lightdm" \
+ XSESSIONS_DIR="/usr/share/xsessions" \
+ REMOTE_SESSIONS_DIR="/usr/share/lightdm/remote-sessions"
+else
+ VBox-liblightdm-gobject_DEFS = \
+ CONFIG_DIR=\"/etc/lightdm\" \
+ XSESSIONS_DIR=\"/usr/share/xsessions\" \
+ REMOTE_SESSIONS_DIR=\"/usr/share/lightdm/remote-sessions\"
+endif
+VBox-liblightdm-gobject_SOURCES = \
+ greeter.c \
+ language.c \
+ layout.c \
+ power.c \
+ session.c \
+ system.c \
+ user.c
+
+include $(FILE_KBUILD_SUB_FOOTER)
diff --git a/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/config.h b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/config.h
new file mode 100644
index 00000000..c06fc08d
--- /dev/null
+++ b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/config.h
@@ -0,0 +1,90 @@
+/* config.h. Generated from config.h.in by configure. */
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Gettext package */
+#define GETTEXT_PACKAGE "lightdm"
+
+/* Greeter session */
+#define GREETER_SESSION "default"
+
+/* User to run greeter as */
+#define GREETER_USER "lightdm"
+
+/* Define to 1 if you have the `clearenv' function. */
+#define HAVE_CLEARENV 1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <security/pam_appl.h> header file. */
+#define HAVE_SECURITY_PAM_APPL_H 1
+
+/* Define to 1 if you have the `setresgid' function. */
+#define HAVE_SETRESGID 1
+
+/* Define to 1 if you have the `setresuid' function. */
+#define HAVE_SETRESUID 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#define LT_OBJDIR ".libs/"
+
+/* Define to 1 if your C compiler doesn't accept -c and -o together. */
+/* #undef NO_MINUS_C_MINUS_O */
+
+/* Name of package */
+#define PACKAGE "lightdm"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT ""
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "lightdm"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "lightdm 1.5.0"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "lightdm"
+
+/* Define to the home page for this package. */
+#define PACKAGE_URL ""
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "1.5.0"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* User session */
+#define USER_SESSION "default"
+
+/* Version number of package */
+#define VERSION "1.5.0"
diff --git a/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/greeter.c b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/greeter.c
new file mode 100644
index 00000000..3d44b562
--- /dev/null
+++ b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/greeter.c
@@ -0,0 +1,1442 @@
+/*
+ * Copyright (C) 2010 Robert Ancell.
+ * Author: Robert Ancell <robert.ancell@canonical.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 2 or version 3 of the License.
+ * See http://www.gnu.org/copyleft/lgpl.html the full text of the license.
+ */
+
+/*
+ * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
+ * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
+ * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
+ * a choice of LGPL license versions is made available with the language indicating
+ * that LGPLv2 or any later version may be used, or where a choice of which version
+ * of the LGPL is applied is otherwise unspecified.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <security/pam_appl.h>
+
+#include "lightdm/greeter.h"
+
+enum {
+ PROP_0,
+ PROP_DEFAULT_SESSION_HINT,
+ PROP_HIDE_USERS_HINT,
+ PROP_SHOW_MANUAL_LOGIN_HINT,
+ PROP_SHOW_REMOTE_LOGIN_HINT,
+ PROP_LOCK_HINT,
+ PROP_HAS_GUEST_ACCOUNT_HINT,
+ PROP_SELECT_USER_HINT,
+ PROP_SELECT_GUEST_HINT,
+ PROP_AUTOLOGIN_USER_HINT,
+ PROP_AUTOLOGIN_GUEST_HINT,
+ PROP_AUTOLOGIN_TIMEOUT_HINT,
+ PROP_AUTHENTICATION_USER,
+ PROP_IN_AUTHENTICATION,
+ PROP_IS_AUTHENTICATED,
+};
+
+enum {
+ SHOW_PROMPT,
+ SHOW_MESSAGE,
+ AUTHENTICATION_COMPLETE,
+ AUTOLOGIN_TIMER_EXPIRED,
+ LAST_SIGNAL
+};
+static guint signals[LAST_SIGNAL] = { 0 };
+
+typedef struct
+{
+ gboolean connected;
+
+ GIOChannel *to_server_channel, *from_server_channel;
+ guint8 *read_buffer;
+ gsize n_read;
+
+ gsize n_responses_waiting;
+ GList *responses_received;
+
+ GHashTable *hints;
+ guint autologin_timeout;
+
+ gchar *authentication_user;
+ gboolean in_authentication;
+ gboolean is_authenticated;
+ guint32 authenticate_sequence_number;
+ gboolean cancelling_authentication;
+} LightDMGreeterPrivate;
+
+G_DEFINE_TYPE (LightDMGreeter, lightdm_greeter, G_TYPE_OBJECT);
+
+#define GET_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_GREETER, LightDMGreeterPrivate)
+
+#define HEADER_SIZE 8
+#define MAX_MESSAGE_LENGTH 1024
+
+/* Messages from the greeter to the server */
+typedef enum
+{
+ GREETER_MESSAGE_CONNECT = 0,
+ GREETER_MESSAGE_AUTHENTICATE,
+ GREETER_MESSAGE_AUTHENTICATE_AS_GUEST,
+ GREETER_MESSAGE_CONTINUE_AUTHENTICATION,
+ GREETER_MESSAGE_START_SESSION,
+ GREETER_MESSAGE_CANCEL_AUTHENTICATION,
+ GREETER_MESSAGE_SET_LANGUAGE,
+ GREETER_MESSAGE_AUTHENTICATE_REMOTE
+} GreeterMessage;
+
+/* Messages from the server to the greeter */
+typedef enum
+{
+ SERVER_MESSAGE_CONNECTED = 0,
+ SERVER_MESSAGE_PROMPT_AUTHENTICATION,
+ SERVER_MESSAGE_END_AUTHENTICATION,
+ SERVER_MESSAGE_SESSION_RESULT
+} ServerMessage;
+
+/**
+ * lightdm_greeter_new:
+ *
+ * Create a new greeter.
+ *
+ * Return value: the new #LightDMGreeter
+ **/
+LightDMGreeter *
+lightdm_greeter_new ()
+{
+ return g_object_new (LIGHTDM_TYPE_GREETER, NULL);
+}
+
+static gboolean
+timed_login_cb (gpointer data)
+{
+ LightDMGreeter *greeter = data;
+ LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
+
+ priv->autologin_timeout = 0;
+ g_signal_emit (G_OBJECT (greeter), signals[AUTOLOGIN_TIMER_EXPIRED], 0);
+
+ return FALSE;
+}
+
+static guint32
+int_length ()
+{
+ return 4;
+}
+
+static void
+write_int (guint8 *buffer, gint buffer_length, guint32 value, gsize *offset)
+{
+ if (*offset + 4 >= buffer_length)
+ return;
+ buffer[*offset] = value >> 24;
+ buffer[*offset+1] = (value >> 16) & 0xFF;
+ buffer[*offset+2] = (value >> 8) & 0xFF;
+ buffer[*offset+3] = value & 0xFF;
+ *offset += 4;
+}
+
+static void
+write_string (guint8 *buffer, gint buffer_length, const gchar *value, gsize *offset)
+{
+ gint length = 0;
+
+ if (value)
+ length = strlen (value);
+ write_int (buffer, buffer_length, length, offset);
+ if (*offset + length >= buffer_length)
+ return;
+ memcpy (buffer + *offset, value, length);
+ *offset += length;
+}
+
+static guint32
+read_int (guint8 *message, gsize message_length, gsize *offset)
+{
+ guint32 value;
+ guint8 *buffer;
+
+ if (message_length - *offset < int_length ())
+ {
+ g_warning ("Not enough space for int, need %i, got %zi", int_length (), message_length - *offset);
+ return 0;
+ }
+
+ buffer = message + *offset;
+ value = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
+ *offset += int_length ();
+
+ return value;
+}
+
+static gchar *
+read_string (guint8 *message, gsize message_length, gsize *offset)
+{
+ guint32 length;
+ gchar *value;
+
+ length = read_int (message, message_length, offset);
+ if (message_length - *offset < length)
+ {
+ g_warning ("Not enough space for string, need %u, got %zu", length, message_length - *offset);
+ return g_strdup ("");
+ }
+
+ value = g_malloc (sizeof (gchar) * (length + 1));
+ memcpy (value, message + *offset, length);
+ value[length] = '\0';
+ *offset += length;
+
+ return value;
+}
+
+static guint32
+string_length (const gchar *value)
+{
+ if (value)
+ return int_length () + strlen (value);
+ else
+ return int_length ();
+}
+
+static void
+write_header (guint8 *buffer, gint buffer_length, guint32 id, guint32 length, gsize *offset)
+{
+ write_int (buffer, buffer_length, id, offset);
+ write_int (buffer, buffer_length, length, offset);
+}
+
+static guint32
+get_message_length (guint8 *message, gsize message_length)
+{
+ gsize offset = 4;
+ return read_int (message, message_length, &offset);
+}
+
+static void
+write_message (LightDMGreeter *greeter, guint8 *message, gsize message_length)
+{
+ LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
+ GIOStatus status;
+ GError *error = NULL;
+ guint32 stated_length;
+
+ /* Double check that we're sending well-formed messages. If we say we're
+ sending more than we do, we end up DOS'ing lightdm as it waits for the
+ rest. If we say we're sending less than we do, we confuse the heck out
+ of lightdm, as it starts reading headers from the middle of our
+ messages. */
+ stated_length = HEADER_SIZE + get_message_length (message, message_length);
+ if (stated_length != message_length)
+ {
+ g_warning ("Refusing to write malformed packet to daemon: declared size is %u, but actual size is %zu", stated_length, message_length);
+ return;
+ }
+
+ status = g_io_channel_write_chars (priv->to_server_channel, (gchar *) message, message_length, NULL, &error);
+ if (error)
+ g_warning ("Error writing to daemon: %s", error->message);
+ g_clear_error (&error);
+ if (status == G_IO_STATUS_NORMAL)
+ g_debug ("Wrote %zi bytes to daemon", message_length);
+ g_io_channel_flush (priv->to_server_channel, NULL);
+}
+
+static void
+handle_connected (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
+{
+ LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
+ gchar *version;
+ GString *hint_string;
+ int timeout;
+
+ version = read_string (message, message_length, offset);
+ hint_string = g_string_new ("");
+ while (*offset < message_length)
+ {
+ gchar *name, *value;
+
+ name = read_string (message, message_length, offset);
+ value = read_string (message, message_length, offset);
+ g_hash_table_insert (priv->hints, name, value);
+ g_string_append_printf (hint_string, " %s=%s", name, value);
+ }
+
+ g_debug ("Connected version=%s%s", version, hint_string->str);
+ g_free (version);
+ g_string_free (hint_string, TRUE);
+
+ /* Set timeout for default login */
+ timeout = lightdm_greeter_get_autologin_timeout_hint (greeter);
+ if (timeout)
+ {
+ g_debug ("Setting autologin timer for %d seconds", timeout);
+ priv->autologin_timeout = g_timeout_add (timeout * 1000, timed_login_cb, greeter);
+ }
+}
+
+static void
+handle_prompt_authentication (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
+{
+ LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
+ guint32 sequence_number, n_messages, i;
+ gchar *username;
+
+ sequence_number = read_int (message, message_length, offset);
+ if (sequence_number != priv->authenticate_sequence_number)
+ {
+ g_debug ("Ignoring prompt authentication with invalid sequence number %d", sequence_number);
+ return;
+ }
+
+ if (priv->cancelling_authentication)
+ {
+ g_debug ("Ignoring prompt authentication as waiting for it to cancel");
+ return;
+ }
+
+ /* Update username */
+ username = read_string (message, message_length, offset);
+ if (strcmp (username, "") == 0)
+ {
+ g_free (username);
+ username = NULL;
+ }
+ g_free (priv->authentication_user);
+ priv->authentication_user = username;
+
+ g_list_free_full (priv->responses_received, g_free);
+ priv->responses_received = NULL;
+ priv->n_responses_waiting = 0;
+
+ n_messages = read_int (message, message_length, offset);
+ g_debug ("Prompt user with %d message(s)", n_messages);
+
+ for (i = 0; i < n_messages; i++)
+ {
+ int style;
+ gchar *text;
+
+ style = read_int (message, message_length, offset);
+ text = read_string (message, message_length, offset);
+
+ // FIXME: Should stop on prompts?
+ switch (style)
+ {
+ case PAM_PROMPT_ECHO_OFF:
+ priv->n_responses_waiting++;
+ g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, text, LIGHTDM_PROMPT_TYPE_SECRET);
+ break;
+ case PAM_PROMPT_ECHO_ON:
+ priv->n_responses_waiting++;
+ g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, text, LIGHTDM_PROMPT_TYPE_QUESTION);
+ break;
+ case PAM_ERROR_MSG:
+ g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, text, LIGHTDM_MESSAGE_TYPE_ERROR);
+ break;
+ case PAM_TEXT_INFO:
+ g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, text, LIGHTDM_MESSAGE_TYPE_INFO);
+ break;
+ }
+
+ g_free (text);
+ }
+}
+
+static void
+handle_end_authentication (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
+{
+ LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
+ guint32 sequence_number, return_code;
+ gchar *username;
+
+ sequence_number = read_int (message, message_length, offset);
+
+ if (sequence_number != priv->authenticate_sequence_number)
+ {
+ g_debug ("Ignoring end authentication with invalid sequence number %d", sequence_number);
+ return;
+ }
+
+ username = read_string (message, message_length, offset);
+ return_code = read_int (message, message_length, offset);
+
+ g_debug ("Authentication complete for user %s with return code %d", username, return_code);
+
+ /* Update username */
+ if (strcmp (username, "") == 0)
+ {
+ g_free (username);
+ username = NULL;
+ }
+ g_free (priv->authentication_user);
+ priv->authentication_user = username;
+
+ priv->cancelling_authentication = FALSE;
+ priv->is_authenticated = (return_code == 0);
+
+ priv->in_authentication = FALSE;
+ g_signal_emit (G_OBJECT (greeter), signals[AUTHENTICATION_COMPLETE], 0);
+}
+
+static guint8 *
+read_message (LightDMGreeter *greeter, gsize *length, gboolean block)
+{
+ LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
+ gsize n_to_read, n_read;
+ guint8 *buffer;
+ GError *error = NULL;
+
+ /* Read the header, or the whole message if we already have that */
+ n_to_read = HEADER_SIZE;
+ if (priv->n_read >= HEADER_SIZE)
+ n_to_read += get_message_length (priv->read_buffer, priv->n_read);
+
+ do
+ {
+ GIOStatus status;
+ status = g_io_channel_read_chars (priv->from_server_channel,
+ (gchar *) priv->read_buffer + priv->n_read,
+ n_to_read - priv->n_read,
+ &n_read,
+ &error);
+ if (error)
+ g_warning ("Error reading from server: %s", error->message);
+ g_clear_error (&error);
+ if (status != G_IO_STATUS_NORMAL)
+ break;
+
+ g_debug ("Read %zi bytes from daemon", n_read);
+
+ priv->n_read += n_read;
+ } while (priv->n_read < n_to_read && block);
+
+ /* Stop if haven't got all the data we want */
+ if (priv->n_read != n_to_read)
+ return FALSE;
+
+ /* If have header, rerun for content */
+ if (priv->n_read == HEADER_SIZE)
+ {
+ n_to_read = get_message_length (priv->read_buffer, priv->n_read);
+ if (n_to_read > 0)
+ {
+ priv->read_buffer = g_realloc (priv->read_buffer, HEADER_SIZE + n_to_read);
+ return read_message (greeter, length, block);
+ }
+ }
+
+ buffer = priv->read_buffer;
+ *length = priv->n_read;
+
+ priv->read_buffer = g_malloc (priv->n_read);
+ priv->n_read = 0;
+
+ return buffer;
+}
+
+static gboolean
+from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data)
+{
+ LightDMGreeter *greeter = data;
+ guint8 *message;
+ gsize message_length, offset;
+ guint32 id;
+
+ message = read_message (greeter, &message_length, FALSE);
+ if (!message)
+ return TRUE;
+
+ offset = 0;
+ id = read_int (message, message_length, &offset);
+ read_int (message, message_length, &offset);
+ switch (id)
+ {
+ case SERVER_MESSAGE_PROMPT_AUTHENTICATION:
+ handle_prompt_authentication (greeter, message, message_length, &offset);
+ break;
+ case SERVER_MESSAGE_END_AUTHENTICATION:
+ handle_end_authentication (greeter, message, message_length, &offset);
+ break;
+ default:
+ g_warning ("Unknown message from server: %d", id);
+ break;
+ }
+ g_free (message);
+
+ return TRUE;
+}
+
+/**
+ * lightdm_greeter_connect_sync:
+ * @greeter: The greeter to connect
+ * @error: return location for a #GError, or %NULL
+ *
+ * Connects the greeter to the display manager. Will block until connected.
+ *
+ * Return value: #TRUE if successfully connected
+ **/
+gboolean
+lightdm_greeter_connect_sync (LightDMGreeter *greeter, GError **error)
+{
+ LightDMGreeterPrivate *priv;
+ const gchar *fd;
+ guint8 message[MAX_MESSAGE_LENGTH];
+ guint8 *response;
+ gsize response_length, offset = 0;
+ guint32 id;
+
+ g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
+
+ priv = GET_PRIVATE (greeter);
+
+ fd = g_getenv ("LIGHTDM_TO_SERVER_FD");
+ if (!fd)
+ {
+ g_warning ("No LIGHTDM_TO_SERVER_FD environment variable");
+ return FALSE;
+ }
+ priv->to_server_channel = g_io_channel_unix_new (atoi (fd));
+ g_io_channel_set_encoding (priv->to_server_channel, NULL, NULL);
+
+ fd = g_getenv ("LIGHTDM_FROM_SERVER_FD");
+ if (!fd)
+ {
+ g_warning ("No LIGHTDM_FROM_SERVER_FD environment variable");
+ return FALSE;
+ }
+ priv->from_server_channel = g_io_channel_unix_new (atoi (fd));
+ g_io_channel_set_encoding (priv->from_server_channel, NULL, NULL);
+ g_io_add_watch (priv->from_server_channel, G_IO_IN, from_server_cb, greeter);
+
+ g_debug ("Connecting to display manager...");
+ write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONNECT, string_length (VERSION), &offset);
+ write_string (message, MAX_MESSAGE_LENGTH, VERSION, &offset);
+ write_message (greeter, message, offset);
+
+ response = read_message (greeter, &response_length, TRUE);
+ if (!response)
+ return FALSE;
+
+ offset = 0;
+ id = read_int (response, response_length, &offset);
+ read_int (response, response_length, &offset);
+ if (id == SERVER_MESSAGE_CONNECTED)
+ handle_connected (greeter, response, response_length, &offset);
+ g_free (response);
+ if (id != SERVER_MESSAGE_CONNECTED)
+ {
+ g_warning ("Expected CONNECTED message, got %d", id);
+ return FALSE;
+ }
+
+ priv->connected = TRUE;
+
+ return TRUE;
+}
+
+/**
+ * lightdm_greeter_get_hint:
+ * @greeter: A #LightDMGreeter
+ * @name: The hint name to query.
+ *
+ * Get a hint.
+ *
+ * Return value: The value for this hint or #NULL if not set.
+ **/
+const gchar *
+lightdm_greeter_get_hint (LightDMGreeter *greeter, const gchar *name)
+{
+ g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
+ return g_hash_table_lookup (GET_PRIVATE (greeter)->hints, name);
+}
+
+/**
+ * lightdm_greeter_get_default_session_hint:
+ * @greeter: A #LightDMGreeter
+ *
+ * Get the default session to use.
+ *
+ * Return value: The session name
+ **/
+const gchar *
+lightdm_greeter_get_default_session_hint (LightDMGreeter *greeter)
+{
+ g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
+ return lightdm_greeter_get_hint (greeter, "default-session");
+}
+
+/**
+ * lightdm_greeter_get_hide_users_hint:
+ * @greeter: A #LightDMGreeter
+ *
+ * Check if user accounts should be shown. If this is TRUE then the list of
+ * accounts should be taken from #LightDMUserList and displayed in the greeter
+ * for the user to choose from. Note that this list can be empty and it is
+ * recommended you show a method for the user to enter a username manually.
+ *
+ * If this option is shown the greeter should only allow these users to be
+ * chosen for login unless the manual login hint is set.
+ *
+ * Return value: #TRUE if the available users should not be shown.
+ */
+gboolean
+lightdm_greeter_get_hide_users_hint (LightDMGreeter *greeter)
+{
+ const gchar *value;
+
+ g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
+ value = lightdm_greeter_get_hint (greeter, "hide-users");
+
+ return g_strcmp0 (value, "true") == 0;
+}
+
+/**
+ * lightdm_greeter_get_show_manual_login_hint:
+ * @greeter: A #LightDMGreeter
+ *
+ * Check if a manual login option should be shown. If set the GUI
+ * should provide a way for a username to be entered manually.
+ * Without this hint a greeter which is showing a user list can
+ * limit logins to only those users.
+ *
+ * Return value: #TRUE if a manual login option should be shown.
+ */
+gboolean
+lightdm_greeter_get_show_manual_login_hint (LightDMGreeter *greeter)
+{
+ const gchar *value;
+
+ g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
+ value = lightdm_greeter_get_hint (greeter, "show-manual-login");
+
+ return g_strcmp0 (value, "true") == 0;
+}
+
+/**
+ * lightdm_greeter_get_show_remote_login_hint:
+ * @greeter: A #LightDMGreeter
+ *
+ * Check if a remote login option should be shown. If set the GUI
+ * should provide a way for a user to log into a remote desktop server.
+ *
+ * Return value: #TRUE if a remote login option should be shown.
+ */
+gboolean
+lightdm_greeter_get_show_remote_login_hint (LightDMGreeter *greeter)
+{
+ const gchar *value;
+
+ g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
+ value = lightdm_greeter_get_hint (greeter, "show-remote-login");
+
+ return g_strcmp0 (value, "true") == 0;
+}
+
+/**
+ * lightdm_greeter_get_lock_hint:
+ * @greeter: A #LightDMGreeter
+ *
+ * Check if the greeter is acting as a lock screen.
+ *
+ * Return value: #TRUE if the greeter was triggered by locking the seat.
+ */
+gboolean
+lightdm_greeter_get_lock_hint (LightDMGreeter *greeter)
+{
+ const gchar *value;
+
+ g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
+ value = lightdm_greeter_get_hint (greeter, "lock-screen");
+
+ return g_strcmp0 (value, "true") == 0;
+}
+
+/**
+ * lightdm_greeter_get_has_guest_account_hint:
+ * @greeter: A #LightDMGreeter
+ *
+ * Check if guest sessions are supported.
+ *
+ * Return value: #TRUE if guest sessions are supported.
+ */
+gboolean
+lightdm_greeter_get_has_guest_account_hint (LightDMGreeter *greeter)
+{
+ const gchar *value;
+
+ g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
+ value = lightdm_greeter_get_hint (greeter, "has-guest-account");
+
+ return g_strcmp0 (value, "true") == 0;
+}
+
+/**
+ * lightdm_greeter_get_select_user_hint:
+ * @greeter: A #LightDMGreeter
+ *
+ * Get the user to select by default.
+ *
+ * Return value: A username
+ */
+const gchar *
+lightdm_greeter_get_select_user_hint (LightDMGreeter *greeter)
+{
+ g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
+ return lightdm_greeter_get_hint (greeter, "select-user");
+}
+
+/**
+ * lightdm_greeter_get_select_guest_hint:
+ * @greeter: A #LightDMGreeter
+ *
+ * Check if the guest account should be selected by default.
+ *
+ * Return value: #TRUE if the guest account should be selected by default.
+ */
+gboolean
+lightdm_greeter_get_select_guest_hint (LightDMGreeter *greeter)
+{
+ const gchar *value;
+
+ g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
+ value = lightdm_greeter_get_hint (greeter, "select-guest");
+
+ return g_strcmp0 (value, "true") == 0;
+}
+
+/**
+ * lightdm_greeter_get_autologin_user_hint:
+ * @greeter: A #LightDMGreeter
+ *
+ * Get the user account to automatically logg into when the timer expires.
+ *
+ * Return value: The user account to automatically log into.
+ */
+const gchar *
+lightdm_greeter_get_autologin_user_hint (LightDMGreeter *greeter)
+{
+ g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
+ return lightdm_greeter_get_hint (greeter, "autologin-user");
+}
+
+/**
+ * lightdm_greeter_get_autologin_guest_hint:
+ * @greeter: A #LightDMGreeter
+ *
+ * Check if the guest account should be automatically logged into when the timer expires.
+ *
+ * Return value: #TRUE if the guest account should be automatically logged into.
+ */
+gboolean
+lightdm_greeter_get_autologin_guest_hint (LightDMGreeter *greeter)
+{
+ const gchar *value;
+
+ g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
+ value = lightdm_greeter_get_hint (greeter, "autologin-guest");
+
+ return g_strcmp0 (value, "true") == 0;
+}
+
+/**
+ * lightdm_greeter_get_autologin_timeout_hint:
+ * @greeter: A #LightDMGreeter
+ *
+ * Get the number of seconds to wait before automaitcally logging in.
+ *
+ * Return value: The number of seconds to wait before automatically logging in or 0 for no timeout.
+ */
+gint
+lightdm_greeter_get_autologin_timeout_hint (LightDMGreeter *greeter)
+{
+ const gchar *value;
+ gint timeout = 0;
+
+ g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
+ value = lightdm_greeter_get_hint (greeter, "autologin-timeout");
+ if (value)
+ timeout = atoi (value);
+ if (timeout < 0)
+ timeout = 0;
+
+ return timeout;
+}
+
+/**
+ * lightdm_greeter_cancel_autologin:
+ * @greeter: A #LightDMGreeter
+ *
+ * Cancel the automatic login.
+ */
+void
+lightdm_greeter_cancel_autologin (LightDMGreeter *greeter)
+{
+ LightDMGreeterPrivate *priv;
+
+ g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
+
+ priv = GET_PRIVATE (greeter);
+
+ if (priv->autologin_timeout)
+ g_source_remove (priv->autologin_timeout);
+ priv->autologin_timeout = 0;
+}
+
+/**
+ * lightdm_greeter_authenticate:
+ * @greeter: A #LightDMGreeter
+ * @username: (allow-none): A username or #NULL to prompt for a username.
+ *
+ * Starts the authentication procedure for a user.
+ **/
+void
+lightdm_greeter_authenticate (LightDMGreeter *greeter, const gchar *username)
+{
+ LightDMGreeterPrivate *priv;
+ guint8 message[MAX_MESSAGE_LENGTH];
+ gsize offset = 0;
+
+ g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
+
+ priv = GET_PRIVATE (greeter);
+
+ g_return_if_fail (priv->connected);
+
+ priv->cancelling_authentication = FALSE;
+ priv->authenticate_sequence_number++;
+ priv->in_authentication = TRUE;
+ priv->is_authenticated = FALSE;
+ if (username != priv->authentication_user)
+ {
+ g_free (priv->authentication_user);
+ priv->authentication_user = g_strdup (username);
+ }
+
+ g_debug ("Starting authentication for user %s...", username);
+ write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE, int_length () + string_length (username), &offset);
+ write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
+ write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
+ write_message (greeter, message, offset);
+}
+
+/**
+ * lightdm_greeter_authenticate_as_guest:
+ * @greeter: A #LightDMGreeter
+ *
+ * Starts the authentication procedure for the guest user.
+ **/
+void
+lightdm_greeter_authenticate_as_guest (LightDMGreeter *greeter)
+{
+ LightDMGreeterPrivate *priv;
+ guint8 message[MAX_MESSAGE_LENGTH];
+ gsize offset = 0;
+
+ g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
+
+ priv = GET_PRIVATE (greeter);
+
+ g_return_if_fail (priv->connected);
+
+ priv->cancelling_authentication = FALSE;
+ priv->authenticate_sequence_number++;
+ priv->in_authentication = TRUE;
+ priv->is_authenticated = FALSE;
+ g_free (priv->authentication_user);
+ priv->authentication_user = NULL;
+
+ g_debug ("Starting authentication for guest account...");
+ write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE_AS_GUEST, int_length (), &offset);
+ write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
+ write_message (greeter, message, offset);
+}
+
+/**
+ * lightdm_greeter_authenticate_autologin:
+ * @greeter: A #LightDMGreeter
+ *
+ * Starts the authentication procedure for the automatic login user.
+ **/
+void
+lightdm_greeter_authenticate_autologin (LightDMGreeter *greeter)
+{
+ const gchar *user;
+
+ user = lightdm_greeter_get_autologin_user_hint (greeter);
+ if (lightdm_greeter_get_autologin_guest_hint (greeter))
+ lightdm_greeter_authenticate_as_guest (greeter);
+ else if (user)
+ lightdm_greeter_authenticate (greeter, user);
+}
+
+/**
+ * lightdm_greeter_authenticate_remote:
+ * @greeter: A #LightDMGreeter
+ * @session: The name of a remote session
+ * @username: (allow-none): A username of #NULL to prompt for a username.
+ *
+ * Start authentication for a remote session type.
+ **/
+void
+lightdm_greeter_authenticate_remote (LightDMGreeter *greeter, const gchar *session, const gchar *username)
+{
+ LightDMGreeterPrivate *priv;
+ guint8 message[MAX_MESSAGE_LENGTH];
+ gsize offset = 0;
+
+ g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
+
+ priv = GET_PRIVATE (greeter);
+
+ g_return_if_fail (priv->connected);
+
+ priv->cancelling_authentication = FALSE;
+ priv->authenticate_sequence_number++;
+ priv->in_authentication = TRUE;
+ priv->is_authenticated = FALSE;
+ g_free (priv->authentication_user);
+ priv->authentication_user = NULL;
+
+ if (username)
+ g_debug ("Starting authentication for remote session %s as user %s...", session, username);
+ else
+ g_debug ("Starting authentication for remote session %s...", session);
+ write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE_REMOTE, int_length () + string_length (session) + string_length (username), &offset);
+ write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset);
+ write_string (message, MAX_MESSAGE_LENGTH, session, &offset);
+ write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
+ write_message (greeter, message, offset);
+}
+
+/**
+ * lightdm_greeter_respond:
+ * @greeter: A #LightDMGreeter
+ * @response: Response to a prompt
+ *
+ * Provide response to a prompt. May be one in a series.
+ **/
+void
+lightdm_greeter_respond (LightDMGreeter *greeter, const gchar *response)
+{
+ LightDMGreeterPrivate *priv;
+ guint8 message[MAX_MESSAGE_LENGTH];
+ gsize offset = 0;
+
+ g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
+ g_return_if_fail (response != NULL);
+
+ priv = GET_PRIVATE (greeter);
+
+ g_return_if_fail (priv->connected);
+ g_return_if_fail (priv->n_responses_waiting > 0);
+
+ priv->n_responses_waiting--;
+ priv->responses_received = g_list_append (priv->responses_received, g_strdup (response));
+
+ if (priv->n_responses_waiting == 0)
+ {
+ guint32 msg_length;
+ GList *iter;
+
+ g_debug ("Providing response to display manager");
+
+ msg_length = int_length ();
+ for (iter = priv->responses_received; iter; iter = iter->next)
+ {
+ msg_length += string_length ((gchar *)iter->data);
+ }
+
+ write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONTINUE_AUTHENTICATION, msg_length, &offset);
+ write_int (message, MAX_MESSAGE_LENGTH, g_list_length (priv->responses_received), &offset);
+ for (iter = priv->responses_received; iter; iter = iter->next)
+ {
+ write_string (message, MAX_MESSAGE_LENGTH, (gchar *)iter->data, &offset);
+ }
+ write_message (greeter, message, offset);
+
+ g_list_free_full (priv->responses_received, g_free);
+ priv->responses_received = NULL;
+ }
+}
+
+/**
+ * lightdm_greeter_cancel_authentication:
+ * @greeter: A #LightDMGreeter
+ *
+ * Cancel the current user authentication.
+ **/
+void
+lightdm_greeter_cancel_authentication (LightDMGreeter *greeter)
+{
+ LightDMGreeterPrivate *priv;
+ guint8 message[MAX_MESSAGE_LENGTH];
+ gsize offset = 0;
+
+ g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
+
+ priv = GET_PRIVATE (greeter);
+
+ g_return_if_fail (priv->connected);
+
+ priv->cancelling_authentication = TRUE;
+ write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CANCEL_AUTHENTICATION, 0, &offset);
+ write_message (greeter, message, offset);
+}
+
+/**
+ * lightdm_greeter_get_in_authentication:
+ * @greeter: A #LightDMGreeter
+ *
+ * Checks if the greeter is in the process of authenticating.
+ *
+ * Return value: #TRUE if the greeter is authenticating a user.
+ **/
+gboolean
+lightdm_greeter_get_in_authentication (LightDMGreeter *greeter)
+{
+ g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
+ return GET_PRIVATE (greeter)->in_authentication;
+}
+
+/**
+ * lightdm_greeter_get_is_authenticated:
+ * @greeter: A #LightDMGreeter
+ *
+ * Checks if the greeter has successfully authenticated.
+ *
+ * Return value: #TRUE if the greeter is authenticated for login.
+ **/
+gboolean
+lightdm_greeter_get_is_authenticated (LightDMGreeter *greeter)
+{
+ g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
+ return GET_PRIVATE (greeter)->is_authenticated;
+}
+
+/**
+ * lightdm_greeter_get_authentication_user:
+ * @greeter: A #LightDMGreeter
+ *
+ * Get the user that is being authenticated.
+ *
+ * Return value: The username of the authentication user being authenticated or #NULL if no authentication in progress.
+ */
+const gchar *
+lightdm_greeter_get_authentication_user (LightDMGreeter *greeter)
+{
+ g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
+ return GET_PRIVATE (greeter)->authentication_user;
+}
+
+/**
+ * lightdm_greeter_set_language:
+ * @greeter: A #LightDMGreeter
+ * @language: The language to use for this user.
+ *
+ * Set the language for the currently authenticated user.
+ **/
+void
+lightdm_greeter_set_language (LightDMGreeter *greeter, const gchar *language)
+{
+ LightDMGreeterPrivate *priv;
+ guint8 message[MAX_MESSAGE_LENGTH];
+ gsize offset = 0;
+
+ g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
+
+ priv = GET_PRIVATE (greeter);
+
+ g_return_if_fail (priv->connected);
+
+ write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_SET_LANGUAGE, string_length (language), &offset);
+ write_string (message, MAX_MESSAGE_LENGTH, language, &offset);
+ write_message (greeter, message, offset);
+}
+
+/**
+ * lightdm_greeter_start_session_sync:
+ * @greeter: A #LightDMGreeter
+ * @session: (allow-none): The session to log into or #NULL to use the default.
+ * @error: return location for a #GError, or %NULL
+ *
+ * Start a session for the authenticated user.
+ *
+ * Return value: TRUE if the session was started.
+ **/
+gboolean
+lightdm_greeter_start_session_sync (LightDMGreeter *greeter, const gchar *session, GError **error)
+{
+ LightDMGreeterPrivate *priv;
+ guint8 message[MAX_MESSAGE_LENGTH];
+ guint8 *response;
+ gsize response_length, offset = 0;
+ guint32 id, return_code = 1;
+
+ g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
+
+ priv = GET_PRIVATE (greeter);
+
+ g_return_val_if_fail (priv->connected, FALSE);
+ g_return_val_if_fail (priv->is_authenticated, FALSE);
+
+ if (session)
+ g_debug ("Starting session %s", session);
+ else
+ g_debug ("Starting default session");
+
+ write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_START_SESSION, string_length (session), &offset);
+ write_string (message, MAX_MESSAGE_LENGTH, session, &offset);
+ write_message (greeter, message, offset);
+
+ response = read_message (greeter, &response_length, TRUE);
+ if (!response)
+ return FALSE;
+
+ offset = 0;
+ id = read_int (response, response_length, &offset);
+ read_int (response, response_length, &offset);
+ if (id == SERVER_MESSAGE_SESSION_RESULT)
+ return_code = read_int (response, response_length, &offset);
+ else
+ g_warning ("Expected SESSION_RESULT message, got %d", id);
+
+ g_free (response);
+
+ return return_code == 0;
+}
+
+static void
+lightdm_greeter_init (LightDMGreeter *greeter)
+{
+ LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
+
+ priv->read_buffer = g_malloc (HEADER_SIZE);
+ priv->hints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+}
+
+static void
+lightdm_greeter_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+}
+
+static void
+lightdm_greeter_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ LightDMGreeter *self;
+
+ self = LIGHTDM_GREETER (object);
+
+ switch (prop_id) {
+ case PROP_DEFAULT_SESSION_HINT:
+ g_value_set_string (value, lightdm_greeter_get_default_session_hint (self));
+ break;
+ case PROP_HIDE_USERS_HINT:
+ g_value_set_boolean (value, lightdm_greeter_get_hide_users_hint (self));
+ break;
+ case PROP_SHOW_MANUAL_LOGIN_HINT:
+ g_value_set_boolean (value, lightdm_greeter_get_show_manual_login_hint (self));
+ break;
+ case PROP_SHOW_REMOTE_LOGIN_HINT:
+ g_value_set_boolean (value, lightdm_greeter_get_show_remote_login_hint (self));
+ break;
+ case PROP_LOCK_HINT:
+ g_value_set_boolean (value, lightdm_greeter_get_lock_hint (self));
+ break;
+ case PROP_HAS_GUEST_ACCOUNT_HINT:
+ g_value_set_boolean (value, lightdm_greeter_get_has_guest_account_hint (self));
+ break;
+ case PROP_SELECT_USER_HINT:
+ g_value_set_string (value, lightdm_greeter_get_select_user_hint (self));
+ break;
+ case PROP_SELECT_GUEST_HINT:
+ g_value_set_boolean (value, lightdm_greeter_get_select_guest_hint (self));
+ break;
+ case PROP_AUTOLOGIN_USER_HINT:
+ g_value_set_string (value, lightdm_greeter_get_autologin_user_hint (self));
+ break;
+ case PROP_AUTOLOGIN_GUEST_HINT:
+ g_value_set_boolean (value, lightdm_greeter_get_autologin_guest_hint (self));
+ break;
+ case PROP_AUTOLOGIN_TIMEOUT_HINT:
+ g_value_set_int (value, lightdm_greeter_get_autologin_timeout_hint (self));
+ break;
+ case PROP_AUTHENTICATION_USER:
+ g_value_set_string (value, lightdm_greeter_get_authentication_user (self));
+ break;
+ case PROP_IN_AUTHENTICATION:
+ g_value_set_boolean (value, lightdm_greeter_get_in_authentication (self));
+ break;
+ case PROP_IS_AUTHENTICATED:
+ g_value_set_boolean (value, lightdm_greeter_get_is_authenticated (self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+marshal_VOID__STRING_INT (GClosure *closure,
+ GValue *return_value G_GNUC_UNUSED,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint G_GNUC_UNUSED,
+ gpointer marshal_data)
+{
+ typedef void (*GMarshalFunc_VOID__STRING_INT) (gpointer data1,
+ gpointer arg_1,
+ gint arg_2,
+ gpointer data2);
+ register GMarshalFunc_VOID__STRING_INT callback;
+ register GCClosure *cc = (GCClosure*) closure;
+ register gpointer data1, data2;
+
+ g_return_if_fail (n_param_values == 3);
+
+ if (G_CCLOSURE_SWAP_DATA (closure))
+ {
+ data1 = closure->data;
+ data2 = g_value_peek_pointer (param_values + 0);
+ }
+ else
+ {
+ data1 = g_value_peek_pointer (param_values + 0);
+ data2 = closure->data;
+ }
+ callback = (GMarshalFunc_VOID__STRING_INT) (marshal_data ? marshal_data : cc->callback);
+
+ callback (data1,
+ (param_values + 1)->data[0].v_pointer,
+ (param_values + 2)->data[0].v_int,
+ data2);
+}
+
+static void
+lightdm_greeter_finalize (GObject *object)
+{
+ LightDMGreeter *self = LIGHTDM_GREETER (object);
+ LightDMGreeterPrivate *priv = GET_PRIVATE (self);
+
+ if (priv->to_server_channel)
+ g_io_channel_unref (priv->to_server_channel);
+ if (priv->from_server_channel)
+ g_io_channel_unref (priv->from_server_channel);
+ g_free (priv->authentication_user);
+ g_hash_table_unref (priv->hints);
+
+ G_OBJECT_CLASS (lightdm_greeter_parent_class)->finalize (object);
+}
+
+static void
+lightdm_greeter_class_init (LightDMGreeterClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (LightDMGreeterPrivate));
+
+ object_class->set_property = lightdm_greeter_set_property;
+ object_class->get_property = lightdm_greeter_get_property;
+ object_class->finalize = lightdm_greeter_finalize;
+
+ g_object_class_install_property (object_class,
+ PROP_DEFAULT_SESSION_HINT,
+ g_param_spec_string ("default-session-hint",
+ "default-session-hint",
+ "Default session hint",
+ NULL,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class,
+ PROP_HIDE_USERS_HINT,
+ g_param_spec_boolean ("hide-users-hint",
+ "hide-users-hint",
+ "Hide users hint",
+ FALSE,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property (object_class,
+ PROP_SHOW_MANUAL_LOGIN_HINT,
+ g_param_spec_boolean ("show-manual-login-hint",
+ "show-manual-login-hint",
+ "Show manual login hint",
+ FALSE,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property (object_class,
+ PROP_SHOW_REMOTE_LOGIN_HINT,
+ g_param_spec_boolean ("show-remote-login-hint",
+ "show-remote-login-hint",
+ "Show remote login hint",
+ FALSE,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property (object_class,
+ PROP_LOCK_HINT,
+ g_param_spec_boolean ("lock-hint",
+ "lock-hint",
+ "Lock hint",
+ FALSE,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property (object_class,
+ PROP_HAS_GUEST_ACCOUNT_HINT,
+ g_param_spec_boolean ("has-guest-account-hint",
+ "has-guest-account-hint",
+ "Has guest account hint",
+ FALSE,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property (object_class,
+ PROP_SELECT_USER_HINT,
+ g_param_spec_string ("select-user-hint",
+ "select-user-hint",
+ "Select user hint",
+ NULL,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property (object_class,
+ PROP_SELECT_GUEST_HINT,
+ g_param_spec_boolean ("select-guest-hint",
+ "select-guest-hint",
+ "Select guest account hint",
+ FALSE,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property (object_class,
+ PROP_AUTOLOGIN_USER_HINT,
+ g_param_spec_string ("autologin-user-hint",
+ "autologin-user-hint",
+ "Autologin user hint",
+ NULL,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property (object_class,
+ PROP_AUTOLOGIN_GUEST_HINT,
+ g_param_spec_boolean ("autologin-guest-hint",
+ "autologin-guest-hint",
+ "Autologin guest account hint",
+ FALSE,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property (object_class,
+ PROP_AUTOLOGIN_TIMEOUT_HINT,
+ g_param_spec_int ("autologin-timeout-hint",
+ "autologin-timeout-hint",
+ "Autologin timeout hint",
+ 0, G_MAXINT, 0,
+ G_PARAM_READABLE));
+
+ g_object_class_install_property (object_class,
+ PROP_AUTHENTICATION_USER,
+ g_param_spec_string ("authentication-user",
+ "authentication-user",
+ "The user being authenticated",
+ NULL,
+ G_PARAM_READABLE));
+ g_object_class_install_property (object_class,
+ PROP_IN_AUTHENTICATION,
+ g_param_spec_boolean ("in-authentication",
+ "in-authentication",
+ "TRUE if a user is being authenticated",
+ FALSE,
+ G_PARAM_READABLE));
+ g_object_class_install_property (object_class,
+ PROP_IS_AUTHENTICATED,
+ g_param_spec_boolean ("is-authenticated",
+ "is-authenticated",
+ "TRUE if the selected user is authenticated",
+ FALSE,
+ G_PARAM_READABLE));
+
+ /**
+ * LightDMGreeter::show-prompt:
+ * @greeter: A #LightDMGreeter
+ * @text: Prompt text
+ * @type: Prompt type
+ *
+ * The ::show-prompt signal gets emitted when the greeter should show a
+ * prompt to the user. The given text should be displayed and an input
+ * field for the user to provide a response.
+ *
+ * Call lightdm_greeter_respond() with the resultant input or
+ * lightdm_greeter_cancel_authentication() to abort the authentication.
+ **/
+ signals[SHOW_PROMPT] =
+ g_signal_new ("show-prompt",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (LightDMGreeterClass, show_prompt),
+ NULL, NULL,
+ marshal_VOID__STRING_INT,
+ G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
+
+ /**
+ * LightDMGreeter::show-message:
+ * @greeter: A #LightDMGreeter
+ * @text: Message text
+ * @type: Message type
+ *
+ * The ::show-message signal gets emitted when the greeter
+ * should show a message to the user.
+ **/
+ signals[SHOW_MESSAGE] =
+ g_signal_new ("show-message",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (LightDMGreeterClass, show_message),
+ NULL, NULL,
+ marshal_VOID__STRING_INT,
+ G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
+
+ /**
+ * LightDMGreeter::authentication-complete:
+ * @greeter: A #LightDMGreeter
+ *
+ * The ::authentication-complete signal gets emitted when the greeter
+ * has completed authentication.
+ *
+ * Call lightdm_greeter_get_is_authenticated() to check if the authentication
+ * was successful.
+ **/
+ signals[AUTHENTICATION_COMPLETE] =
+ g_signal_new ("authentication-complete",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (LightDMGreeterClass, authentication_complete),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ /**
+ * LightDMGreeter::autologin-timer-expired:
+ * @greeter: A #LightDMGreeter
+ *
+ * The ::timed-login signal gets emitted when the automatic login timer has expired.
+ * The application should then call lightdm_greeter_login().
+ **/
+ signals[AUTOLOGIN_TIMER_EXPIRED] =
+ g_signal_new ("autologin-timer-expired",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (LightDMGreeterClass, autologin_timer_expired),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
diff --git a/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/language.c b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/language.c
new file mode 100644
index 00000000..9709619e
--- /dev/null
+++ b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/language.c
@@ -0,0 +1,416 @@
+/*
+ * Copyright (C) 2010 Robert Ancell.
+ * Author: Robert Ancell <robert.ancell@canonical.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 2 or version 3 of the License.
+ * See http://www.gnu.org/copyleft/lgpl.html the full text of the license.
+ */
+
+/*
+ * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
+ * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
+ * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
+ * a choice of LGPL license versions is made available with the language indicating
+ * that LGPLv2 or any later version may be used, or where a choice of which version
+ * of the LGPL is applied is otherwise unspecified.
+ */
+
+#include <string.h>
+#include <locale.h>
+#include <langinfo.h>
+#include <stdio.h>
+#include <glib/gi18n.h>
+
+#include "lightdm/language.h"
+
+enum {
+ PROP_0,
+ PROP_CODE,
+ PROP_NAME,
+ PROP_TERRITORY
+};
+
+typedef struct
+{
+ gchar *code;
+ gchar *name;
+ gchar *territory;
+} LightDMLanguagePrivate;
+
+G_DEFINE_TYPE (LightDMLanguage, lightdm_language, G_TYPE_OBJECT);
+
+#define GET_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_LANGUAGE, LightDMLanguagePrivate)
+
+static gboolean have_languages = FALSE;
+static GList *languages = NULL;
+
+static void
+update_languages (void)
+{
+ gchar *command = "locale -a";
+ gchar *stdout_text = NULL, *stderr_text = NULL;
+ gint exit_status;
+ gboolean result;
+ GError *error = NULL;
+
+ if (have_languages)
+ return;
+
+ result = g_spawn_command_line_sync (command, &stdout_text, &stderr_text, &exit_status, &error);
+ if (error)
+ {
+ g_warning ("Failed to run '%s': %s", command, error->message);
+ g_clear_error (&error);
+ }
+ else if (exit_status != 0)
+ g_warning ("Failed to get languages, '%s' returned %d", command, exit_status);
+ else if (result)
+ {
+ gchar **tokens;
+ int i;
+
+ tokens = g_strsplit_set (stdout_text, "\n\r", -1);
+ for (i = 0; tokens[i]; i++)
+ {
+ LightDMLanguage *language;
+ gchar *code;
+
+ code = g_strchug (tokens[i]);
+ if (code[0] == '\0')
+ continue;
+
+ /* Ignore the non-interesting languages */
+ if (strcmp (command, "locale -a") == 0 && !g_strrstr (code, ".utf8"))
+ continue;
+
+ language = g_object_new (LIGHTDM_TYPE_LANGUAGE, "code", code, NULL);
+ languages = g_list_append (languages, language);
+ }
+
+ g_strfreev (tokens);
+ }
+
+ g_free (stdout_text);
+ g_free (stderr_text);
+
+ have_languages = TRUE;
+}
+
+static gboolean
+is_utf8 (const gchar *code)
+{
+ return g_strrstr (code, ".utf8") || g_strrstr (code, ".UTF-8");
+}
+
+/* Get a valid locale name that can be passed to setlocale(), so we always can use nl_langinfo() to get language and country names. */
+static gchar *
+get_locale_name (const gchar *code)
+{
+ gchar *locale = NULL, *language;
+ char *at;
+ static gchar **avail_locales;
+ gint i;
+
+ if (is_utf8 (code))
+ return (gchar *) code;
+
+ if ((at = strchr (code, '@')))
+ language = g_strndup (code, at - code);
+ else
+ language = g_strdup (code);
+
+ if (!avail_locales)
+ {
+ gchar *locales;
+ GError *error = NULL;
+
+ if (g_spawn_command_line_sync ("locale -a", &locales, NULL, NULL, &error))
+ {
+ avail_locales = g_strsplit (g_strchomp (locales), "\n", -1);
+ g_free (locales);
+ }
+ else
+ {
+ g_warning ("Failed to run 'locale -a': %s", error->message);
+ g_clear_error (&error);
+ }
+ }
+
+ if (avail_locales)
+ {
+ for (i = 0; avail_locales[i]; i++)
+ {
+ gchar *loc = avail_locales[i];
+ if (!g_strrstr (loc, ".utf8"))
+ continue;
+ if (g_str_has_prefix (loc, language))
+ {
+ locale = g_strdup (loc);
+ break;
+ }
+ }
+ }
+
+ g_free (language);
+
+ return locale;
+}
+
+/**
+ * lightdm_get_language:
+ *
+ * Get the current language.
+ *
+ * Return value: (transfer none): The current language or #NULL if no language.
+ **/
+LightDMLanguage *
+lightdm_get_language (void)
+{
+ const gchar *lang;
+ GList *link;
+
+ lang = g_getenv ("LANG");
+ if (!lang)
+ return NULL;
+
+ for (link = lightdm_get_languages (); link; link = link->next)
+ {
+ LightDMLanguage *language = link->data;
+ if (lightdm_language_matches (language, lang))
+ return language;
+ }
+
+ return NULL;
+}
+
+/**
+ * lightdm_get_languages:
+ *
+ * Get a list of languages to present to the user.
+ *
+ * Return value: (element-type LightDMLanguage) (transfer none): A list of #LightDMLanguage that should be presented to the user.
+ **/
+GList *
+lightdm_get_languages (void)
+{
+ update_languages ();
+ return languages;
+}
+
+/**
+ * lightdm_language_get_code:
+ * @language: A #LightDMLanguage
+ *
+ * Get the code of a language.
+ *
+ * Return value: The code of the language
+ **/
+const gchar *
+lightdm_language_get_code (LightDMLanguage *language)
+{
+ g_return_val_if_fail (LIGHTDM_IS_LANGUAGE (language), NULL);
+ return GET_PRIVATE (language)->code;
+}
+
+/**
+ * lightdm_language_get_name:
+ * @language: A #LightDMLanguage
+ *
+ * Get the name of a language.
+ *
+ * Return value: The name of the language
+ **/
+const gchar *
+lightdm_language_get_name (LightDMLanguage *language)
+{
+ LightDMLanguagePrivate *priv;
+
+ g_return_val_if_fail (LIGHTDM_IS_LANGUAGE (language), NULL);
+
+ priv = GET_PRIVATE (language);
+
+ if (!priv->name)
+ {
+ gchar *locale = get_locale_name (priv->code);
+ if (locale)
+ {
+ gchar *current = setlocale (LC_ALL, NULL);
+ setlocale (LC_IDENTIFICATION, locale);
+ setlocale (LC_MESSAGES, "");
+
+ gchar *language_en = nl_langinfo (_NL_IDENTIFICATION_LANGUAGE);
+ if (language_en && strlen (language_en) > 0)
+ priv->name = g_strdup (dgettext ("iso_639_3", language_en));
+
+ setlocale (LC_ALL, current);
+ }
+ if (!priv->name)
+ {
+ gchar **tokens = g_strsplit_set (priv->code, "_.@", 2);
+ priv->name = g_strdup (tokens[0]);
+ g_strfreev (tokens);
+ }
+ }
+
+ return priv->name;
+}
+
+/**
+ * lightdm_language_get_territory:
+ * @language: A #LightDMLanguage
+ *
+ * Get the territory the language is used in.
+ *
+ * Return value: The territory the language is used in.
+ **/
+const gchar *
+lightdm_language_get_territory (LightDMLanguage *language)
+{
+ LightDMLanguagePrivate *priv;
+
+ g_return_val_if_fail (LIGHTDM_IS_LANGUAGE (language), NULL);
+
+ priv = GET_PRIVATE (language);
+
+ if (!priv->territory && strchr (priv->code, '_'))
+ {
+ gchar *locale = get_locale_name (priv->code);
+ if (locale)
+ {
+ gchar *current = setlocale (LC_ALL, NULL);
+ setlocale (LC_IDENTIFICATION, locale);
+ setlocale (LC_MESSAGES, "");
+
+ gchar *country_en = nl_langinfo (_NL_IDENTIFICATION_TERRITORY);
+ if (country_en && strlen (country_en) > 0 && g_strcmp0 (country_en, "ISO") != 0)
+ priv->territory = g_strdup (dgettext ("iso_3166", country_en));
+
+ setlocale (LC_ALL, current);
+ }
+ if (!priv->territory)
+ {
+ gchar **tokens = g_strsplit_set (priv->code, "_.@", 3);
+ priv->territory = g_strdup (tokens[1]);
+ g_strfreev (tokens);
+ }
+ }
+
+ return priv->territory;
+}
+
+/**
+ * lightdm_language_matches:
+ * @language: A #LightDMLanguage
+ * @code: A language code
+ *
+ * Check if a language code matches this language.
+ *
+ * Return value: #TRUE if the code matches this language.
+ **/
+gboolean
+lightdm_language_matches (LightDMLanguage *language, const gchar *code)
+{
+ LightDMLanguagePrivate *priv;
+
+ g_return_val_if_fail (LIGHTDM_IS_LANGUAGE (language), FALSE);
+ g_return_val_if_fail (code != NULL, FALSE);
+
+ priv = GET_PRIVATE (language);
+
+ /* Handle the fact the UTF-8 is specified both as '.utf8' and '.UTF-8' */
+ if (is_utf8 (priv->code) && is_utf8 (code))
+ {
+ /* Match the characters before the '.' */
+ int i;
+ for (i = 0; priv->code[i] && code[i] && priv->code[i] == code[i] && code[i] != '.' ; i++);
+ return priv->code[i] == '.' && code[i] == '.';
+ }
+
+ return g_str_equal (priv->code, code);
+}
+
+static void
+lightdm_language_init (LightDMLanguage *language)
+{
+}
+
+static void
+lightdm_language_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ LightDMLanguage *self = LIGHTDM_LANGUAGE (object);
+ LightDMLanguagePrivate *priv = GET_PRIVATE (self);
+
+ switch (prop_id) {
+ case PROP_CODE:
+ g_free (priv->name);
+ priv->code = g_strdup (g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+lightdm_language_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ LightDMLanguage *self;
+
+ self = LIGHTDM_LANGUAGE (object);
+
+ switch (prop_id) {
+ case PROP_CODE:
+ g_value_set_string (value, lightdm_language_get_code (self));
+ break;
+ case PROP_NAME:
+ g_value_set_string (value, lightdm_language_get_name (self));
+ break;
+ case PROP_TERRITORY:
+ g_value_set_string (value, lightdm_language_get_territory (self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+lightdm_language_class_init (LightDMLanguageClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (LightDMLanguagePrivate));
+
+ object_class->set_property = lightdm_language_set_property;
+ object_class->get_property = lightdm_language_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_CODE,
+ g_param_spec_string ("code",
+ "code",
+ "Language code",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class,
+ PROP_NAME,
+ g_param_spec_string ("name",
+ "name",
+ "Name of the language",
+ NULL,
+ G_PARAM_READABLE));
+ g_object_class_install_property (object_class,
+ PROP_TERRITORY,
+ g_param_spec_string ("territory",
+ "territory",
+ "Territory the language is from",
+ NULL,
+ G_PARAM_READABLE));
+}
diff --git a/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/layout.c b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/layout.c
new file mode 100644
index 00000000..d5057450
--- /dev/null
+++ b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/layout.c
@@ -0,0 +1,344 @@
+/* -*- Mode: C; indent-tabs-mode:nil; tab-width:4 -*-
+ *
+ * Copyright (C) 2010 Robert Ancell.
+ * Author: Robert Ancell <robert.ancell@canonical.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 2 or version 3 of the License.
+ * See http://www.gnu.org/copyleft/lgpl.html the full text of the license.
+ */
+
+/*
+ * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
+ * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
+ * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
+ * a choice of LGPL license versions is made available with the language indicating
+ * that LGPLv2 or any later version may be used, or where a choice of which version
+ * of the LGPL is applied is otherwise unspecified.
+ */
+
+#include <libxklavier/xklavier.h>
+
+#include "lightdm/layout.h"
+
+enum {
+ PROP_0,
+ PROP_NAME,
+ PROP_SHORT_DESCRIPTION,
+ PROP_DESCRIPTION
+};
+
+typedef struct
+{
+ gchar *name;
+ gchar *short_description;
+ gchar *description;
+} LightDMLayoutPrivate;
+
+G_DEFINE_TYPE (LightDMLayout, lightdm_layout, G_TYPE_OBJECT);
+
+#define GET_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_LAYOUT, LightDMLayoutPrivate)
+
+static gboolean have_layouts = FALSE;
+static Display *display = NULL;
+static XklEngine *xkl_engine = NULL;
+static XklConfigRec *xkl_config = NULL;
+static GList *layouts = NULL;
+static LightDMLayout *default_layout = NULL;
+
+static gchar *
+make_layout_string (const gchar *layout, const gchar *variant)
+{
+ if (!layout || layout[0] == 0)
+ return NULL;
+ else if (!variant || variant[0] == 0)
+ return g_strdup (layout);
+ else
+ return g_strdup_printf ("%s\t%s", layout, variant);
+}
+
+static void
+parse_layout_string (const gchar *name, gchar **layout, gchar **variant)
+{
+ gchar **split;
+
+ *layout = NULL;
+ *variant = NULL;
+
+ if (!name)
+ return;
+
+ split = g_strsplit (name, "\t", 2);
+ if (split[0])
+ {
+ *layout = g_strdup (split[0]);
+ if (split[1])
+ *variant = g_strdup (split[1]);
+ }
+ g_strfreev (split);
+}
+
+static void
+variant_cb (XklConfigRegistry *config,
+ const XklConfigItem *item,
+ gpointer data)
+{
+ LightDMLayout *layout;
+ gchar *full_name;
+
+ full_name = make_layout_string (data, item->name);
+
+ layout = g_object_new (LIGHTDM_TYPE_LAYOUT, "name", full_name, "short-description", item->short_description, "description", item->description, NULL);
+ layouts = g_list_append (layouts, layout);
+
+ g_free (full_name);
+}
+
+static void
+layout_cb (XklConfigRegistry *config,
+ const XklConfigItem *item,
+ gpointer data)
+{
+ LightDMLayout *layout;
+
+ layout = g_object_new (LIGHTDM_TYPE_LAYOUT, "name", item->name, "short-description", item->short_description, "description", item->description, NULL);
+ layouts = g_list_append (layouts, layout);
+
+ xkl_config_registry_foreach_layout_variant (config, item->name, variant_cb, (gpointer) item->name);
+}
+
+/**
+ * lightdm_get_layouts:
+ *
+ * Get a list of keyboard layouts to present to the user.
+ *
+ * Return value: (element-type LightDMLayout) (transfer none): A list of #LightDMLayout that should be presented to the user.
+ **/
+GList *
+lightdm_get_layouts (void)
+{
+ XklConfigRegistry *registry;
+
+ if (have_layouts)
+ return layouts;
+
+ display = XOpenDisplay (NULL);
+ xkl_engine = xkl_engine_get_instance (display);
+ xkl_config = xkl_config_rec_new ();
+ if (!xkl_config_rec_get_from_server (xkl_config, xkl_engine))
+ g_warning ("Failed to get Xkl configuration from server");
+
+ registry = xkl_config_registry_get_instance (xkl_engine);
+ xkl_config_registry_load (registry, FALSE);
+ xkl_config_registry_foreach_layout (registry, layout_cb, NULL);
+ g_object_unref (registry);
+
+ have_layouts = TRUE;
+
+ return layouts;
+}
+
+/**
+ * lightdm_set_layout:
+ * @layout: The layout to use
+ *
+ * Set the layout for this session.
+ **/
+void
+lightdm_set_layout (LightDMLayout *dmlayout)
+{
+ XklConfigRec *config;
+ gchar *layout, *variant;
+
+ g_return_if_fail (dmlayout != NULL);
+
+ g_debug ("Setting keyboard layout to '%s'", lightdm_layout_get_name (dmlayout));
+
+ parse_layout_string (lightdm_layout_get_name (dmlayout), &layout, &variant);
+
+ config = xkl_config_rec_new ();
+ config->layouts = g_malloc (sizeof (gchar *) * 2);
+ config->variants = g_malloc (sizeof (gchar *) * 2);
+ config->model = g_strdup (xkl_config->model);
+ config->layouts[0] = layout;
+ config->layouts[1] = NULL;
+ config->variants[0] = variant;
+ config->variants[1] = NULL;
+ if (!xkl_config_rec_activate (config, xkl_engine))
+ g_warning ("Failed to activate XKL config");
+ g_object_unref (config);
+}
+
+/**
+ * lightdm_get_layout:
+ *
+ * Get the current keyboard layout.
+ *
+ * Return value: (transfer none): The currently active layout for this user.
+ **/
+LightDMLayout *
+lightdm_get_layout (void)
+{
+ lightdm_get_layouts ();
+
+ if (layouts && xkl_config && !default_layout)
+ {
+ gchar *full_name;
+ GList *item;
+
+ full_name = make_layout_string (xkl_config->layouts ? xkl_config->layouts[0] : NULL,
+ xkl_config->variants ? xkl_config->variants[0] : NULL);
+
+ for (item = layouts; item; item = item->next)
+ {
+ LightDMLayout *iter_layout = (LightDMLayout *) item->data;
+ if (g_strcmp0 (lightdm_layout_get_name (iter_layout), full_name) == 0)
+ {
+ default_layout = iter_layout;
+ break;
+ }
+ }
+
+ g_free (full_name);
+ }
+
+ return default_layout;
+}
+
+/**
+ * lightdm_layout_get_name:
+ * @layout: A #LightDMLayout
+ *
+ * Get the name of a layout.
+ *
+ * Return value: The name of the layout
+ **/
+const gchar *
+lightdm_layout_get_name (LightDMLayout *layout)
+{
+ g_return_val_if_fail (LIGHTDM_IS_LAYOUT (layout), NULL);
+ return GET_PRIVATE (layout)->name;
+}
+
+/**
+ * lightdm_layout_get_short_description:
+ * @layout: A #LightDMLayout
+ *
+ * Get the short description of a layout.
+ *
+ * Return value: A short description of the layout
+ **/
+const gchar *
+lightdm_layout_get_short_description (LightDMLayout *layout)
+{
+ g_return_val_if_fail (LIGHTDM_IS_LAYOUT (layout), NULL);
+ return GET_PRIVATE (layout)->short_description;
+}
+
+/**
+ * lightdm_layout_get_description:
+ * @layout: A #LightDMLayout
+ *
+ * Get the long description of a layout.
+ *
+ * Return value: A long description of the layout
+ **/
+const gchar *
+lightdm_layout_get_description (LightDMLayout *layout)
+{
+ g_return_val_if_fail (LIGHTDM_IS_LAYOUT (layout), NULL);
+ return GET_PRIVATE (layout)->description;
+}
+
+static void
+lightdm_layout_init (LightDMLayout *layout)
+{
+}
+
+static void
+lightdm_layout_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ LightDMLayout *self = LIGHTDM_LAYOUT (object);
+ LightDMLayoutPrivate *priv = GET_PRIVATE (self);
+
+ switch (prop_id) {
+ case PROP_NAME:
+ g_free (priv->name);
+ priv->name = g_strdup (g_value_get_string (value));
+ break;
+ case PROP_SHORT_DESCRIPTION:
+ g_free (priv->short_description);
+ priv->short_description = g_strdup (g_value_get_string (value));
+ break;
+ case PROP_DESCRIPTION:
+ g_free (priv->description);
+ priv->description = g_strdup (g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+lightdm_layout_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ LightDMLayout *self;
+
+ self = LIGHTDM_LAYOUT (object);
+
+ switch (prop_id) {
+ case PROP_NAME:
+ g_value_set_string (value, lightdm_layout_get_name (self));
+ break;
+ case PROP_SHORT_DESCRIPTION:
+ g_value_set_string (value, lightdm_layout_get_short_description (self));
+ break;
+ case PROP_DESCRIPTION:
+ g_value_set_string (value, lightdm_layout_get_description (self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+lightdm_layout_class_init (LightDMLayoutClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (LightDMLayoutPrivate));
+
+ object_class->set_property = lightdm_layout_set_property;
+ object_class->get_property = lightdm_layout_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_NAME,
+ g_param_spec_string ("name",
+ "name",
+ "Name of the layout",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class,
+ PROP_SHORT_DESCRIPTION,
+ g_param_spec_string ("short-description",
+ "short-description",
+ "Short description of the layout",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class,
+ PROP_DESCRIPTION,
+ g_param_spec_string ("description",
+ "description",
+ "Long description of the layout",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
diff --git a/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/power.c b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/power.c
new file mode 100644
index 00000000..f7830ff2
--- /dev/null
+++ b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/power.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2010-2011 Robert Ancell.
+ * Author: Robert Ancell <robert.ancell@canonical.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 2 or version 3 of the License.
+ * See http://www.gnu.org/copyleft/lgpl.html the full text of the license.
+ */
+
+/*
+ * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
+ * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
+ * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
+ * a choice of LGPL license versions is made available with the language indicating
+ * that LGPLv2 or any later version may be used, or where a choice of which version
+ * of the LGPL is applied is otherwise unspecified.
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <gio/gio.h>
+
+#include "lightdm/power.h"
+
+static GDBusProxy *upower_proxy = NULL;
+static GDBusProxy *ck_proxy = NULL;
+
+static gboolean
+upower_call_function (const gchar *function, gboolean default_result, GError **error)
+{
+ GVariant *result;
+ gboolean function_result = FALSE;
+
+ if (!upower_proxy)
+ {
+ upower_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ "org.freedesktop.UPower",
+ "/org/freedesktop/UPower",
+ "org.freedesktop.UPower",
+ NULL,
+ error);
+ if (!upower_proxy)
+ return FALSE;
+ }
+
+ result = g_dbus_proxy_call_sync (upower_proxy,
+ function,
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ error);
+ if (!result)
+ return default_result;
+
+ if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(b)")))
+ g_variant_get (result, "(b)", &function_result);
+
+ g_variant_unref (result);
+ return function_result;
+}
+
+/**
+ * lightdm_get_can_suspend:
+ *
+ * Checks if authorized to do a system suspend.
+ *
+ * Return value: #TRUE if can suspend the system
+ **/
+gboolean
+lightdm_get_can_suspend (void)
+{
+ return upower_call_function ("SuspendAllowed", FALSE, NULL);
+}
+
+/**
+ * lightdm_suspend:
+ * @error: return location for a #GError, or %NULL
+ *
+ * Triggers a system suspend.
+ *
+ * Return value: #TRUE if suspend initiated.
+ **/
+gboolean
+lightdm_suspend (GError **error)
+{
+ return upower_call_function ("Suspend", TRUE, error);
+}
+
+/**
+ * lightdm_get_can_hibernate:
+ *
+ * Checks if is authorized to do a system hibernate.
+ *
+ * Return value: #TRUE if can hibernate the system
+ **/
+gboolean
+lightdm_get_can_hibernate (void)
+{
+ return upower_call_function ("HibernateAllowed", FALSE, NULL);
+}
+
+/**
+ * lightdm_hibernate:
+ * @error: return location for a #GError, or %NULL
+ *
+ * Triggers a system hibernate.
+ *
+ * Return value: #TRUE if hibernate initiated.
+ **/
+gboolean
+lightdm_hibernate (GError **error)
+{
+ return upower_call_function ("Hibernate", TRUE, error);
+}
+
+static gboolean
+ck_call_function (const gchar *function, gboolean default_result, GError **error)
+{
+ GVariant *result;
+ gboolean function_result = FALSE;
+
+ if (!ck_proxy)
+ {
+ ck_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ "org.freedesktop.ConsoleKit",
+ "/org/freedesktop/ConsoleKit/Manager",
+ "org.freedesktop.ConsoleKit.Manager",
+ NULL,
+ error);
+ if (!ck_proxy)
+ return FALSE;
+ }
+
+ result = g_dbus_proxy_call_sync (ck_proxy,
+ function,
+ NULL,
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ error);
+
+ if (!result)
+ return default_result;
+
+ if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(b)")))
+ g_variant_get (result, "(b)", &function_result);
+
+ g_variant_unref (result);
+ return function_result;
+}
+
+/**
+ * lightdm_get_can_restart:
+ *
+ * Checks if is authorized to do a system restart.
+ *
+ * Return value: #TRUE if can restart the system
+ **/
+gboolean
+lightdm_get_can_restart (void)
+{
+ return ck_call_function ("CanRestart", FALSE, NULL);
+}
+
+/**
+ * lightdm_restart:
+ * @error: return location for a #GError, or %NULL
+ *
+ * Triggers a system restart.
+ *
+ * Return value: #TRUE if restart initiated.
+ **/
+gboolean
+lightdm_restart (GError **error)
+{
+ return ck_call_function ("Restart", TRUE, error);
+}
+
+/**
+ * lightdm_get_can_shutdown:
+ *
+ * Checks if is authorized to do a system shutdown.
+ *
+ * Return value: #TRUE if can shutdown the system
+ **/
+gboolean
+lightdm_get_can_shutdown (void)
+{
+ return ck_call_function ("CanStop", FALSE, NULL);
+}
+
+/**
+ * lightdm_shutdown:
+ * @error: return location for a #GError, or %NULL
+ *
+ * Triggers a system shutdown.
+ *
+ * Return value: #TRUE if shutdown initiated.
+ **/
+gboolean
+lightdm_shutdown (GError **error)
+{
+ return ck_call_function ("Stop", TRUE, error);
+}
diff --git a/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/session.c b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/session.c
new file mode 100644
index 00000000..2df3a1af
--- /dev/null
+++ b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/session.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2010 Robert Ancell.
+ * Author: Robert Ancell <robert.ancell@canonical.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 2 or version 3 of the License.
+ * See http://www.gnu.org/copyleft/lgpl.html the full text of the license.
+ */
+
+/*
+ * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
+ * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
+ * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
+ * a choice of LGPL license versions is made available with the language indicating
+ * that LGPLv2 or any later version may be used, or where a choice of which version
+ * of the LGPL is applied is otherwise unspecified.
+ */
+
+#include <string.h>
+#include <gio/gdesktopappinfo.h>
+
+#include "lightdm/session.h"
+
+enum {
+ PROP_0,
+ PROP_KEY,
+ PROP_NAME,
+ PROP_COMMENT
+};
+
+typedef struct
+{
+ gchar *key;
+ gchar *name;
+ gchar *comment;
+} LightDMSessionPrivate;
+
+G_DEFINE_TYPE (LightDMSession, lightdm_session, G_TYPE_OBJECT);
+
+#define GET_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_SESSION, LightDMSessionPrivate)
+
+static gboolean have_sessions = FALSE;
+static GList *local_sessions = NULL;
+static GList *remote_sessions = NULL;
+
+static gint
+compare_session (gconstpointer a, gconstpointer b)
+{
+ LightDMSessionPrivate *priv_a = GET_PRIVATE (a);
+ LightDMSessionPrivate *priv_b = GET_PRIVATE (b);
+ return strcmp (priv_a->name, priv_b->name);
+}
+
+static LightDMSession *
+load_session (GKeyFile *key_file, const gchar *key)
+{
+ gchar *domain, *name;
+ LightDMSession *session;
+ LightDMSessionPrivate *priv;
+ gchar *try_exec;
+
+ if (g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, NULL) ||
+ g_key_file_get_boolean (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_HIDDEN, NULL))
+ return NULL;
+
+#ifdef G_KEY_FILE_DESKTOP_KEY_GETTEXT_DOMAIN
+ domain = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_GETTEXT_DOMAIN, NULL);
+#else
+ domain = g_key_file_get_string (key_file, G_KEY_FILE_DESKTOP_GROUP, "X-GNOME-Gettext-Domain", NULL);
+#endif
+ name = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NAME, domain, NULL);
+ if (!name)
+ {
+ g_warning ("Ignoring session without name");
+ g_free (domain);
+ return NULL;
+ }
+
+ try_exec = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_TRY_EXEC, domain, NULL);
+ if (try_exec)
+ {
+ gchar *full_path;
+
+ full_path = g_find_program_in_path (try_exec);
+ g_free (try_exec);
+
+ if (!full_path)
+ {
+ g_free (name);
+ g_free (domain);
+ return NULL;
+ }
+ g_free (full_path);
+ }
+
+ session = g_object_new (LIGHTDM_TYPE_SESSION, NULL);
+ priv = GET_PRIVATE (session);
+
+ g_free (priv->key);
+ priv->key = g_strdup (key);
+
+ g_free (priv->name);
+ priv->name = name;
+
+ g_free (priv->comment);
+ priv->comment = g_key_file_get_locale_string (key_file, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_COMMENT, domain, NULL);
+ if (!priv->comment)
+ priv->comment = g_strdup ("");
+
+ g_free (domain);
+
+ return session;
+}
+
+static GList *
+load_sessions (const gchar *sessions_dir)
+{
+ GDir *directory;
+ GList *sessions = NULL;
+ GError *error = NULL;
+
+ directory = g_dir_open (sessions_dir, 0, &error);
+ if (error)
+ g_warning ("Failed to open sessions directory: %s", error->message);
+ g_clear_error (&error);
+ if (!directory)
+ return NULL;
+
+ while (TRUE)
+ {
+ const gchar *filename;
+ gchar *path;
+ GKeyFile *key_file;
+ gboolean result;
+
+ filename = g_dir_read_name (directory);
+ if (filename == NULL)
+ break;
+
+ if (!g_str_has_suffix (filename, ".desktop"))
+ continue;
+
+ path = g_build_filename (sessions_dir, filename, NULL);
+
+ key_file = g_key_file_new ();
+ result = g_key_file_load_from_file (key_file, path, G_KEY_FILE_NONE, &error);
+ if (error)
+ g_warning ("Failed to load session file %s: %s:", path, error->message);
+ g_clear_error (&error);
+
+ if (result)
+ {
+ gchar *key;
+ LightDMSession *session;
+
+ key = g_strndup (filename, strlen (filename) - strlen (".desktop"));
+ session = load_session (key_file, key);
+ if (session)
+ {
+ g_debug ("Loaded session %s (%s, %s)", path, GET_PRIVATE (session)->name, GET_PRIVATE (session)->comment);
+ sessions = g_list_insert_sorted (sessions, session, compare_session);
+ }
+ else
+ g_debug ("Ignoring session %s", path);
+ g_free (key);
+ }
+
+ g_free (path);
+ g_key_file_free (key_file);
+ }
+
+ g_dir_close (directory);
+
+ return sessions;
+}
+
+static void
+update_sessions (void)
+{
+ GKeyFile *config_key_file = NULL;
+ gchar *config_path = NULL;
+ gchar *xsessions_dir;
+ gchar *remote_sessions_dir;
+ gboolean result;
+ GError *error = NULL;
+
+ if (have_sessions)
+ return;
+
+ xsessions_dir = g_strdup (XSESSIONS_DIR);
+ remote_sessions_dir = g_strdup (REMOTE_SESSIONS_DIR);
+
+ /* Use session directory from configuration */
+ /* FIXME: This should be sent in the greeter connection */
+ config_path = g_build_filename (CONFIG_DIR, "lightdm.conf", NULL);
+ config_key_file = g_key_file_new ();
+ result = g_key_file_load_from_file (config_key_file, config_path, G_KEY_FILE_NONE, &error);
+ if (error)
+ g_warning ("Failed to open configuration file: %s", error->message);
+ g_clear_error (&error);
+ if (result)
+ {
+ gchar *value;
+
+ value = g_key_file_get_string (config_key_file, "LightDM", "xsessions-directory", NULL);
+ if (value)
+ {
+ g_free (xsessions_dir);
+ xsessions_dir = value;
+ }
+
+ value = g_key_file_get_string (config_key_file, "LightDM", "remote-sessions-directory", NULL);
+ if (value)
+ {
+ g_free (remote_sessions_dir);
+ remote_sessions_dir = value;
+ }
+ }
+ g_key_file_free (config_key_file);
+ g_free (config_path);
+
+ local_sessions = load_sessions (xsessions_dir);
+ remote_sessions = load_sessions (remote_sessions_dir);
+
+ g_free (xsessions_dir);
+ g_free (remote_sessions_dir);
+
+ have_sessions = TRUE;
+}
+
+/**
+ * lightdm_get_sessions:
+ *
+ * Get the available sessions.
+ *
+ * Return value: (element-type LightDMSession) (transfer none): A list of #LightDMSession
+ **/
+GList *
+lightdm_get_sessions (void)
+{
+ update_sessions ();
+ return local_sessions;
+}
+
+/**
+ * lightdm_get_remote_sessions:
+ *
+ * Get the available remote sessions.
+ *
+ * Return value: (element-type LightDMSession) (transfer none): A list of #LightDMSession
+ **/
+GList *
+lightdm_get_remote_sessions (void)
+{
+ update_sessions ();
+ return remote_sessions;
+}
+
+/**
+ * lightdm_session_get_key:
+ * @session: A #LightDMSession
+ *
+ * Get the key for a session
+ *
+ * Return value: The session key
+ **/
+const gchar *
+lightdm_session_get_key (LightDMSession *session)
+{
+ g_return_val_if_fail (LIGHTDM_IS_SESSION (session), NULL);
+ return GET_PRIVATE (session)->key;
+}
+
+/**
+ * lightdm_session_get_name:
+ * @session: A #LightDMSession
+ *
+ * Get the name for a session
+ *
+ * Return value: The session name
+ **/
+const gchar *
+lightdm_session_get_name (LightDMSession *session)
+{
+ g_return_val_if_fail (LIGHTDM_IS_SESSION (session), NULL);
+ return GET_PRIVATE (session)->name;
+}
+
+/**
+ * lightdm_session_get_comment:
+ * @session: A #LightDMSession
+ *
+ * Get the comment for a session
+ *
+ * Return value: The session comment
+ **/
+const gchar *
+lightdm_session_get_comment (LightDMSession *session)
+{
+ g_return_val_if_fail (LIGHTDM_IS_SESSION (session), NULL);
+ return GET_PRIVATE (session)->comment;
+}
+
+static void
+lightdm_session_init (LightDMSession *session)
+{
+}
+
+static void
+lightdm_session_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+}
+
+static void
+lightdm_session_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ LightDMSession *self;
+
+ self = LIGHTDM_SESSION (object);
+
+ switch (prop_id) {
+ case PROP_KEY:
+ g_value_set_string (value, lightdm_session_get_key (self));
+ break;
+ case PROP_NAME:
+ g_value_set_string (value, lightdm_session_get_name (self));
+ break;
+ case PROP_COMMENT:
+ g_value_set_string (value, lightdm_session_get_comment (self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+lightdm_session_finalize (GObject *object)
+{
+ LightDMSession *self = LIGHTDM_SESSION (object);
+ LightDMSessionPrivate *priv = GET_PRIVATE (self);
+
+ g_free (priv->key);
+ g_free (priv->name);
+ g_free (priv->comment);
+}
+
+static void
+lightdm_session_class_init (LightDMSessionClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (LightDMSessionPrivate));
+
+ object_class->set_property = lightdm_session_set_property;
+ object_class->get_property = lightdm_session_get_property;
+ object_class->finalize = lightdm_session_finalize;
+
+ g_object_class_install_property (object_class,
+ PROP_KEY,
+ g_param_spec_string ("key",
+ "key",
+ "Session key",
+ NULL,
+ G_PARAM_READABLE));
+ g_object_class_install_property (object_class,
+ PROP_NAME,
+ g_param_spec_string ("name",
+ "name",
+ "Session name",
+ NULL,
+ G_PARAM_READABLE));
+ g_object_class_install_property (object_class,
+ PROP_COMMENT,
+ g_param_spec_string ("comment",
+ "comment",
+ "Session comment",
+ NULL,
+ G_PARAM_READABLE));
+}
diff --git a/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/system.c b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/system.c
new file mode 100644
index 00000000..77f8a182
--- /dev/null
+++ b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/system.c
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2010-2011 Robert Ancell.
+ * Author: Robert Ancell <robert.ancell@canonical.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 2 or version 3 of the License.
+ * See http://www.gnu.org/copyleft/lgpl.html the full text of the license.
+ */
+
+/*
+ * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
+ * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
+ * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
+ * a choice of LGPL license versions is made available with the language indicating
+ * that LGPLv2 or any later version may be used, or where a choice of which version
+ * of the LGPL is applied is otherwise unspecified.
+ */
+
+#include <sys/utsname.h>
+
+#include "lightdm/system.h"
+
+static gchar *hostname = NULL;
+
+/**
+ * lightdm_get_hostname:
+ *
+ * Return value: The name of the host we are running on.
+ **/
+const gchar *
+lightdm_get_hostname (void)
+{
+ if (!hostname)
+ {
+ struct utsname info;
+ uname (&info);
+ hostname = g_strdup (info.nodename);
+ }
+
+ return hostname;
+}
diff --git a/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/user.c b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/user.c
new file mode 100644
index 00000000..8df19079
--- /dev/null
+++ b/src/VBox/Additions/linux/lightdm-greeter/liblightdm-gobject-1.5.0/user.c
@@ -0,0 +1,1655 @@
+/* -*- Mode: C; indent-tabs-mode:nil; tab-width:4 -*-
+ *
+ * Copyright (C) 2010 Robert Ancell.
+ * Author: Robert Ancell <robert.ancell@canonical.com>
+ *
+ * This library is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 2 or version 3 of the License.
+ * See http://www.gnu.org/copyleft/lgpl.html the full text of the license.
+ */
+
+/*
+ * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice
+ * other than GPL or LGPL is available it will apply instead, Oracle elects to use only
+ * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where
+ * a choice of LGPL license versions is made available with the language indicating
+ * that LGPLv2 or any later version may be used, or where a choice of which version
+ * of the LGPL is applied is otherwise unspecified.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <string.h>
+#include <sys/utsname.h>
+#include <pwd.h>
+#include <gio/gio.h>
+
+#include "lightdm/user.h"
+
+enum
+{
+ LIST_PROP_0,
+ LIST_PROP_NUM_USERS,
+ LIST_PROP_USERS,
+};
+
+enum
+{
+ USER_PROP_0,
+ USER_PROP_NAME,
+ USER_PROP_REAL_NAME,
+ USER_PROP_DISPLAY_NAME,
+ USER_PROP_HOME_DIRECTORY,
+ USER_PROP_IMAGE,
+ USER_PROP_BACKGROUND,
+ USER_PROP_LANGUAGE,
+ USER_PROP_LAYOUT,
+ USER_PROP_LAYOUTS,
+ USER_PROP_SESSION,
+ USER_PROP_LOGGED_IN,
+ USER_PROP_HAS_MESSAGES
+};
+
+enum
+{
+ USER_ADDED,
+ USER_CHANGED,
+ USER_REMOVED,
+ LAST_LIST_SIGNAL
+};
+static guint list_signals[LAST_LIST_SIGNAL] = { 0 };
+
+enum
+{
+ CHANGED,
+ LAST_USER_SIGNAL
+};
+static guint user_signals[LAST_USER_SIGNAL] = { 0 };
+
+typedef struct
+{
+ /* Connection to AccountsService */
+ GDBusProxy *accounts_service_proxy;
+ GList *user_account_objects;
+
+ /* Connection to DisplayManager */
+ GDBusProxy *display_manager_proxy;
+
+ /* File monitor for password file */
+ GFileMonitor *passwd_monitor;
+
+ /* TRUE if have scanned users */
+ gboolean have_users;
+
+ /* List of users */
+ GList *users;
+
+ /* List of sessions */
+ GList *sessions;
+} LightDMUserListPrivate;
+
+typedef struct
+{
+ GDBusProxy *proxy;
+ LightDMUser *user;
+} UserAccountObject;
+
+typedef struct
+{
+ LightDMUserList *user_list;
+
+ gchar *name;
+ gchar *real_name;
+ gchar *home_directory;
+ gchar *image;
+ gchar *background;
+ gboolean has_messages;
+
+ GKeyFile *dmrc_file;
+ gchar *language;
+ gchar **layouts;
+ gchar *session;
+} LightDMUserPrivate;
+
+typedef struct
+{
+ GObject parent_instance;
+ gchar *path;
+ gchar *username;
+} Session;
+
+typedef struct
+{
+ GObjectClass parent_class;
+} SessionClass;
+
+G_DEFINE_TYPE (LightDMUserList, lightdm_user_list, G_TYPE_OBJECT);
+G_DEFINE_TYPE (LightDMUser, lightdm_user, G_TYPE_OBJECT);
+#define SESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), session_get_type (), Session))
+GType session_get_type (void);
+G_DEFINE_TYPE (Session, session, G_TYPE_OBJECT);
+
+#define GET_LIST_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_USER_LIST, LightDMUserListPrivate)
+#define GET_USER_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_USER, LightDMUserPrivate)
+
+#define PASSWD_FILE "/etc/passwd"
+#define USER_CONFIG_FILE "/etc/lightdm/users.conf"
+
+static LightDMUserList *singleton = NULL;
+
+/**
+ * lightdm_user_list_get_instance:
+ *
+ * Get the user list.
+ *
+ * Return value: (transfer none): the #LightDMUserList
+ **/
+LightDMUserList *
+lightdm_user_list_get_instance (void)
+{
+ if (!singleton)
+ singleton = g_object_new (LIGHTDM_TYPE_USER_LIST, NULL);
+ return singleton;
+}
+
+static LightDMUser *
+get_user_by_name (LightDMUserList *user_list, const gchar *username)
+{
+ LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
+ GList *link;
+
+ for (link = priv->users; link; link = link->next)
+ {
+ LightDMUser *user = link->data;
+ if (strcmp (lightdm_user_get_name (user), username) == 0)
+ return user;
+ }
+
+ return NULL;
+}
+
+static gint
+compare_user (gconstpointer a, gconstpointer b)
+{
+ LightDMUser *user_a = (LightDMUser *) a, *user_b = (LightDMUser *) b;
+ return strcmp (lightdm_user_get_display_name (user_a), lightdm_user_get_display_name (user_b));
+}
+
+static gboolean
+update_passwd_user (LightDMUser *user, const gchar *real_name, const gchar *home_directory, const gchar *image)
+{
+ LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
+
+ if (g_strcmp0 (lightdm_user_get_real_name (user), real_name) == 0 &&
+ g_strcmp0 (lightdm_user_get_home_directory (user), home_directory) == 0 &&
+ g_strcmp0 (lightdm_user_get_image (user), image) == 0)
+ return FALSE;
+
+ g_free (priv->real_name);
+ priv->real_name = g_strdup (real_name);
+ g_free (priv->home_directory);
+ priv->home_directory = g_strdup (home_directory);
+ g_free (priv->image);
+ priv->image = g_strdup (image);
+
+ return TRUE;
+}
+
+static void
+user_changed_cb (LightDMUser *user, LightDMUserList *user_list)
+{
+ g_signal_emit (user_list, list_signals[USER_CHANGED], 0, user);
+}
+
+static void
+load_passwd_file (LightDMUserList *user_list, gboolean emit_add_signal)
+{
+ LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
+ GKeyFile *config;
+ gchar *value;
+ gint minimum_uid;
+ gchar **hidden_users, **hidden_shells;
+ GList *users = NULL, *old_users, *new_users = NULL, *changed_users = NULL, *link;
+ GError *error = NULL;
+
+ g_debug ("Loading user config from %s", USER_CONFIG_FILE);
+
+ config = g_key_file_new ();
+ g_key_file_load_from_file (config, USER_CONFIG_FILE, G_KEY_FILE_NONE, &error);
+ if (error && !g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
+ g_warning ("Failed to load configuration from %s: %s", USER_CONFIG_FILE, error->message); // FIXME: Don't make warning on no file, just info
+ g_clear_error (&error);
+
+ if (g_key_file_has_key (config, "UserList", "minimum-uid", NULL))
+ minimum_uid = g_key_file_get_integer (config, "UserList", "minimum-uid", NULL);
+ else
+ minimum_uid = 500;
+
+ value = g_key_file_get_string (config, "UserList", "hidden-users", NULL);
+ if (!value)
+ value = g_strdup ("nobody nobody4 noaccess");
+ hidden_users = g_strsplit (value, " ", -1);
+ g_free (value);
+
+ value = g_key_file_get_string (config, "UserList", "hidden-shells", NULL);
+ if (!value)
+ value = g_strdup ("/bin/false /usr/sbin/nologin");
+ hidden_shells = g_strsplit (value, " ", -1);
+ g_free (value);
+
+ g_key_file_free (config);
+
+ setpwent ();
+
+ while (TRUE)
+ {
+ struct passwd *entry;
+ LightDMUser *user;
+ LightDMUserPrivate *user_priv;
+ char **tokens;
+ gchar *real_name, *image;
+ int i;
+
+ errno = 0;
+ entry = getpwent ();
+ if (!entry)
+ break;
+
+ /* Ignore system users */
+ if (entry->pw_uid < minimum_uid)
+ continue;
+
+ /* Ignore users disabled by shell */
+ if (entry->pw_shell)
+ {
+ for (i = 0; hidden_shells[i] && strcmp (entry->pw_shell, hidden_shells[i]) != 0; i++);
+ if (hidden_shells[i])
+ continue;
+ }
+
+ /* Ignore certain users */
+ for (i = 0; hidden_users[i] && strcmp (entry->pw_name, hidden_users[i]) != 0; i++);
+ if (hidden_users[i])
+ continue;
+
+ tokens = g_strsplit (entry->pw_gecos, ",", -1);
+ if (tokens[0] != NULL && tokens[0][0] != '\0')
+ real_name = g_strdup (tokens[0]);
+ else
+ real_name = g_strdup ("");
+ g_strfreev (tokens);
+
+ image = g_build_filename (entry->pw_dir, ".face", NULL);
+ if (!g_file_test (image, G_FILE_TEST_EXISTS))
+ {
+ g_free (image);
+ image = g_build_filename (entry->pw_dir, ".face.icon", NULL);
+ if (!g_file_test (image, G_FILE_TEST_EXISTS))
+ {
+ g_free (image);
+ image = NULL;
+ }
+ }
+
+ user = g_object_new (LIGHTDM_TYPE_USER, NULL);
+ user_priv = GET_USER_PRIVATE (user);
+ user_priv->user_list = user_list;
+ g_free (user_priv->name);
+ user_priv->name = g_strdup (entry->pw_name);
+ g_free (user_priv->real_name);
+ user_priv->real_name = real_name;
+ g_free (user_priv->home_directory);
+ user_priv->home_directory = g_strdup (entry->pw_dir);
+ g_free (user_priv->image);
+ user_priv->image = image;
+
+ /* Update existing users if have them */
+ for (link = priv->users; link; link = link->next)
+ {
+ LightDMUser *info = link->data;
+ if (strcmp (lightdm_user_get_name (info), lightdm_user_get_name (user)) == 0)
+ {
+ if (update_passwd_user (info, lightdm_user_get_real_name (user), lightdm_user_get_home_directory (user), lightdm_user_get_image (user)))
+ changed_users = g_list_insert_sorted (changed_users, info, compare_user);
+ g_object_unref (user);
+ user = info;
+ break;
+ }
+ }
+ if (!link)
+ {
+ /* Only notify once we have loaded the user list */
+ if (priv->have_users)
+ new_users = g_list_insert_sorted (new_users, user, compare_user);
+ }
+ users = g_list_insert_sorted (users, user, compare_user);
+ }
+ g_strfreev (hidden_users);
+ g_strfreev (hidden_shells);
+
+ if (errno != 0)
+ g_warning ("Failed to read password database: %s", strerror (errno));
+
+ endpwent ();
+
+ /* Use new user list */
+ old_users = priv->users;
+ priv->users = users;
+
+ /* Notify of changes */
+ for (link = new_users; link; link = link->next)
+ {
+ LightDMUser *info = link->data;
+ g_debug ("User %s added", lightdm_user_get_name (info));
+ g_signal_connect (info, "changed", G_CALLBACK (user_changed_cb), user_list);
+ if (emit_add_signal)
+ g_signal_emit (user_list, list_signals[USER_ADDED], 0, info);
+ }
+ g_list_free (new_users);
+ for (link = changed_users; link; link = link->next)
+ {
+ LightDMUser *info = link->data;
+ g_debug ("User %s changed", lightdm_user_get_name (info));
+ g_signal_emit (info, user_signals[CHANGED], 0);
+ }
+ g_list_free (changed_users);
+ for (link = old_users; link; link = link->next)
+ {
+ GList *new_link;
+
+ /* See if this user is in the current list */
+ for (new_link = priv->users; new_link; new_link = new_link->next)
+ {
+ if (new_link->data == link->data)
+ break;
+ }
+
+ if (!new_link)
+ {
+ LightDMUser *info = link->data;
+ g_debug ("User %s removed", lightdm_user_get_name (info));
+ g_signal_emit (user_list, list_signals[USER_REMOVED], 0, info);
+ g_object_unref (info);
+ }
+ }
+ g_list_free (old_users);
+}
+
+static void
+passwd_changed_cb (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, LightDMUserList *user_list)
+{
+ if (event_type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT)
+ {
+ g_debug ("%s changed, reloading user list", g_file_get_path (file));
+ load_passwd_file (user_list, TRUE);
+ }
+}
+
+static gboolean
+update_user (UserAccountObject *object)
+{
+ LightDMUserPrivate *priv = GET_USER_PRIVATE (object->user);
+ GVariant *result, *value;
+ GVariantIter *iter;
+ gchar *name;
+ GError *error = NULL;
+
+ result = g_dbus_connection_call_sync (g_dbus_proxy_get_connection (object->proxy),
+ "org.freedesktop.Accounts",
+ g_dbus_proxy_get_object_path (object->proxy),
+ "org.freedesktop.DBus.Properties",
+ "GetAll",
+ g_variant_new ("(s)", "org.freedesktop.Accounts.User"),
+ G_VARIANT_TYPE ("(a{sv})"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+ if (error)
+ g_warning ("Error updating user %s: %s", g_dbus_proxy_get_object_path (object->proxy), error->message);
+ g_clear_error (&error);
+ if (!result)
+ return FALSE;
+
+ g_variant_get (result, "(a{sv})", &iter);
+ while (g_variant_iter_loop (iter, "{&sv}", &name, &value))
+ {
+ if (strcmp (name, "UserName") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
+ {
+ gchar *user_name;
+ g_variant_get (value, "&s", &user_name);
+ g_free (priv->name);
+ priv->name = g_strdup (user_name);
+ }
+ else if (strcmp (name, "RealName") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
+ {
+ gchar *real_name;
+ g_variant_get (value, "&s", &real_name);
+ g_free (priv->real_name);
+ priv->real_name = g_strdup (real_name);
+ }
+ else if (strcmp (name, "HomeDirectory") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
+ {
+ gchar *home_directory;
+ g_variant_get (value, "&s", &home_directory);
+ g_free (priv->home_directory);
+ priv->home_directory = g_strdup (home_directory);
+ }
+ else if (strcmp (name, "IconFile") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
+ {
+ gchar *icon_file;
+ g_variant_get (value, "&s", &icon_file);
+ g_free (priv->image);
+ if (strcmp (icon_file, "") == 0)
+ priv->image = NULL;
+ else
+ priv->image = g_strdup (icon_file);
+ }
+ else if (strcmp (name, "BackgroundFile") == 0 && g_variant_is_of_type (value, G_VARIANT_TYPE_STRING))
+ {
+ gchar *background_file;
+ g_variant_get (value, "&s", &background_file);
+ g_free (priv->background);
+ if (strcmp (background_file, "") == 0)
+ priv->background = NULL;
+ else
+ priv->background = g_strdup (background_file);
+ }
+ }
+ g_variant_iter_free (iter);
+
+ g_variant_unref (result);
+
+ return TRUE;
+}
+
+static void
+user_signal_cb (GDBusProxy *proxy, gchar *sender_name, gchar *signal_name, GVariant *parameters, UserAccountObject *object)
+{
+ if (strcmp (signal_name, "Changed") == 0)
+ {
+ if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("()")))
+ {
+ g_debug ("User %s changed", g_dbus_proxy_get_object_path (object->proxy));
+ update_user (object);
+ g_signal_emit (object->user, user_signals[CHANGED], 0);
+ }
+ else
+ g_warning ("Got org.freedesktop.Accounts.User signal Changed with unknown parameters %s", g_variant_get_type_string (parameters));
+ }
+}
+
+static UserAccountObject *
+user_account_object_new (LightDMUserList *user_list, const gchar *path)
+{
+ GDBusProxy *proxy;
+ UserAccountObject *object;
+ GError *error = NULL;
+
+ proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ "org.freedesktop.Accounts",
+ path,
+ "org.freedesktop.Accounts.User",
+ NULL,
+ &error);
+ if (error)
+ g_warning ("Error getting user %s: %s", path, error->message);
+ g_clear_error (&error);
+ if (!proxy)
+ return NULL;
+
+ object = g_malloc0 (sizeof (UserAccountObject));
+ object->user = g_object_new (LIGHTDM_TYPE_USER, NULL);
+ GET_USER_PRIVATE (object->user)->user_list = user_list;
+ object->proxy = proxy;
+ g_signal_connect (proxy, "g-signal", G_CALLBACK (user_signal_cb), object);
+
+ return object;
+}
+
+static void
+user_account_object_free (UserAccountObject *object)
+{
+ if (!object)
+ return;
+ g_object_unref (object->user);
+ g_object_unref (object->proxy);
+ g_free (object);
+}
+
+static UserAccountObject *
+find_user_account_object (LightDMUserList *user_list, const gchar *path)
+{
+ LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
+ GList *link;
+
+ for (link = priv->user_account_objects; link; link = link->next)
+ {
+ UserAccountObject *object = link->data;
+ if (strcmp (g_dbus_proxy_get_object_path (object->proxy), path) == 0)
+ return object;
+ }
+
+ return NULL;
+}
+
+static void
+user_accounts_signal_cb (GDBusProxy *proxy, gchar *sender_name, gchar *signal_name, GVariant *parameters, LightDMUserList *user_list)
+{
+ LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
+
+ if (strcmp (signal_name, "UserAdded") == 0)
+ {
+ if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
+ {
+ gchar *path;
+ UserAccountObject *object;
+
+ g_variant_get (parameters, "(&o)", &path);
+
+ /* Ignore duplicate requests */
+ object = find_user_account_object (user_list, path);
+ if (object)
+ return;
+
+ object = user_account_object_new (user_list, path);
+ if (object && update_user (object))
+ {
+ g_debug ("User %s added", path);
+ priv->user_account_objects = g_list_append (priv->user_account_objects, object);
+ priv->users = g_list_insert_sorted (priv->users, g_object_ref (object->user), compare_user);
+ g_signal_connect (object->user, "changed", G_CALLBACK (user_changed_cb), user_list);
+ g_signal_emit (user_list, list_signals[USER_ADDED], 0, object->user);
+ }
+ else
+ user_account_object_free (object);
+ }
+ else
+ g_warning ("Got UserAccounts signal UserAdded with unknown parameters %s", g_variant_get_type_string (parameters));
+ }
+ else if (strcmp (signal_name, "UserDeleted") == 0)
+ {
+ if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
+ {
+ gchar *path;
+ UserAccountObject *object;
+
+ g_variant_get (parameters, "(&o)", &path);
+
+ object = find_user_account_object (user_list, path);
+ if (!object)
+ return;
+
+ g_debug ("User %s deleted", path);
+ priv->users = g_list_remove (priv->users, object->user);
+ g_object_unref (object->user);
+
+ g_signal_emit (user_list, list_signals[USER_REMOVED], 0, object->user);
+
+ priv->user_account_objects = g_list_remove (priv->user_account_objects, object);
+ user_account_object_free (object);
+ }
+ else
+ g_warning ("Got UserAccounts signal UserDeleted with unknown parameters %s", g_variant_get_type_string (parameters));
+ }
+}
+
+static Session *
+load_session (LightDMUserList *user_list, const gchar *path)
+{
+ LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
+ Session *session = NULL;
+ GVariant *result, *username;
+ GError *error = NULL;
+
+ result = g_dbus_connection_call_sync (g_dbus_proxy_get_connection (priv->display_manager_proxy),
+ "org.freedesktop.DisplayManager",
+ path,
+ "org.freedesktop.DBus.Properties",
+ "Get",
+ g_variant_new ("(ss)", "org.freedesktop.DisplayManager.Session", "UserName"),
+ G_VARIANT_TYPE ("(v)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+ if (error)
+ g_warning ("Error getting UserName from org.freedesktop.DisplayManager.Session: %s", error->message);
+ g_clear_error (&error);
+ if (!result)
+ return NULL;
+
+ g_variant_get (result, "(v)", &username);
+ if (g_variant_is_of_type (username, G_VARIANT_TYPE_STRING))
+ {
+ gchar *name;
+
+ g_variant_get (username, "&s", &name);
+
+ g_debug ("Loaded session %s (%s)", path, name);
+ session = g_object_new (session_get_type (), NULL);
+ session->username = g_strdup (name);
+ session->path = g_strdup (path);
+ priv->sessions = g_list_append (priv->sessions, session);
+ }
+ g_variant_unref (username);
+ g_variant_unref (result);
+
+ return session;
+}
+
+static void
+display_manager_signal_cb (GDBusProxy *proxy, gchar *sender_name, gchar *signal_name, GVariant *parameters, LightDMUserList *user_list)
+{
+ LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
+
+ if (strcmp (signal_name, "SessionAdded") == 0)
+ {
+ if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
+ {
+ gchar *path;
+ Session *session;
+ LightDMUser *user = NULL;
+
+ g_variant_get (parameters, "(&o)", &path);
+ session = load_session (user_list, path);
+ if (session)
+ user = get_user_by_name (user_list, session->username);
+ if (user)
+ g_signal_emit (user, user_signals[CHANGED], 0);
+ }
+ }
+ else if (strcmp (signal_name, "SessionRemoved") == 0)
+ {
+ if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(o)")))
+ {
+ gchar *path;
+ GList *link;
+
+ g_variant_get (parameters, "(&o)", &path);
+
+ for (link = priv->sessions; link; link = link->next)
+ {
+ Session *session = link->data;
+ if (strcmp (session->path, path) == 0)
+ {
+ LightDMUser *user;
+
+ g_debug ("Session %s removed", path);
+ priv->sessions = g_list_remove_link (priv->sessions, link);
+ user = get_user_by_name (user_list, session->username);
+ if (user)
+ g_signal_emit (user, user_signals[CHANGED], 0);
+ g_object_unref (session);
+ break;
+ }
+ }
+ }
+ }
+}
+
+static void
+update_users (LightDMUserList *user_list)
+{
+ LightDMUserListPrivate *priv = GET_LIST_PRIVATE (user_list);
+ GError *error = NULL;
+
+ if (priv->have_users)
+ return;
+ priv->have_users = TRUE;
+
+ priv->accounts_service_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ "org.freedesktop.Accounts",
+ "/org/freedesktop/Accounts",
+ "org.freedesktop.Accounts",
+ NULL,
+ &error);
+ if (error)
+ g_warning ("Error contacting org.freedesktop.Accounts: %s", error->message);
+ g_clear_error (&error);
+
+ /* Check if the service exists */
+ if (priv->accounts_service_proxy)
+ {
+ gchar *name;
+
+ name = g_dbus_proxy_get_name_owner (priv->accounts_service_proxy);
+ if (!name)
+ {
+ g_debug ("org.freedesktop.Accounts does not exist, falling back to passwd file");
+ g_object_unref (priv->accounts_service_proxy);
+ priv->accounts_service_proxy = NULL;
+ }
+ g_free (name);
+ }
+
+ if (priv->accounts_service_proxy)
+ {
+ GVariant *result;
+
+ g_signal_connect (priv->accounts_service_proxy, "g-signal", G_CALLBACK (user_accounts_signal_cb), user_list);
+
+ result = g_dbus_proxy_call_sync (priv->accounts_service_proxy,
+ "ListCachedUsers",
+ g_variant_new ("()"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+ if (error)
+ g_warning ("Error getting user list from org.freedesktop.Accounts: %s", error->message);
+ g_clear_error (&error);
+ if (!result)
+ return;
+
+ if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(ao)")))
+ {
+ GVariantIter *iter;
+ const gchar *path;
+
+ g_debug ("Loading users from org.freedesktop.Accounts");
+ g_variant_get (result, "(ao)", &iter);
+ while (g_variant_iter_loop (iter, "&o", &path))
+ {
+ UserAccountObject *object;
+
+ g_debug ("Loading user %s", path);
+
+ object = user_account_object_new (user_list, path);
+ if (object && update_user (object))
+ {
+ priv->user_account_objects = g_list_append (priv->user_account_objects, object);
+ priv->users = g_list_insert_sorted (priv->users, g_object_ref (object->user), compare_user);
+ g_signal_connect (object->user, "changed", G_CALLBACK (user_changed_cb), user_list);
+ }
+ else
+ user_account_object_free (object);
+ }
+ g_variant_iter_free (iter);
+ }
+ else
+ g_warning ("Unexpected type from ListCachedUsers: %s", g_variant_get_type_string (result));
+
+ g_variant_unref (result);
+ }
+ else
+ {
+ GFile *passwd_file;
+
+ load_passwd_file (user_list, FALSE);
+
+ /* Watch for changes to user list */
+
+ passwd_file = g_file_new_for_path (PASSWD_FILE);
+ priv->passwd_monitor = g_file_monitor (passwd_file, G_FILE_MONITOR_NONE, NULL, &error);
+ g_object_unref (passwd_file);
+ if (error)
+ g_warning ("Error monitoring %s: %s", PASSWD_FILE, error->message);
+ else
+ g_signal_connect (priv->passwd_monitor, "changed", G_CALLBACK (passwd_changed_cb), user_list);
+ g_clear_error (&error);
+ }
+
+ priv->display_manager_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ "org.freedesktop.DisplayManager",
+ "/org/freedesktop/DisplayManager",
+ "org.freedesktop.DisplayManager",
+ NULL,
+ &error);
+ if (error)
+ g_warning ("Error contacting org.freedesktop.DisplayManager: %s", error->message);
+ g_clear_error (&error);
+
+ if (priv->display_manager_proxy)
+ {
+ GVariant *result;
+
+ g_signal_connect (priv->display_manager_proxy, "g-signal", G_CALLBACK (display_manager_signal_cb), user_list);
+
+ result = g_dbus_connection_call_sync (g_dbus_proxy_get_connection (priv->display_manager_proxy),
+ "org.freedesktop.DisplayManager",
+ "/org/freedesktop/DisplayManager",
+ "org.freedesktop.DBus.Properties",
+ "Get",
+ g_variant_new ("(ss)", "org.freedesktop.DisplayManager", "Sessions"),
+ G_VARIANT_TYPE ("(v)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+ if (error)
+ g_warning ("Error getting session list from org.freedesktop.DisplayManager: %s", error->message);
+ g_clear_error (&error);
+ if (!result)
+ return;
+
+ if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(v)")))
+ {
+ GVariant *value;
+ GVariantIter *iter;
+ const gchar *path;
+
+ g_variant_get (result, "(v)", &value);
+
+ g_debug ("Loading sessions from org.freedesktop.DisplayManager");
+ g_variant_get (value, "ao", &iter);
+ while (g_variant_iter_loop (iter, "&o", &path))
+ load_session (user_list, path);
+ g_variant_iter_free (iter);
+
+ g_variant_unref (value);
+ }
+ else
+ g_warning ("Unexpected type from org.freedesktop.DisplayManager.Sessions: %s", g_variant_get_type_string (result));
+
+ g_variant_unref (result);
+ }
+}
+
+/**
+ * lightdm_user_list_get_length:
+ * @user_list: a #LightDMUserList
+ *
+ * Return value: The number of users able to log in
+ **/
+gint
+lightdm_user_list_get_length (LightDMUserList *user_list)
+{
+ g_return_val_if_fail (LIGHTDM_IS_USER_LIST (user_list), 0);
+ update_users (user_list);
+ return g_list_length (GET_LIST_PRIVATE (user_list)->users);
+}
+
+/**
+ * lightdm_user_list_get_users:
+ * @user_list: A #LightDMUserList
+ *
+ * Get a list of users to present to the user. This list may be a subset of the
+ * available users and may be empty depending on the server configuration.
+ *
+ * Return value: (element-type LightDMUser) (transfer none): A list of #LightDMUser that should be presented to the user.
+ **/
+GList *
+lightdm_user_list_get_users (LightDMUserList *user_list)
+{
+ g_return_val_if_fail (LIGHTDM_IS_USER_LIST (user_list), NULL);
+ update_users (user_list);
+ return GET_LIST_PRIVATE (user_list)->users;
+}
+
+/**
+ * lightdm_user_list_get_user_by_name:
+ * @user_list: A #LightDMUserList
+ * @username: Name of user to get.
+ *
+ * Get infomation about a given user or #NULL if this user doesn't exist.
+ *
+ * Return value: (transfer none): A #LightDMUser entry for the given user.
+ **/
+LightDMUser *
+lightdm_user_list_get_user_by_name (LightDMUserList *user_list, const gchar *username)
+{
+ g_return_val_if_fail (LIGHTDM_IS_USER_LIST (user_list), NULL);
+ g_return_val_if_fail (username != NULL, NULL);
+
+ update_users (user_list);
+
+ return get_user_by_name (user_list, username);
+}
+
+static void
+lightdm_user_list_init (LightDMUserList *user_list)
+{
+}
+
+static void
+lightdm_user_list_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+}
+
+static void
+lightdm_user_list_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ LightDMUserList *self;
+
+ self = LIGHTDM_USER_LIST (object);
+
+ switch (prop_id)
+ {
+ case LIST_PROP_NUM_USERS:
+ g_value_set_int (value, lightdm_user_list_get_length (self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+lightdm_user_list_finalize (GObject *object)
+{
+ LightDMUserList *self = LIGHTDM_USER_LIST (object);
+ LightDMUserListPrivate *priv = GET_LIST_PRIVATE (self);
+
+ if (priv->accounts_service_proxy)
+ g_object_unref (priv->accounts_service_proxy);
+ g_list_free_full (priv->user_account_objects, (GDestroyNotify) user_account_object_free);
+ if (priv->passwd_monitor)
+ g_object_unref (priv->passwd_monitor);
+ g_list_free_full (priv->users, g_object_unref);
+ g_list_free_full (priv->sessions, g_object_unref);
+
+ G_OBJECT_CLASS (lightdm_user_list_parent_class)->finalize (object);
+}
+
+static void
+lightdm_user_list_class_init (LightDMUserListClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (LightDMUserListPrivate));
+
+ object_class->set_property = lightdm_user_list_set_property;
+ object_class->get_property = lightdm_user_list_get_property;
+ object_class->finalize = lightdm_user_list_finalize;
+
+ g_object_class_install_property (object_class,
+ LIST_PROP_NUM_USERS,
+ g_param_spec_int ("num-users",
+ "num-users",
+ "Number of login users",
+ 0, G_MAXINT, 0,
+ G_PARAM_READABLE));
+ /**
+ * LightDMUserList::user-added:
+ * @user_list: A #LightDMUserList
+ * @user: The #LightDM user that has been added.
+ *
+ * The ::user-added signal gets emitted when a user account is created.
+ **/
+ list_signals[USER_ADDED] =
+ g_signal_new ("user-added",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (LightDMUserListClass, user_added),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1, LIGHTDM_TYPE_USER);
+
+ /**
+ * LightDMUserList::user-changed:
+ * @user_list: A #LightDMUserList
+ * @user: The #LightDM user that has been changed.
+ *
+ * The ::user-changed signal gets emitted when a user account is modified.
+ **/
+ list_signals[USER_CHANGED] =
+ g_signal_new ("user-changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (LightDMUserListClass, user_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1, LIGHTDM_TYPE_USER);
+
+ /**
+ * LightDMUserList::user-removed:
+ * @user_list: A #LightDMUserList
+ * @user: The #LightDM user that has been removed.
+ *
+ * The ::user-removed signal gets emitted when a user account is removed.
+ **/
+ list_signals[USER_REMOVED] =
+ g_signal_new ("user-removed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (LightDMUserListClass, user_removed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1, LIGHTDM_TYPE_USER);
+}
+
+/**
+ * lightdm_user_get_name:
+ * @user: A #LightDMUser
+ *
+ * Get the name of a user.
+ *
+ * Return value: The name of the given user
+ **/
+const gchar *
+lightdm_user_get_name (LightDMUser *user)
+{
+ g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
+ return GET_USER_PRIVATE (user)->name;
+}
+
+/**
+ * lightdm_user_get_real_name:
+ * @user: A #LightDMUser
+ *
+ * Get the real name of a user.
+ *
+ * Return value: The real name of the given user
+ **/
+const gchar *
+lightdm_user_get_real_name (LightDMUser *user)
+{
+ g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
+ return GET_USER_PRIVATE (user)->real_name;
+}
+
+/**
+ * lightdm_user_get_display_name:
+ * @user: A #LightDMUser
+ *
+ * Get the display name of a user.
+ *
+ * Return value: The display name of the given user
+ **/
+const gchar *
+lightdm_user_get_display_name (LightDMUser *user)
+{
+ LightDMUserPrivate *priv;
+
+ g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
+
+ priv = GET_USER_PRIVATE (user);
+ if (strcmp (priv->real_name, ""))
+ return priv->real_name;
+ else
+ return priv->name;
+}
+
+/**
+ * lightdm_user_get_home_directory:
+ * @user: A #LightDMUser
+ *
+ * Get the home directory for a user.
+ *
+ * Return value: The users home directory
+ */
+const gchar *
+lightdm_user_get_home_directory (LightDMUser *user)
+{
+ g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
+ return GET_USER_PRIVATE (user)->home_directory;
+}
+
+/**
+ * lightdm_user_get_image:
+ * @user: A #LightDMUser
+ *
+ * Get the image URI for a user.
+ *
+ * Return value: The image URI for the given user or #NULL if no URI
+ **/
+const gchar *
+lightdm_user_get_image (LightDMUser *user)
+{
+ g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
+ return GET_USER_PRIVATE (user)->image;
+}
+
+/**
+ * lightdm_user_get_background:
+ * @user: A #LightDMUser
+ *
+ * Get the background file path for a user.
+ *
+ * Return value: The background file path for the given user or #NULL if no path
+ **/
+const gchar *
+lightdm_user_get_background (LightDMUser *user)
+{
+ g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
+ return GET_USER_PRIVATE (user)->background;
+}
+
+static void
+load_dmrc (LightDMUser *user)
+{
+ LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
+ gchar *path;
+ //gboolean have_dmrc;
+
+ if (!priv->dmrc_file)
+ priv->dmrc_file = g_key_file_new ();
+
+ /* Load from the user directory */
+ path = g_build_filename (priv->home_directory, ".dmrc", NULL);
+ /*have_dmrc = */g_key_file_load_from_file (priv->dmrc_file, path, G_KEY_FILE_KEEP_COMMENTS, NULL);
+ g_free (path);
+
+ /* If no ~/.dmrc, then load from the cache */
+ // FIXME
+
+ // FIXME: Watch for changes
+
+ /* The Language field is actually a locale, strip the codeset off it to get the language */
+ if (priv->language)
+ g_free (priv->language);
+ priv->language = g_key_file_get_string (priv->dmrc_file, "Desktop", "Language", NULL);
+ if (priv->language)
+ {
+ gchar *codeset = strchr (priv->language, '.');
+ if (codeset)
+ *codeset = '\0';
+ }
+
+ if (priv->layouts)
+ {
+ g_strfreev (priv->layouts);
+ priv->layouts = NULL;
+ }
+ if (g_key_file_has_key (priv->dmrc_file, "Desktop", "Layout", NULL))
+ {
+ priv->layouts = g_malloc (sizeof (gchar *) * 2);
+ priv->layouts[0] = g_key_file_get_string (priv->dmrc_file, "Desktop", "Layout", NULL);
+ priv->layouts[1] = NULL;
+ }
+
+ if (priv->session)
+ g_free (priv->session);
+ priv->session = g_key_file_get_string (priv->dmrc_file, "Desktop", "Session", NULL);
+}
+
+static GVariant *
+get_property (GDBusProxy *proxy, const gchar *property)
+{
+ GVariant *answer;
+
+ if (!proxy)
+ return NULL;
+
+ answer = g_dbus_proxy_get_cached_property (proxy, property);
+
+ if (!answer)
+ {
+ g_warning ("Could not get accounts property %s", property);
+ return NULL;
+ }
+
+ return answer;
+}
+
+static gboolean
+get_boolean_property (GDBusProxy *proxy, const gchar *property)
+{
+ GVariant *answer;
+ gboolean rv;
+
+ answer = get_property (proxy, property);
+ if (!g_variant_is_of_type (answer, G_VARIANT_TYPE_BOOLEAN))
+ {
+ g_warning ("Unexpected accounts property type for %s: %s",
+ property, g_variant_get_type_string (answer));
+ g_variant_unref (answer);
+ return FALSE;
+ }
+
+ rv = g_variant_get_boolean (answer);
+ g_variant_unref (answer);
+
+ return rv;
+}
+
+static gchar *
+get_string_property (GDBusProxy *proxy, const gchar *property)
+{
+ GVariant *answer;
+ gchar *rv;
+
+ answer = get_property (proxy, property);
+ if (!g_variant_is_of_type (answer, G_VARIANT_TYPE_STRING))
+ {
+ g_warning ("Unexpected accounts property type for %s: %s",
+ property, g_variant_get_type_string (answer));
+ g_variant_unref (answer);
+ return NULL;
+ }
+
+ rv = g_strdup (g_variant_get_string (answer, NULL));
+ if (strcmp (rv, "") == 0)
+ {
+ g_free (rv);
+ rv = NULL;
+ }
+ g_variant_unref (answer);
+
+ return rv;
+}
+
+static gchar **
+get_string_array_property (GDBusProxy *proxy, const gchar *property)
+{
+ GVariant *answer;
+ gchar **rv;
+
+ if (!proxy)
+ return NULL;
+
+ answer = g_dbus_proxy_get_cached_property (proxy, property);
+
+ if (!answer)
+ {
+ g_warning ("Could not get accounts property %s", property);
+ return NULL;
+ }
+
+ if (!g_variant_is_of_type (answer, G_VARIANT_TYPE ("as")))
+ {
+ g_warning ("Unexpected accounts property type for %s: %s",
+ property, g_variant_get_type_string (answer));
+ g_variant_unref (answer);
+ return NULL;
+ }
+
+ rv = g_variant_dup_strv (answer, NULL);
+
+ g_variant_unref (answer);
+ return rv;
+}
+
+static gboolean
+load_accounts_service (LightDMUser *user)
+{
+ LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
+ LightDMUserListPrivate *list_priv = GET_LIST_PRIVATE (priv->user_list);
+ UserAccountObject *account = NULL;
+ GList *iter;
+ gchar **value;
+
+ /* First, find AccountObject proxy */
+ for (iter = list_priv->user_account_objects; iter; iter = iter->next)
+ {
+ UserAccountObject *a = iter->data;
+ if (a->user == user)
+ {
+ account = a;
+ break;
+ }
+ }
+ if (!account)
+ return FALSE;
+
+ /* We have proxy, let's grab some properties */
+ if (priv->language)
+ g_free (priv->language);
+ priv->language = get_string_property (account->proxy, "Language");
+ if (priv->session)
+ g_free (priv->session);
+ priv->session = get_string_property (account->proxy, "XSession");
+
+ value = get_string_array_property (account->proxy, "XKeyboardLayouts");
+ if (value)
+ {
+ if (value[0])
+ {
+ g_strfreev (priv->layouts);
+ priv->layouts = value;
+ }
+ else
+ g_strfreev (value);
+ }
+
+ priv->has_messages = get_boolean_property (account->proxy, "XHasMessages");
+
+ return TRUE;
+}
+
+/* Loads language/layout/session info for user */
+static void
+load_user_values (LightDMUser *user)
+{
+ LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
+
+ load_dmrc (user);
+ load_accounts_service (user); // overrides dmrc values
+
+ /* Ensure a few guarantees */
+ if (priv->layouts == NULL)
+ {
+ priv->layouts = g_malloc (sizeof (gchar *) * 1);
+ priv->layouts[0] = NULL;
+ }
+}
+
+/**
+ * lightdm_user_get_language:
+ * @user: A #LightDMUser
+ *
+ * Get the language for a user.
+ *
+ * Return value: The language for the given user or #NULL if using system defaults.
+ **/
+const gchar *
+lightdm_user_get_language (LightDMUser *user)
+{
+ g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
+ load_user_values (user);
+ return GET_USER_PRIVATE (user)->language;
+}
+
+/**
+ * lightdm_user_get_layout:
+ * @user: A #LightDMUser
+ *
+ * Get the keyboard layout for a user.
+ *
+ * Return value: The keyboard layout for the given user or #NULL if using system defaults. Copy the value if you want to use it long term.
+ **/
+const gchar *
+lightdm_user_get_layout (LightDMUser *user)
+{
+ g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
+ load_user_values (user);
+ return GET_USER_PRIVATE (user)->layouts[0];
+}
+
+/**
+ * lightdm_user_get_layouts:
+ * @user: A #LightDMUser
+ *
+ * Get the configured keyboard layouts for a user.
+ *
+ * Return value: (transfer none): A NULL-terminated array of keyboard layouts for the given user. Copy the values if you want to use them long term.
+ **/
+const gchar * const *
+lightdm_user_get_layouts (LightDMUser *user)
+{
+ g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
+ load_user_values (user);
+ return (const gchar * const *) GET_USER_PRIVATE (user)->layouts;
+}
+
+/**
+ * lightdm_user_get_session:
+ * @user: A #LightDMUser
+ *
+ * Get the session for a user.
+ *
+ * Return value: The session for the given user or #NULL if using system defaults.
+ **/
+const gchar *
+lightdm_user_get_session (LightDMUser *user)
+{
+ g_return_val_if_fail (LIGHTDM_IS_USER (user), NULL);
+ load_user_values (user);
+ return GET_USER_PRIVATE (user)->session;
+}
+
+/**
+ * lightdm_user_get_logged_in:
+ * @user: A #LightDMUser
+ *
+ * Check if a user is logged in.
+ *
+ * Return value: #TRUE if the user is currently logged in.
+ **/
+gboolean
+lightdm_user_get_logged_in (LightDMUser *user)
+{
+ LightDMUserPrivate *priv = GET_USER_PRIVATE (user);
+ LightDMUserListPrivate *list_priv = GET_LIST_PRIVATE (priv->user_list);
+ GList *link;
+
+ g_return_val_if_fail (LIGHTDM_IS_USER (user), FALSE);
+
+ for (link = list_priv->sessions; link; link = link->next)
+ {
+ Session *session = link->data;
+ if (strcmp (session->username, priv->name) == 0)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ * lightdm_user_get_has_messages:
+ * @user: A #LightDMUser
+ *
+ * Check if a user has waiting messages.
+ *
+ * Return value: #TRUE if the user has waiting messages.
+ **/
+gboolean
+lightdm_user_get_has_messages (LightDMUser *user)
+{
+ g_return_val_if_fail (LIGHTDM_IS_USER (user), FALSE);
+ load_user_values (user);
+ return GET_USER_PRIVATE (user)->has_messages;
+}
+
+static void
+lightdm_user_init (LightDMUser *user)
+{
+}
+
+static void
+lightdm_user_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+}
+
+static void
+lightdm_user_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ LightDMUser *self;
+
+ self = LIGHTDM_USER (object);
+
+ switch (prop_id)
+ {
+ case USER_PROP_NAME:
+ g_value_set_string (value, lightdm_user_get_name (self));
+ break;
+ case USER_PROP_REAL_NAME:
+ g_value_set_string (value, lightdm_user_get_real_name (self));
+ break;
+ case USER_PROP_DISPLAY_NAME:
+ g_value_set_string (value, lightdm_user_get_display_name (self));
+ break;
+ case USER_PROP_HOME_DIRECTORY:
+ g_value_set_string (value, lightdm_user_get_home_directory (self));
+ break;
+ case USER_PROP_IMAGE:
+ g_value_set_string (value, lightdm_user_get_image (self));
+ break;
+ case USER_PROP_BACKGROUND:
+ g_value_set_string (value, lightdm_user_get_background (self));
+ break;
+ case USER_PROP_LANGUAGE:
+ g_value_set_string (value, lightdm_user_get_language (self));
+ break;
+ case USER_PROP_LAYOUT:
+ g_value_set_string (value, lightdm_user_get_layout (self));
+ break;
+ case USER_PROP_LAYOUTS:
+ g_value_set_boxed (value, g_strdupv ((gchar **) lightdm_user_get_layouts (self)));
+ break;
+ case USER_PROP_SESSION:
+ g_value_set_string (value, lightdm_user_get_session (self));
+ break;
+ case USER_PROP_LOGGED_IN:
+ g_value_set_boolean (value, lightdm_user_get_logged_in (self));
+ break;
+ case USER_PROP_HAS_MESSAGES:
+ g_value_set_boolean (value, lightdm_user_get_has_messages (self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+lightdm_user_finalize (GObject *object)
+{
+ LightDMUser *self = LIGHTDM_USER (object);
+ LightDMUserPrivate *priv = GET_USER_PRIVATE (self);
+
+ g_free (priv->name);
+ g_free (priv->real_name);
+ g_free (priv->home_directory);
+ g_free (priv->image);
+ g_free (priv->background);
+ g_strfreev (priv->layouts);
+ if (priv->dmrc_file)
+ g_key_file_free (priv->dmrc_file);
+}
+
+static void
+lightdm_user_class_init (LightDMUserClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (LightDMUserPrivate));
+
+ object_class->set_property = lightdm_user_set_property;
+ object_class->get_property = lightdm_user_get_property;
+ object_class->finalize = lightdm_user_finalize;
+
+ g_object_class_install_property (object_class,
+ USER_PROP_NAME,
+ g_param_spec_string ("name",
+ "name",
+ "Username",
+ NULL,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ USER_PROP_REAL_NAME,
+ g_param_spec_string ("real-name",
+ "real-name",
+ "Users real name",
+ NULL,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ USER_PROP_DISPLAY_NAME,
+ g_param_spec_string ("display-name",
+ "display-name",
+ "Users display name",
+ NULL,
+ G_PARAM_READABLE));
+ g_object_class_install_property (object_class,
+ USER_PROP_HOME_DIRECTORY,
+ g_param_spec_string ("home-directory",
+ "home-directory",
+ "Home directory",
+ NULL,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ USER_PROP_IMAGE,
+ g_param_spec_string ("image",
+ "image",
+ "Avatar image",
+ NULL,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ USER_PROP_BACKGROUND,
+ g_param_spec_string ("background",
+ "background",
+ "User background",
+ NULL,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ USER_PROP_LANGUAGE,
+ g_param_spec_string ("language",
+ "language",
+ "Language used by this user",
+ NULL,
+ G_PARAM_READABLE));
+ g_object_class_install_property (object_class,
+ USER_PROP_LAYOUT,
+ g_param_spec_string ("layout",
+ "layout",
+ "Keyboard layout used by this user",
+ NULL,
+ G_PARAM_READABLE));
+ g_object_class_install_property (object_class,
+ USER_PROP_LAYOUTS,
+ g_param_spec_boxed ("layouts",
+ "layouts",
+ "Keyboard layouts used by this user",
+ G_TYPE_STRV,
+ G_PARAM_READABLE));
+ g_object_class_install_property (object_class,
+ USER_PROP_SESSION,
+ g_param_spec_string ("session",
+ "session",
+ "Session used by this user",
+ NULL,
+ G_PARAM_READABLE));
+ g_object_class_install_property (object_class,
+ USER_PROP_LOGGED_IN,
+ g_param_spec_boolean ("logged-in",
+ "logged-in",
+ "TRUE if the user is currently in a session",
+ FALSE,
+ G_PARAM_READWRITE));
+ g_object_class_install_property (object_class,
+ USER_PROP_LOGGED_IN,
+ g_param_spec_boolean ("has-messages",
+ "has-messages",
+ "TRUE if the user is has waiting messages",
+ FALSE,
+ G_PARAM_READWRITE));
+
+ /**
+ * LightDMUser::changed:
+ * @user: A #LightDMUser
+ *
+ * The ::changed signal gets emitted this user account is modified.
+ **/
+ user_signals[CHANGED] =
+ g_signal_new ("changed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (LightDMUserClass, changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+static void
+session_init (Session *session)
+{
+}
+
+static void
+session_finalize (GObject *object)
+{
+ Session *self = SESSION (object);
+
+ g_free (self->path);
+ g_free (self->username);
+}
+
+static void
+session_class_init (SessionClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = session_finalize;
+}