[gdm/multi-stack: 16/31] Add a plugin based extension system to greeter
- From: Ray Strode <halfline src gnome org>
- To: svn-commits-list gnome org
- Subject: [gdm/multi-stack: 16/31] Add a plugin based extension system to greeter
- Date: Fri, 17 Apr 2009 10:26:54 -0400 (EDT)
commit 5231302bd0b9611984639530884b14e6400e786f
Author: Ray Strode <rstrode redhat com>
Date: Fri Feb 6 16:23:48 2009 -0500
Add a plugin based extension system to greeter
This allows plugins to drive which PAM conversations
get run. This commit just adds one plugin "password"
which does the one PAM conversation we've traditionally
run.
---
configure.ac | 45 ++
gui/simple-greeter/Makefile.am | 15 +
gui/simple-greeter/gdm-greeter-client.c | 21 +
gui/simple-greeter/gdm-greeter-client.h | 2 +
gui/simple-greeter/gdm-greeter-login-window.c | 675 ++++++++++++++++----
gui/simple-greeter/gdm-greeter-login-window.glade | 144 +----
gui/simple-greeter/gdm-greeter-login-window.h | 21 +-
gui/simple-greeter/gdm-greeter-plugin.c | 255 ++++++++
gui/simple-greeter/gdm-greeter-plugin.h | 61 ++
gui/simple-greeter/gdm-greeter-session.c | 91 +++-
gui/simple-greeter/gdm-plugin-manager.c | 478 ++++++++++++++
gui/simple-greeter/gdm-plugin-manager.h | 66 ++
gui/simple-greeter/gdm-task-list.c | 216 +++++--
gui/simple-greeter/gdm-task-list.h | 36 +-
gui/simple-greeter/libgdmsimplegreeter/Makefile.am | 46 ++
.../libgdmsimplegreeter/gdm-conversation.c | 147 +++++
.../libgdmsimplegreeter/gdm-conversation.h | 87 +++
.../libgdmsimplegreeter/gdm-greeter-extension.c | 93 +++
.../libgdmsimplegreeter/gdm-greeter-extension.h | 55 ++
gui/simple-greeter/libgdmsimplegreeter/gdm-task.c | 117 ++++
gui/simple-greeter/libgdmsimplegreeter/gdm-task.h | 62 ++
.../libgdmsimplegreeter/gdmsimplegreeter.pc.in | 11 +
gui/simple-greeter/plugins/Makefile.am | 1 +
gui/simple-greeter/plugins/password/Makefile.am | 53 ++
.../plugins/password/gdm-password-extension.c | 316 +++++++++
.../plugins/password/gdm-password-extension.h | 56 ++
.../plugins/password/gdm-password.pam | 19 +
gui/simple-greeter/plugins/password/page.ui | 56 ++
gui/simple-greeter/plugins/password/plugin.c | 40 ++
29 files changed, 2988 insertions(+), 297 deletions(-)
diff --git a/configure.ac b/configure.ac
index 925a353..23df306 100644
--- a/configure.ac
+++ b/configure.ac
@@ -18,6 +18,22 @@ AC_PROG_CXX
AM_PROG_CC_C_O
AC_PROG_LIBTOOL()
+## increment if the plugin interface has additions, changes, removals.
+LT_CURRENT=1
+
+## increment any time the source changes; set to
+## 0 if you increment CURRENT
+LT_REVISION=0
+
+## increment if any interfaces have been added; set to 0
+## if any interfaces have been changed or removed. removal has
+## precedence over adding, so set to 0 if both happened.
+LT_AGE=0
+
+AC_SUBST(LT_CURRENT)
+AC_SUBST(LT_REVISION)
+AC_SUBST(LT_AGE)
+
AC_HEADER_STDC
AC_SUBST(VERSION)
@@ -199,6 +215,15 @@ AC_ARG_WITH(dmconfdir,
AC_SUBST(dmconfdir)
dnl ---------------------------------------------------------------------------
+dnl - Configuration file stuff
+dnl ---------------------------------------------------------------------------
+AC_ARG_WITH(extensionsdatadir,
+ AS_HELP_STRING([--with-extensions-datadir],
+ [directory where extensions store data, default=DATADIR/gdm/simple-greeter/extensions]),
+ extensionsdatadir=${withval}, extensionsdatadir=${datadir}/gdm/simple-greeter/extensions)
+AC_SUBST(extensionsdatadir)
+
+dnl ---------------------------------------------------------------------------
dnl - Configure arguments
dnl ---------------------------------------------------------------------------
@@ -1231,6 +1256,22 @@ fi
AC_SUBST(GDM_XAUTH_DIR)
dnl ---------------------------------------------------------------------------
+dnl - Directory for simple greeter plugins
+dnl ---------------------------------------------------------------------------
+
+AC_ARG_WITH(simple-greeter-plugins-dir,
+ AS_HELP_STRING([--with-simple-greeter-plugins-dir=<dir>],
+ [simple greeter plugins directory]))
+
+if ! test -z "$with_simple_greeter_plugins_dir"; then
+ GDM_SIMPLE_GREETER_PLUGINS_DIR=$with_simple_greeter_plugins_dir
+else
+ GDM_SIMPLE_GREETER_PLUGINS_DIR=${libdir}/gdm/simple-greeter/plugins
+fi
+
+AC_SUBST(GDM_SIMPLE_GREETER_PLUGINS_DIR)
+
+dnl ---------------------------------------------------------------------------
dnl - Finish
dnl ---------------------------------------------------------------------------
@@ -1357,6 +1398,10 @@ docs/Makefile
gui/Makefile
gui/simple-greeter/Makefile
gui/simple-greeter/libnotificationarea/Makefile
+gui/simple-greeter/libgdmsimplegreeter/Makefile
+gui/simple-greeter/libgdmsimplegreeter/gdmsimplegreeter.pc
+gui/simple-greeter/plugins/Makefile
+gui/simple-greeter/plugins/password/Makefile
gui/simple-chooser/Makefile
gui/user-switch-applet/Makefile
utils/Makefile
diff --git a/gui/simple-greeter/Makefile.am b/gui/simple-greeter/Makefile.am
index e2d3996..a9e4d65 100644
--- a/gui/simple-greeter/Makefile.am
+++ b/gui/simple-greeter/Makefile.am
@@ -2,11 +2,14 @@ NULL =
SUBDIRS = \
libnotificationarea \
+ libgdmsimplegreeter \
+ plugins \
$(NULL)
AM_CPPFLAGS = \
-I$(top_srcdir)/common \
-I$(top_srcdir)/gui/simple-greeter/libnotificationarea \
+ -I$(top_srcdir)/gui/simple-greeter/libgdmsimplegreeter \
-DDMCONFDIR=\""$(dmconfdir)"\" \
-DGDMCONFDIR=\"$(gdmconfdir)\" \
-DDATADIR=\""$(datadir)"\" \
@@ -17,6 +20,7 @@ AM_CPPFLAGS = \
-DLIBEXECDIR=\""$(libexecdir)"\" \
-DSBINDIR=\""$(sbindir)"\" \
-DAT_SPI_REGISTRYD_DIR="\"$(AT_SPI_REGISTRYD_DIR)\"" \
+ -DGDM_SIMPLE_GREETER_PLUGINS_DIR="\"$(GDM_SIMPLE_GREETER_PLUGINS_DIR)\""\
$(DISABLE_DEPRECATED_CFLAGS) \
$(GTK_CFLAGS) \
$(SIMPLE_GREETER_CFLAGS) \
@@ -85,10 +89,15 @@ test_greeter_login_window_SOURCES = \
gdm-user-chooser-dialog.c \
gdm-task-list.h \
gdm-task-list.c \
+ gdm-plugin-manager.h \
+ gdm-plugin-manager.c \
+ gdm-greeter-plugin.h \
+ gdm-greeter-plugin.c \
$(NULL)
test_greeter_login_window_LDADD = \
$(top_builddir)/common/libgdmcommon.la \
+ $(top_builddir)/gui/simple-greeter/libgdmsimplegreeter/libgdmsimplegreeter.la \
libgdmuser.la \
$(COMMON_LIBS) \
$(SIMPLE_GREETER_LIBS) \
@@ -140,6 +149,7 @@ test_greeter_panel_SOURCES = \
test_greeter_panel_LDADD = \
$(top_builddir)/common/libgdmcommon.la \
$(top_builddir)/gui/simple-greeter/libnotificationarea/libnotificationarea.la \
+ $(top_builddir)/gui/simple-greeter/libgdmsimplegreeter/libgdmsimplegreeter.la \
$(SIMPLE_GREETER_LIBS) \
$(GTK_LIBS) \
$(GCONF_LIBS) \
@@ -312,10 +322,14 @@ gdm_simple_greeter_SOURCES = \
gdm-language-chooser-dialog.c \
gdm-language-option-widget.h \
gdm-language-option-widget.c \
+ gdm-plugin-manager.h \
+ gdm-plugin-manager.c \
gdm-sessions.h \
gdm-sessions.c \
gdm-session-option-widget.h \
gdm-session-option-widget.c \
+ gdm-greeter-plugin.h \
+ gdm-greeter-plugin.c \
gdm-user-chooser-widget.h \
gdm-user-chooser-widget.c \
gdm-task-list.h \
@@ -326,6 +340,7 @@ gdm_simple_greeter_LDADD = \
$(top_builddir)/common/libgdmcommon.la \
libgdmuser.la \
$(top_builddir)/gui/simple-greeter/libnotificationarea/libnotificationarea.la \
+ $(top_builddir)/gui/simple-greeter/libgdmsimplegreeter/libgdmsimplegreeter.la \
$(COMMON_LIBS) \
$(EXTRA_GREETER_LIBS) \
$(SIMPLE_GREETER_LIBS) \
diff --git a/gui/simple-greeter/gdm-greeter-client.c b/gui/simple-greeter/gdm-greeter-client.c
index 0bd27a9..a9321aa 100644
--- a/gui/simple-greeter/gdm-greeter-client.c
+++ b/gui/simple-greeter/gdm-greeter-client.c
@@ -64,6 +64,7 @@ enum {
INFO_QUERY,
SECRET_INFO_QUERY,
READY,
+ CONVERSATION_STOPPED,
RESET,
SELECTED_USER_CHANGED,
DEFAULT_LANGUAGE_NAME_CHANGED,
@@ -270,6 +271,13 @@ on_ready (GdmGreeterClient *client,
}
static void
+on_conversation_stopped (GdmGreeterClient *client,
+ DBusMessage *message)
+{
+ emit_string_signal_for_message (client, "ConversationStopped", message, CONVERSATION_STOPPED);
+}
+
+static void
on_reset (GdmGreeterClient *client,
DBusMessage *message)
{
@@ -760,6 +768,8 @@ client_dbus_handle_message (DBusConnection *connection,
on_problem (client, message);
} else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "Ready")) {
on_ready (client, message);
+ } else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "ConversationStopped")) {
+ on_conversation_stopped (client, message);
} else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "Reset")) {
on_reset (client, message);
} else if (dbus_message_is_signal (message, GREETER_SERVER_DBUS_INTERFACE, "SelectedUserChanged")) {
@@ -1000,6 +1010,17 @@ gdm_greeter_client_class_init (GdmGreeterClientClass *klass)
G_TYPE_NONE,
1, G_TYPE_STRING);
+ gdm_greeter_client_signals[CONVERSATION_STOPPED] =
+ g_signal_new ("conversation-stopped",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GdmGreeterClientClass, conversation_stopped),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1, G_TYPE_STRING);
+
gdm_greeter_client_signals[RESET] =
g_signal_new ("reset",
G_OBJECT_CLASS_TYPE (object_class),
diff --git a/gui/simple-greeter/gdm-greeter-client.h b/gui/simple-greeter/gdm-greeter-client.h
index 2f857dc..f879307 100644
--- a/gui/simple-greeter/gdm-greeter-client.h
+++ b/gui/simple-greeter/gdm-greeter-client.h
@@ -61,6 +61,8 @@ typedef struct
const char *problem);
void (* ready) (GdmGreeterClient *client,
const char *service_name);
+ void (* conversation_stopped) (GdmGreeterClient *client,
+ const char *service_name);
void (* reset) (GdmGreeterClient *client);
void (* selected_user_changed) (GdmGreeterClient *client,
const char *username);
diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c
index d08404e..2e9a1a0 100644
--- a/gui/simple-greeter/gdm-greeter-login-window.c
+++ b/gui/simple-greeter/gdm-greeter-login-window.c
@@ -1,7 +1,7 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
*
* Copyright (C) 2007 William Jon McCann <mccann jhu edu>
- * Copyright (C) 2008 Red Hat, Inc.
+ * Copyright (C) 2008, 2009 Red Hat, Inc.
*
* 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
@@ -17,6 +17,9 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
+ * Written by: William Jon McCann <mccann jhu edu>
+ * Ray Strode <rstrode redhat com>
+ *
*/
#include "config.h"
@@ -117,6 +120,7 @@ struct GdmGreeterLoginWindowPrivate
GtkWidget *user_chooser;
GtkWidget *conversation_list;
GtkWidget *auth_banner_label;
+ GtkWidget *auth_page_box;
guint display_is_local : 1;
guint is_interactive : 1;
GConfClient *client;
@@ -166,6 +170,9 @@ static void restart_timed_login_timeout (GdmGreeterLoginWindow *login_window
static void on_user_unchosen (GdmUserChooserWidget *user_chooser,
GdmGreeterLoginWindow *login_window);
+static void gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_window,
+ const char *service_name);
+
G_DEFINE_TYPE (GdmGreeterLoginWindow, gdm_greeter_login_window, GTK_TYPE_WINDOW)
static void
@@ -190,9 +197,6 @@ set_sensitive (GdmGreeterLoginWindow *login_window,
{
GtkWidget *box;
- box = glade_xml_get_widget (login_window->priv->xml, "auth-input-box");
- gtk_widget_set_sensitive (box, sensitive);
-
box = glade_xml_get_widget (login_window->priv->xml, "buttonbox");
gtk_widget_set_sensitive (box, sensitive);
@@ -202,27 +206,43 @@ set_sensitive (GdmGreeterLoginWindow *login_window,
static void
set_focus (GdmGreeterLoginWindow *login_window)
{
- GtkWidget *entry;
-
- entry = glade_xml_get_widget (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->xml, "auth-prompt-entry");
+ GdmTask *task;
gdk_window_focus (GTK_WIDGET (login_window)->window, GDK_CURRENT_TIME);
- if (GTK_WIDGET_REALIZED (entry) && ! GTK_WIDGET_HAS_FOCUS (entry)) {
- gtk_widget_grab_focus (entry);
+ task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
+
+ if (gdm_conversation_focus (GDM_CONVERSATION (task))) {
+ char *name;
+ name = gdm_task_get_name (task);
+ g_debug ("GdmGreeterLoginWindow: focusing task %s", name);
+ g_free (name);
} else if (GTK_WIDGET_REALIZED (login_window->priv->user_chooser) && ! GTK_WIDGET_HAS_FOCUS (login_window->priv->user_chooser)) {
gtk_widget_grab_focus (login_window->priv->user_chooser);
}
+ g_object_unref (task);
+}
+
+static gboolean
+set_task_conversation_message (GdmTaskList *task_list,
+ GdmTask *task,
+ const char *message)
+{
+
+ gdm_conversation_set_message (GDM_CONVERSATION (task), message);
+ return FALSE;
}
static void
set_message (GdmGreeterLoginWindow *login_window,
const char *text)
{
- GtkWidget *label;
+ g_return_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window));
- label = glade_xml_get_widget (login_window->priv->xml, "auth-message-label");
- gtk_label_set_text (GTK_LABEL (label), text);
+ gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+ (GdmTaskListForeachFunc)
+ set_task_conversation_message,
+ (gpointer) text);
}
static void
@@ -388,30 +408,76 @@ get_show_restart_buttons (GdmGreeterLoginWindow *login_window)
}
static void
-on_login_button_clicked_answer_query (GtkButton *button,
- GdmGreeterLoginWindow *login_window)
+on_login_button_clicked_timed_login (GtkButton *button,
+ GdmGreeterLoginWindow *login_window)
{
- GtkWidget *entry;
- const char *text;
-
set_busy (login_window);
set_sensitive (login_window, FALSE);
- entry = glade_xml_get_widget (login_window->priv->xml, "auth-prompt-entry");
- text = gtk_entry_get_text (GTK_ENTRY (entry));
-
_gdm_greeter_login_window_set_interactive (login_window, TRUE);
- g_signal_emit (login_window, signals[QUERY_ANSWER], 0, "gdm", text);
}
static void
-on_login_button_clicked_timed_login (GtkButton *button,
- GdmGreeterLoginWindow *login_window)
+hide_task_actions (GdmTask *task)
{
- set_busy (login_window);
- set_sensitive (login_window, FALSE);
+ GtkActionGroup *actions;
- _gdm_greeter_login_window_set_interactive (login_window, TRUE);
+ actions = gdm_conversation_get_actions (GDM_CONVERSATION (task));
+
+ if (actions != NULL) {
+ gtk_action_group_set_visible (actions, FALSE);
+ gtk_action_group_set_sensitive (actions, FALSE);
+ g_object_unref (actions);
+ }
+}
+
+static void
+grab_default_button_for_task (GdmTask *task)
+{
+ GtkActionGroup *actions;
+ GtkAction *action;
+ GSList *proxies, *node;
+
+ actions = gdm_conversation_get_actions (GDM_CONVERSATION (task));
+
+ if (actions == NULL) {
+ return;
+ }
+
+ action = gtk_action_group_get_action (actions, GDM_CONVERSATION_DEFAULT_ACTION);
+ g_object_unref (actions);
+
+ if (action == NULL) {
+ return;
+ }
+
+ proxies = gtk_action_get_proxies (action);
+ for (node = proxies; node != NULL; node = node->next) {
+ GtkWidget *widget;
+
+ widget = GTK_WIDGET (node->data);
+
+ if (GTK_WIDGET_CAN_DEFAULT (widget) &&
+ GTK_WIDGET_VISIBLE (widget)) {
+ gtk_widget_grab_default (widget);
+ break;
+ }
+ }
+
+}
+
+static void
+show_task_actions (GdmTask *task)
+{
+ GtkActionGroup *actions;
+
+ actions = gdm_conversation_get_actions (GDM_CONVERSATION (task));
+
+ if (actions != NULL) {
+ gtk_action_group_set_sensitive (actions, TRUE);
+ gtk_action_group_set_visible (actions, TRUE);
+ g_object_unref (actions);
+ }
}
static void
@@ -419,6 +485,7 @@ set_log_in_button_mode (GdmGreeterLoginWindow *login_window,
int mode)
{
GtkWidget *button;
+ GdmTask *task;
button = glade_xml_get_widget (login_window->priv->xml, "log-in-button");
gtk_widget_grab_default (button);
@@ -431,14 +498,27 @@ set_log_in_button_mode (GdmGreeterLoginWindow *login_window,
switch (mode) {
case LOGIN_BUTTON_HIDDEN:
+ task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
+ if (task != NULL) {
+ hide_task_actions (task);
+ g_object_unref (task);
+ }
+
gtk_widget_hide (button);
break;
case LOGIN_BUTTON_ANSWER_QUERY:
- login_window->priv->login_button_handler_id = g_signal_connect (button, "clicked", G_CALLBACK (on_login_button_clicked_answer_query), login_window);
- gtk_widget_show (button);
+ task = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
+ if (task != NULL) {
+ show_task_actions (task);
+ grab_default_button_for_task (task);
+ g_object_unref (task);
+ }
+
+ gtk_widget_hide (button);
break;
case LOGIN_BUTTON_TIMED_LOGIN:
login_window->priv->login_button_handler_id = g_signal_connect (button, "clicked", G_CALLBACK (on_login_button_clicked_timed_login), login_window);
+
gtk_widget_show (button);
break;
default:
@@ -562,7 +642,7 @@ switch_mode (GdmGreeterLoginWindow *login_window,
show_widget (login_window, "disconnect-button",
! login_window->priv->display_is_local);
- show_widget (login_window, "auth-input-box", FALSE);
+ show_widget (login_window, "auth-page-box", FALSE);
add_sensitize_power_buttons_timeout (login_window);
sensitize_widget (login_window, "shutdown-button", FALSE);
@@ -578,6 +658,7 @@ switch_mode (GdmGreeterLoginWindow *login_window,
show_widget (login_window, "restart-button", FALSE);
show_widget (login_window, "suspend-button", FALSE);
show_widget (login_window, "disconnect-button", FALSE);
+ show_widget (login_window, "auth-page-box", TRUE);
default_name = "log-in-button";
break;
default:
@@ -657,25 +738,40 @@ do_suspend (GdmGreeterLoginWindow *login_window)
g_object_unref (proxy);
}
-static void
-delete_entry_text (GtkWidget *entry)
+static gboolean
+task_has_service_name (GdmTaskList *task_list,
+ GdmTask *task,
+ const char *service_name)
{
- const char *typed_text;
- char *null_text;
+ char *task_service_name;
+ gboolean has_service_name;
+
+ task_service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (task));
+
+ has_service_name = strcmp (service_name, task_service_name) == 0;
+ g_free (task_service_name);
- /* try to scrub out any secret info */
- typed_text = gtk_entry_get_text (GTK_ENTRY (entry));
- null_text = g_strnfill (strlen (typed_text) + 1, '\b');
- gtk_entry_set_text (GTK_ENTRY (entry), null_text);
- gtk_entry_set_text (GTK_ENTRY (entry), "");
+ return has_service_name;
+}
+
+static gboolean
+reset_task (GdmTaskList *task_list,
+ GdmTask *task,
+ GdmGreeterLoginWindow *login_window)
+{
+ char *name;
+
+ name = gdm_task_get_name (task);
+ g_debug ("Resetting task '%s'", name);
+ g_free (name);
+
+ gdm_conversation_reset (GDM_CONVERSATION (task));
+ return FALSE;
}
static void
reset_dialog (GdmGreeterLoginWindow *login_window)
{
- GtkWidget *entry;
- GtkWidget *label;
-
g_debug ("GdmGreeterLoginWindow: Resetting dialog");
set_busy (login_window);
set_sensitive (login_window, FALSE);
@@ -699,16 +795,12 @@ reset_dialog (GdmGreeterLoginWindow *login_window)
login_window->priv->start_session_handler_id = 0;
}
- entry = glade_xml_get_widget (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->xml, "auth-prompt-entry");
-
- delete_entry_text (entry);
+ gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+ (GdmTaskListForeachFunc)
+ reset_task,
+ login_window);
- gtk_entry_set_visibility (GTK_ENTRY (entry), TRUE);
set_message (login_window, "");
-
- label = glade_xml_get_widget (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->xml, "auth-prompt-label");
- gtk_label_set_text (GTK_LABEL (label), "");
-
switch_mode (login_window, MODE_SELECTION);
set_sensitive (login_window, TRUE);
@@ -728,11 +820,22 @@ do_cancel (GdmGreeterLoginWindow *login_window)
}
gboolean
-gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window)
+gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window,
+ const char *service_name)
{
+ GdmTask *task;
+
g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
- reset_dialog (login_window);
+ task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+ (GdmTaskListForeachFunc)
+ task_has_service_name,
+ (gpointer) service_name);
+
+ if (task != NULL) {
+ gdm_conversation_set_ready (GDM_CONVERSATION (task));
+ g_object_unref (task);
+ }
set_sensitive (GDM_GREETER_LOGIN_WINDOW (login_window), TRUE);
set_ready (GDM_GREETER_LOGIN_WINDOW (login_window));
@@ -742,12 +845,63 @@ gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window)
}
gboolean
-gdm_greeter_login_window_reset (GdmGreeterLoginWindow *login_window)
+gdm_greeter_login_window_conversation_stopped (GdmGreeterLoginWindow *login_window,
+ const char *service_name)
{
+ GdmTask *task;
+
g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
+ g_debug ("GdmGreeterLoginWindow: conversation '%s' has stopped", service_name);
+
+ task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+ (GdmTaskListForeachFunc)
+ task_has_service_name,
+ (gpointer) service_name);
+
+ if (task != NULL) {
+ gdm_conversation_reset (GDM_CONVERSATION (task));
+ g_object_unref (task);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+restart_task_conversation (GdmTaskList *task_list,
+ GdmTask *task,
+ GdmGreeterLoginWindow *login_window)
+{
+ char *service_name;
+
+ service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (task));
+ if (service_name != NULL) {
+ char *name;
+
+ name = gdm_task_get_name (task);
+ g_debug ("GdmGreeterLoginWindow: restarting '%s' conversation", name);
+ g_free (name);
+
+ g_signal_emit (login_window, signals[START_CONVERSATION], 0, service_name);
+ g_free (service_name);
+ }
+
+ return FALSE;
+}
+
+gboolean
+gdm_greeter_login_window_reset (GdmGreeterLoginWindow *login_window)
+{
+ g_debug ("GdmGreeterLoginWindow: window reset");
+
+ g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
reset_dialog (GDM_GREETER_LOGIN_WINDOW (login_window));
+ gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+ (GdmTaskListForeachFunc)
+ restart_task_conversation,
+ login_window);
+
return TRUE;
}
@@ -756,12 +910,20 @@ gdm_greeter_login_window_info (GdmGreeterLoginWindow *login_window,
const char *service_name,
const char *text)
{
- g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
+ GdmTask *task;
+ g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
g_debug ("GdmGreeterLoginWindow: info: %s", text);
- if (strcmp (service_name, gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list))) == 0) {
- set_message (GDM_GREETER_LOGIN_WINDOW (login_window), text);
+ task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+ (GdmTaskListForeachFunc)
+ task_has_service_name,
+ (gpointer) service_name);
+
+ if (task != NULL) {
+ gdm_conversation_set_message (GDM_CONVERSATION (task),
+ text);
+ g_object_unref (task);
}
return TRUE;
@@ -772,13 +934,22 @@ gdm_greeter_login_window_problem (GdmGreeterLoginWindow *login_window,
const char *service_name,
const char *text)
{
- g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
+ GdmTask *task;
+ g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
g_debug ("GdmGreeterLoginWindow: problem: %s", text);
- if (strcmp (service_name, gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list))) == 0) {
- set_message (GDM_GREETER_LOGIN_WINDOW (login_window), text);
+ task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+ (GdmTaskListForeachFunc)
+ task_has_service_name,
+ (gpointer) service_name);
+
+ if (task != NULL) {
+ gdm_conversation_set_message (GDM_CONVERSATION (task),
+ text);
+ g_object_unref (task);
}
+
gdk_window_beep (GTK_WIDGET (login_window)->window);
return TRUE;
@@ -816,11 +987,21 @@ gdm_greeter_login_window_request_timed_login (GdmGreeterLoginWindow *login_windo
}
static void
-gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_window)
+on_ready_to_start_session (GdmGreeterLoginWindow *login_window,
+ GParamSpec *param_spec,
+ char *service_name)
+{
+ gdm_greeter_login_window_start_session_when_ready (login_window, service_name);
+ g_free (service_name);
+}
+
+static void
+gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_window,
+ const char *service_name)
{
if (login_window->priv->is_interactive) {
g_debug ("GdmGreeterLoginWindow: starting session");
- g_signal_emit (login_window, signals[START_SESSION], 0);
+ g_signal_emit (login_window, signals[START_SESSION], 0, service_name);
} else {
g_debug ("GdmGreeterLoginWindow: not starting session since "
"user hasn't had an opportunity to pick language "
@@ -830,8 +1011,8 @@ gdm_greeter_login_window_start_session_when_ready (GdmGreeterLoginWindow *login_
*/
login_window->priv->start_session_handler_id =
g_signal_connect (login_window, "notify::is-interactive",
- G_CALLBACK (gdm_greeter_login_window_start_session_when_ready),
- NULL);
+ G_CALLBACK (on_ready_to_start_session),
+ g_strdup (service_name));
/* FIXME: If the user wasn't asked any questions by pam but
* pam still authorized them (passwd -d, or the questions got
@@ -857,26 +1038,24 @@ gdm_greeter_login_window_info_query (GdmGreeterLoginWindow *login_window,
const char *service_name,
const char *text)
{
- GtkWidget *entry;
- GtkWidget *label;
+ GdmTask *task;
g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
- if (strcmp (service_name, gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list))) != 0) {
- return TRUE;
- }
-
g_debug ("GdmGreeterLoginWindow: info query: %s", text);
- entry = glade_xml_get_widget (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->xml, "auth-prompt-entry");
- delete_entry_text (entry);
- gtk_entry_set_visibility (GTK_ENTRY (entry), TRUE);
- set_log_in_button_mode (login_window, LOGIN_BUTTON_ANSWER_QUERY);
+ task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+ (GdmTaskListForeachFunc)
+ task_has_service_name,
+ (gpointer) service_name);
- label = glade_xml_get_widget (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->xml, "auth-prompt-label");
- gtk_label_set_text (GTK_LABEL (label), text);
+ if (task != NULL) {
+ gdm_conversation_ask_question (GDM_CONVERSATION (task),
+ text);
+ g_object_unref (task);
+ }
- show_widget (login_window, "auth-input-box", TRUE);
+ set_log_in_button_mode (login_window, LOGIN_BUTTON_ANSWER_QUERY);
set_sensitive (GDM_GREETER_LOGIN_WINDOW (login_window), TRUE);
set_ready (GDM_GREETER_LOGIN_WINDOW (login_window));
set_focus (GDM_GREETER_LOGIN_WINDOW (login_window));
@@ -891,20 +1070,23 @@ gdm_greeter_login_window_secret_info_query (GdmGreeterLoginWindow *login_window,
const char *service_name,
const char *text)
{
- GtkWidget *entry;
- GtkWidget *label;
+
+ GdmTask *task;
g_return_val_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window), FALSE);
- entry = glade_xml_get_widget (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->xml, "auth-prompt-entry");
- delete_entry_text (entry);
- gtk_entry_set_visibility (GTK_ENTRY (entry), FALSE);
- set_log_in_button_mode (login_window, LOGIN_BUTTON_ANSWER_QUERY);
+ task = gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+ (GdmTaskListForeachFunc)
+ task_has_service_name,
+ (gpointer) service_name);
- label = glade_xml_get_widget (GDM_GREETER_LOGIN_WINDOW (login_window)->priv->xml, "auth-prompt-label");
- gtk_label_set_text (GTK_LABEL (label), text);
+ if (task != NULL) {
+ gdm_conversation_ask_secret (GDM_CONVERSATION (task),
+ text);
+ g_object_unref (task);
+ }
- show_widget (login_window, "auth-input-box", TRUE);
+ set_log_in_button_mode (login_window, LOGIN_BUTTON_ANSWER_QUERY);
set_sensitive (GDM_GREETER_LOGIN_WINDOW (login_window), TRUE);
set_ready (GDM_GREETER_LOGIN_WINDOW (login_window));
set_focus (GDM_GREETER_LOGIN_WINDOW (login_window));
@@ -915,13 +1097,16 @@ gdm_greeter_login_window_secret_info_query (GdmGreeterLoginWindow *login_window,
}
void
-gdm_greeter_login_window_user_authorized (GdmGreeterLoginWindow *login_window)
+gdm_greeter_login_window_user_authorized (GdmGreeterLoginWindow *login_window,
+ const char *service_name)
{
g_return_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window));
- g_debug ("GdmGreeterLoginWindow: user now authorized");
+ g_debug ("GdmGreeterLoginWindow: user now authorized via service %s",
+ service_name);
- gdm_greeter_login_window_start_session_when_ready (login_window);
+ gdm_greeter_login_window_start_session_when_ready (login_window,
+ service_name);
}
static void
@@ -1344,6 +1529,46 @@ on_users_loaded (GdmUserChooserWidget *user_chooser,
gdm_chooser_widget_activate_if_one_item (GDM_CHOOSER_WIDGET (login_window->priv->user_chooser));
}
+static gboolean
+begin_task_verification (GdmTaskList *task_list,
+ GdmTask *task,
+ GdmGreeterLoginWindow *login_window)
+{
+ char *service_name;
+
+ service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (task));
+ if (service_name != NULL) {
+ g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0, service_name);
+ g_free (service_name);
+ }
+
+ return FALSE;
+}
+
+static gboolean
+begin_task_verification_for_selected_user (GdmTaskList *task_list,
+ GdmTask *task,
+ GdmGreeterLoginWindow *login_window)
+{
+ char *user_name;
+ char *service_name;
+
+ user_name = gdm_user_chooser_widget_get_chosen_user_name (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser));
+
+ if (user_name == NULL) {
+ return TRUE;
+ }
+
+ service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (task));
+ if (service_name != NULL) {
+ g_signal_emit (login_window, signals[BEGIN_VERIFICATION_FOR_USER], 0, service_name, user_name);
+ g_free (service_name);
+ }
+
+ g_free (user_name);
+ return FALSE;
+}
+
static void
on_user_chosen (GdmUserChooserWidget *user_chooser,
GdmGreeterLoginWindow *login_window)
@@ -1361,10 +1586,10 @@ on_user_chosen (GdmUserChooserWidget *user_chooser,
0, user_name);
if (strcmp (user_name, GDM_USER_CHOOSER_USER_OTHER) == 0) {
- const char *service_name;
-
- service_name = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
- g_signal_emit (login_window, signals[BEGIN_VERIFICATION], 0, service_name);
+ gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+ (GdmTaskListForeachFunc)
+ begin_task_verification,
+ login_window);
} else if (strcmp (user_name, GDM_USER_CHOOSER_USER_GUEST) == 0) {
/* FIXME: handle guest account stuff */
} else if (strcmp (user_name, GDM_USER_CHOOSER_USER_AUTO) == 0) {
@@ -1378,10 +1603,10 @@ on_user_chosen (GdmUserChooserWidget *user_chooser,
set_log_in_button_mode (login_window, LOGIN_BUTTON_TIMED_LOGIN);
set_message (login_window, _("Select language and click Log In"));
} else {
- const char *service_name;
-
- service_name = gdm_task_list_get_active_task (GDM_TASK_LIST (login_window->priv->conversation_list));
- g_signal_emit (login_window, signals[BEGIN_VERIFICATION_FOR_USER], 0, service_name, user_name);
+ gdm_task_list_foreach_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+ (GdmTaskListForeachFunc)
+ begin_task_verification_for_selected_user,
+ login_window);
}
switch_mode (login_window, MODE_AUTHENTICATION);
@@ -1527,17 +1752,65 @@ create_computer_info (GdmGreeterLoginWindow *login_window)
static void
on_task_activated (GdmGreeterLoginWindow *login_window,
- const char *name)
+ GdmTask *task)
{
- g_debug ("GdmGreeterLoginWindow: starting conversation with '%s'", name);
- g_signal_emit (login_window, signals[START_CONVERSATION], 0, name);
+ GtkWidget *container;
+ char *name;
+
+ name = gdm_task_get_name (task);
+ g_debug ("GdmGreeterLoginWindow: task '%s' activated", name);
+ g_free (name);
+
+ container = g_object_get_data (G_OBJECT (task),
+ "gdm-greeter-login-window-page-container");
+
+ if (container == NULL) {
+ GtkWidget *page;
+
+ container = gtk_alignment_new (0.5, 0.5, 1.0, 1.0);
+ gtk_container_add (GTK_CONTAINER (login_window->priv->auth_page_box),
+ container);
+
+ page = gdm_conversation_get_page (GDM_CONVERSATION (task));
+ if (page != NULL) {
+ gtk_container_add (GTK_CONTAINER (container), page);
+ gtk_widget_show (page);
+ }
+ g_object_set_data (G_OBJECT (task),
+ "gdm-greeter-login-window-page-container",
+ container);
+ }
+
+ gtk_widget_show (container);
+ set_log_in_button_mode (login_window, login_window->priv->dialog_mode);
}
static void
on_task_deactivated (GdmGreeterLoginWindow *login_window,
- const char *name)
+ GdmTask *task)
{
- g_debug ("GdmGreeterLoginWindow: conversation '%s' now in background", name);
+ GtkWidget *container;
+ char *name;
+ GtkActionGroup *actions;
+
+ name = gdm_task_get_name (task);
+ g_debug ("GdmGreeterLoginWindow: task '%s' now in background", name);
+ g_free (name);
+
+ container = g_object_get_data (G_OBJECT (task),
+ "gdm-greeter-login-window-page-container");
+
+ if (container != NULL) {
+ gtk_widget_hide (container);
+ }
+
+ actions = gdm_conversation_get_actions (GDM_CONVERSATION (task));
+
+ if (actions != NULL) {
+ gtk_action_group_set_sensitive (actions, FALSE);
+ gtk_action_group_set_visible (actions, FALSE);
+ g_object_unref (actions);
+ }
}
static GtkWidget *
@@ -1574,7 +1847,6 @@ custom_widget_constructor (GladeXML *xml,
static void
load_theme (GdmGreeterLoginWindow *login_window)
{
- GtkWidget *entry;
GtkWidget *button;
GtkWidget *box;
GtkWidget *image;
@@ -1649,15 +1921,9 @@ load_theme (GdmGreeterLoginWindow *login_window)
login_window);
gtk_widget_show (login_window->priv->conversation_list);
- gdm_task_list_add_task (GDM_TASK_LIST (login_window->priv->conversation_list),
- "password-auth", "dialog-password");
- gdm_task_list_add_task (GDM_TASK_LIST (login_window->priv->conversation_list),
- "fingerprint-auth", "stock_allow-effects");
- gdm_task_list_add_task (GDM_TASK_LIST (login_window->priv->conversation_list),
- "smartcard-auth", "badge-small");
-
login_window->priv->auth_banner_label = glade_xml_get_widget (login_window->priv->xml, "auth-banner-label");
/*make_label_small_italic (login_window->priv->auth_banner_label);*/
+ login_window->priv->auth_page_box = glade_xml_get_widget (login_window->priv->xml, "auth-page-box");
button = glade_xml_get_widget (login_window->priv->xml, "suspend-button");
g_signal_connect (button, "clicked", G_CALLBACK (suspend_button_clicked), login_window);
@@ -1673,14 +1939,6 @@ load_theme (GdmGreeterLoginWindow *login_window)
button = glade_xml_get_widget (login_window->priv->xml, "shutdown-button");
g_signal_connect (button, "clicked", G_CALLBACK (shutdown_button_clicked), login_window);
- entry = glade_xml_get_widget (login_window->priv->xml, "auth-prompt-entry");
- /* Only change the invisible character if it '*' otherwise assume it is OK */
- if ('*' == gtk_entry_get_invisible_char (GTK_ENTRY (entry))) {
- gunichar invisible_char;
- invisible_char = INVISIBLE_CHAR_BLACK_CIRCLE;
- gtk_entry_set_invisible_char (GTK_ENTRY (entry), invisible_char);
- }
-
create_computer_info (login_window);
box = glade_xml_get_widget (login_window->priv->xml, "computer-info-event-box");
@@ -1908,9 +2166,9 @@ gdm_greeter_login_window_class_init (GdmGreeterLoginWindowClass *klass)
G_STRUCT_OFFSET (GdmGreeterLoginWindowClass, start_session),
NULL,
NULL,
- g_cclosure_marshal_VOID__VOID,
+ g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE,
- 0);
+ 1, G_TYPE_STRING);
g_object_class_install_property (object_class,
PROP_DISPLAY_IS_LOCAL,
@@ -1963,6 +2221,187 @@ on_gconf_key_changed (GConfClient *client,
}
}
+static void
+on_conversation_answer (GdmGreeterLoginWindow *login_window,
+ const char *text,
+ GdmConversation *conversation)
+{
+ if (text != NULL) {
+ char *service_name;
+
+ service_name = gdm_conversation_get_service_name (conversation);
+ if (service_name != NULL) {
+ g_signal_emit (login_window, signals[QUERY_ANSWER], 0, service_name, text);
+ g_free (service_name);
+ }
+ }
+
+ set_sensitive (login_window, TRUE);
+ set_ready (login_window);
+}
+
+void
+gdm_greeter_login_window_remove_extension (GdmGreeterLoginWindow *login_window,
+ GdmGreeterExtension *extension)
+{
+ g_return_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window));
+ g_return_if_fail (GDM_IS_GREETER_LOGIN_WINDOW_EXTENSION (extension));
+
+ if (!GDM_IS_CONVERSATION (extension)) {
+ return;
+ }
+}
+
+static void
+on_button_action_label_changed (GtkWidget *button)
+{
+ GtkAction *action;
+ char *text;
+
+ action = gtk_widget_get_action (button);
+
+ g_object_get (G_OBJECT (action), "label", &text, NULL);
+
+ gtk_button_set_label (GTK_BUTTON (button), text);
+ g_free (text);
+}
+
+static void
+on_button_action_icon_name_changed (GtkWidget *button)
+{
+ GtkAction *action;
+ GtkWidget *image;
+
+ action = gtk_widget_get_action (button);
+
+ image = gtk_action_create_icon (GTK_ACTION (action), GTK_ICON_SIZE_BUTTON);
+ gtk_button_set_image (GTK_BUTTON (button), image);
+}
+
+static void
+on_button_action_tooltip_changed (GtkWidget *button)
+{
+ GtkAction *action;
+ char *text;
+
+ action = gtk_widget_get_action (button);
+
+ g_object_get (G_OBJECT (action), "tooltip", &text, NULL);
+
+ gtk_widget_set_tooltip_text (button, text);
+ g_free (text);
+}
+
+GtkWidget *
+create_button_from_action (GtkAction *action)
+{
+ GtkWidget *button;
+
+ button = gtk_button_new ();
+
+ gtk_action_connect_proxy (GTK_ACTION (action), button);
+
+ g_signal_connect_swapped (action,
+ "notify::label",
+ G_CALLBACK (on_button_action_label_changed),
+ button);
+ g_signal_connect_swapped (action,
+ "notify::icon-name",
+ G_CALLBACK (on_button_action_icon_name_changed),
+ button);
+ g_signal_connect_swapped (action,
+ "notify::tooltip",
+ G_CALLBACK (on_button_action_tooltip_changed),
+ button);
+
+ on_button_action_label_changed (button);
+ on_button_action_icon_name_changed (button);
+ on_button_action_tooltip_changed (button);
+
+ if (strcmp (gtk_action_get_name (action),
+ GDM_CONVERSATION_DEFAULT_ACTION) == 0) {
+ GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
+ }
+
+ return button;
+}
+
+static void
+create_buttons_for_actions (GdmGreeterLoginWindow *login_window,
+ GtkActionGroup *actions)
+{
+ GList *action_list;
+ GList *node;
+ GtkWidget *box;
+
+ action_list = gtk_action_group_list_actions (actions);
+
+ box = glade_xml_get_widget (login_window->priv->xml, "buttonbox");
+ for (node = action_list; node != NULL; node = node->next) {
+ GtkAction *action;
+ GtkWidget *button;
+
+ action = node->data;
+
+ button = create_button_from_action (action);
+ gtk_container_add (GTK_CONTAINER (box), button);
+ }
+
+ g_list_free (action_list);
+}
+
+void
+gdm_greeter_login_window_add_extension (GdmGreeterLoginWindow *login_window,
+ GdmGreeterExtension *extension)
+{
+ char *name;
+ char *description;
+ char *service_name;
+ GtkActionGroup *actions;
+
+ g_return_if_fail (GDM_IS_GREETER_LOGIN_WINDOW (login_window));
+ g_return_if_fail (GDM_IS_GREETER_LOGIN_WINDOW_EXTENSION (extension));
+
+ if (!GDM_IS_CONVERSATION (extension)) {
+ return;
+ }
+
+ actions = gdm_conversation_get_actions (GDM_CONVERSATION (extension));
+
+ create_buttons_for_actions (login_window, actions);
+ hide_task_actions (GDM_TASK (extension));
+
+ g_object_unref (actions);
+
+ g_signal_connect_swapped (GDM_CONVERSATION (extension),
+ "answer",
+ G_CALLBACK (on_conversation_answer),
+ login_window);
+
+ name = gdm_task_get_name (GDM_TASK (extension));
+ description = gdm_task_get_description (GDM_TASK (extension));
+
+ g_debug ("GdmGreeterLoginWindow: new extension '%s - %s' added",
+ name, description);
+
+ g_free (name);
+ g_free (description);
+
+ if (gdm_task_list_get_number_of_tasks (GDM_TASK_LIST (login_window->priv->conversation_list)) == 0) {
+ gtk_widget_hide (login_window->priv->conversation_list);
+ } else {
+ gtk_widget_show (login_window->priv->conversation_list);
+ }
+
+ gdm_task_list_add_task (GDM_TASK_LIST (login_window->priv->conversation_list),
+ GDM_TASK (extension));
+
+ service_name = gdm_conversation_get_service_name (GDM_CONVERSATION (extension));
+ g_debug ("GdmGreeterLoginWindow: starting conversation with '%s'", service_name);
+ g_signal_emit (login_window, signals[START_CONVERSATION], 0, service_name);
+ g_free (service_name);
+}
+
static gboolean
on_window_state_event (GtkWidget *widget,
GdkEventWindowState *event,
diff --git a/gui/simple-greeter/gdm-greeter-login-window.glade b/gui/simple-greeter/gdm-greeter-login-window.glade
index 3d9e2ee..76ab718 100644
--- a/gui/simple-greeter/gdm-greeter-login-window.glade
+++ b/gui/simple-greeter/gdm-greeter-login-window.glade
@@ -611,30 +611,29 @@
</child>
<child>
- <widget class="GtkLabel" id="auth-banner-label">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_CENTER</property>
- <property name="wrap">True</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
+ <widget class="GtkLabel" id="auth-banner-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"></property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">True</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
</child>
-
<child>
<widget class="GtkAlignment" id="alignment2">
<property name="visible">True</property>
@@ -660,20 +659,6 @@
<property name="spacing">0</property>
<child>
- <widget class="Custom" id="user-chooser">
- <property name="visible">True</property>
- <property name="int1">0</property>
- <property name="int2">0</property>
- <property name="last_modification_time">Tue, 18 Nov 2008 21:55:38 GMT</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
<widget class="Custom" id="conversation-list">
<property name="visible">True</property>
<property name="int1">0</property>
@@ -686,56 +671,12 @@
<property name="fill">False</property>
</packing>
</child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkHBox" id="auth-input-box">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">6</property>
-
- <child>
- <widget class="GtkLabel" id="auth-prompt-label">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
<child>
- <widget class="GtkEntry" id="auth-prompt-entry">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
- <property name="editable">True</property>
- <property name="visibility">True</property>
- <property name="max_length">0</property>
- <property name="text" translatable="yes"></property>
- <property name="has_frame">True</property>
- <property name="activates_default">True</property>
+ <widget class="Custom" id="user-chooser">
+ <property name="int1">0</property>
+ <property name="int2">0</property>
+ <property name="last_modification_time">Tue, 18 Nov 2008 21:55:38 GMT</property>
</widget>
<packing>
<property name="padding">0</property>
@@ -744,46 +685,21 @@
</packing>
</child>
- <child>
- <placeholder/>
- </child>
</widget>
<packing>
<property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
</packing>
</child>
<child>
- <widget class="GtkHBox" id="auth-message-box">
+ <widget class="GtkHBox" id="auth-page-box">
<property name="visible">True</property>
<property name="homogeneous">False</property>
<property name="spacing">0</property>
-
<child>
- <widget class="GtkLabel" id="auth-message-label">
- <property name="visible">True</property>
- <property name="label" translatable="yes"></property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
+ <placeholder/>
</child>
</widget>
<packing>
diff --git a/gui/simple-greeter/gdm-greeter-login-window.h b/gui/simple-greeter/gdm-greeter-login-window.h
index 559b26b..c312a47 100644
--- a/gui/simple-greeter/gdm-greeter-login-window.h
+++ b/gui/simple-greeter/gdm-greeter-login-window.h
@@ -23,6 +23,9 @@
#define __GDM_GREETER_LOGIN_WINDOW_H
#include <glib-object.h>
+#include "gdm-conversation.h"
+#include "gdm-task.h"
+#include "gdm-greeter-extension.h"
G_BEGIN_DECLS
@@ -33,6 +36,8 @@ G_BEGIN_DECLS
#define GDM_IS_GREETER_LOGIN_WINDOW_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_GREETER_LOGIN_WINDOW))
#define GDM_GREETER_LOGIN_WINDOW_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_GREETER_LOGIN_WINDOW, GdmGreeterLoginWindowClass))
+#define GDM_IS_GREETER_LOGIN_WINDOW_EXTENSION(e) (GDM_IS_CONVERSATION(e) && GDM_IS_TASK(e))
+
typedef struct GdmGreeterLoginWindowPrivate GdmGreeterLoginWindowPrivate;
typedef struct
@@ -62,7 +67,8 @@ typedef struct
const char *text);
void (* cancelled) (GdmGreeterLoginWindow *login_window);
void (* disconnected) (GdmGreeterLoginWindow *login_window);
- void (* start_session) (GdmGreeterLoginWindow *login_window);
+ void (* start_session) (GdmGreeterLoginWindow *login_window,
+ const char *sevice_name);
} GdmGreeterLoginWindowClass;
@@ -71,7 +77,10 @@ GtkWidget * gdm_greeter_login_window_new (gboolean displa
gboolean gdm_greeter_login_window_reset (GdmGreeterLoginWindow *login_window);
-gboolean gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window);
+gboolean gdm_greeter_login_window_ready (GdmGreeterLoginWindow *login_window,
+ const char *service_name);
+gboolean gdm_greeter_login_window_conversation_stopped (GdmGreeterLoginWindow *login_window,
+ const char *service_name);
gboolean gdm_greeter_login_window_info_query (GdmGreeterLoginWindow *login_window,
const char *service_name,
const char *text);
@@ -88,7 +97,13 @@ gboolean gdm_greeter_login_window_problem (GdmGreeterLogin
void gdm_greeter_login_window_request_timed_login (GdmGreeterLoginWindow *login_window,
const char *username,
int delay);
-void gdm_greeter_login_window_user_authorized (GdmGreeterLoginWindow *login_window);
+void gdm_greeter_login_window_user_authorized (GdmGreeterLoginWindow *login_window,
+ const char *service_name);
+
+void gdm_greeter_login_window_add_extension (GdmGreeterLoginWindow *login_window,
+ GdmGreeterExtension *extension);
+void gdm_greeter_login_window_remove_extension (GdmGreeterLoginWindow *login_window,
+ GdmGreeterExtension *extension);
G_END_DECLS
diff --git a/gui/simple-greeter/gdm-greeter-plugin.c b/gui/simple-greeter/gdm-greeter-plugin.c
new file mode 100644
index 0000000..02814a2
--- /dev/null
+++ b/gui/simple-greeter/gdm-greeter-plugin.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * Written by: Ray Strode <rstrode redhat com>
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+
+#include "gdm-greeter-extension.h"
+#include "gdm-greeter-plugin.h"
+
+#define GDM_GREETER_PLUGIN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_GREETER_PLUGIN, GdmGreeterPluginPrivate))
+
+enum {
+ PROP_0,
+ PROP_FILENAME,
+};
+
+enum {
+ LOADED,
+ LOAD_FAILED,
+ UNLOADED,
+ LAST_SIGNAL
+};
+
+struct _GdmGreeterPluginPrivate {
+ GObject parent;
+
+ GModule *module;
+ char *filename;
+
+ GdmGreeterExtension *extension;
+};
+
+static void gdm_greeter_plugin_finalize (GObject *object);
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+G_DEFINE_TYPE (GdmGreeterPlugin, gdm_greeter_plugin, G_TYPE_OBJECT)
+
+static void
+gdm_greeter_plugin_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GdmGreeterPlugin *plugin;
+
+ plugin = GDM_GREETER_PLUGIN (object);
+ switch (param_id) {
+ case PROP_FILENAME:
+ plugin->priv->filename = g_strdup (g_value_get_string (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+gdm_greeter_plugin_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GdmGreeterPlugin *plugin;
+
+ plugin = GDM_GREETER_PLUGIN (object);
+
+ switch (param_id) {
+ case PROP_FILENAME:
+ g_value_set_string (value, plugin->priv->filename);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+gdm_greeter_plugin_class_init (GdmGreeterPluginClass *class)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = G_OBJECT_CLASS (class);
+
+ gobject_class->set_property = gdm_greeter_plugin_set_property;
+ gobject_class->get_property = gdm_greeter_plugin_get_property;
+ gobject_class->finalize = gdm_greeter_plugin_finalize;
+
+ g_object_class_install_property (gobject_class,
+ PROP_FILENAME,
+ g_param_spec_string ("filename",
+ "Filename",
+ "The full path to the plugin.",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+
+ signals [LOADED] =
+ g_signal_new ("loaded",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GdmGreeterPluginClass, loaded),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ signals [LOAD_FAILED] =
+ g_signal_new ("load-failed",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GdmGreeterPluginClass, load_failed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ signals [UNLOADED] =
+ g_signal_new ("unloaded",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GdmGreeterPluginClass, unloaded),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ g_type_class_add_private (class, sizeof (GdmGreeterPluginPrivate));
+}
+
+GdmGreeterPlugin *
+gdm_greeter_plugin_new (const char *filename)
+{
+ GObject *object;
+
+ object = g_object_new (GDM_TYPE_GREETER_PLUGIN,
+ "filename", filename, NULL);
+
+ return GDM_GREETER_PLUGIN (object);
+}
+
+void
+gdm_greeter_plugin_load (GdmGreeterPlugin *plugin)
+{
+ GModule *module;
+ GdmGreeterExtension *extension;
+ union {
+ gpointer symbol;
+ GdmGreeterPluginGetExtensionFunc invoke;
+ } get_extension;
+
+
+ module = g_module_open (plugin->priv->filename, G_MODULE_BIND_LOCAL);
+
+ if (module == NULL) {
+ g_warning ("plugin %s couldn't be opened: %s",
+ plugin->priv->filename,
+ g_module_error ());
+ g_signal_emit (plugin, signals [LOAD_FAILED], 0);
+ return;
+ }
+
+ if (!g_module_symbol (module,
+ "gdm_greeter_plugin_get_extension",
+ &get_extension.symbol) ||
+ !get_extension.symbol) {
+ g_warning ("plugin %s lacks gdm_greeter_plugin_get_extension()",
+ plugin->priv->filename);
+ g_module_close (module);
+ g_signal_emit (plugin, signals [LOAD_FAILED], 0);
+ return;
+ }
+
+ extension = get_extension.invoke ();
+
+ if (!extension) {
+ g_warning ("plugin %s didn't return extension when asked",
+ plugin->priv->filename);
+ g_module_close (module);
+ g_signal_emit (plugin, signals [LOAD_FAILED], 0);
+ }
+
+ if (!GDM_IS_GREETER_EXTENSION (extension)) {
+ g_warning ("plugin %s returned bogus extension when asked",
+ plugin->priv->filename);
+ g_module_close (module);
+ g_signal_emit (plugin, signals [LOAD_FAILED], 0);
+ }
+
+ plugin->priv->module = module;
+ plugin->priv->extension = extension;
+
+ g_signal_emit (plugin, signals [LOADED], 0);
+}
+
+void
+gdm_greeter_plugin_unload (GdmGreeterPlugin *plugin)
+{
+ if (plugin->priv->extension != NULL) {
+ g_object_unref (plugin->priv->extension);
+ plugin->priv->extension = NULL;
+ }
+
+ if (plugin->priv->module != NULL) {
+ g_module_close (plugin->priv->module);
+ plugin->priv->module = NULL;
+ }
+}
+
+const char *
+gdm_greeter_plugin_get_filename (GdmGreeterPlugin *plugin)
+{
+ return plugin->priv->filename;
+}
+
+GdmGreeterExtension *
+gdm_greeter_plugin_get_extension (GdmGreeterPlugin *plugin)
+{
+ return g_object_ref (plugin->priv->extension);
+}
+
+static void
+gdm_greeter_plugin_init (GdmGreeterPlugin *plugin)
+{
+ plugin->priv = GDM_GREETER_PLUGIN_GET_PRIVATE (plugin);
+}
+
+static void
+gdm_greeter_plugin_finalize (GObject *object)
+{
+ GdmGreeterPlugin *plugin;
+
+ plugin = GDM_GREETER_PLUGIN (object);
+
+ gdm_greeter_plugin_unload (plugin);
+}
+
diff --git a/gui/simple-greeter/gdm-greeter-plugin.h b/gui/simple-greeter/gdm-greeter-plugin.h
new file mode 100644
index 0000000..904c231
--- /dev/null
+++ b/gui/simple-greeter/gdm-greeter-plugin.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __GDM_GREETER_PLUGIN
+#define __GDM_GREETER_PLUGIN
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "gdm-greeter-extension.h"
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_GREETER_PLUGIN (gdm_greeter_plugin_get_type ())
+#define GDM_GREETER_PLUGIN(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDM_TYPE_GREETER_PLUGIN, GdmGreeterPlugin))
+#define GDM_IS_GREETER_PLUGIN(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDM_TYPE_GREETER_PLUGIN))
+
+typedef struct _GdmGreeterPlugin GdmGreeterPlugin;
+typedef struct _GdmGreeterPluginPrivate GdmGreeterPluginPrivate;
+typedef struct _GdmGreeterPluginClass GdmGreeterPluginClass;
+
+struct _GdmGreeterPlugin
+{
+ GObject parent;
+ GdmGreeterPluginPrivate *priv;
+};
+
+struct _GdmGreeterPluginClass
+{
+ GObjectClass parent_class;
+
+ void (* loaded) (GdmGreeterPlugin *plugin);
+ void (* load_failed) (GdmGreeterPlugin *plugin);
+ void (* unloaded) (GdmGreeterPlugin *plugin);
+};
+
+GType gdm_greeter_plugin_get_type (void) G_GNUC_CONST;
+GdmGreeterPlugin *gdm_greeter_plugin_new (const char *filename);
+void gdm_greeter_plugin_load (GdmGreeterPlugin *plugin);
+void gdm_greeter_plugin_unload (GdmGreeterPlugin *plugin);
+const char *gdm_greeter_plugin_get_filename (GdmGreeterPlugin *plugin);
+GdmGreeterExtension *gdm_greeter_plugin_get_extension (GdmGreeterPlugin *plugin);
+
+G_END_DECLS
+
+#endif
diff --git a/gui/simple-greeter/gdm-greeter-session.c b/gui/simple-greeter/gdm-greeter-session.c
index 714daa1..adbed6f 100644
--- a/gui/simple-greeter/gdm-greeter-session.c
+++ b/gui/simple-greeter/gdm-greeter-session.c
@@ -38,6 +38,8 @@
#include "gdm-greeter-panel.h"
#include "gdm-greeter-login-window.h"
+#include "gdm-plugin-manager.h"
+
#include "gdm-profile.h"
#define GDM_GREETER_SESSION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_GREETER_SESSION, GdmGreeterSessionPrivate))
@@ -45,9 +47,11 @@
struct GdmGreeterSessionPrivate
{
GdmGreeterClient *client;
+ GdmPluginManager *plugin_manager;
GtkWidget *login_window;
GtkWidget *panel;
+
};
enum {
@@ -91,7 +95,19 @@ on_ready (GdmGreeterClient *client,
{
g_debug ("GdmGreeterSession: Ready");
- gdm_greeter_login_window_ready (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window));
+ gdm_greeter_login_window_ready (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window),
+ service_name);
+}
+
+static void
+on_conversation_stopped (GdmGreeterClient *client,
+ const char *service_name,
+ GdmGreeterSession *session)
+{
+ g_debug ("GdmGreeterSession: Conversation '%s' stopped", service_name);
+
+ gdm_greeter_login_window_conversation_stopped (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window),
+ service_name);
}
static void
@@ -154,10 +170,11 @@ on_timed_login_requested (GdmGreeterClient *client,
static void
on_user_authorized (GdmGreeterClient *client,
+ const char *service_name,
GdmGreeterSession *session)
{
g_debug ("GdmGreeterSession: user authorized");
- gdm_greeter_login_window_user_authorized (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window));
+ gdm_greeter_login_window_user_authorized (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), service_name);
}
static void
@@ -270,7 +287,6 @@ on_cancelled (GdmGreeterLoginWindow *login_window,
{
gdm_greeter_panel_hide_user_options (GDM_GREETER_PANEL (session->priv->panel));
gdm_greeter_client_call_cancel (session->priv->client);
- gdm_greeter_client_call_start_conversation (session->priv->client, "gdm");
}
static void
@@ -282,9 +298,10 @@ on_disconnected (GdmGreeterLoginWindow *login_window,
static void
on_start_session (GdmGreeterLoginWindow *login_window,
+ const char *service_name,
GdmGreeterSession *session)
{
- gdm_greeter_client_call_start_session_when_ready (session->priv->client, "gdm", TRUE);
+ gdm_greeter_client_call_start_session_when_ready (session->priv->client, service_name, TRUE);
}
static int
@@ -436,8 +453,6 @@ gdm_greeter_session_start (GdmGreeterSession *session,
toggle_panel (session, TRUE);
toggle_login_window (session, TRUE);
- gdm_greeter_client_call_start_conversation (session->priv->client, "gdm");
-
gdm_profile_end (NULL);
return res;
@@ -547,6 +562,64 @@ gdm_greeter_session_event_handler (GdkEvent *event,
}
static void
+on_plugins_loaded (GdmGreeterSession *session)
+{
+ g_debug ("GdmGreeterSession: done loading plugins");
+}
+
+static void
+on_plugin_removed (GdmGreeterSession *session,
+ GdmGreeterPlugin *plugin)
+{
+ GdmGreeterExtension *extension;
+
+ extension = gdm_greeter_plugin_get_extension (plugin);
+
+ if (GDM_IS_GREETER_LOGIN_WINDOW_EXTENSION (extension)) {
+ gdm_greeter_login_window_remove_extension (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), extension);
+ }
+ g_object_unref (extension);
+}
+
+static void
+on_plugin_added (GdmGreeterSession *session,
+ GdmGreeterPlugin *plugin)
+{
+ GdmGreeterExtension *extension;
+
+ extension = gdm_greeter_plugin_get_extension (plugin);
+
+ if (GDM_IS_GREETER_LOGIN_WINDOW_EXTENSION (extension)) {
+ gdm_greeter_login_window_add_extension (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), extension);
+ }
+ g_object_unref (extension);
+}
+
+static void
+load_plugins (GdmGreeterSession *session)
+{
+ g_debug ("GdmGreeterSession: loading plugins");
+
+ session->priv->plugin_manager = gdm_plugin_manager_ref_default ();
+
+ g_signal_connect_swapped (session->priv->plugin_manager,
+ "plugins-loaded",
+ G_CALLBACK (on_plugins_loaded),
+ session);
+
+ g_signal_connect_swapped (session->priv->plugin_manager,
+ "plugin-added",
+ G_CALLBACK (on_plugin_added),
+ session);
+
+ g_signal_connect_swapped (session->priv->plugin_manager,
+ "plugin-removed",
+ G_CALLBACK (on_plugin_removed),
+ session);
+
+}
+
+static void
gdm_greeter_session_init (GdmGreeterSession *session)
{
gdm_profile_start (NULL);
@@ -575,6 +648,10 @@ gdm_greeter_session_init (GdmGreeterSession *session)
G_CALLBACK (on_ready),
session);
g_signal_connect (session->priv->client,
+ "conversation-stopped",
+ G_CALLBACK (on_conversation_stopped),
+ session);
+ g_signal_connect (session->priv->client,
"reset",
G_CALLBACK (on_reset),
session);
@@ -609,6 +686,8 @@ gdm_greeter_session_init (GdmGreeterSession *session)
gdk_event_handler_set ((GdkEventFunc) gdm_greeter_session_event_handler,
session, NULL);
+
+ load_plugins (session);
gdm_profile_end (NULL);
}
diff --git a/gui/simple-greeter/gdm-plugin-manager.c b/gui/simple-greeter/gdm-plugin-manager.c
new file mode 100644
index 0000000..49e442c
--- /dev/null
+++ b/gui/simple-greeter/gdm-plugin-manager.c
@@ -0,0 +1,478 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Written By: Ray Strode <rstrode redhat com>
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+#include <glib-object.h>
+#include <gio/gio.h>
+
+#include "gdm-plugin-manager.h"
+#include "gdm-greeter-extension.h"
+
+#define GDM_PLUGIN_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_PLUGIN_MANAGER, GdmPluginManagerPrivate))
+
+typedef struct
+{
+ GModule *module;
+ char *filename;
+ GdmGreeterExtension *extension;
+} GdmPluginManagerPlugin;
+
+typedef struct
+{
+ GdmPluginManager *manager;
+ GCancellable *cancellable;
+} GdmPluginManagerOperation;
+
+struct GdmPluginManagerPrivate
+{
+ GHashTable *plugins;
+
+ GFileMonitor *plugin_dir_monitor;
+ GList *pending_operations;
+};
+
+enum {
+ PLUGINS_LOADED,
+ PLUGIN_ADDED,
+ PLUGIN_REMOVED,
+ LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0, };
+
+static void gdm_plugin_manager_class_init (GdmPluginManagerClass *klass);
+static void gdm_plugin_manager_init (GdmPluginManager *plugin_manager);
+static void gdm_plugin_manager_finalize (GObject *object);
+
+static GObject *plugin_manager_object = NULL;
+
+G_DEFINE_TYPE (GdmPluginManager, gdm_plugin_manager, G_TYPE_OBJECT)
+
+static GdmPluginManagerOperation *
+start_operation (GdmPluginManager *manager)
+{
+ GdmPluginManagerOperation *operation;
+
+ operation = g_new0 (GdmPluginManagerOperation, 1);
+ operation->cancellable = g_cancellable_new ();
+ operation->manager = manager;
+
+ return operation;
+}
+
+static void
+free_operation (GdmPluginManagerOperation *operation)
+{
+ if (operation->cancellable != NULL) {
+ g_object_unref (operation->cancellable);
+ operation->cancellable = NULL;
+ }
+ g_free (operation);
+}
+
+static void
+cancel_operation (GdmPluginManagerOperation *operation)
+{
+ if (operation->cancellable != NULL &&
+ !g_cancellable_is_cancelled (operation->cancellable)) {
+ g_cancellable_cancel (operation->cancellable);
+ }
+
+ free_operation (operation);
+}
+
+static void
+gdm_plugin_manager_track_operation (GdmPluginManager *manager,
+ GdmPluginManagerOperation *operation)
+{
+ manager->priv->pending_operations =
+ g_list_prepend (manager->priv->pending_operations, operation);
+}
+
+static void
+gdm_plugin_manager_untrack_operation (GdmPluginManager *manager,
+ GdmPluginManagerOperation *operation)
+{
+ manager->priv->pending_operations =
+ g_list_remove (manager->priv->pending_operations, operation);
+}
+
+static void
+gdm_plugin_manager_cancel_pending_operations (GdmPluginManager *manager)
+{
+ GList *node;
+
+ node = manager->priv->pending_operations;
+ while (node != NULL) {
+ GList *next_node;
+ GdmPluginManagerOperation *operation;
+
+ operation = node->data;
+ next_node = node->next;
+
+ cancel_operation (operation);
+ manager->priv->pending_operations =
+ g_list_delete_link (manager->priv->pending_operations,
+ node);
+
+ node = next_node;
+ }
+}
+
+static void
+gdm_plugin_manager_class_init (GdmPluginManagerClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gdm_plugin_manager_finalize;
+
+ signals [PLUGINS_LOADED] =
+ g_signal_new ("plugins-loaded",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GdmPluginManagerClass, plugins_loaded),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ signals [PLUGIN_ADDED] =
+ g_signal_new ("plugin-added",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GdmPluginManagerClass, plugin_added),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1, GDM_TYPE_GREETER_PLUGIN);
+ signals [PLUGIN_REMOVED] =
+ g_signal_new ("plugin-removed",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GdmPluginManagerClass, plugin_removed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1, GDM_TYPE_GREETER_PLUGIN);
+
+ g_type_class_add_private (klass, sizeof (GdmPluginManagerPrivate));
+}
+
+static void
+on_plugin_loaded (GdmPluginManager *manager,
+ GdmGreeterPlugin *plugin)
+{
+ g_debug ("GdmPluginManager: plugin '%s' loaded.",
+ gdm_greeter_plugin_get_filename (plugin));
+ g_signal_emit (manager, signals [PLUGIN_ADDED], 0, plugin);
+}
+
+static void
+on_plugin_load_failed (GdmPluginManager *manager,
+ GdmGreeterPlugin *plugin)
+{
+ const char *filename;
+
+ g_debug ("GdmPluginManager: plugin '%s' could not be loaded.",
+ gdm_greeter_plugin_get_filename (plugin));
+ filename = gdm_greeter_plugin_get_filename (plugin);
+ g_hash_table_remove (manager->priv->plugins, filename);
+}
+
+static void
+on_plugin_unloaded (GdmPluginManager *manager,
+ GdmGreeterPlugin *plugin)
+{
+ const char *filename;
+
+ filename = gdm_greeter_plugin_get_filename (plugin);
+ g_hash_table_remove (manager->priv->plugins, filename);
+}
+
+static void
+load_plugin (GdmPluginManager *manager,
+ const char *filename)
+{
+ GdmGreeterPlugin *plugin;
+
+ g_debug ("GdmPluginManager: loading plugin '%s'", filename);
+
+ plugin = gdm_greeter_plugin_new (filename);
+
+ g_signal_connect_swapped (plugin, "loaded",
+ G_CALLBACK (on_plugin_loaded),
+ manager);
+ g_signal_connect_swapped (plugin, "load-failed",
+ G_CALLBACK (on_plugin_load_failed),
+ manager);
+ g_signal_connect_swapped (plugin, "unloaded",
+ G_CALLBACK (on_plugin_unloaded),
+ manager);
+ g_hash_table_insert (manager->priv->plugins,
+ g_strdup (filename), plugin);
+
+ gdm_greeter_plugin_load (plugin);
+}
+
+static void
+on_plugin_info_read (GFileEnumerator *enumerator,
+ GAsyncResult *result,
+ GdmPluginManagerOperation *operation)
+{
+ GdmPluginManager *manager;
+ GFile *plugin_dir_file;
+ GList *file_list, *node;
+ GError *error;
+
+ manager = operation->manager;
+ error = NULL;
+ file_list = g_file_enumerator_next_files_finish (enumerator,
+ result, &error);
+ plugin_dir_file = g_file_enumerator_get_container (enumerator);
+ if (error != NULL) {
+ char *plugin_dir;
+
+ plugin_dir = g_file_get_parse_name (plugin_dir_file);
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ g_debug ("GdmPluginManager: Cancelled reading plugin directory %s",
+ plugin_dir);
+ } else {
+ g_warning ("GdmPluginManager: Unable to read plugin directory %s: %s",
+ plugin_dir, error->message);
+ }
+ g_free (plugin_dir);
+ g_error_free (error);
+ g_object_unref (plugin_dir_file);
+ gdm_plugin_manager_untrack_operation (manager, operation);
+ return;
+ }
+
+#ifndef PLUGIN_ORDERING_FIGURED_OUT
+ node = file_list;
+ while (node != NULL) {
+ GFileInfo *info;
+ GFile *file;
+ char *path;
+ GList *next_node;
+
+ next_node = node->next;
+
+ info = (GFileInfo *) node->data;
+
+ file = g_file_get_child (plugin_dir_file,
+ g_file_info_get_name (info));
+ path = g_file_get_path (file);
+
+ if (g_str_has_suffix (path, "password.so")) {
+ file_list = g_list_delete_link (file_list, node);
+ file_list = g_list_prepend (file_list, info);
+ next_node = NULL;
+ }
+ g_free (path);
+ g_object_unref (file);
+
+ node = next_node;
+ }
+#endif
+
+ node = file_list;
+ while (node != NULL) {
+ GFileInfo *info;
+ GFile *file;
+ char *path;
+
+ info = (GFileInfo *) node->data;
+
+ file = g_file_get_child (plugin_dir_file,
+ g_file_info_get_name (info));
+ path = g_file_get_path (file);
+
+ if (g_str_has_suffix (path, G_MODULE_SUFFIX)) {
+ load_plugin (manager, path);
+ }
+ g_free (path);
+ g_object_unref (file);
+
+ node = node->next;
+ }
+ g_object_unref (plugin_dir_file);
+
+ gdm_plugin_manager_untrack_operation (manager, operation);
+ g_signal_emit (manager, signals [PLUGINS_LOADED], 0);
+
+ g_list_free (file_list);
+}
+
+static void
+on_plugin_dir_opened (GFile *plugin_dir_file,
+ GAsyncResult *result,
+ GdmPluginManagerOperation *open_operation)
+{
+ GdmPluginManager *manager;
+ GFileEnumerator *enumerator;
+ GError *error;
+ GdmPluginManagerOperation *operation;
+
+ manager = open_operation->manager;
+ gdm_plugin_manager_untrack_operation (manager, open_operation);
+
+ error = NULL;
+ enumerator = g_file_enumerate_children_finish (plugin_dir_file,
+ result, &error);
+
+ if (enumerator == NULL) {
+ char *plugin_dir;
+
+ plugin_dir = g_file_get_parse_name (plugin_dir_file);
+
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+ g_debug ("GdmPluginManager: Cancelled opening plugin directory %s",
+ plugin_dir);
+ } else {
+ g_warning ("GdmPluginManager: Unable to open plugin directory %s: %s",
+ plugin_dir, error->message);
+ }
+ g_free (plugin_dir);
+ g_error_free (error);
+ return;
+ }
+
+ operation = start_operation (manager);
+
+ g_file_enumerator_next_files_async (enumerator, G_MAXINT,
+ G_PRIORITY_DEFAULT,
+ operation->cancellable,
+ (GAsyncReadyCallback)
+ on_plugin_info_read,
+ operation);
+
+ gdm_plugin_manager_track_operation (manager, operation);
+}
+
+static void
+load_plugins_in_dir (GdmPluginManager *manager,
+ const char *plugin_dir)
+{
+ GFile *plugin_dir_file;
+ GdmPluginManagerOperation *operation;
+
+ g_debug ("GdmPluginManager: loading plugins in dir '%s'", plugin_dir);
+
+ operation = start_operation (manager);
+ plugin_dir_file = g_file_new_for_path (plugin_dir);
+ g_file_enumerate_children_async (plugin_dir_file, "standard::*",
+ G_FILE_QUERY_INFO_NONE,
+ G_PRIORITY_DEFAULT,
+ operation->cancellable,
+ (GAsyncReadyCallback)
+ on_plugin_dir_opened,
+ operation);
+ g_object_unref (plugin_dir_file);
+ gdm_plugin_manager_track_operation (manager, operation);
+}
+
+static void
+on_plugin_dir_changed (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+ GdmPluginManagerOperation *operation)
+{
+}
+
+static void
+watch_plugin_dir (GdmPluginManager *manager,
+ const char *plugin_dir)
+{
+
+ GdmPluginManagerOperation *operation;
+ GFile *file;
+ GError *error;
+
+ operation = start_operation (manager);
+
+ file = g_file_new_for_path (plugin_dir);
+ manager->priv->plugin_dir_monitor = g_file_monitor_directory (file,
+ G_FILE_MONITOR_NONE,
+ operation->cancellable,
+ &error);
+ if (manager->priv->plugin_dir_monitor != NULL) {
+ g_signal_connect (manager->priv->plugin_dir_monitor,
+ "changed",
+ G_CALLBACK (on_plugin_dir_changed),
+ operation);
+ gdm_plugin_manager_track_operation (manager, operation);
+ } else {
+ g_warning ("Unable to monitor %s: %s",
+ plugin_dir, error->message);
+ g_error_free (error);
+ free_operation (operation);
+ }
+ g_object_unref (file);
+}
+
+static void
+gdm_plugin_manager_init (GdmPluginManager *manager)
+{
+ manager->priv = GDM_PLUGIN_MANAGER_GET_PRIVATE (manager);
+
+ manager->priv->plugins = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ g_object_unref);
+ watch_plugin_dir (manager, GDM_SIMPLE_GREETER_PLUGINS_DIR);
+ load_plugins_in_dir (manager, GDM_SIMPLE_GREETER_PLUGINS_DIR);
+}
+
+static void
+gdm_plugin_manager_finalize (GObject *object)
+{
+ GdmPluginManager *manager;
+
+ manager = GDM_PLUGIN_MANAGER (object);
+
+ g_hash_table_destroy (manager->priv->plugins);
+ g_file_monitor_cancel (manager->priv->plugin_dir_monitor);
+
+ gdm_plugin_manager_cancel_pending_operations (manager);
+
+ G_OBJECT_CLASS (gdm_plugin_manager_parent_class)->finalize (object);
+}
+
+GdmPluginManager *
+gdm_plugin_manager_ref_default (void)
+{
+ if (plugin_manager_object != NULL) {
+ g_object_ref (plugin_manager_object);
+ } else {
+ plugin_manager_object = g_object_new (GDM_TYPE_PLUGIN_MANAGER, NULL);
+ g_object_add_weak_pointer (plugin_manager_object,
+ (gpointer *) &plugin_manager_object);
+ }
+
+ return GDM_PLUGIN_MANAGER (plugin_manager_object);
+}
+
+GdmGreeterPlugin *
+gdm_plugin_manager_get_plugin (GdmPluginManager *manager,
+ const char *name)
+{
+ return g_hash_table_lookup (manager->priv->plugins, name);
+}
diff --git a/gui/simple-greeter/gdm-plugin-manager.h b/gui/simple-greeter/gdm-plugin-manager.h
new file mode 100644
index 0000000..f181140
--- /dev/null
+++ b/gui/simple-greeter/gdm-plugin-manager.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Written by: Ray Strode <rstrode redhat com>
+ *
+ */
+
+#ifndef __GDM_PLUGIN_MANAGER_H
+#define __GDM_PLUGIN_MANAGER_H
+
+#include <glib-object.h>
+
+#include "gdm-greeter-plugin.h"
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_PLUGIN_MANAGER (gdm_plugin_manager_get_type ())
+#define GDM_PLUGIN_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_PLUGIN_MANAGER, GdmPluginManager))
+#define GDM_PLUGIN_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_PLUGIN_MANAGER, GdmPluginManagerClass))
+#define GDM_IS_PLUGIN_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_PLUGIN_MANAGER))
+#define GDM_IS_PLUGIN_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_PLUGIN_MANAGER))
+#define GDM_PLUGIN_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_PLUGIN_MANAGER, GdmPluginManagerClass))
+
+typedef struct GdmPluginManagerPrivate GdmPluginManagerPrivate;
+
+typedef struct
+{
+ GObject parent;
+ GdmPluginManagerPrivate *priv;
+} GdmPluginManager;
+
+typedef struct
+{
+ GObjectClass parent_class;
+
+ void (* plugins_loaded) (GdmPluginManager *plugin_manager);
+ void (* plugin_added) (GdmPluginManager *plugin_manager,
+ GdmGreeterPlugin *plugin);
+ void (* plugin_removed) (GdmPluginManager *plugin_manager,
+ GdmGreeterPlugin *plugin);
+} GdmPluginManagerClass;
+
+GType gdm_plugin_manager_get_type (void);
+
+GdmPluginManager *gdm_plugin_manager_ref_default (void);
+
+GdmGreeterPlugin *gdm_plugin_manager_get_plugin (GdmPluginManager *plugin,
+ const char *name);
+
+G_END_DECLS
+
+#endif /* __GDM_PLUGIN_MANAGER_H */
diff --git a/gui/simple-greeter/gdm-task-list.c b/gui/simple-greeter/gdm-task-list.c
index e0fd3d4..25831a6 100644
--- a/gui/simple-greeter/gdm-task-list.c
+++ b/gui/simple-greeter/gdm-task-list.c
@@ -37,12 +37,6 @@
#define GDM_TASK_LIST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_TASK_LIST, GdmTaskListPrivate))
-typedef struct
-{
- GtkWidget *radio_button;
- char *name;
-} GdmTask;
-
struct GdmTaskListPrivate
{
GtkWidget *box;
@@ -59,54 +53,161 @@ static guint signals[NUMBER_OF_SIGNALS];
static void gdm_task_list_class_init (GdmTaskListClass *klass);
static void gdm_task_list_init (GdmTaskList *task_list);
-static void gdm_task_list_finalize (GObject *object);
+static void gdm_task_list_finalize (GObject *object);
G_DEFINE_TYPE (GdmTaskList, gdm_task_list, GTK_TYPE_ALIGNMENT);
static void
on_task_toggled (GdmTaskList *widget,
- GtkRadioButton *radio_button)
+ GtkRadioButton *button)
{
GdmTask *task;
- task = g_object_get_data (G_OBJECT (radio_button), "gdm-task");
+ task = g_object_get_data (G_OBJECT (button), "gdm-task");
- if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (radio_button))) {
- g_signal_emit (widget, signals[ACTIVATED], 0, task->name);
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) {
+ g_signal_emit (widget, signals[ACTIVATED], 0, task);
} else {
- g_signal_emit (widget, signals[DEACTIVATED], 0, task->name);
+ g_signal_emit (widget, signals[DEACTIVATED], 0, task);
+ }
+}
+
+GdmTask *
+gdm_task_list_foreach_task (GdmTaskList *task_list,
+ GdmTaskListForeachFunc search_func,
+ gpointer data)
+{
+ GList *node;
+
+ for (node = task_list->priv->tasks; node != NULL; node = node->next) {
+ GdmTask *task;
+
+ task = node->data;
+
+ if (search_func (task_list, task, data)) {
+ return g_object_ref (task);
+ }
+ }
+
+ return NULL;
+}
+
+static void
+on_task_enabled (GdmTaskList *task_list,
+ GdmTask *task)
+{
+ GtkWidget *button;
+ GList *task_node;
+
+ button = g_object_get_data (G_OBJECT (task), "gdm-task-list-button");
+
+ gtk_widget_set_sensitive (button, TRUE);
+
+ /* Sort the list such that the tasks the user clicks last end
+ * up first. This doesn't change the order in which the tasks
+ * appear in the UI, but will affect which tasks we implicitly
+ * activate if the currently active task gets disabled.
+ */
+ task_node = g_list_find (task_list->priv->tasks, task);
+ if (task_node != NULL) {
+ task_list->priv->tasks = g_list_delete_link (task_list->priv->tasks, task_node);
+ task_list->priv->tasks = g_list_prepend (task_list->priv->tasks,
+ task);
+ }
+}
+
+static void
+activate_first_available_task (GdmTaskList *task_list)
+{
+ GList *node;
+
+ node = task_list->priv->tasks;
+ while (node != NULL) {
+ GdmTask *task;
+
+ task = GDM_TASK (node->data);
+
+ if (gdm_task_list_set_active_task (task_list, task)) {
+ break;
+ }
+
+ node = node->next;
+ }
+
+}
+
+static void
+on_task_disabled (GdmTaskList *task_list,
+ GdmTask *task)
+{
+ GtkWidget *button;
+ gboolean was_active;
+
+ button = g_object_get_data (G_OBJECT (task), "gdm-task-list-button");
+ was_active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
+
+ gtk_widget_set_sensitive (button, FALSE);
+
+ if (was_active) {
+ activate_first_available_task (task_list);
}
}
void
gdm_task_list_add_task (GdmTaskList *task_list,
- const char *name,
- const char *icon_name)
+ GdmTask *task)
{
- GdmTask *task;
GtkWidget *image;
+ GtkWidget *button;
+ GIcon *icon;
+ char *description;
- task = g_new0 (GdmTask, 1);
-
- task->name = g_strdup (name);
if (task_list->priv->tasks == NULL) {
- task->radio_button = gtk_radio_button_new (NULL);
+ button = gtk_radio_button_new (NULL);
} else {
- task->radio_button = gtk_radio_button_new_from_widget (GTK_RADIO_BUTTON (((GdmTask *) task_list->priv->tasks->data)->radio_button));
+ GdmTask *previous_task;
+ GtkRadioButton *previous_button;
+
+ previous_task = GDM_TASK (task_list->priv->tasks->data);
+ previous_button = GTK_RADIO_BUTTON (g_object_get_data (G_OBJECT (previous_task), "gdm-task-list-button"));
+ button = gtk_radio_button_new_from_widget (previous_button);
}
+ g_object_set_data (G_OBJECT (task), "gdm-task-list-button", button);
+
+ g_object_set (G_OBJECT (button), "draw-indicator", FALSE, NULL);
+ g_object_set_data (G_OBJECT (button), "gdm-task", task);
+ g_signal_connect_swapped (button, "toggled",
+ G_CALLBACK (on_task_toggled),
+ task_list);
+
+ gtk_button_set_focus_on_click (GTK_BUTTON (button), FALSE);
+ gtk_widget_set_sensitive (button, gdm_task_is_enabled (task));
+
+ g_signal_connect_swapped (G_OBJECT (task), "enabled",
+ G_CALLBACK (on_task_enabled),
+ task_list);
+
+ g_signal_connect_swapped (G_OBJECT (task), "disabled",
+ G_CALLBACK (on_task_disabled),
+ task_list);
+
+ icon = gdm_task_get_icon (task);
+ image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_SMALL_TOOLBAR);
+ g_object_unref (icon);
- g_object_set (task->radio_button, "draw-indicator", FALSE, NULL);
- g_object_set_data (G_OBJECT (task->radio_button), "gdm-task", task);
- g_signal_connect_swapped (task->radio_button,
- "toggled", G_CALLBACK (on_task_toggled), task_list);
- image = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_DND);
gtk_widget_show (image);
- gtk_container_add (GTK_CONTAINER (task->radio_button), image);
- gtk_widget_show (task->radio_button);
- gtk_container_add (GTK_CONTAINER (task->radio_button), task_list->priv->box);
+ gtk_container_add (GTK_CONTAINER (button), image);
+ description = gdm_task_get_description (task);
+ gtk_widget_set_tooltip_text (button, description);
+ g_free (description);
+ gtk_widget_show (button);
- gtk_container_add (GTK_CONTAINER (task_list->priv->box), task->radio_button);
+ gtk_container_add (GTK_CONTAINER (task_list->priv->box), button);
task_list->priv->tasks = g_list_append (task_list->priv->tasks, task);
+
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button))) {
+ g_signal_emit (task_list, signals[ACTIVATED], 0, task);
+ }
}
static void
@@ -122,9 +223,9 @@ gdm_task_list_class_init (GdmTaskListClass *klass)
G_STRUCT_OFFSET (GdmTaskListClass, activated),
NULL,
NULL,
- g_cclosure_marshal_VOID__STRING,
+ g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE,
- 1, G_TYPE_STRING);
+ 1, G_TYPE_OBJECT);
signals [DEACTIVATED] = g_signal_new ("deactivated",
G_TYPE_FROM_CLASS (object_class),
@@ -132,22 +233,19 @@ gdm_task_list_class_init (GdmTaskListClass *klass)
G_STRUCT_OFFSET (GdmTaskListClass, deactivated),
NULL,
NULL,
- g_cclosure_marshal_VOID__STRING,
+ g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE,
- 1, G_TYPE_STRING);
+ 1, G_TYPE_OBJECT);
g_type_class_add_private (klass, sizeof (GdmTaskListPrivate));
-}
-
-static void
-gdm_task_list_init (GdmTaskList *widget)
+} static void gdm_task_list_init (GdmTaskList *widget)
{
widget->priv = GDM_TASK_LIST_GET_PRIVATE (widget);
gtk_alignment_set_padding (GTK_ALIGNMENT (widget), 0, 0, 0, 0);
gtk_alignment_set (GTK_ALIGNMENT (widget), 0.0, 0.0, 0, 0);
- widget->priv->box = gtk_hbox_new (FALSE, 2);
+ widget->priv->box = gtk_hbox_new (TRUE, 2);
gtk_widget_show (widget->priv->box);
gtk_container_add (GTK_CONTAINER (widget),
widget->priv->box);
@@ -179,20 +277,46 @@ gdm_task_list_new (void)
return GTK_WIDGET (object);
}
-const char *
+gboolean
+gdm_task_list_task_is_active (GdmTaskList *task_list,
+ GdmTask *task)
+{
+ GtkWidget *button;
+
+ button = g_object_get_data (G_OBJECT (task), "gdm-task-list-button");
+
+ return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button));
+}
+
+GdmTask *
gdm_task_list_get_active_task (GdmTaskList *widget)
{
- GList *node;
+ return gdm_task_list_foreach_task (widget,
+ (GdmTaskListForeachFunc)
+ gdm_task_list_task_is_active,
+ NULL);
+}
- for (node = widget->priv->tasks; node != NULL; node = node->next) {
- GdmTask *task;
+gboolean
+gdm_task_list_set_active_task (GdmTaskList *widget,
+ GdmTask *task)
+{
+ GtkWidget *button;
- task = node->data;
+ button = GTK_WIDGET (g_object_get_data (G_OBJECT (task),
+ "gdm-task-list-button"));
- if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (task->radio_button)) ) {
- return task->name;
+ if (GTK_WIDGET_IS_SENSITIVE (button)) {
+ if (gtk_widget_activate (button)) {
+ return TRUE;
}
}
- return NULL;
+ return FALSE;
+}
+
+int
+gdm_task_list_get_number_of_tasks (GdmTaskList *widget)
+{
+ return g_list_length (widget->priv->tasks);
}
diff --git a/gui/simple-greeter/gdm-task-list.h b/gui/simple-greeter/gdm-task-list.h
index ade21b6..8bc0c0e 100644
--- a/gui/simple-greeter/gdm-task-list.h
+++ b/gui/simple-greeter/gdm-task-list.h
@@ -22,8 +22,11 @@
#define __GDM_TASK_LIST_H
#include <glib-object.h>
+#include <gio/gio.h>
#include <gtk/gtkalignment.h>
+#include "gdm-task.h"
+
G_BEGIN_DECLS
#define GDM_TYPE_TASK_LIST (gdm_task_list_get_type ())
@@ -34,31 +37,44 @@ G_BEGIN_DECLS
#define GDM_TASK_LIST_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_TASK_LIST, GdmTaskListClass))
typedef struct GdmTaskListPrivate GdmTaskListPrivate;
+typedef struct _GdmTaskList GdmTaskList;
-typedef struct
+typedef gboolean (* GdmTaskListForeachFunc) (GdmTaskList *task_list,
+ GdmTask *task,
+ gpointer data);
+
+struct _GdmTaskList
{
GtkAlignment parent;
GdmTaskListPrivate *priv;
-} GdmTaskList;
+};
typedef struct
{
GtkAlignmentClass parent_class;
void (* deactivated) (GdmTaskList *widget,
- const char *name);
+ GdmTask *task);
void (* activated) (GdmTaskList *widget,
- const char *name);
+ GdmTask *task);
} GdmTaskListClass;
+GType gdm_task_list_get_type (void);
+GtkWidget * gdm_task_list_new (void);
+
-GType gdm_task_list_get_type (void);
-GtkWidget * gdm_task_list_new (void);
+gboolean gdm_task_list_task_is_active (GdmTaskList *task_list,
+ GdmTask *task);
+GdmTask * gdm_task_list_get_active_task (GdmTaskList *widget);
+gboolean gdm_task_list_set_active_task (GdmTaskList *widget,
+ GdmTask *task);
+GdmTask * gdm_task_list_foreach_task (GdmTaskList *widget,
+ GdmTaskListForeachFunc foreach_func,
+ gpointer data);
+void gdm_task_list_add_task (GdmTaskList *widget,
+ GdmTask *task);
-const char * gdm_task_list_get_active_task (GdmTaskList *widget);
-void gdm_task_list_add_task (GdmTaskList *widget,
- const char *name,
- const char *icon_name);
+int gdm_task_list_get_number_of_tasks (GdmTaskList *widget);
G_END_DECLS
#endif /* __GDM_TASK_LIST_H */
diff --git a/gui/simple-greeter/libgdmsimplegreeter/Makefile.am b/gui/simple-greeter/libgdmsimplegreeter/Makefile.am
new file mode 100644
index 0000000..1ef5725
--- /dev/null
+++ b/gui/simple-greeter/libgdmsimplegreeter/Makefile.am
@@ -0,0 +1,46 @@
+NULL =
+
+AM_CPPFLAGS = \
+ -I. \
+ -I.. \
+ -DBINDIR=\"$(bindir)\" \
+ -DDATADIR=\"$(datadir)\" \
+ -DLIBDIR=\"$(libdir)\" \
+ -DLIBEXECDIR=\"$(libexecdir)\" \
+ -DLOGDIR=\"$(logdir)\" \
+ -DPIXMAPDIR=\"$(pixmapdir)\" \
+ -DSBINDIR=\"$(sbindir)\" \
+ $(GTK_CFLAGS) \
+ $(NULL)
+
+lib_LTLIBRARIES = \
+ libgdmsimplegreeter.la \
+ $(NULL)
+
+libgdmsimplegreeter_la_SOURCES = \
+ gdm-task.h \
+ gdm-task.c \
+ gdm-conversation.h \
+ gdm-conversation.c \
+ gdm-greeter-extension.h \
+ gdm-greeter-extension.c \
+ $(NULL)
+
+libgdmsimplegreeter_la_LIBADD = \
+ $(GTK_LIBS) \
+ $(NULL)
+
+libgdmsimplegreeter_la_LDFLAGS = \
+ -export-symbols-regex '^[^_].*' \
+ -version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
+ -no-undefined \
+ $(NULL)
+
+headersdir = $(includedir)/gdm/simple-greeter
+headers_HEADERS = gdm-greeter-extension.h
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = gdmsimplegreeter.pc
+
+EXTRA_DIST = gdmsimplegreeter.pc
+MAINTAINERCLEANFILES = Makefile.in
diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c
new file mode 100644
index 0000000..e21c56b
--- /dev/null
+++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.c
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Written By: Ray Strode <rstrode redhat com>
+ *
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <gtk/gtk.h>
+
+#include "gdm-conversation.h"
+#include "gdm-task.h"
+
+
+enum {
+ ANSWER,
+ LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0, };
+
+static void gdm_conversation_class_init (gpointer g_iface);
+
+GType
+gdm_conversation_get_type (void)
+{
+ static GType type = 0;
+
+ if (!type) {
+ type = g_type_register_static_simple (G_TYPE_INTERFACE,
+ "GdmConversation",
+ sizeof (GdmConversationIface),
+ (GClassInitFunc) gdm_conversation_class_init,
+ 0, NULL, 0);
+
+ g_type_interface_add_prerequisite (type, G_TYPE_OBJECT);
+ g_type_interface_add_prerequisite (type, GDM_TYPE_TASK);
+ }
+
+ return type;
+}
+
+static void
+gdm_conversation_class_init (gpointer g_iface)
+{
+ GType iface_type = G_TYPE_FROM_INTERFACE (g_iface);
+
+ signals [ANSWER] =
+ g_signal_new ("answer",
+ iface_type,
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GdmConversationIface, answer),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__STRING,
+ G_TYPE_NONE,
+ 1, G_TYPE_STRING);
+}
+
+void
+gdm_conversation_set_message (GdmConversation *conversation,
+ const char *message)
+{
+ GDM_CONVERSATION_GET_IFACE (conversation)->set_message (conversation, message);
+}
+
+void
+gdm_conversation_ask_question (GdmConversation *conversation,
+ const char *message)
+{
+ GDM_CONVERSATION_GET_IFACE (conversation)->ask_question (conversation, message);
+}
+
+void
+gdm_conversation_ask_secret (GdmConversation *conversation,
+ const char *message)
+{
+ GDM_CONVERSATION_GET_IFACE (conversation)->ask_secret (conversation, message);
+}
+
+void
+gdm_conversation_reset (GdmConversation *conversation)
+{
+ return GDM_CONVERSATION_GET_IFACE (conversation)->reset (conversation);
+}
+
+void
+gdm_conversation_set_ready (GdmConversation *conversation)
+{
+ return GDM_CONVERSATION_GET_IFACE (conversation)->set_ready (conversation);
+}
+
+char *
+gdm_conversation_get_service_name (GdmConversation *conversation)
+{
+ return GDM_CONVERSATION_GET_IFACE (conversation)->get_service_name (conversation);
+}
+
+GtkWidget *
+gdm_conversation_get_page (GdmConversation *conversation)
+{
+ return GDM_CONVERSATION_GET_IFACE (conversation)->get_page (conversation);
+}
+
+GtkActionGroup *
+gdm_conversation_get_actions (GdmConversation *conversation)
+{
+ return GDM_CONVERSATION_GET_IFACE (conversation)->get_actions (conversation);
+}
+
+gboolean
+gdm_conversation_focus (GdmConversation *conversation)
+{
+ return GDM_CONVERSATION_GET_IFACE (conversation)->focus (conversation);
+}
+
+void
+gdm_conversation_request_answer (GdmConversation *conversation)
+{
+ return GDM_CONVERSATION_GET_IFACE (conversation)->request_answer (conversation);
+}
+
+/* protected
+ */
+void
+gdm_conversation_answer (GdmConversation *conversation,
+ const char *answer)
+{
+ g_signal_emit (conversation, signals [ANSWER], 0, answer);
+}
+
diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h
new file mode 100644
index 0000000..f1910cf
--- /dev/null
+++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-conversation.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) Red Hat, Inc.
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Written by: Ray Strode <rstrode redhat com>
+ */
+
+
+#ifndef __GDM_CONVERSATION_H
+#define __GDM_CONVERSATION_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_CONVERSATION (gdm_conversation_get_type ())
+#define GDM_CONVERSATION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_CONVERSATION, GdmConversation))
+#define GDM_CONVERSATION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_CONVERSATION, GdmConversationIface))
+#define GDM_IS_CONVERSATION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_CONVERSATION))
+#define GDM_CONVERSATION_GET_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), GDM_TYPE_CONVERSATION, GdmConversationIface))
+
+#define GDM_CONVERSATION_DEFAULT_ACTION "default-action"
+
+typedef struct _GdmConversation GdmConversation;
+typedef struct _GdmConversationIface GdmConversationIface;
+
+struct _GdmConversationIface
+{
+ GTypeInterface base_iface;
+
+ /* methods */
+ void (* set_message) (GdmConversation *conversation,
+ const char *message);
+ void (* ask_question) (GdmConversation *conversation,
+ const char *message);
+ void (* ask_secret) (GdmConversation *conversation,
+ const char *message);
+ void (* reset) (GdmConversation *conversation);
+ void (* set_ready) (GdmConversation *conversation);
+ char * (* get_service_name) (GdmConversation *conversation);
+ GtkWidget * (* get_page) (GdmConversation *conversation);
+ GtkActionGroup * (* get_actions) (GdmConversation *conversation);
+ void (* request_answer) (GdmConversation *conversation);
+ gboolean (* focus) (GdmConversation *conversation);
+
+ /* signals */
+ char * (* answer) (GdmConversation *conversation);
+};
+
+GType gdm_conversation_get_type (void) G_GNUC_CONST;
+
+void gdm_conversation_set_message (GdmConversation *conversation,
+ const char *message);
+void gdm_conversation_ask_question (GdmConversation *conversation,
+ const char *message);
+void gdm_conversation_ask_secret (GdmConversation *conversation,
+ const char *message);
+void gdm_conversation_reset (GdmConversation *converastion);
+void gdm_conversation_set_ready (GdmConversation *converastion);
+char *gdm_conversation_get_service_name (GdmConversation *conversation);
+GtkWidget *gdm_conversation_get_page (GdmConversation *conversation);
+GtkActionGroup *gdm_conversation_get_actions (GdmConversation *conversation);
+void gdm_conversation_request_answer (GdmConversation *conversation);
+gboolean gdm_conversation_focus (GdmConversation *conversation);
+
+/* protected
+ */
+void gdm_conversation_answer (GdmConversation *conversation,
+ const char *answer);
+
+G_END_DECLS
+
+#endif /* __GDM_CONVERSATION_H */
diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-greeter-extension.c b/gui/simple-greeter/libgdmsimplegreeter/gdm-greeter-extension.c
new file mode 100644
index 0000000..a71d3f7
--- /dev/null
+++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-greeter-extension.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Written By: Ray Strode <rstrode redhat com>
+ *
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "gdm-greeter-extension.h"
+
+enum {
+ LOADED,
+ LOAD_FAILED,
+ LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0, };
+
+static void gdm_greeter_extension_class_init (gpointer g_iface);
+
+GType
+gdm_greeter_extension_get_type (void)
+{
+ static GType greeter_extension_type = 0;
+
+ if (!greeter_extension_type) {
+ greeter_extension_type = g_type_register_static_simple (G_TYPE_INTERFACE,
+ "GdmGreeterExtension",
+ sizeof (GdmGreeterExtensionIface),
+ (GClassInitFunc) gdm_greeter_extension_class_init,
+ 0, NULL, 0);
+
+ g_type_interface_add_prerequisite (greeter_extension_type, G_TYPE_OBJECT);
+ }
+
+ return greeter_extension_type;
+}
+
+static void
+gdm_greeter_extension_class_init (gpointer g_iface)
+{
+ GType iface_type = G_TYPE_FROM_INTERFACE (g_iface);
+
+ signals [LOADED] =
+ g_signal_new ("loaded",
+ iface_type,
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GdmGreeterExtensionIface, loaded),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals [LOADED] =
+ g_signal_new ("load_failed",
+ iface_type,
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GdmGreeterExtensionIface, load_failed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1, G_TYPE_POINTER);
+}
+
+void
+gdm_greeter_extension_loaded (GdmGreeterExtension *extension)
+{
+ g_signal_emit (extension, signals [LOADED], 0);
+}
+
+void
+gdm_greeter_extension_load_failed (GdmGreeterExtension *extension,
+ GError *error)
+{
+ g_signal_emit (extension, signals [LOAD_FAILED], 0, error);
+}
diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-greeter-extension.h b/gui/simple-greeter/libgdmsimplegreeter/gdm-greeter-extension.h
new file mode 100644
index 0000000..283ba0e
--- /dev/null
+++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-greeter-extension.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2009 Red Hat, Inc. *
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Written by: Ray Strode
+ */
+
+#ifndef __GDM_GREETER_EXTENSION_H
+#define __GDM_GREETER_EXTENSION_H
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_GREETER_EXTENSION (gdm_greeter_extension_get_type ())
+#define GDM_GREETER_EXTENSION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_GREETER_EXTENSION, GdmGreeterExtension))
+#define GDM_GREETER_EXTENSION_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_GREETER_EXTENSION, GdmGreeterExtensionClass))
+#define GDM_IS_GREETER_EXTENSION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_GREETER_EXTENSION))
+#define GDM_GREETER_EXTENSION_GET_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), GDM_TYPE_GREETER_EXTENSION, GdmGreeterExtensionIface))
+
+typedef struct _GdmGreeterExtension GdmGreeterExtension;
+typedef struct _GdmGreeterExtensionIface GdmGreeterExtensionIface;
+
+struct _GdmGreeterExtensionIface
+{
+ GTypeInterface base_iface;
+
+ void (* loaded) (GdmGreeterExtension *extension);
+ void (* load_failed) (GdmGreeterExtension *extension,
+ GError *error);
+};
+
+GType gdm_greeter_extension_get_type (void) G_GNUC_CONST;
+
+void gdm_greeter_extension_loaded (GdmGreeterExtension *extension);
+void gdm_greeter_extension_load_failed (GdmGreeterExtension *extension,
+ GError *error);
+
+typedef GdmGreeterExtension * (* GdmGreeterPluginGetExtensionFunc) (void);
+
+G_END_DECLS
+#endif /* __GDM_GREETER_EXTENSION_H */
diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-task.c b/gui/simple-greeter/libgdmsimplegreeter/gdm-task.c
new file mode 100644
index 0000000..f72fa78
--- /dev/null
+++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-task.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Written By: Ray Strode <rstrode redhat com>
+ *
+ */
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include "gdm-task.h"
+
+enum {
+ ENABLED,
+ DISABLED,
+ LAST_SIGNAL
+};
+
+static guint signals [LAST_SIGNAL] = { 0, };
+static void gdm_task_class_init (gpointer g_iface);
+
+GType
+gdm_task_get_type (void)
+{
+ static GType task_type = 0;
+
+ if (!task_type) {
+ task_type = g_type_register_static_simple (G_TYPE_INTERFACE,
+ "GdmTask",
+ sizeof (GdmTaskIface),
+ (GClassInitFunc) gdm_task_class_init,
+ 0, NULL, 0);
+
+ g_type_interface_add_prerequisite (task_type, G_TYPE_OBJECT);
+ }
+
+ return task_type;
+}
+
+GIcon *
+gdm_task_get_icon (GdmTask *task)
+{
+ return GDM_TASK_GET_IFACE (task)->get_icon (task);
+}
+
+char *
+gdm_task_get_description (GdmTask *task)
+{
+ return GDM_TASK_GET_IFACE (task)->get_description (task);
+}
+
+char *
+gdm_task_get_name (GdmTask *task)
+{
+ return GDM_TASK_GET_IFACE (task)->get_name (task);
+}
+
+void
+gdm_task_set_enabled (GdmTask *task,
+ gboolean should_enable)
+{
+ g_object_set_data (G_OBJECT (task), "gdm-task-is-disabled", GINT_TO_POINTER (!should_enable));
+
+ if (should_enable) {
+ g_signal_emit (G_OBJECT (task), signals [ENABLED], 0);
+ } else {
+ g_signal_emit (G_OBJECT (task), signals [DISABLED], 0);
+ }
+}
+
+gboolean
+gdm_task_is_enabled (GdmTask *task)
+{
+ return !g_object_get_data (G_OBJECT (task), "gdm-task-is-disabled");
+}
+
+static void
+gdm_task_class_init (gpointer g_iface)
+{
+ GType iface_type = G_TYPE_FROM_INTERFACE (g_iface);
+
+ signals [ENABLED] =
+ g_signal_new ("enabled",
+ iface_type,
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GdmTaskIface, enabled),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ signals [DISABLED] =
+ g_signal_new ("disabled",
+ iface_type,
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GdmTaskIface, disabled),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+}
diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdm-task.h b/gui/simple-greeter/libgdmsimplegreeter/gdm-task.h
new file mode 100644
index 0000000..9894e65
--- /dev/null
+++ b/gui/simple-greeter/libgdmsimplegreeter/gdm-task.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) Red Hat, Inc.
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Written by: Ray Strode <rstrode redhat com>
+ */
+
+
+#ifndef __GDM_TASK_H
+#define __GDM_TASK_H
+
+#include <glib-object.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_TASK (gdm_task_get_type ())
+#define GDM_TASK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_TASK, GdmTask))
+#define GDM_TASK_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_TASK, GdmTaskIface))
+#define GDM_IS_TASK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_TASK))
+#define GDM_TASK_GET_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), GDM_TYPE_TASK, GdmTaskIface))
+
+typedef struct _GdmTask GdmTask;
+typedef struct _GdmTaskIface GdmTaskIface;
+
+struct _GdmTaskIface
+{
+ GTypeInterface base_iface;
+
+ /* methods */
+ GIcon * (* get_icon) (GdmTask *task);
+ char * (* get_description) (GdmTask *task);
+ char * (* get_name) (GdmTask *task);
+ /* signals */
+ void (* enabled) (GdmTask *task);
+ void (* disabled) (GdmTask *task);
+};
+
+GType gdm_task_get_type (void) G_GNUC_CONST;
+
+GIcon *gdm_task_get_icon (GdmTask *task);
+char *gdm_task_get_description (GdmTask *task);
+char *gdm_task_get_name (GdmTask *task);
+void gdm_task_set_enabled (GdmTask *task,
+ gboolean should_enable);
+gboolean gdm_task_is_enabled (GdmTask *task);
+G_END_DECLS
+
+#endif /* __GDM_TASK_H */
diff --git a/gui/simple-greeter/libgdmsimplegreeter/gdmsimplegreeter.pc.in b/gui/simple-greeter/libgdmsimplegreeter/gdmsimplegreeter.pc.in
new file mode 100644
index 0000000..a429d99
--- /dev/null
+++ b/gui/simple-greeter/libgdmsimplegreeter/gdmsimplegreeter.pc.in
@@ -0,0 +1,11 @@
+prefix= prefix@
+exec_prefix= exec_prefix@
+libdir= libdir@
+includedir= includedir@
+pluginsdir= GDM_SIMPLE_GREETER_PLUGINS_DIR@
+
+Name: GDM Simple Greeter
+Description: Library for GDM Simple Greeter Plugins
+Version: @VERSION@
+Libs: -L${libdir} -lgdmsimplegreeter
+Cflags: -I${includedir}/gdm/simple-greeter
diff --git a/gui/simple-greeter/plugins/Makefile.am b/gui/simple-greeter/plugins/Makefile.am
new file mode 100644
index 0000000..c0390db
--- /dev/null
+++ b/gui/simple-greeter/plugins/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = password
diff --git a/gui/simple-greeter/plugins/password/Makefile.am b/gui/simple-greeter/plugins/password/Makefile.am
new file mode 100644
index 0000000..764904d
--- /dev/null
+++ b/gui/simple-greeter/plugins/password/Makefile.am
@@ -0,0 +1,53 @@
+NULL =
+PAM_SERVICE_NAME = gdm-password
+
+extensiondir = $(extensionsdatadir)/password
+extension_DATA = page.ui
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/common \
+ -I$(top_srcdir)/gui/simple-greeter/libnotificationarea \
+ -I$(top_srcdir)/gui/simple-greeter/libgdmsimplegreeter \
+ -DDMCONFDIR=\""$(dmconfdir)"\" \
+ -DGDMCONFDIR=\"$(gdmconfdir)\" \
+ -DPLUGINDATADIR=\""$(extensiondir)"\" \
+ -DPAMSERVICENAME=\""$(PAM_SERVICE_NAME)"\" \
+ -DSYSCONFDIR=\""$(sysconfdir)"\" \
+ -DLIBLOCALEDIR=\""$(prefix)/lib/locale"\" \
+ -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
+ -DLIBEXECDIR=\""$(libexecdir)"\" \
+ -DSBINDIR=\""$(sbindir)"\" \
+ $(DISABLE_DEPRECATED_CFLAGS) \
+ $(GTK_CFLAGS) \
+ $(SIMPLE_GREETER_CFLAGS) \
+ $(POLKIT_GNOME_CFLAGS) \
+ $(NULL)
+
+plugindir = $(GDM_SIMPLE_GREETER_PLUGINS_DIR)
+plugin_LTLIBRARIES = password.la
+
+password_la_CFLAGS = \
+ $(SIMPLE_GREETER_CFLAGS) \
+ $(NULL)
+
+password_la_LDFLAGS = -module -avoid-version -export-dynamic
+password_la_LIBADD = ../../../../common/libgdmcommon.la \
+ ../../libgdmsimplegreeter/libgdmsimplegreeter.la
+password_la_SOURCES = \
+ gdm-password-extension.h \
+ gdm-password-extension.c \
+ plugin.c
+
+$(PAM_SERVICE_NAME): $(PAM_SERVICE_NAME).pam
+ cp $(PAM_SERVICE_NAME).pam $(PAM_SERVICE_NAME)
+
+pamdir = $(PAM_PREFIX)/pam.d
+pam_DATA = $(PAM_SERVICE_NAME)
+
+EXTRA_DIST = $(extension_DATA) $(PAM_SERVICE_NAME).pam
+CLEANFILES = $(PAM_SERVICE_NAME)
+
+MAINTAINERCLEANFILES = \
+ *~ \
+ $(PAM_SERVICE_NAME) \
+ Makefile.in
diff --git a/gui/simple-greeter/plugins/password/gdm-password-extension.c b/gui/simple-greeter/plugins/password/gdm-password-extension.c
new file mode 100644
index 0000000..fae73be
--- /dev/null
+++ b/gui/simple-greeter/plugins/password/gdm-password-extension.c
@@ -0,0 +1,316 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Written By: Ray Strode <rstrode redhat com>
+ *
+ */
+
+#include <config.h>
+#include "gdm-password-extension.h"
+#include "gdm-conversation.h"
+#include "gdm-task.h"
+
+#include <glib/gi18n-lib.h>
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+
+struct _GdmPasswordExtensionPrivate
+{
+ GIcon *icon;
+ GtkWidget *page;
+ GtkActionGroup *actions;
+
+ GtkWidget *message_label;
+ GtkWidget *prompt_label;
+ GtkWidget *prompt_entry;
+
+ guint answer_pending : 1;
+};
+
+static void gdm_password_extension_finalize (GObject *object);
+
+static void gdm_task_iface_init (GdmTaskIface *iface);
+static void gdm_conversation_iface_init (GdmConversationIface *iface);
+static void gdm_greeter_extension_iface_init (GdmGreeterExtensionIface *iface);
+
+G_DEFINE_TYPE_WITH_CODE (GdmPasswordExtension,
+ gdm_password_extension,
+ G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (GDM_TYPE_GREETER_EXTENSION,
+ gdm_greeter_extension_iface_init)
+ G_IMPLEMENT_INTERFACE (GDM_TYPE_TASK,
+ gdm_task_iface_init)
+ G_IMPLEMENT_INTERFACE (GDM_TYPE_CONVERSATION,
+ gdm_conversation_iface_init));
+
+static void
+gdm_password_extension_set_message (GdmConversation *conversation,
+ const char *message)
+{
+ GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (conversation);
+ gtk_widget_show (extension->priv->message_label);
+ gtk_label_set_text (GTK_LABEL (extension->priv->message_label), message);
+}
+
+static void
+gdm_password_extension_ask_question (GdmConversation *conversation,
+ const char *message)
+{
+ GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (conversation);
+ gtk_widget_show (extension->priv->prompt_label);
+ gtk_label_set_text (GTK_LABEL (extension->priv->prompt_label), message);
+ gtk_entry_set_text (GTK_ENTRY (extension->priv->prompt_entry), "");
+ gtk_entry_set_visibility (GTK_ENTRY (extension->priv->prompt_entry), TRUE);
+ gtk_widget_show (extension->priv->prompt_entry);
+ gtk_widget_grab_focus (extension->priv->prompt_entry);
+ extension->priv->answer_pending = TRUE;
+}
+
+static void
+gdm_password_extension_ask_secret (GdmConversation *conversation,
+ const char *message)
+{
+ GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (conversation);
+ gtk_widget_show (extension->priv->prompt_label);
+ gtk_label_set_text (GTK_LABEL (extension->priv->prompt_label), message);
+ gtk_entry_set_visibility (GTK_ENTRY (extension->priv->prompt_entry), FALSE);
+ gtk_entry_set_text (GTK_ENTRY (extension->priv->prompt_entry), "");
+ gtk_widget_show (extension->priv->prompt_entry);
+ gtk_widget_grab_focus (extension->priv->prompt_entry);
+ extension->priv->answer_pending = TRUE;
+}
+
+static void
+gdm_password_extension_reset (GdmConversation *conversation)
+{
+ GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (conversation);
+ gtk_widget_hide (extension->priv->prompt_label);
+ gtk_label_set_text (GTK_LABEL (extension->priv->prompt_label), "");
+
+ gtk_widget_hide (extension->priv->prompt_entry);
+ gtk_entry_set_text (GTK_ENTRY (extension->priv->prompt_entry), "");
+ gtk_entry_set_visibility (GTK_ENTRY (extension->priv->prompt_entry), TRUE);
+ extension->priv->answer_pending = FALSE;
+
+ gdm_task_set_enabled (GDM_TASK (conversation), FALSE);
+}
+
+static void
+gdm_password_extension_set_ready (GdmConversation *conversation)
+{
+ gdm_task_set_enabled (GDM_TASK (conversation), TRUE);
+}
+
+char *
+gdm_password_extension_get_service_name (GdmConversation *conversation)
+{
+ return g_strdup (PAMSERVICENAME);
+}
+
+GtkWidget *
+gdm_password_extension_get_page (GdmConversation *conversation)
+{
+ GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (conversation);
+ return extension->priv->page;
+}
+
+GtkActionGroup *
+gdm_password_extension_get_actions (GdmConversation *conversation)
+{
+ GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (conversation);
+ return g_object_ref (extension->priv->actions);
+}
+
+void
+gdm_password_extension_request_answer (GdmConversation *conversation)
+{
+ GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (conversation);
+ const char *text;
+
+ if (!extension->priv->answer_pending) {
+ gdm_conversation_answer (conversation, NULL);
+ return;
+ }
+
+ extension->priv->answer_pending = FALSE;
+ text = gtk_entry_get_text (GTK_ENTRY (extension->priv->prompt_entry));
+ gdm_conversation_answer (conversation, text);
+
+ gtk_widget_hide (extension->priv->prompt_entry);
+ gtk_widget_hide (extension->priv->prompt_label);
+ gtk_label_set_text (GTK_LABEL (extension->priv->prompt_label), "");
+ gtk_entry_set_text (GTK_ENTRY (extension->priv->prompt_entry), "");
+}
+
+gboolean
+gdm_password_extension_focus (GdmConversation *conversation)
+{
+ GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (conversation);
+ if (!extension->priv->answer_pending) {
+ gdm_conversation_answer (conversation, NULL);
+ return FALSE;
+ }
+
+ gtk_widget_grab_focus (extension->priv->prompt_entry);
+ return TRUE;
+}
+
+GIcon *
+gdm_password_extension_get_icon (GdmTask *task)
+{
+ GdmPasswordExtension *extension = GDM_PASSWORD_EXTENSION (task);
+ return g_object_ref (extension->priv->icon);
+}
+
+char *
+gdm_password_extension_get_name (GdmTask *task)
+{
+ return g_strdup (_("Password Authentication"));
+}
+
+char *
+gdm_password_extension_get_description (GdmTask *task)
+{
+ return g_strdup (_("Log into session with username and password"));
+}
+
+static void
+gdm_task_iface_init (GdmTaskIface *iface)
+{
+ iface->get_icon = gdm_password_extension_get_icon;
+ iface->get_description = gdm_password_extension_get_description;
+ iface->get_name = gdm_password_extension_get_name;
+}
+
+static void
+gdm_conversation_iface_init (GdmConversationIface *iface)
+{
+ iface->set_message = gdm_password_extension_set_message;
+ iface->ask_question = gdm_password_extension_ask_question;
+ iface->ask_secret = gdm_password_extension_ask_secret;
+ iface->reset = gdm_password_extension_reset;
+ iface->set_ready = gdm_password_extension_set_ready;
+ iface->get_service_name = gdm_password_extension_get_service_name;
+ iface->get_page = gdm_password_extension_get_page;
+ iface->get_actions = gdm_password_extension_get_actions;
+ iface->request_answer = gdm_password_extension_request_answer;
+ iface->focus = gdm_password_extension_focus;
+}
+
+static void
+gdm_greeter_extension_iface_init (GdmGreeterExtensionIface *iface)
+{
+}
+
+static void
+gdm_password_extension_class_init (GdmPasswordExtensionClass *extension_class)
+{
+ GObjectClass *object_class;
+
+ object_class = G_OBJECT_CLASS (extension_class);
+
+ object_class->finalize = gdm_password_extension_finalize;
+
+ g_type_class_add_private (extension_class,
+ sizeof (GdmPasswordExtensionPrivate));
+}
+
+static void
+gdm_password_extension_finalize (GObject *object)
+{
+}
+
+static void
+on_activate_log_in (GdmPasswordExtension *extension)
+{
+ gdm_password_extension_request_answer (GDM_CONVERSATION (extension));
+}
+
+static void
+create_page (GdmPasswordExtension *extension)
+{
+ GtkBuilder *builder;
+ GObject *object;
+ GError *error;
+
+ builder = gtk_builder_new ();
+
+ error = NULL;
+ gtk_builder_add_from_file (builder,
+ PLUGINDATADIR "/page.ui",
+ &error);
+
+ if (error != NULL) {
+ g_warning ("Could not load UI file: %s", error->message);
+ g_error_free (error);
+ return;
+ }
+
+ object = gtk_builder_get_object (builder, "page");
+ g_object_ref (object);
+
+ extension->priv->page = GTK_WIDGET (object);
+
+ object = gtk_builder_get_object (builder, "auth-prompt-label");
+ g_object_ref (object);
+ extension->priv->prompt_label = GTK_WIDGET (object);
+ gtk_widget_hide (extension->priv->prompt_label);
+
+ object = gtk_builder_get_object (builder, "auth-prompt-entry");
+ g_object_ref (object);
+ extension->priv->prompt_entry = GTK_WIDGET (object);
+ gtk_widget_hide (extension->priv->prompt_entry);
+
+ object = gtk_builder_get_object (builder, "auth-message-label");
+ g_object_ref (object);
+ extension->priv->message_label = GTK_WIDGET (object);
+ gtk_widget_show (extension->priv->message_label);
+
+ g_object_unref (builder);
+}
+
+static void
+create_actions (GdmPasswordExtension *extension)
+{
+ GtkAction *action;
+
+ extension->priv->actions = gtk_action_group_new ("gdm-password-extension");
+
+ action = gtk_action_new (GDM_CONVERSATION_DEFAULT_ACTION,
+ _("Log In"),
+ _("Log into the currently selected sesson"),
+ NULL);
+ g_signal_connect_swapped (action, "activate",
+ G_CALLBACK (on_activate_log_in), extension);
+ g_object_set (G_OBJECT (action), "icon-name", "go-home", NULL);
+ gtk_action_group_add_action (extension->priv->actions,
+ action);
+}
+
+static void
+gdm_password_extension_init (GdmPasswordExtension *extension)
+{
+ extension->priv = G_TYPE_INSTANCE_GET_PRIVATE (extension,
+ GDM_TYPE_PASSWORD_EXTENSION,
+ GdmPasswordExtensionPrivate);
+
+ extension->priv->icon = g_themed_icon_new ("dialog-password");
+ create_page (extension);
+ create_actions (extension);
+
+ gdm_password_extension_reset (GDM_CONVERSATION (extension));
+}
diff --git a/gui/simple-greeter/plugins/password/gdm-password-extension.h b/gui/simple-greeter/plugins/password/gdm-password-extension.h
new file mode 100644
index 0000000..99fe17b
--- /dev/null
+++ b/gui/simple-greeter/plugins/password/gdm-password-extension.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * 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; either version 2, or (at your option)
+ * any later version.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * Written By: Ray Strode <rstrode redhat com>
+ */
+
+#ifndef __GDM_PASSWORD_EXTENSION_H
+#define __GDM_PASSWORD_EXTENSION_H
+
+#include <glib-object.h>
+#include "gdm-greeter-extension.h"
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_PASSWORD_EXTENSION (gdm_password_extension_get_type ())
+#define GDM_PASSWORD_EXTENSION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GDM_TYPE_PASSWORD_EXTENSION, GdmPasswordExtension))
+#define GDM_PASSWORD_EXTENSION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDM_TYPE_PASSWORD_EXTENSION, GdmPasswordExtensionClass))
+#define GDM_IS_PASSWORD_EXTENSION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GDM_TYPE_PASSWORD_EXTENSION))
+#define GDM_IS_PASSWORD_EXTENSION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDM_TYPE_PASSWORD_EXTENSION))
+#define GDM_PASSWORD_EXTENSION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GDM_TYPE_PASSWORD_EXTENSION, GdmPasswordExtensionClass))
+
+typedef struct _GdmPasswordExtensionPrivate GdmPasswordExtensionPrivate;
+
+typedef struct
+{
+ GObject parent;
+ GdmPasswordExtensionPrivate *priv;
+} GdmPasswordExtension;
+
+typedef struct
+{
+ GObjectClass parent_class;
+} GdmPasswordExtensionClass;
+
+GType gdm_password_extension_get_type (void);
+
+GdmPasswordExtension *gdm_password_extension_new (void);
+
+G_END_DECLS
+
+#endif /* GDM_PASSWORD_EXTENSION_H */
diff --git a/gui/simple-greeter/plugins/password/gdm-password.pam b/gui/simple-greeter/plugins/password/gdm-password.pam
new file mode 100644
index 0000000..bac431d
--- /dev/null
+++ b/gui/simple-greeter/plugins/password/gdm-password.pam
@@ -0,0 +1,19 @@
+# Sample PAM file for doing password authentication.
+# Distros should replace this with what makes sense for them.
+auth required pam_env.so
+auth sufficient pam_unix.so nullok try_first_pass
+auth requisite pam_succeed_if.so uid >= 500 quiet
+auth required pam_deny.so
+
+account required pam_unix.so
+account sufficient pam_localuser.so
+account sufficient pam_succeed_if.so uid < 500 quiet
+account required pam_permit.so
+
+password requisite pam_cracklib.so try_first_pass retry=3 type=
+password sufficient pam_unix.so nullok try_first_pass use_authtok
+password required pam_deny.so
+
+session optional pam_keyinit.so revoke
+session required pam_limits.so
+session required pam_unix.so
diff --git a/gui/simple-greeter/plugins/password/page.ui b/gui/simple-greeter/plugins/password/page.ui
new file mode 100644
index 0000000..fe6da78
--- /dev/null
+++ b/gui/simple-greeter/plugins/password/page.ui
@@ -0,0 +1,56 @@
+<?xml version="1.0"?>
+<interface>
+ <requires lib="gtk+" version="2.14"/>
+ <object class="GtkVBox" id="page">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkHBox" id="auth-input-box">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="auth-prompt-label">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkEntry" id="auth-prompt-entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="activates_default">True</property>
+ </object>
+ <packing>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkHBox" id="auth-message-box">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkLabel" id="auth-message-label">
+ <property name="visible">True</property>
+ </object>
+ <packing>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/gui/simple-greeter/plugins/password/plugin.c b/gui/simple-greeter/plugins/password/plugin.c
new file mode 100644
index 0000000..9b87c67
--- /dev/null
+++ b/gui/simple-greeter/plugins/password/plugin.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2009 Red Hat, Inc.
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Written By: Ray Strode <rstrode redhat com>
+ *
+ */
+
+#include "gdm-password-extension.h"
+
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+
+GdmGreeterExtension *
+gdm_greeter_plugin_get_extension (void)
+{
+ static GObject *extension;
+
+ if (extension != NULL) {
+ g_object_ref (extension);
+ } else {
+ extension = g_object_new (GDM_TYPE_PASSWORD_EXTENSION, NULL);
+ g_object_add_weak_pointer (extension, (gpointer *) &extension);
+ }
+
+ return GDM_GREETER_EXTENSION (extension);
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]