? configure.ac.glitz
? data/lock-dialog-default.glade.new
? savers/gste-slideshow.c.glitz
? savers/gste-slideshow.c.new
? savers/prettygraph.png
Index: data/gnome-screensaver.schemas.in
===================================================================
RCS file: /cvs/gnome/gnome-screensaver/data/gnome-screensaver.schemas.in,v
retrieving revision 1.15
diff -p -u -r1.15 gnome-screensaver.schemas.in
--- data/gnome-screensaver.schemas.in	8 Jun 2006 22:36:07 -0000	1.15
+++ data/gnome-screensaver.schemas.in	26 Jul 2006 22:22:59 -0000
@@ -114,6 +114,39 @@
     </schema>
 
     <schema>
+      <key>/schemas/apps/gnome-screensaver/embedded_keyboard_enabled</key>
+      <applyto>/apps/gnome-screensaver/embedded_keyboard_enabled</applyto>
+      <owner>gnome-screensaver</owner>
+      <type>bool</type>
+      <default>FALSE</default>
+      <locale name="C">
+        <short>Allow embedding a keyboard into the window</short>
+        <long>
+          Set this to TRUE to allow embedding a keyboard into the
+          window when trying to unlock.  The "keyboard_command" key
+          must be set with the appropriate command.
+        </long>
+      </locale>
+    </schema>
+
+    <schema>
+      <key>/schemas/apps/gnome-screensaver/embedded_keyboard_command</key>
+      <applyto>/apps/gnome-screensaver/embedded_keyboard_command</applyto>
+      <owner>gnome-screensaver</owner>
+      <type>string</type>
+      <default></default>
+      <locale name="C">
+        <short>Embedded keyboard command</short>
+        <long>
+          The command that will be run, if the "embedded_keyboard_enabled" key
+          is set to TRUE, to embed a keyboard widget into the window.
+          This command should implement an XEMBED plug interface and
+          output a window XID on the standard output.
+        </long>
+      </locale>
+    </schema>
+
+    <schema>
       <key>/schemas/apps/gnome-screensaver/logout_enabled</key>
       <applyto>/apps/gnome-screensaver/logout_enabled</applyto>
       <owner>gnome-screensaver</owner>
Index: src/gs-manager.c
===================================================================
RCS file: /cvs/gnome/gnome-screensaver/src/gs-manager.c,v
retrieving revision 1.57
diff -p -u -r1.57 gs-manager.c
--- src/gs-manager.c	12 Jul 2006 23:02:14 -0000	1.57
+++ src/gs-manager.c	26 Jul 2006 22:23:00 -0000
@@ -52,10 +52,12 @@ struct GSManagerPrivate
 
         guint        lock_enabled : 1;
         guint        logout_enabled : 1;
+        guint        keyboard_enabled : 1;
         guint        user_switch_enabled : 1;
         guint        throttled : 1;
 
         char        *logout_command;
+        char        *keyboard_command;
 
         /* State */
         guint        active : 1;
@@ -89,10 +91,12 @@ enum {
         PROP_LOCK_ENABLED,
         PROP_LOGOUT_ENABLED,
         PROP_USER_SWITCH_ENABLED,
+        PROP_KEYBOARD_ENABLED,
         PROP_LOCK_TIMEOUT,
         PROP_CYCLE_TIMEOUT,
         PROP_LOGOUT_TIMEOUT,
         PROP_LOGOUT_COMMAND,
+        PROP_KEYBOARD_COMMAND,
         PROP_ACTIVE,
         PROP_THROTTLED,
 };
@@ -408,6 +412,22 @@ gs_manager_set_logout_enabled (GSManager
 }
 
 void
+gs_manager_set_keyboard_enabled (GSManager *manager,
+                                 gboolean   enabled)
+{
+        g_return_if_fail (GS_IS_MANAGER (manager));
+
+        if (manager->priv->keyboard_enabled != enabled) {
+                GSList *l;
+
+                manager->priv->keyboard_enabled = enabled;
+                for (l = manager->priv->windows; l; l = l->next) {
+                        gs_window_set_keyboard_enabled (l->data, enabled);
+                }
+        }
+}
+
+void
 gs_manager_set_user_switch_enabled (GSManager *manager,
                                     gboolean   user_switch_enabled)
 {
@@ -500,6 +520,8 @@ void
 gs_manager_set_logout_command (GSManager  *manager,
                                const char *command)
 {
+        GSList *l;
+
         g_return_if_fail (GS_IS_MANAGER (manager));
 
         g_free (manager->priv->logout_command);
@@ -509,6 +531,31 @@ gs_manager_set_logout_command (GSManager
         } else {
                 manager->priv->logout_command = NULL;
         }
+
+        for (l = manager->priv->windows; l; l = l->next) {
+                gs_window_set_logout_command (l->data, manager->priv->logout_command);
+        }
+}
+
+void
+gs_manager_set_keyboard_command (GSManager  *manager,
+                                 const char *command)
+{
+        GSList *l;
+
+        g_return_if_fail (GS_IS_MANAGER (manager));
+
+        g_free (manager->priv->keyboard_command);
+
+        if (command) {
+                manager->priv->keyboard_command = g_strdup (command);
+        } else {
+                manager->priv->keyboard_command = NULL;
+        }
+
+        for (l = manager->priv->windows; l; l = l->next) {
+                gs_window_set_logout_command (l->data, manager->priv->keyboard_command);
+        }
 }
 
 gboolean
@@ -618,6 +665,9 @@ gs_manager_set_property (GObject        
         case PROP_LOGOUT_ENABLED:
                 gs_manager_set_logout_enabled (self, g_value_get_boolean (value));
                 break;
+        case PROP_KEYBOARD_ENABLED:
+                gs_manager_set_keyboard_enabled (self, g_value_get_boolean (value));
+                break;
         case PROP_USER_SWITCH_ENABLED:
                 gs_manager_set_user_switch_enabled (self, g_value_get_boolean (value));
                 break;
@@ -627,6 +677,9 @@ gs_manager_set_property (GObject        
         case PROP_LOGOUT_COMMAND:
                 gs_manager_set_logout_command (self, g_value_get_string (value));
                 break;
+        case PROP_KEYBOARD_COMMAND:
+                gs_manager_set_keyboard_command (self, g_value_get_string (value));
+                break;
         case PROP_CYCLE_TIMEOUT:
                 gs_manager_set_cycle_timeout (self, g_value_get_long (value));
                 break;
@@ -659,6 +712,9 @@ gs_manager_get_property (GObject        
         case PROP_LOGOUT_ENABLED:
                 g_value_set_boolean (value, self->priv->logout_enabled);
                 break;
+        case PROP_KEYBOARD_ENABLED:
+                g_value_set_boolean (value, self->priv->keyboard_enabled);
+                break;
         case PROP_USER_SWITCH_ENABLED:
                 g_value_set_boolean (value, self->priv->user_switch_enabled);
                 break;
@@ -668,6 +724,9 @@ gs_manager_get_property (GObject        
         case PROP_LOGOUT_COMMAND:
                 g_value_set_string (value, self->priv->logout_command);
                 break;
+        case PROP_KEYBOARD_COMMAND:
+                g_value_set_string (value, self->priv->keyboard_command);
+                break;
         case PROP_CYCLE_TIMEOUT:
                 g_value_set_long (value, self->priv->cycle_timeout);
                 break;
@@ -843,6 +902,7 @@ gs_manager_finalize (GObject *object)
 
         free_themes (manager);
         g_free (manager->priv->logout_command);
+        g_free (manager->priv->keyboard_command);
 
         remove_unfade_idle (manager);
         remove_timers (manager);
@@ -1242,6 +1302,8 @@ gs_manager_create_window (GSManager *man
                 gs_window_set_logout_enabled (window, manager->priv->logout_enabled);
                 gs_window_set_logout_timeout (window, manager->priv->logout_timeout);
                 gs_window_set_logout_command (window, manager->priv->logout_command);
+                gs_window_set_keyboard_enabled (window, manager->priv->keyboard_enabled);
+                gs_window_set_keyboard_command (window, manager->priv->keyboard_command);
 
                 connect_window_signals (manager, window);
 
Index: src/gs-manager.h
===================================================================
RCS file: /cvs/gnome/gnome-screensaver/src/gs-manager.h,v
retrieving revision 1.14
diff -p -u -r1.14 gs-manager.h
--- src/gs-manager.h	12 Jul 2006 23:02:14 -0000	1.14
+++ src/gs-manager.h	26 Jul 2006 22:23:00 -0000
@@ -67,6 +67,10 @@ void        gs_manager_get_lock_active  
                                              gboolean   *lock_active);
 void        gs_manager_set_lock_active      (GSManager  *manager,
                                              gboolean    lock_active);
+void        gs_manager_set_keyboard_enabled (GSManager  *manager,
+                                             gboolean    enabled);
+void        gs_manager_set_keyboard_command (GSManager  *manager,
+                                             const char *command);
 void        gs_manager_set_lock_enabled     (GSManager  *manager,
                                              gboolean    lock_enabled);
 void        gs_manager_set_lock_timeout     (GSManager  *manager,
Index: src/gs-monitor.c
===================================================================
RCS file: /cvs/gnome/gnome-screensaver/src/gs-monitor.c,v
retrieving revision 1.54
diff -p -u -r1.54 gs-monitor.c
--- src/gs-monitor.c	5 Jul 2006 18:27:52 -0000	1.54
+++ src/gs-monitor.c	26 Jul 2006 22:23:00 -0000
@@ -279,8 +279,10 @@ _gs_monitor_update_from_prefs (GSMonitor
         gs_manager_set_lock_timeout (monitor->priv->manager, monitor->priv->prefs->lock_timeout);
         gs_manager_set_logout_enabled (monitor->priv->manager, monitor->priv->prefs->logout_enabled);
         gs_manager_set_user_switch_enabled (monitor->priv->manager, monitor->priv->prefs->user_switch_enabled);
+        gs_manager_set_keyboard_enabled (monitor->priv->manager, monitor->priv->prefs->keyboard_enabled);
         gs_manager_set_logout_timeout (monitor->priv->manager, monitor->priv->prefs->logout_timeout);
         gs_manager_set_logout_command (monitor->priv->manager, monitor->priv->prefs->logout_command);
+        gs_manager_set_keyboard_command (monitor->priv->manager, monitor->priv->prefs->keyboard_command);
         gs_manager_set_cycle_timeout (monitor->priv->manager, monitor->priv->prefs->cycle);
         gs_manager_set_mode (monitor->priv->manager, monitor->priv->prefs->mode);
         gs_manager_set_themes (monitor->priv->manager, monitor->priv->prefs->themes);
Index: src/gs-prefs.c
===================================================================
RCS file: /cvs/gnome/gnome-screensaver/src/gs-prefs.c,v
retrieving revision 1.22
diff -p -u -r1.22 gs-prefs.c
--- src/gs-prefs.c	5 Jul 2006 18:27:52 -0000	1.22
+++ src/gs-prefs.c	26 Jul 2006 22:23:01 -0000
@@ -46,6 +46,8 @@ static void gs_prefs_finalize   (GObject
 #define KEY_LOGOUT_ENABLED KEY_DIR "/logout_enabled"
 #define KEY_LOGOUT_DELAY   KEY_DIR "/logout_delay"
 #define KEY_LOGOUT_COMMAND KEY_DIR "/logout_command"
+#define KEY_KEYBOARD_ENABLED KEY_DIR "/embedded_keyboard_enabled"
+#define KEY_KEYBOARD_COMMAND KEY_DIR "/embedded_keyboard_command"
 
 #define GS_PREFS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GS_TYPE_PREFS, GSPrefsPrivate))
 
@@ -210,6 +212,27 @@ _gs_prefs_set_lock_enabled (GSPrefs *pre
 }
 
 static void
+_gs_prefs_set_keyboard_enabled (GSPrefs *prefs,
+                                gboolean value)
+{
+        prefs->keyboard_enabled = value;
+}
+
+static void
+_gs_prefs_set_keyboard_command (GSPrefs    *prefs,
+                                const char *value)
+{
+        g_free (prefs->keyboard_command);
+        prefs->keyboard_command = NULL;
+
+       if (value) {
+               /* FIXME: check command */
+
+               prefs->keyboard_command = g_strdup (value);
+        }
+}
+
+static void
 _gs_prefs_set_logout_enabled (GSPrefs *prefs,
                               gboolean value)
 {
@@ -323,6 +346,23 @@ gs_prefs_load_from_gconf (GSPrefs *prefs
                 key_error_and_free (KEY_THEMES, error);
         }
 
+        /* Embedded keyboard options */
+
+        bvalue = gconf_client_get_bool (prefs->priv->gconf_client, KEY_KEYBOARD_ENABLED, &error);
+        if (! error) {
+                _gs_prefs_set_keyboard_enabled (prefs, bvalue);
+        } else {
+                key_error_and_free (KEY_KEYBOARD_ENABLED, error);
+        }
+
+        string = gconf_client_get_string (prefs->priv->gconf_client, KEY_KEYBOARD_COMMAND, &error);
+        if (! error) {
+                _gs_prefs_set_keyboard_command (prefs, string);
+        } else {
+                key_error_and_free (KEY_KEYBOARD_COMMAND, error);
+        }
+        g_free (string);
+
         /* Logout options */
 
         bvalue = gconf_client_get_bool (prefs->priv->gconf_client, KEY_LOGOUT_ENABLED, &error);
@@ -487,6 +527,32 @@ key_changed_cb (GConfClient *client,
 
                         delay = gconf_value_get_int (value);
                         _gs_prefs_set_cycle_timeout (prefs, delay);
+
+                        changed = TRUE;
+                } else {
+                        invalid_type_warning (key);
+                }
+
+        } else if (strcmp (key, KEY_KEYBOARD_ENABLED) == 0) {
+
+                if (value->type == GCONF_VALUE_BOOL) {
+                        gboolean enabled;
+
+                        enabled = gconf_value_get_bool (value);
+                        _gs_prefs_set_keyboard_enabled (prefs, enabled);
+
+                        changed = TRUE;
+                } else {
+                        invalid_type_warning (key);
+                }
+
+        } else if (strcmp (key, KEY_KEYBOARD_COMMAND) == 0) {
+
+                if (value->type == GCONF_VALUE_STRING) {
+                        const char *command;
+
+                        command = gconf_value_get_string (value);
+                        _gs_prefs_set_keyboard_command (prefs, command);
 
                         changed = TRUE;
                 } else {
Index: src/gs-prefs.h
===================================================================
RCS file: /cvs/gnome/gnome-screensaver/src/gs-prefs.h,v
retrieving revision 1.12
diff -p -u -r1.12 gs-prefs.h
--- src/gs-prefs.h	5 Jul 2006 18:27:52 -0000	1.12
+++ src/gs-prefs.h	26 Jul 2006 22:23:01 -0000
@@ -50,6 +50,7 @@ typedef struct
         guint            lock_enabled : 1;		/* whether to lock when active */
         guint            logout_enabled : 1;	/* Whether to offer the logout option */
         guint            user_switch_enabled : 1;	/* Whether to offer the user switch option */
+        guint            keyboard_enabled : 1;	/* Whether to try to embed a keyboard */
 
         guint            timeout;	       	/* how much idle time before activation */
         guint            lock_timeout;		/* how long after activation locking starts */
@@ -57,6 +58,7 @@ typedef struct
         guint            cycle;			/* how long each theme should run */
 
         char            *logout_command;        /* command to use to logout */
+        char            *keyboard_command;      /* command to use to embed a keyboard */
 
         GSList          *themes;       		/* the screensaver themes to run */
         GSSaverMode      mode;			/* theme selection mode */
Index: src/gs-window-x11.c
===================================================================
RCS file: /cvs/gnome/gnome-screensaver/src/gs-window-x11.c,v
retrieving revision 1.67
diff -p -u -r1.67 gs-window-x11.c
--- src/gs-window-x11.c	24 Jul 2006 20:17:07 -0000	1.67
+++ src/gs-window-x11.c	26 Jul 2006 22:23:02 -0000
@@ -59,11 +59,16 @@ struct GSWindowPrivate
         guint      lock_enabled : 1;
         guint      user_switch_enabled : 1;
         guint      logout_enabled : 1;
+        guint      keyboard_enabled : 1;
+
         guint64    logout_timeout;
         char      *logout_command;
+        char      *keyboard_command;
 
-        GtkWidget *box;
-        GtkWidget *socket;
+        GtkWidget *vbox;
+        GtkWidget *lock_box;
+        GtkWidget *lock_socket;
+        GtkWidget *keyboard_socket;
 
         guint      popup_dialog_idle_id;
 
@@ -73,10 +78,13 @@ struct GSWindowPrivate
 
         guint      watchdog_timer_id;
 
-        gint       pid;
-        gint       watch_id;
+        gint       lock_pid;
+        gint       lock_watch_id;
         gint       dialog_response;
 
+        gint       keyboard_pid;
+        gint       keyboard_watch_id;
+
         GList     *key_events;
 
         gdouble    last_x;
@@ -98,6 +106,8 @@ enum {
         PROP_OBSCURED,
         PROP_LOCK_ENABLED,
         PROP_LOGOUT_ENABLED,
+        PROP_KEYBOARD_ENABLED,
+        PROP_KEYBOARD_COMMAND,
         PROP_LOGOUT_COMMAND,
         PROP_LOGOUT_TIMEOUT,
         PROP_MONITOR
@@ -655,6 +665,7 @@ get_env_vars (GtkWidget *widget)
         int        i;
         static const char *allowed_env_vars [] = {
                 "PATH",
+                "LD_LIBRARY_PATH",
                 "SESSION_MANAGER",
                 "XAUTHORITY",
                 "XAUTHLOCALHOSTNAME",
@@ -712,7 +723,7 @@ spawn_on_window (GSWindow *window,
 
         error = NULL;
         if (! g_shell_parse_argv (command, &argc, &argv, &error)) {
-                g_warning ("Could not parse command: %s", error->message);
+                gs_debug ("Could not parse command: %s", error->message);
                 g_error_free (error);
                 return FALSE;
         }
@@ -739,7 +750,7 @@ spawn_on_window (GSWindow *window,
         g_ptr_array_free (env, TRUE);
 
         if (! result) {
-                g_warning ("Could not start command '%s': %s", command, error->message);
+                gs_debug ("Could not start command '%s': %s", command, error->message);
                 g_error_free (error);
                 g_strfreev (argv);
                 return FALSE;
@@ -772,24 +783,52 @@ spawn_on_window (GSWindow *window,
 }
 
 static void
-plug_added (GtkWidget *widget,
-            GSWindow  *window)
+lock_plug_added (GtkWidget *widget,
+                 GSWindow  *window)
 {
-        gtk_widget_show (window->priv->socket);
+        gtk_widget_show (widget);
 }
 
 static gboolean
-plug_removed (GtkWidget *widget,
-              GSWindow  *window)
+lock_plug_removed (GtkWidget *widget,
+                   GSWindow  *window)
 {
-        gtk_widget_hide (window->priv->socket);
-        gtk_container_remove (GTK_CONTAINER (window), GTK_WIDGET (window->priv->box));
-        window->priv->box = NULL;
+        gtk_widget_hide (widget);
+        gtk_container_remove (GTK_CONTAINER (window->priv->vbox), GTK_WIDGET (window->priv->lock_box));
+        window->priv->lock_box = NULL;
 
         return TRUE;
 }
 
 static void
+keyboard_plug_added (GtkWidget *widget,
+                     GSWindow  *window)
+{
+        gtk_widget_show (widget);
+}
+
+static gboolean
+keyboard_plug_removed (GtkWidget *widget,
+                       GSWindow  *window)
+{
+        gtk_widget_hide (widget);
+        gtk_container_remove (GTK_CONTAINER (window->priv->vbox), GTK_WIDGET (window->priv->keyboard_socket));
+
+        return TRUE;
+}
+
+static void
+keyboard_socket_destroyed (GtkWidget *widget,
+                           GSWindow  *window)
+{
+        g_signal_handlers_disconnect_by_func (widget, keyboard_socket_destroyed, window);
+        g_signal_handlers_disconnect_by_func (widget, keyboard_plug_added, window);
+        g_signal_handlers_disconnect_by_func (widget, keyboard_plug_removed, window);
+
+        window->priv->keyboard_socket = NULL;
+}
+
+static void
 forward_key_events (GSWindow *window)
 {
         window->priv->key_events = g_list_reverse (window->priv->key_events);
@@ -820,49 +859,46 @@ remove_key_events (GSWindow *window)
 }
 
 static void
-socket_show (GtkWidget *widget,
-             GSWindow  *window)
+lock_socket_show (GtkWidget *widget,
+                  GSWindow  *window)
 {
-        gtk_widget_child_focus (window->priv->socket, GTK_DIR_TAB_FORWARD);
+        gtk_widget_child_focus (window->priv->lock_socket, GTK_DIR_TAB_FORWARD);
 
         /* send queued events to the dialog */
         forward_key_events (window);
 }
 
 static void
-socket_destroyed (GtkWidget *widget,
-                  GSWindow  *window)
+lock_socket_destroyed (GtkWidget *widget,
+                       GSWindow  *window)
 {
-        g_signal_handlers_disconnect_by_func (window->priv->socket, socket_show, window);
-        g_signal_handlers_disconnect_by_func (window->priv->socket, socket_destroyed, window);
-        g_signal_handlers_disconnect_by_func (window->priv->socket, plug_added, window);
-        g_signal_handlers_disconnect_by_func (window->priv->socket, plug_removed, window);
+        g_signal_handlers_disconnect_by_func (widget, lock_socket_show, window);
+        g_signal_handlers_disconnect_by_func (widget, lock_socket_destroyed, window);
+        g_signal_handlers_disconnect_by_func (widget, lock_plug_added, window);
+        g_signal_handlers_disconnect_by_func (widget, lock_plug_removed, window);
 
-        window->priv->socket = NULL;
+        window->priv->lock_socket = NULL;
 }
 
 static void
-create_socket (GSWindow *window,
-               guint32   id)
+create_keyboard_socket (GSWindow *window,
+                        guint32   id)
 {
-        window->priv->socket = gtk_socket_new ();
-        window->priv->box = gtk_alignment_new (0.5, 0.5, 0, 0);
-        gtk_widget_show (window->priv->box);
-
-        gtk_container_add (GTK_CONTAINER (window), window->priv->box);
+        int height;
 
-        gtk_container_add (GTK_CONTAINER (window->priv->box), window->priv->socket);
+        height = (gdk_screen_get_height (gtk_widget_get_screen (GTK_WIDGET (window)))) / 4;
 
-        g_signal_connect (window->priv->socket, "show",
-                          G_CALLBACK (socket_show), window);
-        g_signal_connect (window->priv->socket, "destroy",
-                          G_CALLBACK (socket_destroyed), window);
-        g_signal_connect (window->priv->socket, "plug_added",
-                          G_CALLBACK (plug_added), window);
-        g_signal_connect (window->priv->socket, "plug_removed",
-                          G_CALLBACK (plug_removed), window);
+        window->priv->keyboard_socket = gtk_socket_new ();
+        gtk_widget_set_size_request (window->priv->keyboard_socket, -1, height);
 
-        gtk_socket_add_id (GTK_SOCKET (window->priv->socket), id);
+        g_signal_connect (window->priv->keyboard_socket, "destroy",
+                          G_CALLBACK (keyboard_socket_destroyed), window);
+        g_signal_connect (window->priv->keyboard_socket, "plug_added",
+                          G_CALLBACK (keyboard_plug_added), window);
+        g_signal_connect (window->priv->keyboard_socket, "plug_removed",
+                          G_CALLBACK (keyboard_plug_removed), window);
+        gtk_box_pack_start (GTK_BOX (window->priv->vbox), window->priv->keyboard_socket, FALSE, FALSE, 0);
+        gtk_socket_add_id (GTK_SOCKET (window->priv->keyboard_socket), id);
 }
 
 /* adapted from gspawn.c */
@@ -878,7 +914,7 @@ wait_on_child (int pid)
                 } else if (errno == ECHILD) {
                         ; /* do nothing, child already reaped */
                 } else {
-                        g_warning ("waitpid () should not fail in 'GSWindow'");
+                        gs_debug ("waitpid () should not fail in 'GSWindow'");
                 }
         }
 
@@ -886,19 +922,142 @@ wait_on_child (int pid)
 }
 
 static void
+keyboard_command_finish (GSWindow *window)
+{
+        g_return_if_fail (GS_IS_WINDOW (window));
+
+        gs_debug ("Keyboard finished");
+
+        if (window->priv->keyboard_pid > 0) {
+                int exit_status;
+
+                exit_status = wait_on_child (window->priv->keyboard_pid);
+
+                g_spawn_close_pid (window->priv->keyboard_pid);
+                window->priv->keyboard_pid = 0;
+        }
+}
+
+static gboolean
+keyboard_command_watch (GIOChannel   *source,
+                        GIOCondition  condition,
+                        GSWindow     *window)
+{
+        gboolean finished = FALSE;
+
+        g_return_val_if_fail (GS_IS_WINDOW (window), FALSE);
+
+        if (condition & G_IO_IN) {
+                GIOStatus status;
+                GError   *error = NULL;
+                char     *line;
+
+                status = g_io_channel_read_line (source, &line, NULL, NULL, &error);
+
+                switch (status) {
+                case G_IO_STATUS_NORMAL:
+                        {
+                                guint32 id;
+                                char    c;
+                                gs_debug ("keyboard command output: %s", line);
+                                if (1 == sscanf (line, " %" G_GUINT32_FORMAT " %c", &id, &c)) {
+                                        create_keyboard_socket (window, id);
+                                }
+                                g_free (line);
+                        }
+                        break;
+                case G_IO_STATUS_EOF:
+                        finished = TRUE;
+                        break;
+                case G_IO_STATUS_ERROR:
+                        finished = TRUE;
+                        fprintf (stderr, "Error reading fd from child: %s\n", error->message);
+                        return FALSE;
+                case G_IO_STATUS_AGAIN:
+                default:
+                        break;
+                }
+
+        } else if (condition & G_IO_HUP) {
+                finished = TRUE;
+        }
+
+        if (finished) {
+                window->priv->keyboard_watch_id = 0;
+                keyboard_command_finish (window);
+                return FALSE;
+        }
+
+        return TRUE;
+}
+
+static void
+embed_keyboard (GSWindow *window)
+{
+        gboolean res;
+
+        if (! window->priv->keyboard_enabled
+            || window->priv->keyboard_command == NULL)
+                return;
+
+        gs_debug ("Adding embedded keyboard widget");
+
+        /* FIXME: verify command is safe */
+
+        gs_debug ("Running command: %s", window->priv->keyboard_command);
+
+        res = spawn_on_window (window,
+                               window->priv->keyboard_command,
+                               &window->priv->keyboard_pid,
+                               (GIOFunc)keyboard_command_watch,
+                               window,
+                               &window->priv->keyboard_watch_id);
+        if (! res) {
+                gs_debug ("Could not start command: %s", window->priv->keyboard_command);
+        }
+}
+
+static void
+create_lock_socket (GSWindow *window,
+                    guint32   id)
+{
+        window->priv->lock_socket = gtk_socket_new ();
+        window->priv->lock_box = gtk_alignment_new (0.5, 0.5, 0, 0);
+        gtk_widget_show (window->priv->lock_box);
+        gtk_box_pack_start (GTK_BOX (window->priv->vbox), window->priv->lock_box, TRUE, TRUE, 0);
+
+        gtk_container_add (GTK_CONTAINER (window->priv->lock_box), window->priv->lock_socket);
+
+        g_signal_connect (window->priv->lock_socket, "show",
+                          G_CALLBACK (lock_socket_show), window);
+        g_signal_connect (window->priv->lock_socket, "destroy",
+                          G_CALLBACK (lock_socket_destroyed), window);
+        g_signal_connect (window->priv->lock_socket, "plug_added",
+                          G_CALLBACK (lock_plug_added), window);
+        g_signal_connect (window->priv->lock_socket, "plug_removed",
+                          G_CALLBACK (lock_plug_removed), window);
+
+        gtk_socket_add_id (GTK_SOCKET (window->priv->lock_socket), id);
+
+        if (window->priv->keyboard_enabled) {
+                embed_keyboard (window);
+        }
+}
+
+static void
 gs_window_dialog_finish (GSWindow *window)
 {
         g_return_if_fail (GS_IS_WINDOW (window));
 
         gs_debug ("Dialog finished");
 
-        if (window->priv->pid > 0) {
+        if (window->priv->lock_pid > 0) {
                 int exit_status;
 
-                exit_status = wait_on_child (window->priv->pid);
+                exit_status = wait_on_child (window->priv->lock_pid);
 
-                g_spawn_close_pid (window->priv->pid);
-                window->priv->pid = 0;
+                g_spawn_close_pid (window->priv->lock_pid);
+                window->priv->lock_pid = 0;
         }
 
         /* remove events for the case were we failed to show socket */
@@ -922,11 +1081,11 @@ shake_dialog (GSWindow *window)
                         right = 30;
                 }
 
-                if (! window->priv->box) {
+                if (! window->priv->lock_box) {
                         break;
                 }
 
-                gtk_alignment_set_padding (GTK_ALIGNMENT (window->priv->box),
+                gtk_alignment_set_padding (GTK_ALIGNMENT (window->priv->lock_box),
                                            0, 0,
                                            left,
                                            right);
@@ -940,9 +1099,9 @@ shake_dialog (GSWindow *window)
 }
 
 static gboolean
-command_watch (GIOChannel   *source,
-               GIOCondition  condition,
-               GSWindow     *window)
+lock_command_watch (GIOChannel   *source,
+                    GIOCondition  condition,
+                    GSWindow     *window)
 {
         gboolean finished = FALSE;
 
@@ -963,7 +1122,7 @@ command_watch (GIOChannel   *source,
                                 guint32 id;
                                 char    c;
                                 if (1 == sscanf (line, " WINDOW ID= %" G_GUINT32_FORMAT " %c", &id, &c)) {
-                                        create_socket (window, id);
+                                        create_lock_socket (window, id);
                                 }
                         } else if (strstr (line, "NOTICE=")) {
                                 if (strstr (line, "NOTICE=AUTH FAILED")) {
@@ -1011,7 +1170,7 @@ command_watch (GIOChannel   *source,
                 window->priv->last_x = -1;
                 window->priv->last_y = -1;
 
-                window->priv->watch_id = 0;
+                window->priv->lock_watch_id = 0;
 
                 return FALSE;
         }
@@ -1078,12 +1237,12 @@ popup_dialog_idle (GSWindow *window)
 
         result = spawn_on_window (window,
                                   command->str,
-                                  &window->priv->pid,
-                                  (GIOFunc)command_watch,
+                                  &window->priv->lock_pid,
+                                  (GIOFunc)lock_command_watch,
                                   window,
-                                  &window->priv->watch_id);
+                                  &window->priv->lock_watch_id);
         if (! result) {
-                g_warning ("Could not start command: %s", command->str);
+                gs_debug ("Could not start command: %s", command->str);
         }
 
         g_string_free (command, TRUE);
@@ -1105,7 +1264,7 @@ gs_window_request_unlock (GSWindow *wind
                 return;
         }
 
-        if (window->priv->watch_id > 0) {
+        if (window->priv->lock_watch_id > 0) {
                 return;
         }
 
@@ -1156,6 +1315,30 @@ gs_window_get_screen (GSWindow  *window)
 }
 
 void
+gs_window_set_keyboard_enabled (GSWindow *window,
+                                gboolean  enabled)
+{
+        g_return_if_fail (GS_IS_WINDOW (window));
+
+        window->priv->keyboard_enabled = enabled;
+}
+
+void
+gs_window_set_keyboard_command (GSWindow   *window,
+                                const char *command)
+{
+        g_return_if_fail (GS_IS_WINDOW (window));
+
+        g_free (window->priv->keyboard_command);
+
+        if (command != NULL) {
+                window->priv->keyboard_command = g_strdup (command);
+        } else {
+                window->priv->keyboard_command = NULL;
+        }
+}
+
+void
 gs_window_set_logout_enabled (GSWindow *window,
                               gboolean  logout_enabled)
 {
@@ -1240,6 +1423,12 @@ gs_window_set_property (GObject         
         case PROP_LOCK_ENABLED:
                 gs_window_set_lock_enabled (self, g_value_get_boolean (value));
                 break;
+        case PROP_KEYBOARD_ENABLED:
+                gs_window_set_keyboard_enabled (self, g_value_get_boolean (value));
+                break;
+        case PROP_KEYBOARD_COMMAND:
+                gs_window_set_keyboard_command (self, g_value_get_string (value));
+                break;
         case PROP_LOGOUT_ENABLED:
                 gs_window_set_logout_enabled (self, g_value_get_boolean (value));
                 break;
@@ -1272,6 +1461,12 @@ gs_window_get_property (GObject    *obje
         case PROP_LOCK_ENABLED:
                 g_value_set_boolean (value, self->priv->lock_enabled);
                 break;
+        case PROP_KEYBOARD_ENABLED:
+                g_value_set_boolean (value, self->priv->keyboard_enabled);
+                break;
+        case PROP_KEYBOARD_COMMAND:
+                g_value_set_string (value, self->priv->keyboard_command);
+                break;
         case PROP_LOGOUT_ENABLED:
                 g_value_set_boolean (value, self->priv->logout_enabled);
                 break;
@@ -1318,7 +1513,7 @@ maybe_handle_activity (GSWindow *window)
         handled = FALSE;
 
         /* if we already have a socket then don't bother */
-        if (! window->priv->socket
+        if (! window->priv->lock_socket
             && GTK_WIDGET_IS_SENSITIVE (GTK_WIDGET (window))) {
                 g_signal_emit (window, signals [ACTIVITY], 0, &handled);
         }
@@ -1605,12 +1800,26 @@ gs_window_class_init (GSWindowClass *kla
                                                             0,
                                                             G_PARAM_READWRITE));
         g_object_class_install_property (object_class,
-                                         PROP_LOGOUT_TIMEOUT,
+                                         PROP_LOGOUT_COMMAND,
                                          g_param_spec_string ("logout-command",
                                                               NULL,
                                                               NULL,
                                                               NULL,
                                                               G_PARAM_READWRITE));
+        g_object_class_install_property (object_class,
+                                         PROP_KEYBOARD_ENABLED,
+                                         g_param_spec_boolean ("keyboard-enabled",
+                                                               NULL,
+                                                               NULL,
+                                                               FALSE,
+                                                               G_PARAM_READWRITE));
+        g_object_class_install_property (object_class,
+                                         PROP_KEYBOARD_COMMAND,
+                                         g_param_spec_string ("keyboard-command",
+                                                              NULL,
+                                                              NULL,
+                                                              NULL,
+                                                              G_PARAM_READWRITE));
 
         g_object_class_install_property (object_class,
                                          PROP_MONITOR,
@@ -1658,14 +1867,22 @@ gs_window_init (GSWindow *window)
                                | GDK_ENTER_NOTIFY_MASK
                                | GDK_LEAVE_NOTIFY_MASK);
         force_no_pixmap_background (GTK_WIDGET (window));
+
+        window->priv->vbox = gtk_vbox_new (FALSE, 12);
+        gtk_widget_show (window->priv->vbox);
+        gtk_container_add (GTK_CONTAINER (window), window->priv->vbox);
 }
 
 static void
-remove_command_watch (GSWindow *window)
+remove_command_watches (GSWindow *window)
 {
-        if (window->priv->watch_id != 0) {
-                g_source_remove (window->priv->watch_id);
-                window->priv->watch_id = 0;
+        if (window->priv->lock_watch_id != 0) {
+                g_source_remove (window->priv->lock_watch_id);
+                window->priv->lock_watch_id = 0;
+        }
+        if (window->priv->keyboard_watch_id != 0) {
+                g_source_remove (window->priv->keyboard_watch_id);
+                window->priv->keyboard_watch_id = 0;
         }
 }
 
@@ -1682,6 +1899,7 @@ gs_window_finalize (GObject *object)
         g_return_if_fail (window->priv != NULL);
 
         g_free (window->priv->logout_command);
+        g_free (window->priv->keyboard_command);
 
         remove_watchdog_timer (window);
         remove_popup_dialog_idle (window);
@@ -1692,12 +1910,17 @@ gs_window_finalize (GObject *object)
 
         remove_key_events (window);
 
-        remove_command_watch (window);
+        remove_command_watches (window);
+
+        if (window->priv->keyboard_pid > 0) {
+                signal_pid (window->priv->keyboard_pid, SIGTERM);
+        }
+        keyboard_command_finish (window);
 
         /* If a dialog is up we need to signal it
            and wait on it */
-        if (window->priv->pid > 0) {
-                signal_pid (window->priv->pid, SIGTERM);
+        if (window->priv->lock_pid > 0) {
+                signal_pid (window->priv->lock_pid, SIGTERM);
         }
         gs_window_dialog_finish (window);
 
Index: src/gs-window.h
===================================================================
RCS file: /cvs/gnome/gnome-screensaver/src/gs-window.h,v
retrieving revision 1.11
diff -p -u -r1.11 gs-window.h
--- src/gs-window.h	12 Jul 2006 23:02:14 -0000	1.11
+++ src/gs-window.h	26 Jul 2006 22:23:02 -0000
@@ -69,6 +69,10 @@ void        gs_window_set_lock_enabled  
                                           gboolean   lock_enabled);
 void        gs_window_set_logout_enabled (GSWindow  *window,
                                           gboolean   logout_enabled);
+void        gs_window_set_keyboard_enabled (GSWindow  *window,
+                                            gboolean   enabled);
+void        gs_window_set_keyboard_command (GSWindow   *window,
+                                            const char *command);
 void        gs_window_set_user_switch_enabled (GSWindow  *window,
                                                gboolean   user_switch_enabled);
 void        gs_window_set_logout_timeout (GSWindow  *window,
