summaryrefslogtreecommitdiff
path: root/trunk/gui/greeter
diff options
context:
space:
mode:
authorBrian Cameron <bcameron@src.gnome.org>2007-05-14 02:05:04 +0000
committerBrian Cameron <bcameron@src.gnome.org>2007-05-14 02:05:04 +0000
commit9cc46d1815650cf479f2b513d905e1aefa46a82c (patch)
tree5d02f5d3b659f6f242f744763a571bc06642f109 /trunk/gui/greeter
parent27ec7d8d3e9fdb00663dc26d57075e24fcadaa08 (diff)
downloadgdm-9cc46d1815650cf479f2b513d905e1aefa46a82c.tar.gz
Tagged for release 2.19.1
svn path=/tags/GDM2_2_19_1/; revision=4918
Diffstat (limited to 'trunk/gui/greeter')
-rw-r--r--trunk/gui/greeter/.cvsignore6
-rw-r--r--trunk/gui/greeter/Makefile.am96
-rwxr-xr-xtrunk/gui/greeter/gdmthemetester.in109
-rw-r--r--trunk/gui/greeter/greeter.c1681
-rw-r--r--trunk/gui/greeter/greeter.dtd79
-rw-r--r--trunk/gui/greeter/greeter.h32
-rw-r--r--trunk/gui/greeter/greeter_canvas_item.c773
-rw-r--r--trunk/gui/greeter/greeter_canvas_item.h33
-rw-r--r--trunk/gui/greeter/greeter_canvas_text.c213
-rw-r--r--trunk/gui/greeter/greeter_canvas_text.h33
-rw-r--r--trunk/gui/greeter/greeter_configuration.h72
-rw-r--r--trunk/gui/greeter/greeter_dialogs.c25
-rw-r--r--trunk/gui/greeter/greeter_dialogs.h26
-rw-r--r--trunk/gui/greeter/greeter_events.c256
-rw-r--r--trunk/gui/greeter/greeter_events.h35
-rw-r--r--trunk/gui/greeter/greeter_geometry.c623
-rw-r--r--trunk/gui/greeter/greeter_geometry.h27
-rw-r--r--trunk/gui/greeter/greeter_item.c249
-rw-r--r--trunk/gui/greeter/greeter_item.h231
-rw-r--r--trunk/gui/greeter/greeter_item_capslock.c133
-rw-r--r--trunk/gui/greeter/greeter_item_capslock.h27
-rw-r--r--trunk/gui/greeter/greeter_item_clock.c68
-rw-r--r--trunk/gui/greeter/greeter_item_clock.h27
-rw-r--r--trunk/gui/greeter/greeter_item_customlist.c667
-rw-r--r--trunk/gui/greeter/greeter_item_customlist.h28
-rw-r--r--trunk/gui/greeter/greeter_item_pam.c456
-rw-r--r--trunk/gui/greeter/greeter_item_pam.h36
-rw-r--r--trunk/gui/greeter/greeter_item_timed.c156
-rw-r--r--trunk/gui/greeter/greeter_item_timed.h29
-rw-r--r--trunk/gui/greeter/greeter_item_ulist.c479
-rw-r--r--trunk/gui/greeter/greeter_item_ulist.h32
-rw-r--r--trunk/gui/greeter/greeter_parser.c1997
-rw-r--r--trunk/gui/greeter/greeter_parser.h48
-rw-r--r--trunk/gui/greeter/greeter_session.c271
-rw-r--r--trunk/gui/greeter/greeter_session.h26
-rw-r--r--trunk/gui/greeter/greeter_system.c594
-rw-r--r--trunk/gui/greeter/greeter_system.h29
-rw-r--r--trunk/gui/greeter/themes/.cvsignore3
-rw-r--r--trunk/gui/greeter/themes/Makefile.am1
-rw-r--r--trunk/gui/greeter/themes/circles/.cvsignore3
-rw-r--r--trunk/gui/greeter/themes/circles/GdmGreeterTheme.desktop.in11
-rw-r--r--trunk/gui/greeter/themes/circles/Makefile.am19
-rw-r--r--trunk/gui/greeter/themes/circles/background.svg39
-rw-r--r--trunk/gui/greeter/themes/circles/circles.xml116
-rw-r--r--trunk/gui/greeter/themes/circles/flower.pngbin0 -> 120376 bytes
-rw-r--r--trunk/gui/greeter/themes/circles/help.pngbin0 -> 2138 bytes
-rw-r--r--trunk/gui/greeter/themes/circles/options.pngbin0 -> 2297 bytes
-rw-r--r--trunk/gui/greeter/themes/circles/screenshot.pngbin0 -> 16847 bytes
-rw-r--r--trunk/gui/greeter/themes/happygnome-list/.cvsignore3
-rw-r--r--trunk/gui/greeter/themes/happygnome-list/GdmGreeterTheme.desktop.in11
-rw-r--r--trunk/gui/greeter/themes/happygnome-list/Makefile.am18
-rw-r--r--trunk/gui/greeter/themes/happygnome-list/background.svg39
-rw-r--r--trunk/gui/greeter/themes/happygnome-list/gnome-logo.svg33
-rw-r--r--trunk/gui/greeter/themes/happygnome-list/happygnome.xml128
-rw-r--r--trunk/gui/greeter/themes/happygnome-list/options.pngbin0 -> 1619 bytes
-rw-r--r--trunk/gui/greeter/themes/happygnome-list/screenshot.pngbin0 -> 12711 bytes
-rw-r--r--trunk/gui/greeter/themes/happygnome/.cvsignore3
-rw-r--r--trunk/gui/greeter/themes/happygnome/GdmGreeterTheme.desktop.in11
-rw-r--r--trunk/gui/greeter/themes/happygnome/Makefile.am18
-rw-r--r--trunk/gui/greeter/themes/happygnome/background.svg39
-rw-r--r--trunk/gui/greeter/themes/happygnome/gnome-logo.svg33
-rw-r--r--trunk/gui/greeter/themes/happygnome/happygnome.xml128
-rw-r--r--trunk/gui/greeter/themes/happygnome/options.pngbin0 -> 1619 bytes
-rw-r--r--trunk/gui/greeter/themes/happygnome/screenshot.pngbin0 -> 7217 bytes
64 files changed, 10358 insertions, 0 deletions
diff --git a/trunk/gui/greeter/.cvsignore b/trunk/gui/greeter/.cvsignore
new file mode 100644
index 00000000..7db66fb3
--- /dev/null
+++ b/trunk/gui/greeter/.cvsignore
@@ -0,0 +1,6 @@
+Makefile
+Makefile.in
+gdmgreeter
+.deps
+.libs
+gdmthemetester
diff --git a/trunk/gui/greeter/Makefile.am b/trunk/gui/greeter/Makefile.am
new file mode 100644
index 00000000..efcbc5f6
--- /dev/null
+++ b/trunk/gui/greeter/Makefile.am
@@ -0,0 +1,96 @@
+SUBDIRS = . themes
+
+## Process this file with automake to produce makefile.in
+INCLUDES = \
+ -I. \
+ -I$(top_srcdir)/gui \
+ -I$(top_srcdir)/daemon \
+ -I$(top_srcdir)/common \
+ -DAUTHDIR=\""$(authdir)"\" \
+ -DDATADIR=\""$(datadir)"\" \
+ -DDMCONFDIR=\""$(dmconfdir)"\" \
+ -DGDM_CONFIG_FILE=\"$(gdmconfdir)/gdm.conf\" \
+ -DGDMLOCALEDIR=\""$(gdmlocaledir)"\" \
+ -DGNOMELOCALEDIR=\""$(datadir)/locale"\" \
+ -DLIBEXECDIR=\""$(libexecdir)"\" \
+ -DSBINDIR=\""$(sbindir)"\" \
+ -DPIXMAPDIR=\""$(pixmapdir)"\" \
+ $(GUI_CFLAGS) \
+ $(PANGO_CFLAGS) \
+ $(PANGOFT_CFLAGS) \
+ $(GREETER_CFLAGS)
+
+#
+# -DG_DISABLE_DEPRECATED \
+# -DGDK_DISABLE_DEPRECATED \
+# -DGDK_PIXBUF_DISABLE_DEPRECATED \
+# -DGTK_DISABLE_DEPRECATED \
+# -DGNOME_DISABLE_DEPRECATED \
+#
+
+libexec_PROGRAMS = \
+ gdmgreeter
+
+bin_SCRIPTS = \
+ gdmthemetester
+
+CLEANFILES = gdmthemetester
+
+gdmthemetester: $(srcdir)/gdmthemetester.in
+ sed -e 's,[@]libexecdir[@],$(libexecdir),g' \
+ <$(srcdir)/gdmthemetester.in >gdmthemetester
+
+gdmgreeter_SOURCES = \
+ greeter.c \
+ greeter.h \
+ greeter_canvas_text.c \
+ greeter_canvas_text.h \
+ greeter_canvas_item.c \
+ greeter_canvas_item.h \
+ greeter_configuration.h \
+ greeter_events.c \
+ greeter_events.h \
+ greeter_geometry.c \
+ greeter_geometry.h \
+ greeter_item.c \
+ greeter_item_timed.c \
+ greeter_item_timed.h \
+ greeter_item_capslock.c \
+ greeter_item_capslock.h \
+ greeter_item_clock.c \
+ greeter_item_clock.h \
+ greeter_item.h \
+ greeter_item_pam.c \
+ greeter_item_pam.h \
+ greeter_item_ulist.c \
+ greeter_item_ulist.h \
+ greeter_item_customlist.c \
+ greeter_item_customlist.h \
+ greeter_parser.c \
+ greeter_parser.h \
+ greeter_session.c \
+ greeter_session.h \
+ greeter_system.c \
+ greeter_system.h
+
+gdmgreeter_LDADD = \
+ $(EXTRA_GREETER_LIBS) \
+ -L$(top_builddir)/gui \
+ -lgdmwm \
+ -lgdmcommon \
+ $(top_builddir)/common/libgdmcommon.a \
+ $(GLIB_LIBS) \
+ $(GOBJECT_LIBS) \
+ $(PANGO_LIBS) \
+ $(PANGOFT_LIBS) \
+ $(GDK_LIBS) \
+ $(GDKPIXBUF_LIBS) \
+ $(GREETER_LIBS) \
+ $(X_EXTRA_LIBS) \
+ $(XINERAMA_LIBS) \
+ $(X_LIBS) \
+ -lX11
+
+EXTRA_DIST = \
+ gdmthemetester.in \
+ greeter.dtd
diff --git a/trunk/gui/greeter/gdmthemetester.in b/trunk/gui/greeter/gdmthemetester.in
new file mode 100755
index 00000000..139e1e01
--- /dev/null
+++ b/trunk/gui/greeter/gdmthemetester.in
@@ -0,0 +1,109 @@
+#!/bin/sh
+
+gdmwhich () {
+ COMMAND="$1"
+ OUTPUT=
+ IFS=:
+ for dir in $PATH
+ do
+ if test -x "$dir/$COMMAND" ; then
+ if test "x$OUTPUT" = "x" ; then
+ OUTPUT="$dir/$COMMAND"
+ fi
+ fi
+ done
+ IFS=$OLD_IFS
+ echo "$OUTPUT"
+}
+
+echo
+echo "GDM Theme Tester"
+echo
+echo "Be sure to test all the environments:"
+echo " console, console-timed, flexi, remote-flexi, xdmcp"
+echo "Also be sure to test using caps lock"
+echo
+
+XNEST=`gdmwhich Xnest`
+GDMXNEST=`gdmwhich gdmXnest`
+GDMGREETER="@libexecdir@/gdmgreeter"
+
+if [ x$XNEST = x ]; then
+ echo "ERROR: Xnest not found"
+ echo ""
+ exit 1
+fi
+
+if [ x$GDMXNEST = x ]; then
+ echo "ERROR: gdmXnest not found"
+ echo ""
+ exit 1
+fi
+
+if [ x$GDMGREETER = x ]; then
+ echo "ERROR: gdmgreeter not found"
+ echo ""
+ exit 1
+fi
+
+USAGE="
+Usage: $0 <environment> <theme>
+<environment> is one of: console, console-timed, flexi, remote-flexi, xdmcp
+<theme> is either the path of the theme or the name of an installed theme
+
+If you set the environment variable XNESTSIZE to <width>x<height> (e.g. 800x600)
+you can test the greeter at that resolution
+"
+if [ "$#" != 2 ]; then
+ echo "$USAGE"
+ exit 1
+fi
+
+GDM_THEME="$2"
+DOING_GDM_DEVELOPMENT=yes
+GDM_PARENT_DISPLAY="$DISPLAY"
+export GDM_THEME DOING_GDM_DEVELOPMENT GDM_PARENT_DISPLAY
+
+case $1 in
+console)
+ GDM_IS_LOCAL=yes
+ export GDM_IS_LOCAL
+ ;;
+console-timed)
+ GDM_IS_LOCAL=yes
+ GDM_FAKE_TIMED=yes
+ export GDM_IS_LOCAL GDM_FAKE_TIMED
+ ;;
+flexi)
+ GDM_IS_LOCAL=yes
+ GDM_FLEXI_SERVER=yes
+ export GDM_IS_LOCAL GDM_FLEXI_SERVER
+ ;;
+remote-flexi)
+ GDM_FLEXI_SERVER=yes
+ export GDM_FLEXI_SERVER
+ ;;
+xdmcp)
+ ;;
+*)
+ echo "$USAGE"
+ exit 1
+ ;;
+esac
+
+if [ "x$XNESTSIZE" = x ] ; then
+ eval `gdmXnest -b`
+else
+ eval `gdmXnest -b -o "-geometry $XNESTSIZE"`
+fi
+export DISPLAY
+
+if [ "x$GDM_PARENT_DISPLAY" = "x$DISPLAY" ]; then
+ echo "ERROR: Can't start the Xnest server"
+ exit 1
+fi
+
+# This may not be necessary
+sleep 1
+
+@libexecdir@/gdmgreeter
diff --git a/trunk/gui/greeter/greeter.c b/trunk/gui/greeter/greeter.c
new file mode 100644
index 00000000..47c26722
--- /dev/null
+++ b/trunk/gui/greeter/greeter.c
@@ -0,0 +1,1681 @@
+/* GDM - The GNOME Display Manager
+ * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
+ *
+ * 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
+ */
+
+#include "config.h"
+
+#include <libintl.h>
+#include <locale.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+
+#if HAVE_PAM
+#include <security/pam_appl.h>
+#define PW_ENTRY_SIZE PAM_MAX_RESP_SIZE
+#else
+#define PW_ENTRY_SIZE GDM_MAX_PASS
+#endif
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#include <libgnomecanvas/libgnomecanvas.h>
+
+#include "gdm-common.h"
+#include "gdm-socket-protocol.h"
+#include "gdm-daemon-config-keys.h"
+
+#include "gdm.h"
+#include "gdmwm.h"
+#include "gdmcomm.h"
+#include "gdmcommon.h"
+#include "gdmconfig.h"
+#include "gdmsession.h"
+#include "gdmlanguages.h"
+
+#include "greeter.h"
+#include "greeter_configuration.h"
+#include "greeter_parser.h"
+#include "greeter_geometry.h"
+#include "greeter_item_clock.h"
+#include "greeter_item_pam.h"
+#include "greeter_item_ulist.h"
+#include "greeter_item_customlist.h"
+#include "greeter_item_capslock.h"
+#include "greeter_item_timed.h"
+#include "greeter_events.h"
+#include "greeter_session.h"
+#include "greeter_system.h"
+
+gboolean DOING_GDM_DEVELOPMENT = FALSE;
+
+GtkWidget *window;
+GtkWidget *canvas;
+
+gboolean GDM_IS_LOCAL = FALSE;
+static gboolean ignore_buttons = FALSE;
+gboolean GdmHaltFound = FALSE;
+gboolean GdmRebootFound = FALSE;
+gboolean *GdmCustomCmdsFound = NULL;
+gboolean GdmAnyCustomCmdsFound = FALSE;
+gboolean GdmSuspendFound = FALSE;
+gboolean GdmConfiguratorFound = FALSE;
+
+/* FIXME: hack */
+GreeterItemInfo *welcome_string_info = NULL;
+GreeterItemInfo *root = NULL;
+
+extern gboolean session_dir_whacked_out;
+extern gboolean require_quarter;
+extern gint gdm_timed_delay;
+extern GtkButton *gtk_ok_button;
+extern GtkButton *gtk_start_again_button;
+
+gboolean greeter_probably_login_prompt = FALSE;
+static gboolean first_prompt = TRUE;
+
+static void process_operation (guchar opcode, const gchar *args);
+
+void
+greeter_ignore_buttons (gboolean val)
+{
+ ignore_buttons = val;
+}
+
+static char *get_theme_file (const char *in, char **theme_dir);
+
+/* If in random theme mode then grab a random theme from those selected.
+ * If a theme doesn't exist, try the rest of the list from the randomly chosen
+ * position for one that does.
+ */
+static char *
+get_random_theme ()
+{
+ char **vec;
+ char *themes_list;
+ char *theme = NULL;
+ char *dir;
+ int size;
+ int chosen;
+ int i;
+
+ themes_list = gdm_config_get_string (GDM_KEY_GRAPHICAL_THEMES);
+
+ if (ve_string_empty (themes_list))
+ return NULL;
+
+ vec = g_strsplit (themes_list, GDM_DELIMITER_THEMES, -1);
+ if (vec == NULL)
+ return NULL;
+
+ /* Get Number of elements in vector */
+ for (size = 0; vec[size] != NULL; size++) {}
+
+ /* Get Random Theme from list */
+ srand ( time(NULL) );
+ chosen = rand() % size;
+
+ /* Find a theme that exists */
+ for (i = 0; i < size; i++) {
+ int j;
+ char *file;
+
+ j = (i + chosen >= size) ? i+chosen-size : i+chosen;
+ file = get_theme_file( vec[j], &dir );
+
+ g_free(file);
+ if (g_file_test(dir, G_FILE_TEST_IS_DIR)) {
+ g_free(dir);
+ theme = g_strdup (vec[j]);
+ break;
+ }
+ g_free(dir);
+ }
+
+ g_strfreev (vec);
+
+ return theme;
+}
+
+static gboolean
+greeter_ctrl_handler (GIOChannel *source,
+ GIOCondition cond,
+ gint fd)
+{
+ gchar buf[PIPE_SIZE];
+ gchar *p;
+ gsize len;
+
+ /* If this is not incoming i/o then return */
+ if (cond != G_IO_IN)
+ return TRUE;
+
+ /* Read random garbage from i/o channel until first STX is found */
+ do {
+ g_io_channel_read_chars (source, buf, 1, &len, NULL);
+
+ if (len != 1)
+ return TRUE;
+ } while (buf[0] && buf[0] != STX);
+
+ memset (buf, '\0', sizeof (buf));
+ if (g_io_channel_read_chars (source, buf, sizeof (buf) - 1, &len, NULL) !=
+ G_IO_STATUS_NORMAL)
+ return TRUE;
+
+ p = memchr (buf, STX, len);
+ if (p != NULL) {
+ len = p - buf;
+ g_io_channel_seek_position (source, -((sizeof (buf) - 1) - len), G_SEEK_CUR, NULL);
+ memset (buf + len, '\0', (sizeof (buf) - 1) - len);
+ }
+ buf[len - 1] = '\0';
+
+ process_operation ((guchar) buf[0], buf + 1);
+ return TRUE;
+}
+
+static GtkWidget *
+hig_dialog_new (GtkWindow *parent,
+ GtkDialogFlags flags,
+ GtkMessageType type,
+ GtkButtonsType buttons,
+ const gchar *primary_message,
+ const gchar *secondary_message)
+{
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (parent),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ type,
+ buttons,
+ "%s", primary_message);
+
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ "%s", secondary_message);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), "");
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+ gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 14);
+
+ return dialog;
+}
+
+static void
+process_operation (guchar op_code,
+ const gchar *args)
+{
+ GtkWidget *dlg;
+ char *tmp;
+ char *session;
+ GreeterItemInfo *conversation_info;
+ static GnomeCanvasItem *disabled_cover = NULL;
+ gint lookup_status = SESSION_LOOKUP_SUCCESS;
+ gchar *firstmsg = NULL;
+ gchar *secondmsg = NULL;
+ gint save_session = GTK_RESPONSE_NO;
+
+ /* Parse opcode */
+ switch (op_code) {
+ case GDM_SETLOGIN:
+ /* somebody is trying to fool us this is the user that
+ * wants to log in, and well, we are the gullible kind */
+
+ greeter_item_pam_set_user (args);
+ printf ("%c\n", STX);
+ fflush (stdout);
+ break;
+
+ case GDM_PROMPT:
+ tmp = ve_locale_to_utf8 (args);
+ if (tmp != NULL && strcmp (tmp, _("Username:")) == 0) {
+ gdm_common_login_sound (gdm_config_get_string (GDM_KEY_SOUND_PROGRAM),
+ gdm_config_get_string (GDM_KEY_SOUND_ON_LOGIN_FILE),
+ gdm_config_get_bool (GDM_KEY_SOUND_ON_LOGIN));
+ greeter_probably_login_prompt = TRUE;
+ }
+ if (gtk_ok_button != NULL)
+ gtk_widget_set_sensitive (GTK_WIDGET (gtk_ok_button), FALSE);
+
+ if (gtk_start_again_button != NULL)
+ gtk_widget_set_sensitive (GTK_WIDGET (gtk_start_again_button), !first_prompt);
+
+ first_prompt = FALSE;
+
+ greeter_ignore_buttons (FALSE);
+
+ greeter_item_pam_prompt (tmp, PW_ENTRY_SIZE, TRUE);
+ g_free (tmp);
+ break;
+
+ case GDM_NOECHO:
+ tmp = ve_locale_to_utf8 (args);
+
+ greeter_probably_login_prompt = FALSE;
+
+ if (gtk_ok_button != NULL)
+ gtk_widget_set_sensitive (GTK_WIDGET (gtk_ok_button), FALSE);
+
+ if (gtk_start_again_button != NULL)
+ gtk_widget_set_sensitive (GTK_WIDGET (gtk_start_again_button), !first_prompt);
+
+ first_prompt = FALSE;
+
+ greeter_ignore_buttons (FALSE);
+ greeter_item_pam_prompt (tmp, PW_ENTRY_SIZE, FALSE);
+ g_free (tmp);
+
+ break;
+
+ case GDM_MSG:
+ tmp = ve_locale_to_utf8 (args);
+ greeter_item_pam_message (tmp);
+ g_free (tmp);
+ printf ("%c\n", STX);
+ fflush (stdout);
+ break;
+
+ case GDM_ERRBOX:
+ tmp = ve_locale_to_utf8 (args);
+ greeter_item_pam_error (tmp);
+ g_free (tmp);
+
+ printf ("%c\n", STX);
+ fflush (stdout);
+ break;
+
+ case GDM_ERRDLG:
+ /* we should be now fine for focusing new windows */
+ gdm_wm_focus_new_windows (TRUE);
+
+ tmp = ve_locale_to_utf8 (args);
+ dlg = hig_dialog_new (NULL /* parent */,
+ GTK_DIALOG_MODAL /* flags */,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ tmp,
+ "");
+ g_free (tmp);
+
+ gdm_wm_center_window (GTK_WINDOW (dlg));
+
+ gdm_wm_no_login_focus_push ();
+ gtk_dialog_run (GTK_DIALOG (dlg));
+ gtk_widget_destroy (dlg);
+ gdm_wm_no_login_focus_pop ();
+
+ printf ("%c\n", STX);
+ fflush (stdout);
+ break;
+
+ case GDM_SESS:
+ tmp = ve_locale_to_utf8 (args);
+ session = gdm_session_lookup (tmp, &lookup_status);
+ if (lookup_status != SESSION_LOOKUP_SUCCESS) {
+ switch (lookup_status) {
+ case SESSION_LOOKUP_PREFERRED_MISSING:
+ firstmsg = g_strdup_printf (_("Do you wish to make %s the default for "
+ "future sessions?"),
+ gdm_session_name (tmp));
+ secondmsg = g_strdup_printf (_("Your preferred session type %s is not "
+ "installed on this computer."),
+ gdm_session_name (gdm_get_default_session ()));
+ save_session = gdm_wm_query_dialog (firstmsg, secondmsg,
+ _("Make _Default"), _("Just _Log In"), TRUE);
+
+ g_free (firstmsg);
+ g_free (secondmsg);
+ gdm_set_save_session (save_session);
+ break;
+
+ case SESSION_LOOKUP_DEFAULT_MISMATCH:
+ firstmsg = g_strdup_printf (_("Do you wish to make %s the default for "
+ "future sessions?"),
+ gdm_session_name (session));
+ secondmsg = g_strdup_printf (_("You have chosen %s for this "
+ "session, but your default "
+ "setting is %s."),
+ gdm_session_name (session),
+ gdm_session_name (tmp));
+ save_session = gdm_wm_query_dialog (firstmsg, secondmsg,
+ _("Make _Default"), _("Just For _This Session"), TRUE);
+
+ g_free (firstmsg);
+ g_free (secondmsg);
+ gdm_set_save_session (save_session);
+ break;
+ case SESSION_LOOKUP_USE_SWITCHDESK:
+ firstmsg = g_strdup_printf (_("You have chosen %s for this "
+ "session"),
+ gdm_session_name (session));
+ secondmsg = g_strdup_printf (_("If you wish to make %s "
+ "the default for future sessions, "
+ "run the 'switchdesk' utility "
+ "(System->Desktop Switching Tool from "
+ "the panel menu)."),
+ gdm_session_name (session));
+ gdm_wm_message_dialog (firstmsg, secondmsg);
+ g_free (firstmsg);
+ g_free (secondmsg);
+ break;
+
+ default:
+ break;
+ }
+ }
+ g_free (tmp);
+ if (gdm_get_save_session () == GTK_RESPONSE_CANCEL) {
+ printf ("%c%s\n", STX, GDM_RESPONSE_CANCEL);
+ } else {
+ tmp = ve_locale_from_utf8 (session);
+ printf ("%c%s\n", STX, tmp);
+ g_free (tmp);
+ }
+ fflush (stdout);
+ g_free (session);
+ break;
+
+ case GDM_LANG:
+ gdm_lang_op_lang (args);
+ break;
+
+ case GDM_SSESS:
+ if (gdm_get_save_session () == GTK_RESPONSE_YES)
+ printf ("%cY\n", STX);
+ else
+ printf ("%c\n", STX);
+ fflush (stdout);
+
+ break;
+
+ case GDM_SLANG:
+ gdm_lang_op_slang (args);
+ break;
+
+ case GDM_SETLANG:
+ gdm_lang_op_setlang (args);
+ break;
+
+ case GDM_ALWAYS_RESTART:
+ gdm_lang_op_always_restart (args);
+ break;
+
+ case GDM_RESET:
+ /* fall thru to reset */
+
+ case GDM_RESETOK:
+
+ if (gtk_ok_button != NULL)
+ gtk_widget_set_sensitive (GTK_WIDGET (gtk_ok_button), FALSE);
+ if (gtk_start_again_button != NULL)
+ gtk_widget_set_sensitive (GTK_WIDGET (gtk_start_again_button), FALSE);
+
+ first_prompt = TRUE;
+
+ conversation_info = greeter_lookup_id ("pam-conversation");
+
+ if (conversation_info)
+ {
+ tmp = ve_locale_to_utf8 (args);
+ g_object_set (G_OBJECT (conversation_info->item),
+ "text", tmp,
+ NULL);
+ g_free (tmp);
+ }
+
+ printf ("%c\n", STX);
+ fflush (stdout);
+ greeter_ignore_buttons (FALSE);
+ greeter_item_ulist_enable ();
+
+ break;
+
+ case GDM_QUIT:
+ greeter_item_timed_stop ();
+
+ if (require_quarter) {
+ /* we should be now fine for focusing new windows */
+ gdm_wm_focus_new_windows (TRUE);
+
+ dlg = hig_dialog_new (NULL /* parent */,
+ GTK_DIALOG_MODAL /* flags */,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_OK,
+ /* translators: This is a nice and evil eggie text, translate
+ * to your favourite currency */
+ _("Please insert 25 cents "
+ "to log in."),
+ "");
+ gdm_wm_center_window (GTK_WINDOW (dlg));
+
+ gdm_wm_no_login_focus_push ();
+ gtk_dialog_run (GTK_DIALOG (dlg));
+ gtk_widget_destroy (dlg);
+ gdm_wm_no_login_focus_pop ();
+ }
+
+ greeter_item_pam_leftover_messages ();
+
+ gdk_flush ();
+
+ if (greeter_show_only_background (root)) {
+ GdkPixbuf *background;
+ int width, height;
+
+ gtk_window_get_size (GTK_WINDOW (window), &width, &height);
+ background = gdk_pixbuf_get_from_drawable (NULL, gtk_widget_get_root_window(window), NULL, 0, 0, 0, 0 ,width, height);
+ if (background) {
+ gdm_common_set_root_background (background);
+ g_object_unref (background);
+ }
+ }
+
+ printf ("%c\n", STX);
+ fflush (stdout);
+
+ /* screw gtk_main_quit, we want to make sure we definately die */
+ _exit (EXIT_SUCCESS);
+ break;
+
+ case GDM_STARTTIMER:
+ greeter_item_timed_start ();
+
+ printf ("%c\n", STX);
+ fflush (stdout);
+ break;
+
+ case GDM_STOPTIMER:
+ greeter_item_timed_stop ();
+
+ printf ("%c\n", STX);
+ fflush (stdout);
+ break;
+
+ case GDM_DISABLE:
+ gtk_widget_set_sensitive (window, FALSE);
+
+ if (disabled_cover == NULL)
+ {
+ disabled_cover = gnome_canvas_item_new
+ (gnome_canvas_root (GNOME_CANVAS (canvas)),
+ GNOME_TYPE_CANVAS_RECT,
+ "x1", 0.0,
+ "y1", 0.0,
+ "x2", (double)canvas->allocation.width,
+ "y2", (double)canvas->allocation.height,
+ "fill_color_rgba", (guint)0x00000088,
+ NULL);
+ }
+
+ printf ("%c\n", STX);
+ fflush (stdout);
+ break;
+
+ case GDM_ENABLE:
+ gtk_widget_set_sensitive (window, TRUE);
+
+ if (disabled_cover != NULL)
+ {
+ gtk_object_destroy (GTK_OBJECT (disabled_cover));
+ disabled_cover = NULL;
+ }
+
+ printf ("%c\n", STX);
+ fflush (stdout);
+ break;
+
+ /* These are handled separately so ignore them here and send
+ * back a NULL response so that the daemon quits sending them */
+ case GDM_NEEDPIC:
+ case GDM_READPIC:
+ printf ("%c\n", STX);
+ fflush (stdout);
+ break;
+
+ case GDM_NOFOCUS:
+ gdm_wm_no_login_focus_push ();
+
+ printf ("%c\n", STX);
+ fflush (stdout);
+ break;
+
+ case GDM_FOCUS:
+ gdm_wm_no_login_focus_pop ();
+
+ printf ("%c\n", STX);
+ fflush (stdout);
+ break;
+
+ case GDM_SAVEDIE:
+ /* Set busy cursor */
+ gdm_common_setup_cursor (GDK_WATCH);
+
+ gdm_wm_save_wm_order ();
+
+ gdk_flush ();
+
+ _exit (EXIT_SUCCESS);
+
+ case GDM_QUERY_CAPSLOCK:
+ if (greeter_is_capslock_on ())
+ printf ("%cY\n", STX);
+ else
+ printf ("%c\n", STX);
+ fflush (stdout);
+
+ break;
+
+ default:
+ gdm_common_fail_greeter ("Unexpected greeter command received: '%c'", op_code);
+ break;
+ }
+}
+
+static gboolean
+key_press_event (GtkWidget *widget, GdkEventKey *key, gpointer data)
+{
+ if (DOING_GDM_DEVELOPMENT && (key->keyval == GDK_Escape))
+ {
+ process_operation (GDM_QUIT, NULL);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/*
+ * The buttons with these handlers never appear in the F10 menu,
+ * so they can make use of callback data.
+ */
+static void
+greeter_ok_handler (GreeterItemInfo *info,
+ gpointer user_data)
+{
+ if (ignore_buttons == FALSE)
+ {
+ GreeterItemInfo *entry_info = greeter_lookup_id ("user-pw-entry");
+ if (entry_info && entry_info->item &&
+ GNOME_IS_CANVAS_WIDGET (entry_info->item) &&
+ GTK_IS_ENTRY (GNOME_CANVAS_WIDGET (entry_info->item)->widget))
+ {
+ GtkWidget *entry;
+ entry = GNOME_CANVAS_WIDGET (entry_info->item)->widget;
+ greeter_ignore_buttons (TRUE);
+ greeter_item_pam_login (GTK_ENTRY (entry), entry_info);
+ }
+ }
+}
+
+static void
+greeter_cancel_handler (GreeterItemInfo *info,
+ gpointer user_data)
+{
+ if (ignore_buttons == FALSE)
+ {
+ greeter_item_ulist_unset_selected_user ();
+ greeter_item_ulist_disable ();
+ greeter_ignore_buttons (TRUE);
+ printf ("%c%c%c\n", STX, BEL, GDM_INTERRUPT_CANCEL);
+ fflush (stdout);
+ }
+}
+
+static void
+greeter_language_handler (GreeterItemInfo *info,
+ gpointer user_data)
+{
+ gdm_lang_handler (user_data);
+}
+
+static void
+greeter_setup_items (void)
+{
+ greeter_item_clock_setup ();
+ greeter_item_pam_setup ();
+
+ /* This will query the daemon for pictures through stdin/stdout! */
+ greeter_item_ulist_setup ();
+
+ greeter_item_capslock_setup (window);
+ greeter_item_timed_setup ();
+ greeter_item_register_action_callback ("ok_button",
+ greeter_ok_handler,
+ (gpointer) window);
+ greeter_item_register_action_callback ("cancel_button",
+ greeter_cancel_handler,
+ (gpointer) window);
+ greeter_item_register_action_callback ("language_button",
+ greeter_language_handler,
+ NULL);
+ greeter_item_register_action_callback ("disconnect_button",
+ (ActionFunc)gtk_main_quit,
+ NULL);
+ greeter_item_system_setup ();
+ greeter_item_session_setup ();
+
+ /* Setup the custom widgets */
+ greeter_item_customlist_setup ();
+}
+
+enum {
+ RESPONSE_RESTART,
+ RESPONSE_REBOOT,
+ RESPONSE_CLOSE
+};
+
+static int
+verify_gdm_version (void)
+{
+ const char *gdm_version;
+ const char *gdm_protocol_version;
+
+ gdm_version = g_getenv ("GDM_VERSION");
+ gdm_protocol_version = g_getenv ("GDM_GREETER_PROTOCOL_VERSION");
+
+ if (! DOING_GDM_DEVELOPMENT &&
+ ((gdm_protocol_version != NULL &&
+ strcmp (gdm_protocol_version, GDM_GREETER_PROTOCOL_VERSION) != 0) ||
+ (gdm_protocol_version == NULL &&
+ (gdm_version == NULL ||
+ strcmp (gdm_version, VERSION) != 0))) &&
+ (g_getenv ("GDM_IS_LOCAL") != NULL))
+ {
+ GtkWidget *dialog;
+ gchar *msg;
+
+ gdm_wm_init (0);
+ gdm_wm_focus_new_windows (TRUE);
+
+ msg = g_strdup_printf (_("The greeter version (%s) does not match the daemon "
+ "version. "
+ "You have probably just upgraded GDM. "
+ "Please restart the GDM daemon or the computer."),
+ VERSION);
+
+ dialog = hig_dialog_new (NULL /* parent */,
+ GTK_DIALOG_MODAL /* flags */,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("Cannot start the greeter"),
+ msg);
+ g_free (msg);
+
+ gtk_widget_show_all (dialog);
+ gdm_wm_center_window (GTK_WINDOW (dialog));
+
+ gdm_common_setup_cursor (GDK_LEFT_PTR);
+
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+
+ return EXIT_SUCCESS;
+ }
+
+ if (! DOING_GDM_DEVELOPMENT &&
+ gdm_protocol_version == NULL &&
+ gdm_version == NULL)
+ {
+ GtkWidget *dialog;
+ gchar *msg;
+
+ gdm_wm_init (0);
+ gdm_wm_focus_new_windows (TRUE);
+
+ msg = g_strdup_printf (_("The greeter version (%s) does not match the daemon "
+ "version. "
+ "You have probably just upgraded GDM. "
+ "Please restart the GDM daemon or the computer."),
+ VERSION);
+
+ dialog = hig_dialog_new (NULL /* parent */,
+ GTK_DIALOG_MODAL /* flags */,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_NONE,
+ _("Cannot start the greeter"),
+ msg);
+ g_free (msg);
+
+ gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+ _("Restart Machine"),
+ RESPONSE_REBOOT,
+ GTK_STOCK_CLOSE,
+ RESPONSE_CLOSE,
+ NULL);
+
+ gtk_widget_show_all (dialog);
+ gdm_wm_center_window (GTK_WINDOW (dialog));
+
+ gdm_common_setup_cursor (GDK_LEFT_PTR);
+
+ switch (gtk_dialog_run (GTK_DIALOG (dialog)))
+ {
+ case RESPONSE_REBOOT:
+ gtk_widget_destroy (dialog);
+ return DISPLAY_REBOOT;
+ default:
+ gtk_widget_destroy (dialog);
+ return DISPLAY_ABORT;
+ }
+ }
+
+ if (! DOING_GDM_DEVELOPMENT &&
+ ((gdm_protocol_version != NULL &&
+ strcmp (gdm_protocol_version, GDM_GREETER_PROTOCOL_VERSION) != 0) ||
+ (gdm_protocol_version == NULL &&
+ strcmp (gdm_version, VERSION) != 0)))
+ {
+ GtkWidget *dialog;
+ gchar *msg;
+
+ gdm_wm_init (0);
+ gdm_wm_focus_new_windows (TRUE);
+
+ msg = g_strdup_printf (_("The greeter version (%s) does not match the daemon "
+ "version (%s). "
+ "You have probably just upgraded GDM. "
+ "Please restart the GDM daemon or the computer."),
+ VERSION, gdm_version);
+
+ dialog = hig_dialog_new (NULL /* parent */,
+ GTK_DIALOG_MODAL /* flags */,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_NONE,
+ _("Cannot start the greeter"),
+ msg);
+ g_free (msg);
+
+ gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+ _("Restart GDM"),
+ RESPONSE_RESTART,
+ _("Restart Machine"),
+ RESPONSE_REBOOT,
+ GTK_STOCK_CLOSE,
+ RESPONSE_CLOSE,
+ NULL);
+
+
+ gtk_widget_show_all (dialog);
+ gdm_wm_center_window (GTK_WINDOW (dialog));
+
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), RESPONSE_RESTART);
+
+ gdm_common_setup_cursor (GDK_LEFT_PTR);
+
+ switch (gtk_dialog_run (GTK_DIALOG (dialog)))
+ {
+ case RESPONSE_RESTART:
+ gtk_widget_destroy (dialog);
+ return DISPLAY_RESTARTGDM;
+ case RESPONSE_REBOOT:
+ gtk_widget_destroy (dialog);
+ return DISPLAY_REBOOT;
+ default:
+ gtk_widget_destroy (dialog);
+ return DISPLAY_ABORT;
+ }
+ }
+
+ return 0;
+}
+
+static void
+gdm_set_welcomemsg (void)
+{
+ char *welcomemsg = gdm_common_get_welcomemsg ();
+
+ if (welcome_string_info->data.text.orig_text != NULL)
+ g_free (welcome_string_info->data.text.orig_text);
+
+ welcome_string_info->data.text.orig_text = welcomemsg;
+ greeter_item_update_text (welcome_string_info);
+}
+
+/*
+ * If new configuration keys are added to this program, make sure to add the
+ * key to the gdm_read_config and gdm_reread_config functions. Note if the
+ * number of configuration values used by gdmlogin is greater than
+ * GDM_SUP_MAX_MESSAGES defined in daemon/gdm.h (currently defined to be 80),
+ * consider bumping that number so that all the config can be read in one
+ * socket connection.
+ */
+static void
+gdm_read_config (void)
+{
+ gint i;
+
+ /* Read config data in bulk */
+ gdmcomm_comm_bulk_start ();
+
+ /*
+ * Read all the keys at once and close sockets connection so we do
+ * not have to keep the socket open.
+ */
+ gdm_config_get_string (GDM_KEY_GRAPHICAL_THEME);
+ gdm_config_get_string (GDM_KEY_GRAPHICAL_THEMES);
+ gdm_config_get_string (GDM_KEY_GRAPHICAL_THEME_DIR);
+ gdm_config_get_string (GDM_KEY_GTKRC);
+ gdm_config_get_string (GDM_KEY_GTK_THEME);
+ gdm_config_get_string (GDM_KEY_INCLUDE);
+ gdm_config_get_string (GDM_KEY_EXCLUDE);
+ gdm_config_get_string (GDM_KEY_SESSION_DESKTOP_DIR);
+ gdm_config_get_string (GDM_KEY_LOCALE_FILE);
+ gdm_config_get_string (GDM_KEY_HALT);
+ gdm_config_get_string (GDM_KEY_REBOOT);
+ gdm_config_get_string (GDM_KEY_SUSPEND);
+ gdm_config_get_string (GDM_KEY_CONFIGURATOR);
+ gdm_config_get_string (GDM_KEY_INFO_MSG_FILE);
+ gdm_config_get_string (GDM_KEY_INFO_MSG_FONT);
+ gdm_config_get_string (GDM_KEY_TIMED_LOGIN);
+ gdm_config_get_string (GDM_KEY_GRAPHICAL_THEMED_COLOR);
+ gdm_config_get_string (GDM_KEY_BACKGROUND_COLOR);
+ gdm_config_get_string (GDM_KEY_DEFAULT_FACE);
+ gdm_config_get_string (GDM_KEY_DEFAULT_SESSION);
+ gdm_config_get_string (GDM_KEY_SOUND_PROGRAM);
+ gdm_config_get_string (GDM_KEY_SOUND_ON_LOGIN_FILE);
+ gdm_config_get_string (GDM_KEY_USE_24_CLOCK);
+ gdm_config_get_string (GDM_KEY_WELCOME);
+ gdm_config_get_string (GDM_KEY_REMOTE_WELCOME);
+ gdm_config_get_string (GDM_KEY_RBAC_SYSTEM_COMMAND_KEYS);
+ gdm_config_get_string (GDM_KEY_SYSTEM_COMMANDS_IN_MENU);
+
+ gdm_config_get_int (GDM_KEY_XINERAMA_SCREEN);
+ gdm_config_get_int (GDM_KEY_TIMED_LOGIN_DELAY);
+ gdm_config_get_int (GDM_KEY_FLEXI_REAP_DELAY_MINUTES);
+ gdm_config_get_int (GDM_KEY_MAX_ICON_HEIGHT);
+ gdm_config_get_int (GDM_KEY_MAX_ICON_WIDTH);
+ gdm_config_get_int (GDM_KEY_MINIMAL_UID);
+ gdm_config_get_bool (GDM_KEY_ENTRY_CIRCLES);
+ gdm_config_get_bool (GDM_KEY_ENTRY_INVISIBLE);
+ gdm_config_get_bool (GDM_KEY_SHOW_XTERM_FAILSAFE);
+ gdm_config_get_bool (GDM_KEY_SHOW_GNOME_FAILSAFE);
+ gdm_config_get_bool (GDM_KEY_INCLUDE_ALL);
+ gdm_config_get_bool (GDM_KEY_SYSTEM_MENU);
+ gdm_config_get_bool (GDM_KEY_CONFIG_AVAILABLE);
+ gdm_config_get_bool (GDM_KEY_CHOOSER_BUTTON);
+ gdm_config_get_bool (GDM_KEY_TIMED_LOGIN_ENABLE);
+ gdm_config_get_bool (GDM_KEY_GRAPHICAL_THEME_RAND);
+ gdm_config_get_bool (GDM_KEY_SHOW_LAST_SESSION);
+ gdm_config_get_bool (GDM_KEY_ALLOW_ROOT);
+ gdm_config_get_bool (GDM_KEY_ALLOW_REMOTE_ROOT);
+ gdm_config_get_bool (GDM_KEY_SOUND_ON_LOGIN);
+ gdm_config_get_bool (GDM_KEY_DEFAULT_WELCOME);
+ gdm_config_get_bool (GDM_KEY_DEFAULT_REMOTE_WELCOME);
+ gdm_config_get_bool (GDM_KEY_ADD_GTK_MODULES);
+ gdm_config_get_bool (GDM_KEY_BROWSER);
+
+ /* Keys for custom commands */
+ for (i = 0; i < GDM_CUSTOM_COMMAND_MAX; i++) {
+ gchar * key_string = NULL;
+ key_string = g_strdup_printf("%s%d=", GDM_KEY_CUSTOM_CMD_TEMPLATE, i);
+ gdm_config_get_string (key_string);
+
+ key_string = g_strdup_printf("%s%d=", GDM_KEY_CUSTOM_CMD_LABEL_TEMPLATE, i);
+ gdm_config_get_string (key_string);
+
+ key_string = g_strdup_printf("%s%d=", GDM_KEY_CUSTOM_CMD_LR_LABEL_TEMPLATE, i);
+ gdm_config_get_string (key_string);
+
+ key_string = g_strdup_printf("%s%d=", GDM_KEY_CUSTOM_CMD_TEXT_TEMPLATE, i);
+ gdm_config_get_string (key_string);
+
+ key_string = g_strdup_printf("%s%d=", GDM_KEY_CUSTOM_CMD_TOOLTIP_TEMPLATE, i);
+ gdm_config_get_string (key_string);
+
+ g_free (key_string);
+ }
+
+ /* Keys not to include in reread_config */
+ gdm_config_get_string (GDM_KEY_SESSION_DESKTOP_DIR);
+ gdm_config_get_string (GDM_KEY_PRE_FETCH_PROGRAM);
+
+ gdmcomm_comm_bulk_stop ();
+}
+
+static gboolean
+greeter_reread_config (int sig, gpointer data)
+{
+ gint i;
+ gboolean custom_changed = FALSE;
+
+ /* Read config data in bulk */
+ gdmcomm_comm_bulk_start ();
+
+ /* FIXME: The following is evil, we should update on the fly rather
+ * then just restarting */
+ /* Also we may not need to check ALL those keys but just a few */
+ if (gdm_config_reload_string (GDM_KEY_GRAPHICAL_THEME) ||
+ gdm_config_reload_string (GDM_KEY_GRAPHICAL_THEMES) ||
+ gdm_config_reload_string (GDM_KEY_GRAPHICAL_THEME_DIR) ||
+ gdm_config_reload_string (GDM_KEY_GTKRC) ||
+ gdm_config_reload_string (GDM_KEY_GTK_THEME) ||
+ gdm_config_reload_string (GDM_KEY_INCLUDE) ||
+ gdm_config_reload_string (GDM_KEY_EXCLUDE) ||
+ gdm_config_reload_string (GDM_KEY_SESSION_DESKTOP_DIR) ||
+ gdm_config_reload_string (GDM_KEY_LOCALE_FILE) ||
+ gdm_config_reload_string (GDM_KEY_HALT) ||
+ gdm_config_reload_string (GDM_KEY_REBOOT) ||
+ gdm_config_reload_string (GDM_KEY_SUSPEND) ||
+ gdm_config_reload_string (GDM_KEY_CONFIGURATOR) ||
+ gdm_config_reload_string (GDM_KEY_INFO_MSG_FILE) ||
+ gdm_config_reload_string (GDM_KEY_INFO_MSG_FONT) ||
+ gdm_config_reload_string (GDM_KEY_TIMED_LOGIN) ||
+ gdm_config_reload_string (GDM_KEY_GRAPHICAL_THEMED_COLOR) ||
+ gdm_config_reload_string (GDM_KEY_BACKGROUND_COLOR) ||
+ gdm_config_reload_string (GDM_KEY_DEFAULT_FACE) ||
+ gdm_config_reload_string (GDM_KEY_DEFAULT_SESSION) ||
+ gdm_config_reload_string (GDM_KEY_RBAC_SYSTEM_COMMAND_KEYS) ||
+ gdm_config_reload_string (GDM_KEY_SYSTEM_COMMANDS_IN_MENU) ||
+
+ gdm_config_reload_int (GDM_KEY_XINERAMA_SCREEN) ||
+ gdm_config_reload_int (GDM_KEY_TIMED_LOGIN_DELAY) ||
+ gdm_config_reload_int (GDM_KEY_FLEXI_REAP_DELAY_MINUTES) ||
+ gdm_config_reload_int (GDM_KEY_MAX_ICON_HEIGHT) ||
+ gdm_config_reload_int (GDM_KEY_MAX_ICON_WIDTH) ||
+ gdm_config_reload_int (GDM_KEY_MINIMAL_UID) ||
+
+ gdm_config_reload_bool (GDM_KEY_ENTRY_CIRCLES) ||
+ gdm_config_reload_bool (GDM_KEY_ENTRY_INVISIBLE) ||
+ gdm_config_reload_bool (GDM_KEY_SHOW_XTERM_FAILSAFE) ||
+ gdm_config_reload_bool (GDM_KEY_SHOW_GNOME_FAILSAFE) ||
+ gdm_config_reload_bool (GDM_KEY_INCLUDE_ALL) ||
+ gdm_config_reload_bool (GDM_KEY_SYSTEM_MENU) ||
+ gdm_config_reload_bool (GDM_KEY_CONFIG_AVAILABLE) ||
+ gdm_config_reload_bool (GDM_KEY_CHOOSER_BUTTON) ||
+ gdm_config_reload_bool (GDM_KEY_TIMED_LOGIN_ENABLE) ||
+ gdm_config_reload_bool (GDM_KEY_GRAPHICAL_THEME_RAND) ||
+ gdm_config_reload_bool (GDM_KEY_SHOW_LAST_SESSION) ||
+ gdm_config_reload_bool (GDM_KEY_ALLOW_ROOT) ||
+ gdm_config_reload_bool (GDM_KEY_ALLOW_REMOTE_ROOT) ||
+ gdm_config_reload_bool (GDM_KEY_ADD_GTK_MODULES) ||
+ gdm_config_reload_bool (GDM_KEY_BROWSER)) {
+
+ /* Set busy cursor */
+ gdm_common_setup_cursor (GDK_WATCH);
+
+ gdm_wm_save_wm_order ();
+ gdmcomm_comm_bulk_stop ();
+
+ _exit (DISPLAY_RESTARTGREETER);
+ }
+
+ for (i = 0; i < GDM_CUSTOM_COMMAND_MAX; i++) {
+ gchar *key_string = NULL;
+ key_string = g_strdup_printf("%s%d=", GDM_KEY_CUSTOM_CMD_TEMPLATE, i);
+ if (gdm_config_reload_string (key_string))
+ custom_changed = TRUE;
+
+ key_string = g_strdup_printf("%s%d=", GDM_KEY_CUSTOM_CMD_LABEL_TEMPLATE, i);
+ if (gdm_config_reload_string (key_string))
+ custom_changed = TRUE;
+
+ key_string = g_strdup_printf("%s%d=", GDM_KEY_CUSTOM_CMD_LR_LABEL_TEMPLATE, i);
+ if (gdm_config_reload_string (key_string))
+ custom_changed = TRUE;
+
+ key_string = g_strdup_printf("%s%d=", GDM_KEY_CUSTOM_CMD_TEXT_TEMPLATE, i);
+ if (gdm_config_reload_string (key_string))
+ custom_changed = TRUE;
+
+ key_string = g_strdup_printf("%s%d=", GDM_KEY_CUSTOM_CMD_TOOLTIP_TEMPLATE, i);
+ if (gdm_config_reload_string (key_string))
+ custom_changed = TRUE;
+
+ g_free (key_string);
+ }
+
+ if(custom_changed){
+ /* Set busy cursor */
+ gdm_common_setup_cursor (GDK_WATCH);
+
+ gdm_wm_save_wm_order ();
+ gdmcomm_comm_bulk_stop ();
+
+ _exit (DISPLAY_RESTARTGREETER);
+ }
+
+ gdm_config_reload_string (GDM_KEY_SOUND_PROGRAM);
+ gdm_config_reload_bool (GDM_KEY_SOUND_ON_LOGIN);
+ gdm_config_reload_string (GDM_KEY_SOUND_ON_LOGIN_FILE);
+ gdm_config_reload_string (GDM_KEY_USE_24_CLOCK);
+
+ if (gdm_config_reload_string (GDM_KEY_WELCOME) ||
+ gdm_config_reload_bool (GDM_KEY_DEFAULT_WELCOME) ||
+ gdm_config_reload_string (GDM_KEY_REMOTE_WELCOME) ||
+ gdm_config_reload_bool (GDM_KEY_DEFAULT_REMOTE_WELCOME)) {
+
+ gdm_set_welcomemsg ();
+
+ /* Set busy cursor */
+ gdm_common_setup_cursor (GDK_WATCH);
+
+ gdm_wm_save_wm_order ();
+ gdmcomm_comm_bulk_stop ();
+
+ _exit (DISPLAY_RESTARTGREETER);
+ }
+
+ gdmcomm_comm_bulk_stop ();
+
+ return TRUE;
+}
+
+static void
+greeter_done (int sig)
+{
+ _exit (EXIT_SUCCESS);
+}
+
+
+static char *
+get_theme_file (const char *in, char **theme_dir)
+{
+ char *file, *dir, *info, *s;
+
+ if (in == NULL)
+ in = "circles";
+
+ *theme_dir = NULL;
+
+ if (g_path_is_absolute (in))
+ {
+ dir = g_strdup (in);
+ }
+ else
+ {
+ dir = NULL;
+ if (DOING_GDM_DEVELOPMENT)
+ {
+ if (g_access (in, F_OK) == 0)
+ {
+ dir = g_strdup (in);
+ }
+ else
+ {
+ dir = g_build_filename ("themes", in, NULL);
+ if (g_access (dir, F_OK) != 0)
+ {
+ g_free (dir);
+ dir = NULL;
+ }
+ }
+ }
+ if (dir == NULL)
+ dir = g_build_filename (gdm_config_get_string (GDM_KEY_GRAPHICAL_THEME_DIR), in, NULL);
+ }
+
+ *theme_dir = dir;
+
+ info = g_build_filename (dir, "GdmGreeterTheme.desktop", NULL);
+ if (g_access (info, F_OK) != 0) {
+ g_free (info);
+ info = g_build_filename (dir, "GdmGreeterTheme.info", NULL);
+ }
+ if (g_access (info, F_OK) != 0)
+ {
+ char *base = g_path_get_basename (in);
+ /* just guess the name, we have no info about the theme at
+ * this point */
+ g_free (info);
+ file = g_strdup_printf ("%s/%s.xml", dir, base);
+ g_free (base);
+ return file;
+ }
+
+ s = gdm_get_theme_greeter (info, in);
+ file = g_build_filename (dir, s, NULL);
+
+ g_free (info);
+ g_free (s);
+
+ return file;
+}
+
+/* The reaping stuff */
+static time_t last_reap_delay = 0;
+
+static gboolean
+delay_reaping (GSignalInvocationHint *ihint,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer data)
+{
+ last_reap_delay = time (NULL);
+ return TRUE;
+}
+
+static gboolean
+reap_flexiserver (gpointer data)
+{
+ int reapminutes = gdm_config_get_int (GDM_KEY_FLEXI_REAP_DELAY_MINUTES);
+
+ if (reapminutes > 0 &&
+ ((time (NULL) - last_reap_delay) / 60) > reapminutes) {
+ _exit (DISPLAY_REMANAGE);
+ }
+ return TRUE;
+}
+
+static gboolean
+gdm_event (GSignalInvocationHint *ihint,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer data)
+{
+ GdkEvent *event;
+
+ /* HAAAAAAAAAAAAAAAAACK */
+ /* Since the user has not logged in yet and may have left/right
+ * mouse buttons switched, we just translate every right mouse click
+ * to a left mouse click */
+ if (n_param_values != 2 ||
+ !G_VALUE_HOLDS (&param_values[1], GDK_TYPE_EVENT))
+ return FALSE;
+
+ event = g_value_get_boxed (&param_values[1]);
+ if ((event->type == GDK_BUTTON_PRESS ||
+ event->type == GDK_2BUTTON_PRESS ||
+ event->type == GDK_3BUTTON_PRESS ||
+ event->type == GDK_BUTTON_RELEASE)
+ && event->button.button == 3)
+ event->button.button = 1;
+
+ /* Support Ctrl-U for blanking the username/password entry */
+ if (event->type == GDK_KEY_PRESS &&
+ (event->key.state & GDK_CONTROL_MASK) &&
+ (event->key.keyval == GDK_u ||
+ event->key.keyval == GDK_U)) {
+
+ GreeterItemInfo *entry_info = greeter_lookup_id ("user-pw-entry");
+ if (entry_info && entry_info->item &&
+ GNOME_IS_CANVAS_WIDGET (entry_info->item) &&
+ GTK_IS_ENTRY (GNOME_CANVAS_WIDGET (entry_info->item)->widget))
+ {
+ GtkWidget *entry;
+ entry = GNOME_CANVAS_WIDGET (entry_info->item)->widget;
+ gtk_entry_set_text (GTK_ENTRY (entry), "");
+ }
+ }
+
+ return TRUE;
+}
+
+int
+main (int argc, char *argv[])
+{
+ char *bg_color;
+ struct sigaction hup;
+ struct sigaction term;
+ sigset_t mask;
+ GIOChannel *ctrlch;
+ GError *error;
+ char *theme_file;
+ char *theme_dir;
+ gchar *gdm_graphical_theme;
+ const char *gdm_gtk_theme;
+ guint sid;
+ int r;
+ gint i;
+
+ if (g_getenv ("DOING_GDM_DEVELOPMENT") != NULL)
+ DOING_GDM_DEVELOPMENT = TRUE;
+
+ bindtextdomain (GETTEXT_PACKAGE, GNOMELOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+
+ setlocale (LC_ALL, "");
+
+ if (ve_string_empty (g_getenv ("GDM_IS_LOCAL")))
+ GDM_IS_LOCAL = FALSE;
+ else
+ GDM_IS_LOCAL = TRUE;
+
+ /*
+ * gdm_common_atspi_launch () needs gdk initialized.
+ * We cannot start gtk before the registry is running
+ * because the atk-bridge will crash.
+ */
+ gdk_init (&argc, &argv);
+ if (! DOING_GDM_DEVELOPMENT) {
+ gdm_common_atspi_launch ();
+ }
+
+ gtk_init (&argc, &argv);
+
+ gdm_common_setup_cursor (GDK_WATCH);
+
+ gdm_common_log_init ();
+ gdm_common_log_set_debug (gdm_config_get_bool (GDM_KEY_DEBUG));
+
+ /* Read all configuration at once, so the values get cached */
+ gdm_read_config ();
+
+ if ( ! ve_string_empty (gdm_config_get_string (GDM_KEY_GTKRC)))
+ gtk_rc_parse (gdm_config_get_string (GDM_KEY_GTKRC));
+
+ gdm_gtk_theme = g_getenv ("GDM_GTK_THEME");
+ if (ve_string_empty (gdm_gtk_theme))
+ gdm_gtk_theme = gdm_config_get_string (GDM_KEY_GTK_THEME);
+
+ if ( ! ve_string_empty (gdm_gtk_theme)) {
+ gdm_set_theme (gdm_gtk_theme);
+ }
+
+ gdm_wm_screen_init (gdm_config_get_int (GDM_KEY_XINERAMA_SCREEN));
+
+ r = verify_gdm_version ();
+ if (r != 0)
+ return r;
+
+ /* Load the background as early as possible so GDM does not leave */
+ /* the background unfilled. The cursor should be a watch already */
+ /* but just in case */
+ bg_color = gdm_config_get_string (GDM_KEY_GRAPHICAL_THEMED_COLOR);
+ /* If a graphical theme color does not exist fallback to the plain color */
+ if (ve_string_empty (bg_color)) {
+ bg_color = gdm_config_get_string (GDM_KEY_BACKGROUND_COLOR);
+ }
+ gdm_common_setup_background_color (bg_color);
+ greeter_session_init ();
+ gdm_lang_initialize_model (gdm_config_get_string (GDM_KEY_LOCALE_FILE));
+
+ ve_signal_add (SIGHUP, greeter_reread_config, NULL);
+
+ hup.sa_handler = ve_signal_notify;
+ hup.sa_flags = 0;
+ sigemptyset (&hup.sa_mask);
+ sigaddset (&hup.sa_mask, SIGCHLD);
+
+ if (sigaction (SIGHUP, &hup, NULL) < 0) {
+ gdm_common_fail_greeter ("%s: Error setting up %s signal handler: %s", "main",
+ "HUP", strerror (errno));
+ }
+
+ term.sa_handler = greeter_done;
+ term.sa_flags = 0;
+ sigemptyset (&term.sa_mask);
+ sigaddset (&term.sa_mask, SIGCHLD);
+
+ if G_UNLIKELY (sigaction (SIGINT, &term, NULL) < 0) {
+ gdm_common_fail_greeter ("%s: Error setting up %s signal handler: %s", "main",
+ "INT", strerror (errno));
+ }
+
+ if G_UNLIKELY (sigaction (SIGTERM, &term, NULL) < 0) {
+ gdm_common_fail_greeter ("%s: Error setting up %s signal handler: %s", "main",
+ "TERM", strerror (errno));
+ }
+
+ sigemptyset (&mask);
+ sigaddset (&mask, SIGTERM);
+ sigaddset (&mask, SIGHUP);
+ sigaddset (&mask, SIGINT);
+
+ if G_UNLIKELY (sigprocmask (SIG_UNBLOCK, &mask, NULL) == -1) {
+ gdm_common_fail_greeter ("Could not set signal mask!");
+ }
+
+ /* ignore SIGCHLD */
+ sigemptyset (&mask);
+ sigaddset (&mask, SIGCHLD);
+
+ if G_UNLIKELY (sigprocmask (SIG_BLOCK, &mask, NULL) == -1) {
+ gdm_common_fail_greeter ("Could not set signal mask!");
+ }
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+ if G_UNLIKELY (DOING_GDM_DEVELOPMENT) {
+ g_signal_connect (G_OBJECT (window), "key_press_event",
+ G_CALLBACK (key_press_event), NULL);
+ }
+
+ canvas = gnome_canvas_new_aa ();
+ GTK_WIDGET_UNSET_FLAGS (canvas, GTK_CAN_FOCUS);
+ gnome_canvas_set_scroll_region (GNOME_CANVAS (canvas),
+ 0.0, 0.0,
+ (double) gdm_wm_screen.width,
+ (double) gdm_wm_screen.height);
+ gtk_window_set_decorated (GTK_WINDOW (window), FALSE);
+ gtk_window_set_default_size (GTK_WINDOW (window),
+ gdm_wm_screen.width,
+ gdm_wm_screen.height);
+ gtk_container_add (GTK_CONTAINER (window), canvas);
+
+ /*
+ * Initialize the value with the default value so the first time it
+ * is displayed it doesn't show as 0. Also determine if the Halt,
+ * Reboot, Suspend and Configurator commands work.
+ */
+ gdm_timed_delay = gdm_config_get_int (GDM_KEY_TIMED_LOGIN_DELAY);
+ GdmHaltFound = gdm_working_command_exists (gdm_config_get_string (GDM_KEY_HALT));
+ GdmRebootFound = gdm_working_command_exists (gdm_config_get_string (GDM_KEY_REBOOT));
+ GdmSuspendFound = gdm_working_command_exists (gdm_config_get_string (GDM_KEY_SUSPEND));
+ GdmConfiguratorFound = gdm_working_command_exists (gdm_config_get_string (GDM_KEY_CONFIGURATOR));
+
+ GdmCustomCmdsFound = g_new0 (gboolean, GDM_CUSTOM_COMMAND_MAX);
+ for (i = 0; i < GDM_CUSTOM_COMMAND_MAX; i++) {
+ gchar * key_string = NULL;
+ /* For each possible custom command */
+ key_string = g_strdup_printf("%s%d=", GDM_KEY_CUSTOM_CMD_TEMPLATE, i);
+ GdmCustomCmdsFound[i] = gdm_working_command_exists (gdm_config_get_string (key_string));
+ if (GdmCustomCmdsFound[i])
+ GdmAnyCustomCmdsFound = TRUE;
+
+ g_free (key_string);
+ }
+
+ if (g_getenv ("GDM_THEME") != NULL)
+ gdm_graphical_theme = g_strdup (g_getenv ("GDM_THEME"));
+ else if (gdm_config_get_bool (GDM_KEY_GRAPHICAL_THEME_RAND))
+ gdm_graphical_theme = get_random_theme ();
+ else
+ gdm_graphical_theme = gdm_config_get_string (GDM_KEY_GRAPHICAL_THEME);
+
+ theme_file = get_theme_file (gdm_graphical_theme, &theme_dir);
+
+ error = NULL;
+ root = greeter_parse (theme_file, theme_dir,
+ GNOME_CANVAS (canvas),
+ gdm_wm_screen.width,
+ gdm_wm_screen.height,
+ &error);
+
+ if G_UNLIKELY (root == NULL)
+ {
+ GtkWidget *dialog;
+ char *s;
+ char *tmp;
+
+ gdm_wm_init (0);
+ gdm_wm_focus_new_windows (TRUE);
+
+ tmp = ve_filename_to_utf8 (ve_sure_string (gdm_graphical_theme));
+ s = g_strdup_printf (_("There was an error loading the "
+ "theme %s"), tmp);
+ g_free (tmp);
+ dialog = hig_dialog_new (NULL /* parent */,
+ GTK_DIALOG_MODAL /* flags */,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ s,
+ (error && error->message) ? error->message : "");
+ g_free (s);
+
+ gtk_widget_show_all (dialog);
+ gdm_wm_center_window (GTK_WINDOW (dialog));
+
+ gdm_common_setup_cursor (GDK_LEFT_PTR);
+
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+
+ if (DOING_GDM_DEVELOPMENT)
+ {
+ exit (1);
+ }
+ }
+
+ if G_UNLIKELY (error)
+ g_clear_error (&error);
+
+ /* Try circles.xml */
+ if G_UNLIKELY (root == NULL)
+ {
+ g_free (theme_file);
+ g_free (theme_dir);
+ theme_file = get_theme_file ("circles", &theme_dir);
+ root = greeter_parse (theme_file, theme_dir,
+ GNOME_CANVAS (canvas),
+ gdm_wm_screen.width,
+ gdm_wm_screen.height,
+ NULL);
+ }
+
+ g_free (theme_file);
+
+ if G_UNLIKELY (root != NULL && greeter_lookup_id ("user-pw-entry") == NULL)
+ {
+ GtkWidget *dialog;
+
+ gdm_wm_init (0);
+ gdm_wm_focus_new_windows (TRUE);
+
+ dialog = hig_dialog_new (NULL /* parent */,
+ GTK_DIALOG_MODAL /* flags */,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("The greeter theme is corrupt"),
+ _("The theme does not contain "
+ "definition for the username/password "
+ "entry element."));
+
+ gtk_widget_show_all (dialog);
+ gdm_wm_center_window (GTK_WINDOW (dialog));
+
+ gdm_common_setup_cursor (GDK_LEFT_PTR);
+
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+
+ root = NULL;
+ }
+
+ /* FIXME: beter information should be printed */
+ if G_UNLIKELY (DOING_GDM_DEVELOPMENT && root == NULL)
+ {
+ g_warning ("No theme could be loaded");
+ exit (1);
+ }
+
+ if G_UNLIKELY (root == NULL)
+ {
+ GtkWidget *dialog;
+
+ gdm_wm_init (0);
+ gdm_wm_focus_new_windows (TRUE);
+
+ dialog = hig_dialog_new (NULL /* parent */,
+ GTK_DIALOG_MODAL /* flags */,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("There was an error loading the "
+ "theme, and the default theme "
+ "could not be loaded. "
+ "Attempting to start the "
+ "standard greeter"),
+ "");
+
+ gtk_widget_show_all (dialog);
+ gdm_wm_center_window (GTK_WINDOW (dialog));
+
+ gdm_common_setup_cursor (GDK_LEFT_PTR);
+
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+
+ execl (LIBEXECDIR "/gdmlogin", LIBEXECDIR "/gdmlogin", NULL);
+ execlp ("gdmlogin", "gdmlogin", NULL);
+
+ dialog = hig_dialog_new (NULL /* parent */,
+ GTK_DIALOG_MODAL /* flags */,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("The GTK+ greeter could not be started. "
+ "This display will abort and you may "
+ "have to login another way and fix the "
+ "installation of GDM"),
+ "");
+
+ gtk_widget_show_all (dialog);
+ gdm_wm_center_window (GTK_WINDOW (dialog));
+
+ gdm_common_setup_cursor (GDK_LEFT_PTR);
+
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+
+ _exit (DISPLAY_ABORT);
+ }
+
+ greeter_layout (root, GNOME_CANVAS (canvas));
+
+ greeter_setup_items ();
+
+ if G_LIKELY (! DOING_GDM_DEVELOPMENT) {
+ ctrlch = g_io_channel_unix_new (STDIN_FILENO);
+ g_io_channel_set_encoding (ctrlch, NULL, NULL);
+ g_io_channel_set_buffered (ctrlch, TRUE);
+ g_io_channel_set_flags (ctrlch,
+ g_io_channel_get_flags (ctrlch) | G_IO_FLAG_NONBLOCK,
+ NULL);
+ g_io_add_watch (ctrlch,
+ G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+ (GIOFunc) greeter_ctrl_handler,
+ NULL);
+ g_io_channel_unref (ctrlch);
+ }
+
+ gdm_common_setup_blinking ();
+
+ gtk_widget_show_all (window);
+ gtk_window_move (GTK_WINDOW (window), gdm_wm_screen.x, gdm_wm_screen.y);
+ gtk_widget_show_now (window);
+
+ greeter_item_ulist_unset_selected_user ();
+ greeter_item_ulist_enable ();
+ greeter_item_ulist_check_show_userlist ();
+
+ /* can it ever happen that it'd be NULL here ??? */
+ if G_UNLIKELY (window->window != NULL)
+ {
+ gdm_wm_init (GDK_WINDOW_XWINDOW (window->window));
+
+ /* Run the focus, note that this will work no matter what
+ * since gdm_wm_init will set the display to the gdk one
+ * if it fails */
+ gdm_wm_focus_window (GDK_WINDOW_XWINDOW (window->window));
+ }
+
+ if G_UNLIKELY (session_dir_whacked_out)
+ {
+ GtkWidget *dialog;
+
+ gdm_wm_focus_new_windows (TRUE);
+
+ dialog = hig_dialog_new (NULL /* parent */,
+ GTK_DIALOG_MODAL /* flags */,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("Session directory is missing"),
+ _("Your session directory is missing or empty! "
+ "There are two available sessions you can use, but "
+ "you should log in and correct the gdm configuration."));
+ gtk_widget_show_all (dialog);
+ gdm_wm_center_window (GTK_WINDOW (dialog));
+
+ gdm_common_setup_cursor (GDK_LEFT_PTR);
+
+ gdm_wm_no_login_focus_push ();
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ gdm_wm_no_login_focus_pop ();
+ }
+
+ if G_UNLIKELY (g_getenv ("GDM_WHACKED_GREETER_CONFIG") != NULL)
+ {
+ GtkWidget *dialog;
+
+ gdm_wm_focus_new_windows (TRUE);
+
+ dialog = hig_dialog_new (NULL /* parent */,
+ GTK_DIALOG_MODAL /* flags */,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_OK,
+ _("Configuration is not correct"),
+ _("The configuration file contains an invalid command "
+ "line for the login dialog, so running the "
+ "default command. Please fix your configuration."));
+
+ gtk_widget_show_all (dialog);
+ gdm_wm_center_window (GTK_WINDOW (dialog));
+
+ gdm_common_setup_cursor (GDK_LEFT_PTR);
+
+ gdm_wm_no_login_focus_push ();
+ gtk_dialog_run (GTK_DIALOG (dialog));
+ gtk_widget_destroy (dialog);
+ gdm_wm_no_login_focus_pop ();
+ }
+
+ /* if a flexiserver, reap self after some time */
+ if (gdm_config_get_int (GDM_KEY_FLEXI_REAP_DELAY_MINUTES) > 0 &&
+ ! ve_string_empty (g_getenv ("GDM_FLEXI_SERVER")) &&
+ /* but don't reap Xnest flexis */
+ ve_string_empty (g_getenv ("GDM_PARENT_DISPLAY")))
+ {
+ sid = g_signal_lookup ("activate",
+ GTK_TYPE_MENU_ITEM);
+ g_signal_add_emission_hook (sid,
+ 0 /* detail */,
+ delay_reaping,
+ NULL /* data */,
+ NULL /* destroy_notify */);
+
+ sid = g_signal_lookup ("key_press_event",
+ GTK_TYPE_WIDGET);
+ g_signal_add_emission_hook (sid,
+ 0 /* detail */,
+ delay_reaping,
+ NULL /* data */,
+ NULL /* destroy_notify */);
+
+ sid = g_signal_lookup ("button_press_event",
+ GTK_TYPE_WIDGET);
+ g_signal_add_emission_hook (sid,
+ 0 /* detail */,
+ delay_reaping,
+ NULL /* data */,
+ NULL /* destroy_notify */);
+
+ last_reap_delay = time (NULL);
+ g_timeout_add (60*1000, reap_flexiserver, NULL);
+ }
+
+ sid = g_signal_lookup ("event",
+ GTK_TYPE_WIDGET);
+ g_signal_add_emission_hook (sid,
+ 0 /* detail */,
+ gdm_event,
+ NULL /* data */,
+ NULL /* destroy_notify */);
+
+ gdm_wm_restore_wm_order ();
+
+ gdm_wm_show_info_msg_dialog (gdm_config_get_string (GDM_KEY_INFO_MSG_FILE),
+ gdm_config_get_string (GDM_KEY_INFO_MSG_FONT));
+
+ gdm_common_setup_cursor (GDK_LEFT_PTR);
+ gdm_wm_center_cursor ();
+ gdm_common_pre_fetch_launch ();
+ gtk_main ();
+
+ return 0;
+}
diff --git a/trunk/gui/greeter/greeter.dtd b/trunk/gui/greeter/greeter.dtd
new file mode 100644
index 00000000..74fa7b9d
--- /dev/null
+++ b/trunk/gui/greeter/greeter.dtd
@@ -0,0 +1,79 @@
+<!-- dtd for greeter -->
+<!ENTITY % colorattrs "file CDATA #IMPLIED
+ color CDATA #IMPLIED
+ font CDATA #IMPLIED
+ tint CDATA #IMPLIED">
+<!ELEMENT greeter (item+)>
+<!ELEMENT item (pos | normal? | active? | prelight? | children? | show? | text? | fixed? | box? | listitem? | border?)*>
+<!ELEMENT children (item+)>
+<!ELEMENT pos EMPTY>
+<!ELEMENT show EMPTY>
+<!ELEMENT text (#PCDATA)>
+<!ELEMENT normal EMPTY>
+<!ELEMENT active EMPTY>
+<!ELEMENT prelight EMPTY>
+<!ELEMENT stock EMPTY>
+<!ELEMENT fixed (item+)>
+<!ELEMENT box (item+)>
+<!ELEMENT listitem (text+)>
+<!-- additional elements-->
+<!ELEMENT border EMPTY>
+
+<!-- internal id's are one of (user-pw-entry | caps-lock-warning | clock | pam-error | pam-message | pam-prompt | pam-warning | timed-label | language_button | disconnect_button | reboot_button | halt_button | session_button | suspend_button | system_button | config_button | chooser_button | userlist)
+ but there can be other id's -->
+<!ATTLIST item
+ type (rect | entry | pixmap | label | svg | rect | list) #REQUIRED
+ id CDATA #IMPLIED
+ button (true | false) #IMPLIED
+ background (true | false) #IMPLIED
+>
+<!ATTLIST pos
+ x CDATA #IMPLIED
+ y CDATA #IMPLIED
+ anchor CDATA "c"
+ width CDATA #IMPLIED
+ height CDATA #IMPLIED
+>
+<!ATTLIST normal
+ %colorattrs;
+ alpha CDATA #IMPLIED
+>
+<!ATTLIST active
+ %colorattrs;
+ alpha CDATA #IMPLIED
+>
+<!ATTLIST prelight
+ %colorattrs;
+ file CDATA #IMPLIED
+>
+<!ATTLIST stock
+ type (language | session | system | disconnect | quit | caps-lock-warning | timed-label | welcome-label | username-label | config | chooser) #REQUIRED
+>
+<!ATTLIST box
+ orientation (horizontal | vertical) "horizontal"
+ spacing CDATA #IMPLIED
+ xpadding CDATA #IMPLIED
+ ypadding CDATA #IMPLIED
+ min-width CDATA #IMPLIED
+ min-height CDATA #IMPLIED
+>
+<!-- console,console-fixed,console-flexi,remote-flexi,flexi,remote-->
+<!ATTLIST show
+ modes CDATA #IMPLIED
+ type (config | chooser | system | halt | reboot | suspend | timed) #IMPLIED
+>
+<!ATTLIST text
+ xml:lang CDATA #IMPLIED
+>
+<!ATTLIST listitem
+ id CDATA #REQUIRED
+>
+
+<!-- <border red="0" green="0" blue="10" alpha="255"/>-->
+
+<!ATTLIST border
+ red CDATA #IMPLIED
+ green CDATA #IMPLIED
+ blue CDATA #IMPLIED
+ alpha CDATA #IMPLIED
+>
diff --git a/trunk/gui/greeter/greeter.h b/trunk/gui/greeter/greeter.h
new file mode 100644
index 00000000..8be51441
--- /dev/null
+++ b/trunk/gui/greeter/greeter.h
@@ -0,0 +1,32 @@
+/* GDM - The GNOME Display Manager
+ * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
+ *
+ * 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 __GREETER_H__
+#define __GREETER_H__
+
+#include <gtk/gtk.h>
+
+extern gboolean DOING_GDM_DEVELOPMENT;
+extern GtkWidget *canvas;
+extern GtkWidget *window;
+
+extern gboolean greeter_probably_login_prompt;
+
+void greeter_ignore_buttons (gboolean val);
+
+#endif
diff --git a/trunk/gui/greeter/greeter_canvas_item.c b/trunk/gui/greeter/greeter_canvas_item.c
new file mode 100644
index 00000000..dd32aed0
--- /dev/null
+++ b/trunk/gui/greeter/greeter_canvas_item.c
@@ -0,0 +1,773 @@
+/* GDM - The GNOME Display Manager
+ * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
+ *
+ * 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
+ */
+
+#include "config.h"
+
+#include <math.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <librsvg/rsvg.h>
+
+#include "gdm.h"
+#include "gdmcommon.h"
+#include "gdmconfig.h"
+
+#include "gdm-common.h"
+#include "gdm-daemon-config-keys.h"
+
+#include "greeter.h"
+#include "greeter_item.h"
+#include "greeter_events.h"
+#include "greeter_system.h"
+#include "greeter_canvas_item.h"
+#include "greeter_configuration.h"
+#include "greeter_canvas_text.h"
+#include "greeter_parser.h"
+
+/* Keep track of buttons so they can be set sensitive/insensitive */
+GtkButton *gtk_ok_button = NULL;
+GtkButton *gtk_start_again_button = NULL;
+
+static void
+apply_tint (GdkPixbuf *pixbuf, guint32 tint_color)
+{
+ guchar *pixels;
+ guint r, g, b;
+ gboolean has_alpha;
+ guint w, h, stride;
+ guint pixel_stride;
+ guchar *line;
+ int i;
+
+ pixels = gdk_pixbuf_get_pixels (pixbuf);
+ has_alpha = gdk_pixbuf_get_has_alpha (pixbuf);
+
+ r = (tint_color & 0xff0000) >> 16;
+ g = (tint_color & 0x00ff00) >> 8;
+ b = (tint_color & 0x0000ff);
+
+ w = gdk_pixbuf_get_width (pixbuf);
+ h = gdk_pixbuf_get_height (pixbuf);
+ stride = gdk_pixbuf_get_rowstride (pixbuf);
+
+ pixel_stride = (has_alpha) ? 4 : 3;
+
+ while (h-->0)
+ {
+ line = pixels;
+
+ for (i = 0; i < w; i++)
+ {
+ line[0] = line[0] * r / 0xff;
+ line[1] = line[1] * g / 0xff;
+ line[2] = line[2] * b / 0xff;
+ line += pixel_stride;
+ }
+
+ pixels += stride;
+ }
+}
+
+static GdkPixbuf *
+transform_pixbuf (GdkPixbuf *orig,
+ gboolean has_tint, guint32 tint_color,
+ double alpha, gint width, gint height)
+{
+ GdkPixbuf *scaled;
+ gint p_width, p_height;
+
+ p_width = gdk_pixbuf_get_width (orig);
+ p_height = gdk_pixbuf_get_height (orig);
+
+ if (p_width != width ||
+ p_height != height ||
+ alpha < 1.0 ||
+ has_tint)
+ {
+ int alpha_i;
+
+ if (alpha >= 1.0)
+ alpha_i = 0xff;
+ else if (alpha <= 0.0)
+ alpha_i = 0;
+ else
+ alpha_i = (guint) floor (0xff*alpha);
+ if (alpha != 0xff)
+ {
+ scaled = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, width, height);
+ gdk_pixbuf_fill (scaled, 0);
+ gdk_pixbuf_composite (orig, scaled, 0, 0, width, height,
+ 0, 0, (double)width/p_width, (double)height/p_height,
+ GDK_INTERP_BILINEAR, alpha_i);
+ }
+ else
+ scaled = gdk_pixbuf_scale_simple (orig, width, height, GDK_INTERP_BILINEAR);
+ }
+ else
+ scaled = g_object_ref (orig);
+
+ if (has_tint)
+ apply_tint (scaled, tint_color);
+
+ return scaled;
+}
+
+static void
+activate_button (GtkWidget *widget, gpointer data)
+{
+ const char *id = data;
+ if (id != NULL)
+ greeter_item_run_action_callback (id);
+}
+
+static void
+menubar_done (GtkMenuShell *menushell, gpointer data)
+{
+ GreeterItemInfo *entry_info = greeter_lookup_id ("user-pw-entry");
+ GtkWidget *entry = GNOME_CANVAS_WIDGET (entry_info->item)->widget;
+
+ gtk_widget_grab_focus (entry);
+}
+
+static GtkWidget *
+make_menubar (void)
+{
+ GtkWidget *w, *menu;
+ GtkWidget *menubar = gtk_menu_bar_new ();
+
+ /* FIXME: add translatable string here */
+ w = gtk_menu_item_new_with_label ("Menu");
+ gtk_menu_shell_append (GTK_MENU_SHELL (menubar), w);
+ gtk_widget_show (GTK_WIDGET (w));
+
+ menu = gtk_menu_new ();
+ gtk_menu_item_set_submenu (GTK_MENU_ITEM (w), menu);
+
+ w = gtk_menu_item_new_with_mnemonic (_("Select _Language..."));
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), w);
+ gtk_widget_show (GTK_WIDGET (w));
+ g_signal_connect (G_OBJECT (w), "activate",
+ G_CALLBACK (activate_button),
+ "language_button");
+
+ w = gtk_menu_item_new_with_mnemonic (_("Select _Session..."));
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), w);
+ gtk_widget_show (GTK_WIDGET (w));
+ g_signal_connect (G_OBJECT (w), "activate",
+ G_CALLBACK (activate_button),
+ "session_button");
+
+ greeter_system_append_system_menu (menu);
+
+ /* Add a quit/disconnect item when in xdmcp mode or flexi mode */
+ /* Do note that the order is important, we always want "Quit" for
+ * flexi, even if not local (non-local xnest). and Disconnect
+ * only for xdmcp */
+ if ( ! ve_string_empty (g_getenv ("GDM_FLEXI_SERVER"))) {
+ w = gtk_menu_item_new_with_mnemonic (_("_Quit"));
+ } else if (ve_string_empty (g_getenv ("GDM_IS_LOCAL"))) {
+ w = gtk_menu_item_new_with_mnemonic (_("D_isconnect"));
+ } else {
+ w = NULL;
+ }
+ if (w != NULL) {
+ GtkWidget *sep;
+ /* add separator before the quit */
+ sep = gtk_separator_menu_item_new ();
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), sep);
+ gtk_widget_show (GTK_WIDGET (sep));
+
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), w);
+ gtk_widget_show (GTK_WIDGET (w));
+ g_signal_connect (G_OBJECT (w), "activate",
+ G_CALLBACK (gtk_main_quit), NULL);
+ }
+
+ g_signal_connect (G_OBJECT(gtk_menu_item_get_submenu(
+ gtk_container_get_children(GTK_CONTAINER(menubar))->data)), "selection-done", G_CALLBACK (menubar_done), NULL);
+
+ return menubar;
+}
+
+static void
+get_gdk_color_from_rgb (GdkColor *c, guint32 rgb)
+{
+ c->red = ((rgb & 0xff0000) >> 16) * 0x101;
+ c->green = ((rgb & 0xff00) >> 8) * 0x101;
+ c->blue = (rgb & 0xff) * 0x101;
+ c->pixel = 0;
+}
+
+static void
+menu_position_func (GtkMenu *menu,
+ int *x,
+ int *y,
+ gboolean *push_in,
+ GreeterItemInfo *item)
+{
+ GtkAllocation rect;
+ GtkRequisition requisition;
+
+ rect = item->allocation;
+ gtk_widget_size_request (GTK_WIDGET (menu), &requisition);
+ *x = rect.x;
+ if (requisition.height <= rect.y)
+ *y = rect.y - requisition.height;
+ else
+ *y = rect.y + rect.height;
+
+ *push_in = TRUE;
+}
+
+/*
+ * The button with this handler never appears in the F10 menu, so
+ * it can make use of callback data.
+ */
+static void
+greeter_options_handler (GreeterItemInfo *item, GtkWidget *menubar)
+{
+ gtk_menu_popup (GTK_MENU(gtk_menu_item_get_submenu(
+ gtk_container_get_children(GTK_CONTAINER(menubar))->data)),
+ NULL, NULL, (GtkMenuPositionFunc)menu_position_func,
+ item, 0, gtk_get_current_event_time());
+}
+
+static void
+greeter_item_run_button_action_callback (GtkButton *button, const char *id)
+{
+ GreeterItemInfo *entry_info = greeter_lookup_id ("user-pw-entry");
+ GtkWidget *entry = GNOME_CANVAS_WIDGET (entry_info->item)->widget;
+
+ greeter_item_run_action_callback (id);
+ gtk_widget_grab_focus (entry);
+}
+
+void
+greeter_item_create_canvas_item (GreeterItemInfo *item)
+{
+ GnomeCanvasGroup *group;
+ GtkJustification just;
+ GtkWidget *entry;
+ GtkWidget *gtkbutton;
+ GtkWidget *list;
+ GtkWidget *swin;
+ double x1, y1, x2, y2;
+ int i;
+ GtkAllocation rect;
+ char *text;
+ GtkTooltips *tooltips;
+ char *num_locale;
+ GdkColor c;
+
+ if (item->item != NULL)
+ return;
+
+ if ( ! greeter_item_is_visible (item))
+ return;
+
+ g_assert (item->parent->group_item);
+
+ if (item->fixed_children != NULL ||
+ item->box_children != NULL)
+ {
+ item->group_item =
+ (GnomeCanvasGroup *)gnome_canvas_item_new (item->parent->group_item,
+ GNOME_TYPE_CANVAS_GROUP,
+ "x", (gdouble) 0.0,
+ "y", (gdouble) 0.0,
+ NULL);
+ group = item->group_item;
+ }
+ else
+ group = item->parent->group_item;
+
+ rect = item->allocation;
+
+
+ x1 = (gdouble) rect.x;
+ y1 = (gdouble) rect.y;
+ x2 = (gdouble) rect.x + rect.width;
+ y2 = (gdouble) rect.y + rect.height;
+
+ switch (item->item_type) {
+ case GREETER_ITEM_TYPE_RECT:
+ item->item = gnome_canvas_item_new (group,
+ GNOME_TYPE_CANVAS_RECT,
+ "x1", x1,
+ "y1", y1,
+ "x2", x2,
+ "y2", y2,
+ "fill_color_rgba", item->data.rect.colors[GREETER_ITEM_STATE_NORMAL],
+ NULL);
+ break;
+ case GREETER_ITEM_TYPE_SVG:
+ num_locale = g_strdup (setlocale (LC_NUMERIC, NULL));
+ setlocale (LC_NUMERIC, "C");
+ for (i = 0; i < GREETER_ITEM_STATE_MAX; i++)
+ {
+ if (item->data.pixmap.files[i] != NULL)
+ {
+ if (i > 0 &&
+ item->data.pixmap.files[0] != NULL &&
+ item->data.pixmap.pixbufs[0] != NULL &&
+ strcmp (item->data.pixmap.files[0], item->data.pixmap.files[i]) == 0)
+ item->data.pixmap.pixbufs[i] = g_object_ref (item->data.pixmap.pixbufs[0]);
+ else
+ item->data.pixmap.pixbufs[i] =
+ gdk_pixbuf_new_from_file_at_size (item->data.pixmap.files[i], rect.width, rect.height, NULL);
+ }
+ else
+ item->data.pixmap.pixbufs[i] = NULL;
+ }
+ setlocale (LC_NUMERIC, num_locale);
+ g_free (num_locale);
+ num_locale = NULL;
+
+ /* Fall through */
+ case GREETER_ITEM_TYPE_PIXMAP:
+ for (i = 0; i < GREETER_ITEM_STATE_MAX; i++)
+ {
+ GdkPixbuf *pb = item->data.pixmap.pixbufs[i];
+ if (pb != NULL)
+ {
+ item->data.pixmap.pixbufs[i] =
+ transform_pixbuf (pb,
+ (item->data.pixmap.have_tint & (1<<i)), item->data.pixmap.tints[i],
+ (double)item->data.pixmap.alphas[i] / 256.0, rect.width, rect.height);
+ g_object_unref (pb);
+ }
+ }
+
+ if (item->data.pixmap.pixbufs[GREETER_ITEM_STATE_NORMAL] != NULL)
+ item->item = gnome_canvas_item_new (group,
+ GNOME_TYPE_CANVAS_PIXBUF,
+ "x", (gdouble) x1,
+ "y", (gdouble) y1,
+ "pixbuf", item->data.pixmap.pixbufs[GREETER_ITEM_STATE_NORMAL],
+ NULL);
+ break;
+ case GREETER_ITEM_TYPE_LABEL:
+ text = gdm_common_expand_text (item->data.text.orig_text);
+
+ /* Justification is taken from the anchor */
+ if (item->anchor == GTK_ANCHOR_NORTH_WEST ||
+ item->anchor == GTK_ANCHOR_SOUTH_WEST ||
+ item->anchor == GTK_ANCHOR_WEST)
+ just = GTK_JUSTIFY_LEFT;
+ else if (item->anchor == GTK_ANCHOR_NORTH_EAST ||
+ item->anchor == GTK_ANCHOR_SOUTH_EAST ||
+ item->anchor == GTK_ANCHOR_EAST)
+ just = GTK_JUSTIFY_RIGHT;
+ else
+ just = GTK_JUSTIFY_CENTER;
+
+ item->item = gnome_canvas_item_new (group,
+ GREETER_TYPE_CANVAS_TEXT,
+ "text", "",
+ "x", x1,
+ "y", y1,
+ "anchor", item->anchor,
+ "font_desc", item->data.text.fonts[GREETER_ITEM_STATE_NORMAL],
+ "fill_color_rgba", item->data.text.colors[GREETER_ITEM_STATE_NORMAL],
+ "justification", just,
+ NULL);
+
+ greeter_canvas_item_break_set_string (item,
+ text,
+ TRUE /* markup */,
+ item->data.text.real_max_width,
+ NULL /* width */,
+ NULL /* height */,
+ NULL /* canvas */,
+ item->item);
+ g_free (text);
+
+ /* if there is an accelerator we do an INCREDIBLE hack */
+ if (strchr (item->data.text.orig_text, '_') != NULL)
+ {
+ GreeterItemInfo *button;
+ GtkWidget *fake_button = gtk_button_new_with_mnemonic (item->data.text.orig_text);
+ gtk_widget_show (fake_button);
+ GTK_WIDGET_UNSET_FLAGS (fake_button, GTK_CAN_FOCUS);
+ gnome_canvas_item_new (gnome_canvas_root (GNOME_CANVAS (canvas)),
+ GNOME_TYPE_CANVAS_WIDGET,
+ "widget", fake_button,
+ "x", (double)-999.0,
+ "y", (double)-999.0,
+ "height", (double)20.0,
+ "width", (double)20.0,
+ NULL);
+ button = item->my_button;
+ if (button == NULL)
+ button = item;
+ g_signal_connect_data (G_OBJECT (fake_button), "clicked",
+ G_CALLBACK (activate_button),
+ g_strdup (button->id),
+ (GClosureNotify)g_free,
+ 0 /* connect_flags */);
+ }
+
+ break;
+
+ case GREETER_ITEM_TYPE_BUTTON:
+ gtkbutton = gtk_button_new_with_mnemonic (item->data.text.orig_text);
+ gtk_widget_set_name (gtkbutton, item->id);
+ if (strcmp (ve_sure_string (item->id), "ok_button") == 0) {
+ gtk_ok_button = GTK_BUTTON (gtkbutton);
+ } else if (strcmp (ve_sure_string (item->id), "cancel_button") == 0) {
+ gtk_start_again_button = GTK_BUTTON (gtkbutton);
+ }
+
+ g_signal_connect (G_OBJECT (gtkbutton), "clicked",
+ G_CALLBACK (greeter_item_run_button_action_callback),
+ item->id);
+
+ item->item = gnome_canvas_item_new (group,
+ GNOME_TYPE_CANVAS_WIDGET,
+ "widget", gtkbutton,
+ "x", x1,
+ "y", y1,
+ "height", (double)rect.height,
+ "width", (double)rect.width,
+ NULL);
+
+ break;
+
+ case GREETER_ITEM_TYPE_ENTRY:
+ entry = gtk_entry_new ();
+ gtk_widget_set_name (entry, "user-pw-entry");
+ gtk_entry_set_has_frame (GTK_ENTRY (entry), FALSE);
+
+ if (gdm_config_get_bool (GDM_KEY_ENTRY_INVISIBLE))
+ gtk_entry_set_invisible_char (GTK_ENTRY (entry), 0);
+ else if (gdm_config_get_bool (GDM_KEY_ENTRY_CIRCLES))
+ gtk_entry_set_invisible_char (GTK_ENTRY (entry), 0x25cf);
+
+ gtk_widget_modify_font (entry, item->data.text.fonts[GREETER_ITEM_STATE_NORMAL]);
+
+ get_gdk_color_from_rgb (&c, item->data.text.colors[GREETER_ITEM_STATE_NORMAL]);
+ gtk_widget_modify_text (entry, GTK_STATE_NORMAL, &c);
+
+ if (item->id != NULL && strcmp (item->id, "user-pw-entry") == 0) {
+ /* HACK! Add a menubar, this is kind of evil isn't it,
+ * should probably be done in the pam item setup thingie.
+ * but this is really widget kind of thing. I dunno where
+ * this belongs but it's a hack here. */
+ item->data.text.menubar = make_menubar ();
+
+ gnome_canvas_item_new (gnome_canvas_root (GNOME_CANVAS (canvas)),
+ GNOME_TYPE_CANVAS_WIDGET,
+ "widget", item->data.text.menubar,
+ "x", (double)x1,
+ "y", (double)y1,
+ "height", (double)rect.height,
+ "width", (double)rect.width,
+ NULL);
+
+ greeter_item_register_action_callback ("options_button",
+ (ActionFunc)greeter_options_handler,
+ item->data.text.menubar);
+
+ /* Here add a tooltip, so that the user knows about F10 */
+ tooltips = gtk_tooltips_new ();
+ gtk_tooltips_set_tip (tooltips, GTK_WIDGET (entry),
+ _("Answer questions here and press Enter "
+ "when done. For a menu press F10."),
+ NULL);
+
+ /* FIXME: how to make this accessible??? */
+ }
+
+ item->item = gnome_canvas_item_new (group,
+ GNOME_TYPE_CANVAS_WIDGET,
+ "widget", entry,
+ "x", x1,
+ "y", y1,
+ "height", (double)rect.height,
+ "width", (double)rect.width,
+ NULL);
+
+ /* cursor blinking is evil on remote displays, don't do it forever */
+ gdm_common_setup_blinking_entry (entry);
+
+ break;
+
+ case GREETER_ITEM_TYPE_LIST:
+ /* Note a list type must be setup later and we will add the list store
+ * to it then, depending on the type. Likely userlist is the
+ * only type we support */
+
+ if (item->data.list.combo_type) {
+ list = gtk_combo_box_new_text ();
+
+ item->item = gnome_canvas_item_new (group,
+ GNOME_TYPE_CANVAS_WIDGET,
+ "widget", list,
+ "x", x1,
+ "y", y1,
+ "height", (double)rect.height,
+ "width", (double)rect.width,
+ NULL);
+ } else {
+ list = gtk_tree_view_new ();
+
+ swin = gtk_scrolled_window_new (NULL, NULL);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (swin),
+ GTK_SHADOW_NONE);
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (swin),
+ GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
+ gtk_container_add (GTK_CONTAINER (swin), list);
+
+ item->item = gnome_canvas_item_new (group,
+ GNOME_TYPE_CANVAS_WIDGET,
+ "widget", swin,
+ "x", x1,
+ "y", y1,
+ "height", (double)rect.height,
+ "width", (double)rect.width,
+ NULL);
+ }
+
+ break;
+ }
+
+ if (item->item_type == GREETER_ITEM_TYPE_RECT ||
+ item->item_type == GREETER_ITEM_TYPE_SVG ||
+ item->item_type == GREETER_ITEM_TYPE_PIXMAP ||
+ item->item_type == GREETER_ITEM_TYPE_LABEL)
+ g_signal_connect (G_OBJECT (item->item), "event",
+ G_CALLBACK (greeter_item_event_handler),
+ item);
+}
+
+/* This is so evil it hurts */
+static char *
+make_ugly_long_string_with_line_breaks (const char *orig)
+{
+ const char *p;
+ int n_chars, i;
+ GString *foo = g_string_new (NULL);
+ gboolean in_element = FALSE;
+
+ n_chars = g_utf8_strlen (orig, -1);
+ p = orig;
+
+ i = 0;
+ while (i < n_chars) {
+ gunichar ch = g_utf8_get_char (p);
+ if (ch == '<')
+ in_element = TRUE;
+ else if (ch == '>')
+ in_element = FALSE;
+ g_string_append_unichar (foo, ch);
+ if ( ! in_element)
+ g_string_append_unichar (foo, '\n');
+ p = g_utf8_next_char (p);
+ i++;
+ }
+
+ return g_string_free (foo, FALSE);
+}
+
+/* This function is very VERY evil */
+static gboolean
+append_word (GString *str, GString *line, GString *word, const char *after, int max_width, const char *textattr, GnomeCanvasItem *canvas_item)
+{
+ int width, height;
+ char *post = make_ugly_long_string_with_line_breaks (after);
+ char *try = g_strconcat (str->str, word->str, "\n", post, NULL);
+ g_free (post);
+ gnome_canvas_item_set (GNOME_CANVAS_ITEM (canvas_item), textattr, try, NULL);
+ g_free (try);
+
+ pango_layout_get_pixel_size (GNOME_CANVAS_TEXT (canvas_item)->layout, &width, &height);
+
+ if (width > max_width) {
+ if ( ! ve_string_empty (line->str)) {
+ if (str->len > 0 &&
+ str->str[str->len-1] == ' ') {
+ g_string_truncate (str, str->len-1);
+ }
+ g_string_append_unichar (str, '\n');
+ }
+ g_string_assign (line, word->str);
+ g_string_append (str, word->str);
+ g_string_assign (word, "");
+
+ return TRUE;
+ } else {
+ g_string_append (line, word->str);
+ g_string_append (str, word->str);
+ g_string_assign (word, "");
+
+ return FALSE;
+ }
+}
+
+/* This function is very VERY evil */
+/* Note that it should just use pango and do all the right things rather then
+ the utter hacks it tries to do. But I couldn't figure out how to do this
+ simply with pango and how to interact with markup properly (it seems easy
+ to do if there is no markup */
+void
+greeter_canvas_item_break_set_string (GreeterItemInfo *info,
+ const char *orig,
+ gboolean markup,
+ int max_width,
+ int *width,
+ int *height,
+ GnomeCanvas *canvas,
+ GnomeCanvasItem *real_item)
+{
+ PangoLogAttr *attrs;
+ int n_chars;
+ GString *str;
+ GString *word;
+ GString *line;
+ int i;
+ int n_attrs;
+ int ia;
+ const char *p;
+ int in_current_row;
+ GnomeCanvasItem *canvas_item;
+ const char *textattr;
+ int lwidth, lheight;
+
+ str = g_string_new (NULL);
+ word = g_string_new (NULL);
+ line = g_string_new (NULL);
+
+ /* avoid errors and even possible crashes */
+ if (markup && ! pango_parse_markup (orig, -1, 0, NULL, NULL, NULL, NULL)) {
+ markup = FALSE;
+ }
+
+ textattr = markup ? "markup" : "text";
+
+ /* A gross hack */
+ if (real_item != NULL)
+ canvas_item = real_item;
+ else
+ canvas_item = gnome_canvas_item_new (gnome_canvas_root (canvas),
+ GREETER_TYPE_CANVAS_TEXT,
+ textattr, "",
+ "x", 0.0,
+ "y", 0.0,
+ "font_desc", info->data.text.fonts[GREETER_ITEM_STATE_NORMAL],
+ NULL);
+
+ if (max_width == 0) {
+ gnome_canvas_item_set (GNOME_CANVAS_ITEM (canvas_item), textattr, orig, NULL);
+ pango_layout_get_pixel_size (GNOME_CANVAS_TEXT (canvas_item)->layout, width, height);
+
+ if (real_item != canvas_item) {
+ gtk_object_destroy (GTK_OBJECT (canvas_item));
+ g_string_free (line, TRUE);
+ g_string_free (word, TRUE);
+ g_string_free (str, TRUE);
+ }
+ return;
+ }
+
+ n_chars = g_utf8_strlen (orig, -1);
+
+ gnome_canvas_item_set (GNOME_CANVAS_ITEM (canvas_item), textattr, orig, NULL);
+ pango_layout_get_pixel_size (GNOME_CANVAS_TEXT (canvas_item)->layout, &lwidth, &lheight);
+ if (lwidth <= max_width) {
+ if (width != NULL)
+ *width = lwidth;
+ if (height != NULL)
+ *height = lheight;
+ if (real_item != canvas_item) {
+ gtk_object_destroy (GTK_OBJECT (canvas_item));
+ g_string_free (line, TRUE);
+ g_string_free (word, TRUE);
+ g_string_free (str, TRUE);
+ }
+ return;
+ }
+
+ pango_layout_get_log_attrs (GNOME_CANVAS_TEXT (canvas_item)->layout, &attrs, &n_attrs);
+
+ i = 0;
+ ia = 0;
+ in_current_row = 0;
+ p = orig;
+ while (i < n_chars) {
+ gunichar ch;
+
+ ch = g_utf8_get_char (p);
+
+ if (markup && ch == '<') {
+ while (i < n_chars) {
+ g_string_append_unichar (word, ch);
+ p = g_utf8_next_char (p);
+ i++;
+
+ if (ch == '>') {
+ ch = g_utf8_get_char (p);
+ break;
+ } else {
+ ch = g_utf8_get_char (p);
+ }
+ }
+ if (i >= n_chars)
+ break;
+ }
+
+ if (attrs[ia].is_line_break && in_current_row > 0) {
+ if (append_word (str, line, word, p, max_width, textattr, canvas_item))
+ in_current_row = 0;
+ }
+
+ in_current_row++;
+ g_string_append_unichar (word, ch);
+
+ p = g_utf8_next_char (p);
+ i++;
+ ia++;
+
+ /* eeek! */
+ if (ia >= n_attrs) {
+ while (i < n_chars) {
+ ch = g_utf8_get_char (p);
+ g_string_append_unichar (word, ch);
+ p = g_utf8_next_char (p);
+ i++;
+ }
+ break;
+ }
+ }
+
+ if ( ! ve_string_empty (word->str))
+ append_word (str, line, word, "", max_width, textattr, canvas_item);
+
+ gnome_canvas_item_set (GNOME_CANVAS_ITEM (canvas_item), textattr, str->str, NULL);
+ pango_layout_get_pixel_size (GNOME_CANVAS_TEXT (canvas_item)->layout, width, height);
+
+ if (real_item != canvas_item)
+ gtk_object_destroy (GTK_OBJECT (canvas_item));
+ g_free (attrs);
+
+ g_string_free (line, TRUE);
+ g_string_free (word, TRUE);
+
+ g_string_free (str, TRUE);
+}
+
diff --git a/trunk/gui/greeter/greeter_canvas_item.h b/trunk/gui/greeter/greeter_canvas_item.h
new file mode 100644
index 00000000..cbea3eef
--- /dev/null
+++ b/trunk/gui/greeter/greeter_canvas_item.h
@@ -0,0 +1,33 @@
+/* GDM - The GNOME Display Manager
+ * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
+ *
+ * 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 GREETER_CANVAS_ITEM_H
+#define GREETER_CANVAS_ITEM_H
+
+void greeter_item_create_canvas_item (GreeterItemInfo *item);
+
+void greeter_canvas_item_break_set_string (GreeterItemInfo *info,
+ const char *orig,
+ gboolean markup,
+ int max_width,
+ int *width,
+ int *height,
+ GnomeCanvas *canvas,
+ GnomeCanvasItem *real_item);
+
+#endif /* GREETER_CANVAS_ITEM_H */
diff --git a/trunk/gui/greeter/greeter_canvas_text.c b/trunk/gui/greeter/greeter_canvas_text.c
new file mode 100644
index 00000000..961f5190
--- /dev/null
+++ b/trunk/gui/greeter/greeter_canvas_text.c
@@ -0,0 +1,213 @@
+#include <string.h>
+
+#include "greeter_canvas_text.h"
+
+#include <libgnomecanvas/gnome-canvas.h>
+#include <libgnomecanvas/gnome-canvas-text.h>
+#include <pango/pangoft2.h>
+
+
+enum
+{
+ PROP_0,
+ PROP_TEXT,
+ PROP_MARKUP
+};
+
+static void greeter_canvas_text_class_init (GreeterCanvasTextClass *class);
+static void greeter_canvas_text_init (GreeterCanvasText *text);
+static void greeter_canvas_text_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void greeter_canvas_text_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+G_DEFINE_TYPE (GreeterCanvasText, greeter_canvas_text, GNOME_TYPE_CANVAS_TEXT)
+
+static void
+greeter_canvas_text_class_init (GreeterCanvasTextClass *greeter_class)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = G_OBJECT_CLASS (greeter_class);
+
+ gobject_class->set_property = greeter_canvas_text_set_property;
+ gobject_class->get_property = greeter_canvas_text_get_property;
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_TEXT,
+ g_param_spec_string ("text",
+ "Text",
+ "Text to render",
+ NULL,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_MARKUP,
+ g_param_spec_string ("markup",
+ "Markup",
+ "Markup to render",
+ NULL,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+}
+
+static void
+greeter_canvas_text_init (GreeterCanvasText *text)
+{
+}
+
+static gdouble
+greeter_canvas_text_get_screen_dpi (GreeterCanvasText *text)
+{
+ GdkDisplay *display;
+ GdkScreen *screen;
+ GdkAtom atom, type;
+ gint resources_length;
+ gchar *resources, *resource, *end;
+ gdouble dpi;
+ static const gdouble default_dpi = 96.0;
+
+ atom = gdk_atom_intern ("RESOURCE_MANAGER", TRUE);
+
+ if (atom == 0)
+ return default_dpi;
+
+ display =
+ gtk_widget_get_display (GTK_WIDGET (GNOME_CANVAS_ITEM (text)->canvas));
+
+ if (display == NULL)
+ return default_dpi;
+
+ screen =
+ gtk_widget_get_screen (GTK_WIDGET (GNOME_CANVAS_ITEM (text)->canvas));
+
+ if (screen == NULL)
+ return default_dpi;
+
+ gdk_error_trap_push ();
+ if (!gdk_property_get (gdk_screen_get_root_window (screen),
+ atom, GDK_TARGET_STRING,
+ 0, G_MAXINT,
+ FALSE,
+ &type, NULL, &resources_length,
+ (void *) &resources))
+ {
+ gdk_error_trap_pop ();
+ return default_dpi;
+ }
+
+ gdk_display_sync (display);
+ gdk_error_trap_pop ();
+
+ if (type != GDK_TARGET_STRING)
+ return default_dpi;
+
+ if (resources == NULL)
+ return default_dpi;
+
+ resource = strstr (resources, "Xft.dpi:\t");
+
+ if (resource == NULL)
+ return default_dpi;
+
+ resource += sizeof ("Xft.dpi:\t") - 1;
+
+ dpi = strtod (resource, &end);
+
+ g_assert (end != NULL);
+
+ if ((end == resource) || (*end != '\n'))
+ return default_dpi;
+
+ g_free (resources);
+
+ if (dpi < G_MINDOUBLE)
+ return default_dpi;
+
+ return dpi;
+}
+
+static void
+greeter_canvas_text_init_layout (GreeterCanvasText *greeter_item)
+{
+ GnomeCanvasItem *item;
+ GnomeCanvasText *text;
+
+ PangoContext *gtk_context, *context;
+ static PangoFT2FontMap *font_map;
+ gdouble dpi;
+
+ item = GNOME_CANVAS_ITEM (greeter_item);
+ text = GNOME_CANVAS_TEXT (greeter_item);
+
+ if (text->layout != NULL)
+ return;
+
+ gtk_context = gtk_widget_get_pango_context (GTK_WIDGET (item->canvas));
+
+ if (font_map == NULL)
+ {
+ font_map = (PangoFT2FontMap *) pango_ft2_font_map_new ();
+ dpi = greeter_canvas_text_get_screen_dpi (greeter_item);
+ pango_ft2_font_map_set_resolution (font_map, dpi, dpi);
+ }
+
+ context = pango_ft2_font_map_create_context (font_map);
+
+ pango_context_set_language (context,
+ pango_context_get_language (gtk_context));
+ pango_context_set_base_dir (context,
+ pango_context_get_base_dir (gtk_context));
+ pango_context_set_font_description (context,
+ pango_context_get_font_description (gtk_context));
+
+ text->layout = pango_layout_new (context);
+ g_object_unref (context);
+}
+
+static void
+greeter_canvas_text_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (param_id)
+ {
+ case PROP_TEXT:
+ greeter_canvas_text_init_layout (GREETER_CANVAS_TEXT (object));
+ g_object_set_property (object, "GnomeCanvasText::text", value);
+ break;
+ case PROP_MARKUP:
+ greeter_canvas_text_init_layout (GREETER_CANVAS_TEXT (object));
+ g_object_set_property (object, "GnomeCanvasText::markup", value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+static void
+greeter_canvas_text_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (param_id)
+ {
+ case PROP_TEXT:
+ g_object_get_property (object, "GnomeCanvasText::text", value);
+ break;
+ case PROP_MARKUP:
+ g_object_get_property (object, "GnomeCanvasText::markup", value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
diff --git a/trunk/gui/greeter/greeter_canvas_text.h b/trunk/gui/greeter/greeter_canvas_text.h
new file mode 100644
index 00000000..f2131023
--- /dev/null
+++ b/trunk/gui/greeter/greeter_canvas_text.h
@@ -0,0 +1,33 @@
+#ifndef GREETER_CANVAS_TEXT_H
+#define GREETER_CANVAS_TEXT_H
+
+#include <libgnomecanvas/gnome-canvas.h>
+#include <libgnomecanvas/gnome-canvas-text.h>
+
+G_BEGIN_DECLS
+
+#define GREETER_TYPE_CANVAS_TEXT (greeter_canvas_text_get_type ())
+#define GREETER_CANVAS_TEXT(obj) (GTK_CHECK_CAST ((obj), GREETER_TYPE_CANVAS_TEXT, GreeterCanvasText))
+#define GREETER_CANVAS_TEXT_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GREETER_TYPE_CANVAS_TEXT, GreeterCanvasTextClass))
+#define GREETER_IS_CANVAS_TEXT(obj) (GTK_CHECK_TYPE ((obj), GREETER_TYPE_CANVAS_TEXT))
+#define GREETER_IS_CANVAS_TEXT_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GREETER_TYPE_CANVAS_TEXT))
+#define GREETER_CANVAS_TEXT_GET_CLASS(obj) (GTK_CHECK_GET_CLASS ((obj), GREETER_TYPE_CANVAS_TEXT, GreeterCanvasTextClass))
+
+
+typedef struct _GreeterCanvasText GreeterCanvasText;
+typedef struct _GreeterCanvasTextClass GreeterCanvasTextClass;
+
+struct _GreeterCanvasText {
+ GnomeCanvasText text;
+};
+
+struct _GreeterCanvasTextClass {
+ GnomeCanvasTextClass parent_class;
+};
+
+
+GType greeter_canvas_text_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif
diff --git a/trunk/gui/greeter/greeter_configuration.h b/trunk/gui/greeter/greeter_configuration.h
new file mode 100644
index 00000000..d4dabaf9
--- /dev/null
+++ b/trunk/gui/greeter/greeter_configuration.h
@@ -0,0 +1,72 @@
+/* GDM - The GNOME Display Manager
+ * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
+ *
+ * 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 GREETER_CONFIGURATION_H
+#define GREETER_CONFIGURATION_H
+
+extern gboolean GdmUseCirclesInEntry;
+extern gboolean GdmUseInvisibleInEntry;
+extern gboolean GdmShowGnomeFailsafeSession;
+extern gboolean GdmShowXtermFailsafeSession;
+extern gboolean GdmShowLastSession;
+extern gboolean GdmSystemMenu;
+extern gboolean GdmConfigAvailable;
+extern gboolean GdmChooserButton;
+extern gchar *GdmHalt;
+extern gchar *GdmReboot;
+extern gchar *GdmSuspend;
+extern gchar *GdmConfigurator;
+extern gboolean GdmHaltFound;
+extern gboolean GdmRebootFound;
+extern gboolean GdmCustomCmdFound;
+extern gboolean *GdmCustomCmdsFound;
+extern gboolean GdmAnyCustomCmdsFound;
+extern gboolean GdmSuspendFound;
+extern gboolean GdmConfiguratorFound;
+extern gchar *GdmSessionDir;
+extern gchar *GdmDefaultSession;
+extern gchar *GdmDefaultLocale;
+extern gchar *GdmLocaleFile;
+extern gboolean GdmTimedLoginEnable;
+extern gboolean GdmUse24Clock;
+extern gchar *GdmTimedLogin;
+extern gint GdmTimedLoginDelay;
+extern gchar *GdmGlobalFaceDir;
+extern gchar *GdmDefaultFace;
+extern gint GdmIconMaxHeight;
+extern gint GdmIconMaxWidth;
+extern gchar *GdmExclude;
+extern int GdmMinimalUID;
+extern gboolean GdmAllowRoot;
+extern gboolean GdmAllowRemoteRoot;
+extern gchar *GdmWelcome;
+extern gchar *GdmServAuthDir;
+extern gchar *GdmInfoMsgFile;
+extern gchar *GdmInfoMsgFont;
+extern gchar *GdmSoundProgram;
+extern gchar *GdmSoundOnLoginReadyFile;
+extern gchar *GdmSoundOnLoginSuccessFile;
+extern gchar *GdmSoundOnLoginFailureFile;
+extern gboolean GdmSoundOnLoginReady;
+extern gboolean GdmSoundOnLoginSuccess;
+extern gboolean GdmSoundOnLoginFailure;
+
+extern gboolean GDM_IS_LOCAL;
+extern gboolean DOING_GDM_DEVELOPMENT;
+
+#endif /* GREETER_CONFIGURATION_H */
diff --git a/trunk/gui/greeter/greeter_dialogs.c b/trunk/gui/greeter/greeter_dialogs.c
new file mode 100644
index 00000000..ceb4c1ac
--- /dev/null
+++ b/trunk/gui/greeter/greeter_dialogs.c
@@ -0,0 +1,25 @@
+/* GDM - The GNOME Display Manager
+ * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
+ *
+ * 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
+ */
+
+#include "greeter_dialogs.h"
+
+
+GtkWidget *
+greeter_lang_dialog (void)
+{
+}
diff --git a/trunk/gui/greeter/greeter_dialogs.h b/trunk/gui/greeter/greeter_dialogs.h
new file mode 100644
index 00000000..c2f3e7f7
--- /dev/null
+++ b/trunk/gui/greeter/greeter_dialogs.h
@@ -0,0 +1,26 @@
+/* GDM - The GNOME Display Manager
+ * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
+ *
+ * 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 __GREETER_DIALOGS_H__
+#define __GREETER_DIALOGS_H__
+
+#include <gtk/gtk.h>
+
+GtkWidget *greeter_lang_dialog (void);
+
+#endif
diff --git a/trunk/gui/greeter/greeter_events.c b/trunk/gui/greeter/greeter_events.c
new file mode 100644
index 00000000..34b96040
--- /dev/null
+++ b/trunk/gui/greeter/greeter_events.c
@@ -0,0 +1,256 @@
+/* GDM - The GNOME Display Manager
+ * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
+ *
+ * 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
+ */
+
+#include "config.h"
+
+#include <gtk/gtk.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "greeter_item.h"
+#include "greeter_parser.h"
+#include "greeter_events.h"
+
+struct CallbackInfo {
+ ActionFunc func;
+ gpointer user_data;
+};
+
+static GHashTable *callback_hash = NULL;
+
+static void
+state_run (GreeterItemInfo *info,
+ GreeterItemState old_state)
+{
+ if (info->state != old_state &&
+ info->have_state & (1<<(info->state)) &&
+ info->have_state != (1<<GREETER_ITEM_STATE_NORMAL) &&
+ info->item != NULL)
+ {
+ if (GREETER_ITEM_TYPE_IS_PIXMAP (info) &&
+ info->data.pixmap.pixbufs[info->state] != NULL)
+ gnome_canvas_item_set (info->item,
+ "pixbuf", info->data.pixmap.pixbufs[info->state],
+ NULL);
+ if ((GREETER_ITEM_TYPE_IS_TEXT (info) ||
+ GREETER_ITEM_TYPE_IS_RECT (info)) &&
+ info->data.rect.have_color & (1<<(info->state)))
+ gnome_canvas_item_set (info->item,
+ "fill_color_rgba", info->data.rect.colors[info->state],
+ NULL);
+ if (GREETER_ITEM_TYPE_IS_TEXT (info) &&
+ info->data.text.fonts[info->state] != NULL)
+ gnome_canvas_item_set (info->item,
+ "font_desc", info->data.text.fonts[info->state],
+ NULL);
+ }
+}
+
+static void propagate_state (GreeterItemInfo *info,
+ GreeterItemState old_state);
+
+static void
+propagate_state_foreach (gpointer data, gpointer user_data)
+{
+ GreeterItemInfo *info = data;
+ GreeterItemState state = GPOINTER_TO_INT (user_data);
+ GreeterItemState old_state;
+
+ old_state = info->state;
+ info->state = state;
+
+ propagate_state (info, old_state);
+}
+
+static void
+propagate_state (GreeterItemInfo *info,
+ GreeterItemState old_state)
+{
+ state_run (info, old_state);
+
+ g_list_foreach (info->fixed_children, propagate_state_foreach,
+ GINT_TO_POINTER ((int) info->state));
+ g_list_foreach (info->box_children, propagate_state_foreach,
+ GINT_TO_POINTER ((int) info->state));
+}
+
+static void propagate_reset_state (GreeterItemInfo *info,
+ GreeterItemState old_state);
+
+static void
+propagate_reset_state_foreach (gpointer data, gpointer user_data)
+{
+ GreeterItemInfo *info = data;
+ GreeterItemState old_state;
+
+ old_state = info->state;
+ info->state = info->base_state;
+
+ propagate_state (info, old_state);
+}
+
+static void
+propagate_reset_state (GreeterItemInfo *info,
+ GreeterItemState old_state)
+{
+ state_run (info, old_state);
+
+ g_list_foreach (info->fixed_children, propagate_reset_state_foreach, NULL);
+ g_list_foreach (info->box_children, propagate_reset_state_foreach, NULL);
+}
+
+void
+greeter_item_run_action_callback (const char *id)
+{
+ struct CallbackInfo *cb_info;
+ GreeterItemInfo *info;
+
+ g_return_if_fail (id != NULL);
+
+ if G_UNLIKELY (callback_hash == NULL)
+ return;
+
+ info = greeter_lookup_id (id);
+ cb_info = g_hash_table_lookup (callback_hash, id);
+
+ /*
+ * If run_action_callback gets called and there is no
+ * callback function registered, don't try to call it.
+ * This can happen because the button_release event
+ * tries calling the callback function for any
+ * item that has an id (like the Username field).
+ */
+ if (cb_info)
+ (*cb_info->func) (info, cb_info->user_data);
+}
+
+gint
+greeter_item_event_handler (GnomeCanvasItem *item,
+ GdkEvent *event,
+ gpointer data)
+{
+ GreeterItemState old_state;
+ GreeterItemInfo *info;
+ GreeterItemInfo *button;
+
+ info = data;
+ button = info->my_button;
+ if (button != NULL && button != info)
+ {
+ /* FIXME: this is a hack, we have not really left the container,
+ * but the container gets a stupid leave event and
+ * we send it an enter event back, it does two event propagations
+ * one of them is pointless. */
+ /* if this is a button, fake an event on the button */
+ return greeter_item_event_handler (button->item,
+ event,
+ button);
+ }
+
+ old_state = info->state;
+
+ switch (event->type) {
+ case GDK_ENTER_NOTIFY:
+ info->mouse_over = TRUE;
+ break;
+
+ case GDK_LEAVE_NOTIFY:
+ info->mouse_over = FALSE;
+ break;
+
+ case GDK_BUTTON_PRESS:
+ info->mouse_down = TRUE;
+ break;
+
+ case GDK_BUTTON_RELEASE:
+ info->mouse_down = FALSE;
+
+ if (info->mouse_over && info->id && callback_hash)
+ greeter_item_run_action_callback (info->id);
+
+ /* Make sure entry has focus if a type BUTTON has been pressed. */
+ if (info->item_type == GREETER_ITEM_TYPE_BUTTON) {
+ GreeterItemInfo *entry_info = greeter_lookup_id ("user-pw-entry");
+ GtkWidget *entry = GNOME_CANVAS_WIDGET (entry_info->item)->widget;
+
+ if (entry_info && entry_info->item &&
+ GNOME_IS_CANVAS_WIDGET (entry_info->item) &&
+ GTK_IS_ENTRY (GNOME_CANVAS_WIDGET (entry_info->item)->widget))
+ {
+ /* Make sure entry has focus after button press */
+ gtk_widget_grab_focus (entry);
+ }
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ if (info->mouse_over)
+ {
+ if (info->mouse_down)
+ info->state = GREETER_ITEM_STATE_ACTIVE;
+ else
+ info->state = GREETER_ITEM_STATE_PRELIGHT;
+ }
+ else
+ info->state = GREETER_ITEM_STATE_NORMAL;
+
+ info->base_state = info->state;
+
+ if (info->state != old_state)
+ {
+ if (info->canvasbutton)
+ {
+ if (info->state == GREETER_ITEM_STATE_NORMAL)
+ propagate_reset_state (info, old_state);
+ else
+ propagate_state (info, old_state);
+ }
+ else
+ state_run (info, old_state);
+ }
+
+ return FALSE;
+}
+
+void
+greeter_item_register_action_callback (char *id,
+ ActionFunc func,
+ gpointer user_data)
+{
+ struct CallbackInfo *info;
+
+ if G_UNLIKELY (callback_hash == NULL)
+ callback_hash = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ g_free);
+
+ info = g_new (struct CallbackInfo, 1);
+
+ info->func = func;
+ info->user_data = user_data;
+
+ g_hash_table_insert (callback_hash,
+ g_strdup (id),
+ info);
+}
+
diff --git a/trunk/gui/greeter/greeter_events.h b/trunk/gui/greeter/greeter_events.h
new file mode 100644
index 00000000..1c1ba1d7
--- /dev/null
+++ b/trunk/gui/greeter/greeter_events.h
@@ -0,0 +1,35 @@
+/* GDM - The GNOME Display Manager
+ * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
+ *
+ * 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 GREETER_EVENTS_H
+#define GREETER_EVENTS_H
+
+typedef void (*ActionFunc) (GreeterItemInfo *info,
+ gpointer user_data);
+
+gint greeter_item_event_handler (GnomeCanvasItem *item,
+ GdkEvent *event,
+ gpointer data);
+
+void greeter_item_register_action_callback (char *id,
+ ActionFunc func,
+ gpointer user_data);
+
+void greeter_item_run_action_callback (const char *id);
+
+#endif /* GREETER_EVENTS_H */
diff --git a/trunk/gui/greeter/greeter_geometry.c b/trunk/gui/greeter/greeter_geometry.c
new file mode 100644
index 00000000..265b19be
--- /dev/null
+++ b/trunk/gui/greeter/greeter_geometry.c
@@ -0,0 +1,623 @@
+/* GDM - The GNOME Display Manager
+ * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
+ *
+ * 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
+ */
+
+#include "config.h"
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <librsvg/rsvg.h>
+#include "gdmcommon.h"
+#include "gdmwm.h"
+#include "greeter_geometry.h"
+#include "greeter_canvas_item.h"
+
+static void greeter_item_size_request (GreeterItemInfo *item,
+ GtkRequisition *requisition_out,
+ gint parent_width,
+ gint parent_height,
+ GnomeCanvas *canvas);
+static void greeter_size_allocate_fixed (GreeterItemInfo *fixed,
+ GList *items,
+ GnomeCanvas *canvas);
+static void greeter_size_allocate_box (GreeterItemInfo *box,
+ GList *items,
+ GnomeCanvas *canvas,
+ GtkAllocation *allocation);
+static void fixup_from_anchor (GtkAllocation *rect,
+ GtkAnchorType anchor);
+static void update_real_max_width (GreeterItemInfo *info,
+ int max_width);
+
+static void
+update_real_max_width (GreeterItemInfo *info, int max_width)
+{
+ if (info->data.text.real_max_width == 0 ||
+ info->data.text.real_max_width > max_width)
+ info->data.text.real_max_width = max_width;
+}
+
+
+/* Position the item */
+static void
+greeter_item_size_allocate (GreeterItemInfo *item,
+ GtkAllocation *allocation,
+ GnomeCanvas *canvas)
+{
+ item->allocation = *allocation;
+
+ if ( ! greeter_item_is_visible (item))
+ return;
+
+ if (item->item == NULL)
+ greeter_item_create_canvas_item (item);
+
+ if (item->fixed_children)
+ greeter_size_allocate_fixed (item,
+ item->fixed_children,
+ canvas);
+
+ if (item->box_children)
+ greeter_size_allocate_box (item,
+ item->box_children,
+ canvas,
+ allocation);
+
+}
+
+static void
+fixup_from_anchor (GtkAllocation *rect,
+ GtkAnchorType anchor)
+{
+ switch (anchor)
+ {
+ case GTK_ANCHOR_NW:
+ break;
+ case GTK_ANCHOR_N:
+ rect->x -= rect->width/2;
+ break;
+ case GTK_ANCHOR_NE:
+ rect->x -= rect->width;
+ break;
+
+ case GTK_ANCHOR_W:
+ rect->y -= rect->height/2;
+ break;
+ case GTK_ANCHOR_CENTER:
+ rect->x -= rect->width/2;
+ rect->y -= rect->height/2;
+ break;
+ case GTK_ANCHOR_E:
+ rect->x -= rect->width;
+ rect->y -= rect->height/2;
+ break;
+
+ case GTK_ANCHOR_SW:
+ rect->y -= rect->height;
+ break;
+ case GTK_ANCHOR_S:
+ rect->x -= rect->width/2;
+ rect->y -= rect->height;
+ break;
+ case GTK_ANCHOR_SE:
+ rect->x -= rect->width;
+ rect->y -= rect->height;
+ break;
+ default:
+ break;
+ }
+}
+
+/* Position the children of the parent given
+ * the size */
+static void
+greeter_size_allocate_fixed (GreeterItemInfo *fixed,
+ GList *items,
+ GnomeCanvas *canvas)
+{
+ GList *l;
+ GreeterItemInfo *child;
+ GtkRequisition requisition;
+ GtkAllocation child_allocation;
+
+ l = items;
+ while (l != NULL)
+ {
+ child = l->data;
+ l = l->next;
+
+ if ( ! greeter_item_is_visible (child))
+ continue;
+
+ greeter_item_size_request (child,
+ &requisition,
+ fixed->allocation.width,
+ fixed->allocation.height,
+ canvas);
+
+ child_allocation.x = fixed->allocation.x;
+ child_allocation.y = fixed->allocation.y;
+
+ child_allocation.width = requisition.width;
+ child_allocation.height = requisition.height;
+
+ if (child->x_type == GREETER_ITEM_POS_ABSOLUTE)
+ child_allocation.x += ( ! child->x_negative) ? child->x : fixed->allocation.width + child->x;
+ else if (child->x_type == GREETER_ITEM_POS_RELATIVE)
+ child_allocation.x += fixed->allocation.width * child->x / 100.0;
+
+ if (child->y_type == GREETER_ITEM_POS_ABSOLUTE)
+ child_allocation.y += ( ! child->y_negative) ? child->y : fixed->allocation.height + child->y;
+ else if (child->y_type == GREETER_ITEM_POS_RELATIVE)
+ child_allocation.y += fixed->allocation.height * child->y / 100.0;
+
+ if (child->item_type != GREETER_ITEM_TYPE_LABEL)
+ fixup_from_anchor (&child_allocation, child->anchor);
+
+ greeter_item_size_allocate (child,
+ &child_allocation,
+ canvas);
+ }
+}
+
+
+/* Position the children of the parent given
+ * the size */
+static void
+greeter_size_allocate_box (GreeterItemInfo *box,
+ GList *items,
+ GnomeCanvas *canvas,
+ GtkAllocation *allocation)
+{
+ GreeterItemInfo *child;
+ GList *children;
+ GtkAllocation child_allocation;
+ GtkRequisition child_requisition;
+ gint nvis_children;
+ gint nexpand_children;
+ gint child_major_size;
+ gint major_size;
+ gint extra;
+ gint major;
+ gint w, h;
+
+ nvis_children = 0;
+ nexpand_children = 0;
+
+ children = items;
+ while (children)
+ {
+ child = children->data;
+ children = children->next;
+
+ if (greeter_item_is_visible (child))
+ {
+ nvis_children += 1;
+ if (child->expand)
+ nexpand_children += 1;
+ }
+ }
+
+ if (nvis_children > 0)
+ {
+ if (box->box_orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ if (box->box_homogeneous)
+ {
+ major_size = (allocation->width -
+ box->box_x_padding * 2 -
+ (nvis_children - 1) * box->box_spacing);
+ extra = major_size / nvis_children;
+ }
+ else if (nexpand_children > 0)
+ {
+ major_size = (gint) allocation->width - (gint) box->requisition.width;
+ extra = major_size / nexpand_children;
+ }
+ else
+ {
+ major_size = 0;
+ extra = 0;
+ }
+
+ major = allocation->x + box->box_x_padding;
+ }
+ else
+ {
+ if (box->box_homogeneous)
+ {
+ major_size = (allocation->height -
+ box->box_y_padding * 2 -
+ (nvis_children - 1) * box->box_spacing);
+ extra = major_size / nvis_children;
+ }
+ else if (nexpand_children > 0)
+ {
+ major_size = (gint) allocation->height - (gint) box->requisition.height;
+ extra = major_size / nexpand_children;
+ }
+ else
+ {
+ major_size = 0;
+ extra = 0;
+ }
+
+ major = allocation->y + box->box_y_padding;
+ }
+
+
+ children = items;
+ while (children)
+ {
+ child = children->data;
+ children = children->next;
+
+ if ( ! greeter_item_is_visible (child))
+ continue;
+
+ if (box->box_homogeneous)
+ {
+ if (nvis_children == 1)
+ child_major_size = major_size;
+ else
+ child_major_size = extra;
+
+ major_size -= extra;
+
+ nvis_children -= 1;
+ }
+ else
+ {
+ greeter_item_size_request (child,
+ &child_requisition,
+ 0, 0, canvas);
+
+ if (box->box_orientation == GTK_ORIENTATION_HORIZONTAL)
+ child_major_size = child_requisition.width;
+ else
+ child_major_size = child_requisition.height;
+
+ if (child->expand)
+ {
+ if (nexpand_children == 1)
+ child_major_size += major_size;
+ else
+ child_major_size += extra;
+
+ nexpand_children -= 1;
+ major_size -= extra;
+ }
+ }
+
+ /* Dirty the child requisition, since
+ * we now know the right parent size.
+ */
+ child->has_requisition = FALSE;
+ w = (box->box_orientation == GTK_ORIENTATION_HORIZONTAL) ? child_major_size : allocation->width - 2 * box->box_x_padding;
+ h = (box->box_orientation == GTK_ORIENTATION_HORIZONTAL) ? allocation->height - 2 * box->box_y_padding : child_major_size;
+
+ greeter_item_size_request (child,
+ &child_requisition,
+ w, h, canvas);
+
+ child_allocation.width = child_requisition.width;
+ child_allocation.height = child_requisition.height;
+
+ if (box->box_orientation == GTK_ORIENTATION_VERTICAL &&
+ child->item_type == GREETER_ITEM_TYPE_LABEL) {
+ update_real_max_width (child, allocation->width);
+ }
+
+ if (box->box_orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ child_allocation.x = major;
+ child_allocation.y = allocation->y + box->box_y_padding;
+ }
+ else
+ {
+ child_allocation.x = allocation->x + box->box_x_padding;
+ child_allocation.y = major;
+ }
+
+ if (child->x_type == GREETER_ITEM_POS_ABSOLUTE)
+ child_allocation.x += ( ! child->x_negative) ? child->x : w + child->x;
+ else if (child->x_type == GREETER_ITEM_POS_RELATIVE)
+ child_allocation.x += w * child->x / 100.0;
+
+ if (child->y_type == GREETER_ITEM_POS_ABSOLUTE)
+ child_allocation.y += ( ! child->y_negative) ? child->y : h + child->y;
+ else if (child->y_type == GREETER_ITEM_POS_RELATIVE)
+ child_allocation.y += h * child->y / 100.0;
+
+ if (child->item_type != GREETER_ITEM_TYPE_LABEL)
+ fixup_from_anchor (&child_allocation, child->anchor);
+
+ if (child_allocation.x + child_allocation.width > allocation->x + allocation->width)
+ child_allocation.width -= (child_allocation.x + child_allocation.width
+ - allocation->x - allocation->width);
+
+ greeter_item_size_allocate (child,
+ &child_allocation,
+ canvas);
+
+ major += child_major_size + box->box_spacing;
+ }
+ }
+}
+
+static void
+greeter_size_request_box (GreeterItemInfo *box,
+ GtkRequisition *requisition,
+ GnomeCanvas *canvas)
+{
+
+ GreeterItemInfo *child;
+ GtkRequisition child_requisition;
+ GList *children;
+ gint nvis_children;
+
+ requisition->width = 0;
+ requisition->height = 0;
+
+ nvis_children = 0;
+
+ children = box->box_children;
+ while (children)
+ {
+ child = children->data;
+ children = children->next;
+
+ if ( ! greeter_item_is_visible (child))
+ continue;
+
+ greeter_item_size_request (child,
+ &child_requisition,
+ 0, 0, canvas);
+
+ if (box->box_orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ if (box->box_homogeneous)
+ {
+ requisition->width = MAX (requisition->width,
+ child_requisition.width);
+ }
+ else
+ {
+ requisition->width += child_requisition.width;
+ }
+
+ requisition->height = MAX (requisition->height, child_requisition.height);
+ }
+ else
+ {
+ if (box->box_homogeneous)
+ {
+ requisition->height = MAX (requisition->height,
+ child_requisition.height);
+ }
+ else
+ {
+ requisition->height += child_requisition.height;
+ }
+
+ requisition->width = MAX (requisition->width, child_requisition.width);
+ }
+
+
+ nvis_children += 1;
+ }
+
+ if (nvis_children > 0)
+ {
+
+ if (box->box_orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ if (box->box_homogeneous)
+ requisition->width *= nvis_children;
+ requisition->width += (nvis_children - 1) * box->box_spacing;
+ }
+ else
+ {
+ if (box->box_homogeneous)
+ requisition->height *= nvis_children;
+ requisition->height += (nvis_children - 1) * box->box_spacing;
+ }
+ }
+
+ requisition->width += box->box_x_padding * 2;
+ requisition->height += box->box_y_padding * 2;
+
+ requisition->width = MAX (requisition->width, box->box_min_width);
+ requisition->height = MAX (requisition->height, box->box_min_height);
+}
+
+/* Calculate the requested minimum size of the item */
+static void
+greeter_item_size_request (GreeterItemInfo *item,
+ GtkRequisition *requisition_out,
+ gint parent_width,
+ gint parent_height,
+ GnomeCanvas *canvas)
+{
+ GtkRequisition *req;
+ GtkRequisition box_requisition = {0, 0};
+ int set_width = 0;
+ int set_height = 0;
+
+ if (item->has_requisition)
+ {
+ *requisition_out = item->requisition;
+ return;
+ }
+
+ req = &item->requisition;
+
+ req->width = 0;
+ req->height = 0;
+
+ if (item->width_type == GREETER_ITEM_SIZE_BOX ||
+ item->height_type == GREETER_ITEM_SIZE_BOX)
+ {
+ greeter_size_request_box (item,
+ &box_requisition,
+ canvas);
+ }
+
+ switch (item->width_type)
+ {
+ case GREETER_ITEM_SIZE_ABSOLUTE:
+ set_width = (item->width > 0) ? item->width : parent_width + item->width;
+ break;
+ case GREETER_ITEM_SIZE_RELATIVE:
+ set_width = item->width*parent_width / 100.0;
+ break;
+ case GREETER_ITEM_SIZE_BOX:
+ set_width = box_requisition.width;
+ break;
+ case GREETER_ITEM_SIZE_SCALE:
+ case GREETER_ITEM_SIZE_UNSET:
+ break;
+ }
+
+ switch (item->height_type)
+ {
+ case GREETER_ITEM_SIZE_ABSOLUTE:
+ set_height = (item->height > 0) ? item->height : parent_height + item->height;
+ break;
+ case GREETER_ITEM_SIZE_RELATIVE:
+ set_height = item->height*parent_height / 100.0;
+ break;
+ case GREETER_ITEM_SIZE_BOX:
+ set_height = box_requisition.height;
+ break;
+ case GREETER_ITEM_SIZE_SCALE:
+ case GREETER_ITEM_SIZE_UNSET:
+ break;
+ }
+
+ if (item->item_type == GREETER_ITEM_TYPE_LABEL)
+ {
+ int width, height;
+ char *text;
+ int max_width = G_MAXINT;
+
+ /* This is not the ugly hack you're looking for.
+ * You can go about your business.
+ * Move Along
+ */
+ text = gdm_common_expand_text (item->data.text.orig_text);
+
+ if (set_width > 0)
+ max_width = set_width;
+
+ if (item->data.text.max_width < max_width)
+ max_width = item->data.text.max_width;
+
+ if (item->data.text.max_screen_percent_width/100.0 * gdm_wm_screen.width < max_width)
+ max_width = item->data.text.max_screen_percent_width/100.0 * gdm_wm_screen.width;
+
+ greeter_canvas_item_break_set_string (item,
+ text,
+ TRUE /* markup */,
+ max_width,
+ &width,
+ &height,
+ canvas,
+ NULL /* real_item */);
+
+ req->width = width;
+ req->height = height;
+
+ g_free (text);
+ }
+
+ if (item->item_type == GREETER_ITEM_TYPE_PIXMAP)
+ {
+ req->width = gdk_pixbuf_get_width (item->data.pixmap.pixbufs[0]);
+ req->height = gdk_pixbuf_get_height (item->data.pixmap.pixbufs[0]);
+ }
+
+ if (item->item_type == GREETER_ITEM_TYPE_SVG)
+ {
+ GdkPixbuf *svg;
+
+ svg = rsvg_pixbuf_from_file (item->data.pixmap.files[0], NULL);
+ req->width = gdk_pixbuf_get_width (svg);
+ req->height = gdk_pixbuf_get_height (svg);
+ g_object_unref (svg);
+ }
+
+ if (item->item_type == GREETER_ITEM_TYPE_BUTTON)
+ {
+#define ITEM_BUTTON_MIN_RECOMMANDED_WIDTH_OFFSET 15
+#define ITEM_BUTTON_MIN_RECOMMANDED_HEIGHT_OFFSET 10
+ PangoLayout *layout;
+ int pango_width, pango_height;
+ int pix_width, pix_height;
+
+ GtkWidget *dummy_w = gtk_button_new ();
+
+ layout = gtk_widget_create_pango_layout (dummy_w, item->data.text.orig_text);
+
+ pango_layout_get_size (layout, &pango_width, &pango_height);
+
+ pix_height = PANGO_PIXELS (pango_height) + ITEM_BUTTON_MIN_RECOMMANDED_HEIGHT_OFFSET;
+ pix_width = PANGO_PIXELS (pango_width) + ITEM_BUTTON_MIN_RECOMMANDED_WIDTH_OFFSET;
+
+ if (pix_width > item->parent->box_min_width)
+ req->width = pix_width;
+ else
+ req->width = item->parent->box_min_width;
+
+ if (pix_height > item->parent->box_min_height)
+ req->height = pix_height;
+ else
+ req->height = item->parent->box_min_height;
+ }
+
+ if (req->width > 0 && req->height > 0)
+ {
+ if (item->width_type == GREETER_ITEM_SIZE_SCALE && set_height > 0)
+ set_width = (req->width * set_height) / req->height;
+ else if (item->height_type == GREETER_ITEM_SIZE_SCALE && set_width > 0)
+ set_height = (req->height * set_width) / req->width;
+ }
+
+ if (set_width > 0)
+ req->width = set_width;
+ if (set_height > 0)
+ req->height = set_height;
+
+ *requisition_out = item->requisition;
+ item->has_requisition = TRUE;
+}
+
+
+
+void
+greeter_layout (GreeterItemInfo *root_item,
+ GnomeCanvas *canvas)
+{
+ root_item->allocation.x = 0;
+ root_item->allocation.y = 0;
+ root_item->allocation.width = root_item->width;
+ root_item->allocation.height = root_item->height;
+
+ greeter_size_allocate_fixed (root_item,
+ root_item->fixed_children,
+ canvas);
+}
diff --git a/trunk/gui/greeter/greeter_geometry.h b/trunk/gui/greeter/greeter_geometry.h
new file mode 100644
index 00000000..182ef9e9
--- /dev/null
+++ b/trunk/gui/greeter/greeter_geometry.h
@@ -0,0 +1,27 @@
+/* GDM - The GNOME Display Manager
+ * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
+ *
+ * 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 GREETER_GEOMETRY_H
+#define GREETER_GEOMETRY_H
+
+#include "greeter_item.h"
+
+void greeter_layout (GreeterItemInfo *root_item,
+ GnomeCanvas *canvas);
+
+#endif
diff --git a/trunk/gui/greeter/greeter_item.c b/trunk/gui/greeter/greeter_item.c
new file mode 100644
index 00000000..b6838114
--- /dev/null
+++ b/trunk/gui/greeter/greeter_item.c
@@ -0,0 +1,249 @@
+/* GDM - The GNOME Display Manager
+ * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
+ *
+ * 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
+ */
+
+#include "config.h"
+
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "gdm.h"
+#include "gdmwm.h"
+#include "gdmconfig.h"
+#include "gdmcommon.h"
+#include "misc.h"
+
+#include "gdm-common.h"
+#include "gdm-daemon-config-keys.h"
+
+#include "greeter_item.h"
+#include "greeter_configuration.h"
+
+extern gboolean GdmHaltFound;
+extern gboolean GdmRebootFound;
+extern gboolean GdmCustomCmdFound;
+extern gboolean *GdmCustomCmdsFound;
+extern gboolean GdmSuspendFound;
+extern gboolean GdmConfiguratorFound;
+
+GreeterItemInfo *
+greeter_item_info_new (GreeterItemInfo *parent,
+ GreeterItemType type)
+{
+ GreeterItemInfo *info;
+ int i;
+
+ info = g_new0 (GreeterItemInfo, 1);
+
+ info->item_type = type;
+ info->parent = parent;
+
+ info->anchor = GTK_ANCHOR_NW;
+ info->x_type = GREETER_ITEM_POS_UNSET;
+ info->y_type = GREETER_ITEM_POS_UNSET;
+ info->width_type = GREETER_ITEM_SIZE_UNSET;
+ info->height_type = GREETER_ITEM_SIZE_UNSET;
+
+ if (type != GREETER_ITEM_TYPE_LIST)
+ {
+ for (i=0; i< GREETER_ITEM_STATE_MAX; i++)
+ {
+ /* these happen to coincide for all
+ items but list */
+ info->data.rect.alphas[i] = 0xff;
+ }
+ }
+
+ info->box_orientation = GTK_ORIENTATION_VERTICAL;
+
+ info->state = GREETER_ITEM_STATE_NORMAL;
+ info->base_state = GREETER_ITEM_STATE_NORMAL;
+
+ info->show_modes = GREETER_ITEM_SHOW_EVERYWHERE;
+
+ info->canvasbutton = FALSE;
+ info->gtkbutton = FALSE;
+ info->background = FALSE;
+
+ if (GREETER_ITEM_TYPE_IS_TEXT (info))
+ {
+ info->data.text.max_width = 0xffff;
+ info->data.text.max_screen_percent_width = 90;
+ info->data.text.real_max_width = 0;
+ info->data.text.menubar= NULL;
+ }
+
+ return info;
+}
+
+void
+greeter_item_info_free (GreeterItemInfo *info)
+{
+ int i;
+ GList *list;
+
+ for (i = 0; i < GREETER_ITEM_STATE_MAX; i++)
+ {
+ if (GREETER_ITEM_TYPE_IS_PIXMAP (info))
+ {
+ if (info->data.pixmap.pixbufs[i] != NULL)
+ g_object_unref (G_OBJECT (info->data.pixmap.pixbufs[i]));
+ if (info->data.pixmap.files[i] != NULL)
+ g_free (info->data.pixmap.files[i]);
+ }
+ else if (GREETER_ITEM_TYPE_IS_TEXT (info))
+ {
+ if (info->data.text.fonts[i] != NULL)
+ pango_font_description_free (info->data.text.fonts[i]);
+ }
+ }
+
+ list = info->fixed_children;
+ info->fixed_children = NULL;
+ g_list_foreach (list, (GFunc) greeter_item_info_free, NULL);
+ g_list_free (list);
+
+ list = info->box_children;
+ info->box_children = NULL;
+ g_list_foreach (list, (GFunc) greeter_item_info_free, NULL);
+ g_list_free (list);
+
+ if (GREETER_ITEM_TYPE_IS_TEXT (info))
+ g_free (info->data.text.orig_text);
+
+ /* FIXME: what about custom list items! */
+
+ g_free (info->id);
+ g_free (info->show_type);
+
+ memset (info, 0, sizeof (GreeterItemInfo));
+ g_free (info);
+}
+
+void
+greeter_item_update_text (GreeterItemInfo *info)
+{
+ char *text;
+ if (info && info->item &&
+ GNOME_IS_CANVAS_TEXT (info->item) &&
+ GREETER_ITEM_TYPE_IS_TEXT (info))
+ {
+ text = gdm_common_expand_text (info->data.text.orig_text);
+
+ g_object_set (G_OBJECT (info->item),
+ "markup", text,
+ NULL);
+
+ g_free (text);
+ }
+
+}
+
+gboolean
+greeter_item_is_visible (GreeterItemInfo *info)
+{
+ static gboolean checked = FALSE;
+ static gboolean GDM_IS_LOCAL = FALSE;
+ static gboolean GDM_FLEXI_SERVER = FALSE;
+ gboolean sysmenu = FALSE;
+ gint i = 0;
+
+ if ( ! checked)
+ {
+ if (g_getenv ("GDM_IS_LOCAL") != NULL)
+ GDM_IS_LOCAL = TRUE;
+ if (g_getenv ("GDM_FLEXI_SERVER") != NULL)
+ GDM_FLEXI_SERVER = TRUE;
+ }
+
+ if (GDM_IS_LOCAL && ! GDM_FLEXI_SERVER &&
+ ! (info->show_modes & GREETER_ITEM_SHOW_CONSOLE_FIXED))
+ return FALSE;
+ if (GDM_IS_LOCAL && GDM_FLEXI_SERVER &&
+ ! (info->show_modes & GREETER_ITEM_SHOW_CONSOLE_FLEXI))
+ return FALSE;
+ if ( ! GDM_IS_LOCAL && GDM_FLEXI_SERVER &&
+ ! (info->show_modes & GREETER_ITEM_SHOW_REMOTE_FLEXI))
+ return FALSE;
+ if ( ! GDM_IS_LOCAL && ! GDM_FLEXI_SERVER &&
+ ! (info->show_modes & GREETER_ITEM_SHOW_REMOTE))
+ return FALSE;
+
+ if ((gdm_wm_screen.width < info->minimum_required_screen_width) ||
+ (gdm_wm_screen.height < info->minimum_required_screen_height))
+ return FALSE;
+
+ sysmenu = gdm_config_get_bool (GDM_KEY_SYSTEM_MENU);
+
+ /*
+ * Disable Configuration if using accessibility (AddGtkModules) since
+ * using it with accessibility causes a hang.
+ */
+ if (( ! gdm_config_get_bool (GDM_KEY_CONFIG_AVAILABLE) ||
+ gdm_config_get_bool (GDM_KEY_ADD_GTK_MODULES) ||
+ ! sysmenu ||
+ ! GdmConfiguratorFound) &&
+ (info->show_type != NULL &&
+ strcmp (info->show_type, "config") == 0))
+ return FALSE;
+
+ if (( ! gdm_config_get_bool (GDM_KEY_CHOOSER_BUTTON) || ! sysmenu) &&
+ (info->show_type != NULL &&
+ strcmp (info->show_type, "chooser") == 0))
+ return FALSE;
+
+ if ( ! sysmenu && info->show_type != NULL &&
+ strcmp (info->show_type, "system") == 0)
+ return FALSE;
+
+ if (( ! sysmenu || ! GdmHaltFound) &&
+ (info->show_type != NULL &&
+ strcmp (info->show_type, "halt") == 0))
+ return FALSE;
+ if (( ! sysmenu || ! GdmRebootFound) &&
+ (info->show_type != NULL &&
+ strcmp (info->show_type, "reboot") == 0))
+ return FALSE;
+ if (( ! sysmenu || ! GdmSuspendFound) &&
+ (info->show_type != NULL &&
+ strcmp (info->show_type, "suspend") == 0))
+ return FALSE;
+
+ for (i = 0; i < GDM_CUSTOM_COMMAND_MAX; i++) {
+ gchar * key_string = g_strdup_printf ("custom_cmd%d", i);
+ if (( ! sysmenu || ! GdmCustomCmdsFound[i]) &&
+ (info->show_type != NULL &&
+ strcmp (info->show_type, key_string) == 0)) {
+ g_free (key_string);
+ return FALSE;
+ }
+ g_free (key_string);
+ }
+
+ if (( ! gdm_config_get_bool (GDM_KEY_TIMED_LOGIN_ENABLE) ||
+ ve_string_empty (gdm_config_get_string (GDM_KEY_TIMED_LOGIN)) ||
+ NULL == g_getenv("GDM_TIMED_LOGIN_OK")) &&
+ (info->show_type != NULL &&
+ strcmp (info->show_type, "timed") == 0))
+ return FALSE;
+
+ return TRUE;
+}
diff --git a/trunk/gui/greeter/greeter_item.h b/trunk/gui/greeter/greeter_item.h
new file mode 100644
index 00000000..c72b5424
--- /dev/null
+++ b/trunk/gui/greeter/greeter_item.h
@@ -0,0 +1,231 @@
+/* GDM - The GNOME Display Manager
+ * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
+ *
+ * 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 GREETER_ITEM_H
+#define GREETER_ITEM_H
+
+#include <libgnomecanvas/libgnomecanvas.h>
+
+typedef struct _GreeterItemInfo GreeterItemInfo;
+typedef struct _GreeterItemListItem GreeterItemListItem;
+typedef enum _GreeterItemState GreeterItemState;
+typedef enum _GreeterItemType GreeterItemType;
+typedef enum _GreeterItemSizeType GreeterItemSizeType;
+typedef enum _GreeterItemPosType GreeterItemPosType;
+typedef enum _GreeterItemShowModes GreeterItemShowModes;
+
+/* Make sure to adjust the bitfield in the structure if
+ you make this larger */
+enum _GreeterItemState {
+ GREETER_ITEM_STATE_NORMAL,
+ GREETER_ITEM_STATE_PRELIGHT,
+ GREETER_ITEM_STATE_ACTIVE,
+ GREETER_ITEM_STATE_MAX
+};
+
+/* Make sure to adjust the bitfield in the structure if
+ you make this larger */
+enum _GreeterItemType {
+ GREETER_ITEM_TYPE_RECT,
+ GREETER_ITEM_TYPE_SVG,
+ GREETER_ITEM_TYPE_PIXMAP,
+ GREETER_ITEM_TYPE_LABEL,
+ GREETER_ITEM_TYPE_ENTRY,
+ GREETER_ITEM_TYPE_LIST,
+ GREETER_ITEM_TYPE_BUTTON
+};
+
+/* Make sure to adjust the bitfield in the structure if
+ you make this larger */
+enum _GreeterItemSizeType {
+ GREETER_ITEM_SIZE_UNSET,
+ GREETER_ITEM_SIZE_ABSOLUTE,
+ GREETER_ITEM_SIZE_RELATIVE,
+ GREETER_ITEM_SIZE_BOX,
+ GREETER_ITEM_SIZE_SCALE
+};
+
+/* Make sure to adjust the bitfield in the structure if
+ you make this larger */
+enum _GreeterItemPosType {
+ GREETER_ITEM_POS_UNSET,
+ GREETER_ITEM_POS_ABSOLUTE,
+ GREETER_ITEM_POS_RELATIVE
+};
+
+/* Make sure to adjust the bitfield in the structure if
+ you make this larger */
+enum _GreeterItemShowModes {
+ GREETER_ITEM_SHOW_EVERYWHERE = 0xf,
+ GREETER_ITEM_SHOW_NOWHERE = 0,
+ GREETER_ITEM_SHOW_CONSOLE_FIXED = 1<<0,
+ GREETER_ITEM_SHOW_CONSOLE = (1<<0) | (1<<1),
+ GREETER_ITEM_SHOW_CONSOLE_FLEXI = 1<<1,
+ GREETER_ITEM_SHOW_REMOTE_FLEXI = 1<<2,
+ GREETER_ITEM_SHOW_FLEXI = (1<<1) | (1<<2),
+ GREETER_ITEM_SHOW_REMOTE = 1<<3
+};
+
+struct _GreeterItemInfo {
+ GreeterItemInfo *parent;
+
+ GtkAnchorType anchor;
+ float x;
+ float y;
+ float width;
+ float height;
+
+ int minimum_required_screen_width;
+ int minimum_required_screen_height;
+
+ GreeterItemPosType x_type:2;
+ GreeterItemPosType y_type:2;
+ GreeterItemSizeType width_type:4;
+ GreeterItemSizeType height_type:4;
+ guint x_negative:1; /* needed for -0 */
+ guint y_negative:1; /* needed for -0 */
+
+ /* For packed items */
+ guint expand:1;
+
+ /* The item type */
+ GreeterItemType item_type:4;
+
+ GreeterItemShowModes show_modes:4;
+
+ /* Runtime state: */
+ GreeterItemState state:2;
+ GreeterItemState base_state:2;
+ guint mouse_down:1;
+ guint mouse_over:1;
+
+ /* box flags */
+ guint box_homogeneous:1;
+
+ /* is a canvas rectangle that acts like a button */
+ /* (see the my_button comment) */
+ guint canvasbutton:1;
+
+ /* is a real GTK button (not the fake canvas button) */
+ guint gtkbutton:1;
+
+ /* item is used to draw background */
+ guint background:1;
+
+ /* geometry handling: */
+ guint has_requisition:1;
+ GtkRequisition requisition;
+ GtkAllocation allocation;
+
+ /* Button can propagate states and collect states from underlying items,
+ * it should be a parent of this item */
+ GreeterItemInfo *my_button;
+
+ char *show_type; /* timed, system, config, chooser, halt, suspend, reboot */
+
+ char *id;
+
+ GList *box_children;
+ GtkOrientation box_orientation;
+ guint16 box_x_padding;
+ guint16 box_y_padding;
+ guint16 box_min_width;
+ guint16 box_min_height;
+ guint16 box_spacing;
+
+ /* Container data */
+ GList *fixed_children;
+
+ union {
+ /* Note: we want to have alphas, colors and have_color coincide for
+ * all types that have it */
+#define GREETER_ITEM_TYPE_IS_TEXT(info) ((info)->item_type == GREETER_ITEM_TYPE_LABEL || (info)->item_type == GREETER_ITEM_TYPE_ENTRY)
+ struct {
+ guint8 alphas[GREETER_ITEM_STATE_MAX];
+ guint32 colors[GREETER_ITEM_STATE_MAX];
+
+ guint8 have_color; /* this is a bitfield since these are
+ true/false values */
+
+ PangoFontDescription *fonts[GREETER_ITEM_STATE_MAX];
+ char *orig_text;
+ guint16 max_width;
+ guint8 max_screen_percent_width;
+ guint16 real_max_width;
+ GtkWidget *menubar;
+ } text; /* text and entry (entry only uses fonts) */
+
+#define GREETER_ITEM_TYPE_IS_PIXMAP(info) ((info)->item_type == GREETER_ITEM_TYPE_PIXMAP || (info)->item_type == GREETER_ITEM_TYPE_SVG)
+ struct {
+ guint8 alphas[GREETER_ITEM_STATE_MAX];
+ guint32 tints[GREETER_ITEM_STATE_MAX];
+ guint8 have_tint; /* this is a bitfield since these are
+ true/false values */
+
+ char *files[GREETER_ITEM_STATE_MAX];
+ GdkPixbuf *pixbufs[GREETER_ITEM_STATE_MAX];
+ } pixmap;
+
+#define GREETER_ITEM_TYPE_IS_LIST(info) ((info)->item_type == GREETER_ITEM_TYPE_LIST)
+ struct {
+ char *icon_color;
+ char *label_color;
+ /* If this is a custom list, then these are the items
+ to pick from */
+ GList *items;
+ gboolean combo_type;
+ } list;
+
+#define GREETER_ITEM_TYPE_IS_RECT(info) ((info)->item_type == GREETER_ITEM_TYPE_RECT)
+ struct {
+ guint8 alphas[GREETER_ITEM_STATE_MAX];
+ guint32 colors[GREETER_ITEM_STATE_MAX];
+
+ guint8 have_color; /* this is a bitfield since these are
+ true/false values */
+ } rect;
+ } data;
+
+ guint8 have_state; /* this is a bitfield since these are
+ true/false values */
+
+ /* Canvas data: */
+ GnomeCanvasItem *item;
+ GnomeCanvasGroup *group_item;
+};
+
+struct _GreeterItemListItem {
+ char *id;
+ char *text;
+};
+
+gint greeter_item_event_handler (GnomeCanvasItem *item,
+ GdkEvent *event,
+ gpointer data);
+
+GreeterItemInfo *greeter_item_info_new (GreeterItemInfo *parent,
+ GreeterItemType type);
+void greeter_item_info_free (GreeterItemInfo *info);
+
+char *greeter_item_expand_text (const char *text);
+
+void greeter_item_update_text (GreeterItemInfo *info);
+
+gboolean greeter_item_is_visible (GreeterItemInfo *info);
+
+#endif /* GREETER_ITEM_H */
diff --git a/trunk/gui/greeter/greeter_item_capslock.c b/trunk/gui/greeter/greeter_item_capslock.c
new file mode 100644
index 00000000..385c0374
--- /dev/null
+++ b/trunk/gui/greeter/greeter_item_capslock.c
@@ -0,0 +1,133 @@
+/* GDM - The GNOME Display Manager
+ * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
+ *
+ * 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
+ */
+
+#include "config.h"
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <gdk/gdkkeysyms.h>
+#include <string.h>
+#include <gdk/gdkx.h>
+#include <X11/XKBlib.h>
+
+#include "greeter_parser.h"
+#include "greeter_item_capslock.h"
+
+static gboolean caps_lock_state = FALSE;
+
+static Display *
+get_parent_display (void)
+{
+ static gboolean tested = FALSE;
+ static Display *dsp = NULL;
+
+ if (tested)
+ return dsp;
+
+ tested = TRUE;
+
+ if (g_getenv ("GDM_PARENT_DISPLAY") != NULL)
+ {
+ char *old_xauth = g_strdup (g_getenv ("XAUTHORITY"));
+ if (g_getenv ("GDM_PARENT_XAUTHORITY") != NULL)
+ {
+ g_setenv ("XAUTHORITY",
+ g_getenv ("GDM_PARENT_XAUTHORITY"), TRUE);
+ }
+ dsp = XOpenDisplay (g_getenv ("GDM_PARENT_DISPLAY"));
+ if (old_xauth != NULL)
+ g_setenv ("XAUTHORITY", old_xauth, TRUE);
+ else
+ g_unsetenv ("XAUTHORITY");
+ g_free (old_xauth);
+ }
+
+ return dsp;
+}
+
+gboolean
+greeter_is_capslock_on (void)
+{
+ XkbStateRec states;
+ Display *dsp;
+
+ /* HACK! incredible hack, if this is set we get
+ * indicator state from the parent display, since we must be inside an
+ * Xnest */
+ dsp = get_parent_display ();
+ if (dsp == NULL)
+ dsp = GDK_DISPLAY ();
+
+ if (XkbGetState (dsp, XkbUseCoreKbd, &states) != Success)
+ return FALSE;
+
+ return (states.locked_mods & LockMask) != 0;
+}
+
+
+static void
+capslock_update (gboolean new_state)
+{
+ GreeterItemInfo *info;
+ GnomeCanvasItem *item;
+
+ caps_lock_state = new_state;
+
+ info = greeter_lookup_id ("caps-lock-warning");
+
+ if (info)
+ {
+ if (info->group_item != NULL)
+ item = GNOME_CANVAS_ITEM (info->group_item);
+ else
+ item = info->item;
+
+ if (caps_lock_state)
+ {
+ gnome_canvas_item_show (item);
+ }
+ else
+ {
+ gnome_canvas_item_hide (item);
+ }
+ }
+}
+
+static gboolean
+cl_key_press_event (GtkWidget *widget, GdkEventKey *key, gpointer data)
+{
+ gboolean new_state;
+
+ new_state = greeter_is_capslock_on ();
+ if (new_state != caps_lock_state)
+ capslock_update (new_state);
+
+ return FALSE;
+}
+
+
+gboolean
+greeter_item_capslock_setup (GtkWidget *window)
+{
+ capslock_update (greeter_is_capslock_on ());
+
+ g_signal_connect (G_OBJECT (window), "key_press_event",
+ G_CALLBACK (cl_key_press_event), NULL);
+ return TRUE;
+}
+
diff --git a/trunk/gui/greeter/greeter_item_capslock.h b/trunk/gui/greeter/greeter_item_capslock.h
new file mode 100644
index 00000000..089ce591
--- /dev/null
+++ b/trunk/gui/greeter/greeter_item_capslock.h
@@ -0,0 +1,27 @@
+/* GDM - The GNOME Display Manager
+ * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
+ *
+ * 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 __GREETER_ITEM_CAPSLOCK_H__
+#define __GREETER_ITEM_CAPSLOCK_H__
+
+#include "greeter_item.h"
+
+gboolean greeter_item_capslock_setup (GtkWidget *window);
+gboolean greeter_is_capslock_on (void);
+
+#endif
diff --git a/trunk/gui/greeter/greeter_item_clock.c b/trunk/gui/greeter/greeter_item_clock.c
new file mode 100644
index 00000000..0779f9ab
--- /dev/null
+++ b/trunk/gui/greeter/greeter_item_clock.c
@@ -0,0 +1,68 @@
+/* GDM - The GNOME Display Manager
+ * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
+ *
+ * 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
+ */
+
+#include "config.h"
+
+#include <gtk/gtk.h>
+#include <time.h>
+#include "greeter_item_clock.h"
+#include "greeter_parser.h"
+
+static gboolean
+update_clock (gpointer data)
+{
+ GreeterItemInfo *info = data;
+ struct tm *the_tm;
+ time_t the_time;
+ gint time_til_next_min;
+
+ greeter_item_update_text (info);
+
+ time (&the_time);
+ the_tm = localtime (&the_time);
+ /* account for leap seconds */
+ time_til_next_min = 60 - the_tm->tm_sec;
+ time_til_next_min = (time_til_next_min>=0?time_til_next_min:0);
+
+ g_timeout_add (time_til_next_min*1000, update_clock, info);
+
+ return FALSE;
+}
+
+
+gboolean
+greeter_item_clock_setup (void)
+{
+ GreeterItemInfo *info;
+
+ info = greeter_lookup_id ("clock");
+ if (info)
+ update_clock (info);
+
+ return TRUE;
+}
+
+void
+greeter_item_clock_update (void)
+{
+ GreeterItemInfo *info;
+
+ info = greeter_lookup_id ("clock");
+ if (info)
+ greeter_item_update_text (info);
+}
diff --git a/trunk/gui/greeter/greeter_item_clock.h b/trunk/gui/greeter/greeter_item_clock.h
new file mode 100644
index 00000000..d2af2bf9
--- /dev/null
+++ b/trunk/gui/greeter/greeter_item_clock.h
@@ -0,0 +1,27 @@
+/* GDM - The GNOME Display Manager
+ * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
+ *
+ * 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 __GREETER_ITEM_CLOCK_H__
+#define __GREETER_ITEM_CLOCK_H__
+
+#include "greeter_item.h"
+
+gboolean greeter_item_clock_setup (void);
+void greeter_item_clock_update (void);
+
+#endif
diff --git a/trunk/gui/greeter/greeter_item_customlist.c b/trunk/gui/greeter/greeter_item_customlist.c
new file mode 100644
index 00000000..6ab9cccd
--- /dev/null
+++ b/trunk/gui/greeter/greeter_item_customlist.c
@@ -0,0 +1,667 @@
+/* GDM - The GNOME Display Manager
+ * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
+ *
+ * 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
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <glib/gi18n.h>
+#include <gtk/gtk.h>
+
+#include "gdm.h"
+#include "gdmconfig.h"
+#include "gdmsession.h"
+#include "gdmlanguages.h"
+
+#include "gdm-common.h"
+#include "gdm-daemon-config-keys.h"
+#include "gdm-socket-protocol.h"
+
+#include "greeter_item.h"
+#include "greeter_configuration.h"
+#include "greeter_item_customlist.h"
+#include "greeter_parser.h"
+#include "greeter_session.h"
+
+#define LAST_LANGUAGE "Last"
+
+/*
+ * Keep track of the session/language widgets so we can
+ * set their values when the session/language dialogs are
+ * changed.
+ */
+static GtkWidget *session_widget = NULL;
+static GtkWidget *language_widget = NULL;
+static gchar *session_key = NULL;
+
+extern GList *sessions;
+extern GHashTable *sessnames;
+
+enum
+{
+ GREETER_LIST_TEXT = 0,
+ GREETER_LIST_ID
+};
+
+/*
+ * This function sets the custom list when the session list has changed in
+ * the session dialog (launched from session button or F10 menu).
+ */
+void
+greeter_custom_set_session (gchar *session)
+{
+ GList *tmp;
+ int i=0;
+
+ /*
+ * Since the sessions are created before the session list is generated,
+ * keep track of the session and set active row when it is setup. This
+ * function will get a NULL when the session is initialized to NULL
+ * at startup, so just return.
+ */
+ if (session == NULL)
+ return;
+ else
+ {
+ /*
+ * If the session_widget hasn't been setup yet (which it won't be when
+ * the greeter_sessioninit function is called, then just store the
+ * session and we'll set the value when the combo box is initialized later.
+ */
+ g_free (session_key);
+ session_key = g_strdup (session);
+ }
+
+ /* Do nothing if there is no session widget */
+ if (session_widget == NULL)
+ return;
+
+ /* Last isn't in the session list, so handle separate. */
+ if (strcmp (session, LAST_SESSION) == 0)
+ {
+ if (GTK_IS_COMBO_BOX (session_widget))
+ {
+ gtk_combo_box_set_active (GTK_COMBO_BOX (session_widget), 0);
+ }
+ else if (GTK_IS_SCROLLED_WINDOW (session_widget) &&
+ GTK_IS_TREE_VIEW (GTK_BIN (session_widget)->child))
+ {
+ GtkTreeView *tv = GTK_TREE_VIEW (GTK_BIN (session_widget)->child);
+ GtkTreeModel *tm = gtk_tree_view_get_model (tv);
+ GtkTreeSelection *selection = gtk_tree_view_get_selection (tv);
+ GtkTreeIter loopiter;
+
+ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tm), &loopiter))
+ gtk_tree_selection_select_iter (selection, &loopiter);
+ }
+ }
+
+ /*
+ * Handle for either combo box or list style, depending on which is being
+ * used.
+ . */
+ if (GTK_IS_COMBO_BOX (session_widget))
+ {
+ for (tmp = sessions; tmp != NULL; tmp = tmp->next)
+ {
+ char *file;
+
+ i++;
+ file = tmp->data;
+ if (strcmp (session, file) == 0)
+ {
+ gtk_combo_box_set_active (GTK_COMBO_BOX (session_widget), i);
+ break;
+ }
+ }
+ }
+ else if (GTK_IS_SCROLLED_WINDOW (session_widget) &&
+ GTK_IS_TREE_VIEW (GTK_BIN (session_widget)->child))
+ {
+ GtkTreeView *tv = GTK_TREE_VIEW (GTK_BIN (session_widget)->child);
+ GtkTreeModel *tm = gtk_tree_view_get_model (tv);
+ GtkTreeSelection *selection = gtk_tree_view_get_selection (tv);
+ GtkTreeIter loopiter;
+
+ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tm), &loopiter))
+ {
+ do
+ {
+ char *file;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (tm), &loopiter, GREETER_LIST_ID, &file, -1);
+ if (file != NULL && strcmp (session, file) == 0)
+ {
+ GtkTreePath *path = gtk_tree_model_get_path (tm, &loopiter);
+
+ gtk_tree_selection_select_iter (selection, &loopiter);
+ gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (tv),
+ path, NULL,
+ FALSE, 0.0, 0.0);
+ gtk_tree_path_free (path);
+ break;
+ }
+ } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (tm), &loopiter));
+ }
+ }
+}
+
+/*
+ * This function sets the custom list when the language list has changed in
+ * the language dialog (launched from language button or F10 menu).
+ */
+void
+lang_set_custom_callback (gchar *language)
+{
+ GtkListStore *lang_model = gdm_lang_get_model ();
+ GtkTreeIter iter;
+ gboolean valid;
+ char *locale_name;
+ int i=0;
+
+ /* Do nothing if there is no language widget */
+ if (language_widget == NULL)
+ return;
+
+ /*
+ * Handle for either combo box or list style, depending on which is being
+ * used.
+ . */
+ if (GTK_IS_COMBO_BOX (language_widget))
+ {
+ valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (lang_model),
+ &iter);
+ while (valid)
+ {
+ gtk_tree_model_get (GTK_TREE_MODEL (lang_model), &iter,
+ LOCALE_COLUMN, &locale_name, -1);
+
+ if (strcmp (language, locale_name) == 0)
+ {
+ gtk_combo_box_set_active (GTK_COMBO_BOX (language_widget), i);
+ break;
+ }
+ valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (lang_model), &iter);
+ i++;
+ }
+ }
+ else if (GTK_IS_SCROLLED_WINDOW (language_widget) &&
+ GTK_IS_TREE_VIEW (GTK_BIN (language_widget)->child))
+ {
+ GtkTreeView *tv = GTK_TREE_VIEW (GTK_BIN (language_widget)->child);
+ GtkTreeModel *tm = gtk_tree_view_get_model (tv);
+ GtkTreeSelection *selection = gtk_tree_view_get_selection (tv);
+ GtkTreeIter loopiter;
+
+ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tm), &loopiter))
+ {
+ do
+ {
+ char *locale_file;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (tm), &loopiter, GREETER_LIST_ID, &locale_file, -1);
+ if (locale_file != NULL && strcmp (language, locale_file) == 0)
+ {
+ GtkTreePath *path = gtk_tree_model_get_path (tm, &loopiter);
+
+ gtk_tree_selection_select_iter (selection, &loopiter);
+ gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (tv),
+ path, NULL,
+ FALSE, 0.0, 0.0);
+ gtk_tree_path_free (path);
+ break;
+ }
+ } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (tm), &loopiter));
+ }
+ }
+}
+
+/* Helper function to set custom list values */
+static void
+populate_list (GtkTreeModel *tm, GtkTreeSelection *selection, GList *list_items)
+{
+ GList *li;
+
+ for (li = list_items; li != NULL; li = li->next)
+ {
+ GtkTreeIter iter = {0};
+ GreeterItemListItem *litem = li->data;
+ gtk_list_store_append (GTK_LIST_STORE (tm), &iter);
+ gtk_list_store_set (GTK_LIST_STORE (tm), &iter,
+ GREETER_LIST_TEXT, litem->text,
+ GREETER_LIST_ID, litem->id,
+ -1);
+ }
+}
+
+/* Helper function to set session values */
+static void
+populate_session (GObject * object)
+{
+ GList *tmp;
+
+ /* Last isn't in the session list, so add separate. */
+ if (GTK_IS_COMBO_BOX (object))
+ gtk_combo_box_append_text (GTK_COMBO_BOX (object), _("Last session"));
+ else if (GTK_IS_TREE_MODEL (object))
+ {
+ GtkTreeIter loopiter;
+ GtkTreeModel *tm = GTK_TREE_MODEL (object);
+
+ gtk_list_store_append (GTK_LIST_STORE (tm), &loopiter);
+
+ gtk_list_store_set (GTK_LIST_STORE (tm), &loopiter,
+ GREETER_LIST_TEXT, _("Last session"),
+ GREETER_LIST_ID, LAST_SESSION,
+ -1);
+ }
+
+ /* Loop through the sessions and set the custom list values. */
+ for (tmp = sessions; tmp != NULL; tmp = tmp->next)
+ {
+ GdmSession *session;
+ char *file;
+
+ file = (char *) tmp->data;
+ session = g_hash_table_lookup (sessnames, file);
+
+ if (GTK_IS_COMBO_BOX (object))
+ {
+ if (session->clearname != NULL)
+ gtk_combo_box_append_text (GTK_COMBO_BOX (object), (session->clearname));
+ else
+ gtk_combo_box_append_text (GTK_COMBO_BOX (object), (session->name));
+ }
+ else if (GTK_IS_TREE_MODEL (object))
+ {
+ GtkTreeIter loopiter;
+ GtkTreeModel *tm = GTK_TREE_MODEL (object);
+ gchar *to_display;
+
+ gtk_list_store_append (GTK_LIST_STORE (tm), &loopiter);
+ if (session->clearname != NULL)
+ to_display = session->clearname;
+ else
+ to_display = session->name;
+
+ gtk_list_store_set (GTK_LIST_STORE (tm), &loopiter,
+ GREETER_LIST_TEXT, to_display,
+ GREETER_LIST_ID, file,
+ -1);
+ }
+ }
+
+ /*
+ * Set the session if one exists, this will calback and set the
+ * custom list
+ */
+ if (session_key != NULL)
+ greeter_custom_set_session (session_key);
+}
+
+/* Helper function to set language values */
+static void
+populate_language (GObject *object)
+{
+ GtkListStore *lang_model = gdm_lang_get_model ();
+ GtkTreeIter iter;
+ char *name, *untranslated, *lang_display_name, *locale_name;
+ gboolean valid;
+
+ valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (lang_model),
+ &iter);
+ while (valid)
+ {
+ gtk_tree_model_get (GTK_TREE_MODEL (lang_model), &iter,
+ TRANSLATED_NAME_COLUMN, &name,
+ UNTRANSLATED_NAME_COLUMN, &untranslated,
+ LOCALE_COLUMN, &locale_name, -1);
+
+ if (untranslated)
+ lang_display_name = g_strdup_printf ("%s (%s)", name, untranslated);
+ else
+ lang_display_name = g_strdup (name);
+
+ if (GTK_IS_COMBO_BOX (object))
+ gtk_combo_box_append_text (GTK_COMBO_BOX (object), lang_display_name);
+ else if (GTK_IS_TREE_MODEL (object))
+ {
+ GtkTreeIter loopiter;
+ GtkTreeModel *tm = GTK_TREE_MODEL (object);
+
+ gtk_list_store_append (GTK_LIST_STORE (tm), &loopiter);
+ gtk_list_store_set (GTK_LIST_STORE (tm), &loopiter,
+ GREETER_LIST_TEXT, lang_display_name,
+ GREETER_LIST_ID, locale_name,
+ -1);
+ }
+ valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (lang_model), &iter);
+ }
+}
+
+/* Callback helper function to set session value */
+static void
+combo_session_selected (char *session_val)
+{
+ GList *tmp;
+ char *file;
+
+ /* Last isn't in the session list, so add separate. */
+ if (strcmp (session_val, _("Last session")) == 0)
+ greeter_set_session (LAST_SESSION);
+ else
+ {
+ /*
+ * Loop through the sessions to find the row the
+ * user has selected, and set that session.
+ */
+ for (tmp = sessions; tmp != NULL; tmp = tmp->next)
+ {
+ GdmSession *session;
+ char *name;
+
+ file = tmp->data;
+ session = g_hash_table_lookup (sessnames, file);
+
+ if (session->clearname)
+ name = session->clearname;
+ else
+ name = session->name;
+
+ if (strcmp (name, session_val) == 0)
+ {
+ greeter_set_session (file);
+ break;
+ }
+ }
+ }
+}
+
+/* Callback function for combo style custom lists */
+static void
+combo_selected (GtkComboBox *combo, GreeterItemInfo *item)
+{
+ char *id = NULL;
+ char *file;
+ char *active;
+
+ if (ve_string_empty (item->id))
+ return;
+
+ active = gtk_combo_box_get_active_text (combo);
+
+ if (strcmp (item->id, "session") == 0)
+ {
+ combo_session_selected (active);
+ }
+ else if (strcmp (item->id, "language") == 0)
+ {
+ /*
+ * Since combo boxes can't store the ID value, have to do some
+ * extra work to figure out which row is selected.
+ */
+ GtkListStore *lang_model = gdm_lang_get_model ();
+ GtkTreeIter iter;
+ char *name, *untranslated, *lang_display_name, *locale_name;
+ gboolean valid;
+
+ valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (lang_model),
+ &iter);
+ while (valid)
+ {
+ gtk_tree_model_get (GTK_TREE_MODEL (lang_model), &iter,
+ TRANSLATED_NAME_COLUMN, &name,
+ UNTRANSLATED_NAME_COLUMN, &untranslated,
+ LOCALE_COLUMN, &locale_name, -1);
+
+ if (untranslated)
+ lang_display_name = g_strdup_printf ("%s (%s)", name, untranslated);
+ else
+ lang_display_name = g_strdup (name);
+
+ if (strcmp (lang_display_name, active) == 0)
+ {
+ gdm_lang_set_restart_dialog (locale_name);
+ break;
+ }
+ g_free (lang_display_name);
+ valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (lang_model), &iter);
+ }
+ }
+ else
+ {
+ if (DOING_GDM_DEVELOPMENT)
+ return;
+
+ id = gtk_combo_box_get_active_text (combo);
+ file = g_strdup_printf ("%s/%s.GreeterInfo",
+ ve_sure_string (gdm_config_get_string (GDM_KEY_SERV_AUTHDIR)),
+ ve_sure_string (g_getenv ("DISPLAY")));
+
+ gdm_save_customlist_data (file, item->id, id);
+ }
+}
+
+/* Setup combo sytle custom list */
+static void
+setup_combo_customlist (GtkComboBox *combo, GreeterItemInfo *item)
+{
+ GList *li;
+
+ g_signal_connect (G_OBJECT (combo), "changed",
+ G_CALLBACK (combo_selected), item);
+
+ /* Make sure that focus never leaves username/password entry */
+ gtk_combo_box_set_focus_on_click (combo, FALSE);
+
+ if (strcmp (item->id, "session") == 0)
+ {
+ populate_session (G_OBJECT (combo));
+ /*
+ * Do not select since the session_init will initialize the
+ * value and cause the combo list to get set without needing
+ * to do it here.
+ */
+ }
+ else if (strcmp (item->id, "language") == 0)
+ {
+ populate_language (G_OBJECT (combo));
+ /* Select first */
+ gtk_combo_box_set_active (combo, 0);
+ }
+ else
+ {
+ for (li = item->data.list.items; li != NULL; li = li->next)
+ {
+ GreeterItemListItem *litem = li->data;
+ gtk_combo_box_append_text (combo, litem->text);
+ }
+ /* Select first */
+ gtk_combo_box_set_active (combo, 0);
+ }
+}
+
+/* Callback function for list style custom lists */
+static void
+list_selected (GtkTreeSelection *selection, GreeterItemInfo *item)
+{
+ GtkTreeModel *tm = NULL;
+ GtkTreeIter iter = {0};
+ char *id = NULL;
+ char *file;
+
+ if (ve_string_empty (item->id))
+ return;
+
+ if (gtk_tree_selection_get_selected (selection, &tm, &iter))
+ {
+ gtk_tree_model_get (tm, &iter, GREETER_LIST_ID,
+ &id, -1);
+ }
+
+ /*
+ * Note for session and language we are using the id to store the
+ * value to pass in.
+ */
+ if (strcmp (item->id, "session") == 0)
+ {
+ if (id != NULL)
+ greeter_set_session (id);
+ }
+ else if (strcmp (item->id, "language") == 0)
+ {
+ if (id != NULL)
+ gdm_lang_set_restart_dialog (id);
+ }
+ else
+ {
+ if (DOING_GDM_DEVELOPMENT)
+ return;
+
+ file = g_strdup_printf ("%s/%s.GreeterInfo",
+ ve_sure_string (gdm_config_get_string (GDM_KEY_SERV_AUTHDIR)),
+ ve_sure_string (g_getenv ("DISPLAY")));
+
+ gdm_save_customlist_data (file, item->id, id);
+ }
+}
+
+static gboolean custom_list_release_event (GtkWidget *widget,
+ GdkEventSelection *event,
+ gpointer user_data)
+{
+ GreeterItemInfo *entry_info = greeter_lookup_id ("user-pw-entry");
+
+ /* Make sure that focus never leaves username/password entry */
+ if (entry_info && entry_info->item &&
+ GNOME_IS_CANVAS_WIDGET (entry_info->item) &&
+ GTK_IS_ENTRY (GNOME_CANVAS_WIDGET (entry_info->item)->widget))
+ {
+ GtkWidget *entry = GNOME_CANVAS_WIDGET (entry_info->item)->widget;
+ gtk_widget_grab_focus (entry);
+ }
+ return FALSE;
+}
+
+/* Setup custom list style */
+static void
+setup_customlist (GtkWidget *tv, GreeterItemInfo *item)
+{
+ GtkTreeModel *tm;
+ GtkTreeViewColumn *column;
+ GtkTreeSelection *selection;
+ GtkTreeIter iter = {0};
+
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tv),
+ FALSE);
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tv));
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
+
+ g_signal_connect (selection, "changed",
+ G_CALLBACK (list_selected),
+ item);
+
+ tm = (GtkTreeModel *)gtk_list_store_new (2,
+ G_TYPE_STRING,
+ G_TYPE_STRING);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (tv), tm);
+
+ column = gtk_tree_view_column_new_with_attributes
+ ("Choice",
+ gtk_cell_renderer_text_new (),
+ "text", GREETER_LIST_TEXT,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (tv), column);
+
+ g_signal_connect (tv, "button_release_event",
+ G_CALLBACK (custom_list_release_event),
+ NULL);
+
+ if (strcmp (item->id, "session") == 0)
+ {
+ populate_session (G_OBJECT (tm));
+ /*
+ * Do not select since the session_init will initialize the
+ * value and cause the combo list to get set without needing
+ * to do it here.
+ */
+ }
+ else if (strcmp (item->id, "language") == 0)
+ {
+ populate_language (G_OBJECT (tm));
+
+ /* Select first item */
+ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tm), &iter))
+ gtk_tree_selection_select_iter (selection, &iter);
+ }
+ else
+ {
+ populate_list (tm, selection, item->data.list.items);
+
+ /* Select first item */
+ if (gtk_tree_model_get_iter_first (GTK_TREE_MODEL (tm), &iter))
+ gtk_tree_selection_select_iter (selection, &iter);
+ }
+}
+
+/*
+ * This function initializes all custom lists aside from
+ * the userlist (face browser), which is handled
+ * separately.
+ */
+gboolean
+greeter_item_customlist_setup (void)
+{
+ const GList *custom_items = greeter_custom_items ();
+ const GList *li;
+ for (li = custom_items; li != NULL; li = li->next)
+ {
+ GreeterItemInfo *info = li->data;
+
+ if (info != NULL &&
+ info->item_type == GREETER_ITEM_TYPE_LIST &&
+ info->item != NULL &&
+ GNOME_IS_CANVAS_WIDGET (info->item))
+ {
+ GtkWidget *sw = GNOME_CANVAS_WIDGET (info->item)->widget;
+
+ /*
+ * Store these so that when the values change in the
+ * F10 session/language dialogs, we can easily modify
+ * them.
+ */
+ if (strcmp (info->id, "session") == 0)
+ session_widget = sw;
+ else if (strcmp (info->id, "language") == 0)
+ language_widget = sw;
+
+ /* If combo or list style, process appropriately */
+ if (GTK_IS_SCROLLED_WINDOW (sw) &&
+ GTK_IS_TREE_VIEW (GTK_BIN (sw)->child))
+ {
+ setup_customlist (GTK_BIN (sw)->child, info);
+ }
+ else if (GTK_IS_COMBO_BOX (sw))
+ {
+ setup_combo_customlist (GTK_COMBO_BOX (sw), info);
+ }
+ }
+ }
+ return TRUE;
+}
+
diff --git a/trunk/gui/greeter/greeter_item_customlist.h b/trunk/gui/greeter/greeter_item_customlist.h
new file mode 100644
index 00000000..edcdd735
--- /dev/null
+++ b/trunk/gui/greeter/greeter_item_customlist.h
@@ -0,0 +1,28 @@
+/* GDM - The GNOME Display Manager
+ * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
+ *
+ * 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 __GREETER_ITEM_CUSTOMLIST_H__
+#define __GREETER_ITEM_CUSTOMLIST_H__
+
+#include "greeter_item.h"
+
+gboolean greeter_item_customlist_setup (void);
+void greeter_custom_set_session (gchar *session);
+void lang_set_custom_callback (gchar *language);
+
+#endif
diff --git a/trunk/gui/greeter/greeter_item_pam.c b/trunk/gui/greeter/greeter_item_pam.c
new file mode 100644
index 00000000..59fa1e46
--- /dev/null
+++ b/trunk/gui/greeter/greeter_item_pam.c
@@ -0,0 +1,456 @@
+/* GDM - The GNOME Display Manager
+ * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
+ *
+ * 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
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <gdk/gdkkeysyms.h>
+
+#include "gdm-common.h"
+#include "gdm-socket-protocol.h"
+
+#include "greeter.h"
+#include "greeter_item.h"
+#include "greeter_item_pam.h"
+#include "greeter_item_ulist.h"
+#include "greeter_item_timed.h"
+#include "greeter_parser.h"
+#include "greeter_configuration.h"
+#include "greeter_canvas_item.h"
+#include "gdm.h"
+#include "gdmwm.h"
+#include "gdmcommon.h"
+
+static gboolean messages_to_give = FALSE;
+static gboolean replace_msg = TRUE;
+static guint err_box_clear_handler = 0;
+
+gchar *greeter_current_user = NULL;
+
+gboolean require_quarter = FALSE;
+
+extern gboolean greeter_probably_login_prompt;
+extern GtkButton *gtk_ok_button;
+extern GtkButton *gtk_start_again_button;
+
+static void
+greeter_item_pam_error_set (gboolean display)
+{
+ GreeterItemInfo *info;
+ GnomeCanvasItem *item;
+
+ info = greeter_lookup_id ("pam-error-logo");
+
+ if (info)
+ {
+ if (info->group_item != NULL)
+ item = GNOME_CANVAS_ITEM (info->group_item);
+ else
+ item = info->item;
+
+ if (display)
+ gnome_canvas_item_show (item);
+ else
+ gnome_canvas_item_hide (item);
+ }
+}
+
+void
+greeter_item_pam_set_user (const char *user)
+{
+ g_free (greeter_current_user);
+ greeter_current_user = g_strdup (user);
+ greeter_item_ulist_set_user (user);
+}
+
+static gboolean
+evil (GtkEntry *entry, const char *user)
+{
+ /* do not translate */
+ if (strcmp (user, "Gimme Random Cursor") == 0) {
+ gdm_common_setup_cursor (((rand () >> 3) % (GDK_LAST_CURSOR/2)) * 2);
+ gtk_entry_set_text (GTK_ENTRY (entry), "");
+ return TRUE;
+ /* do not translate */
+ } else if (strcmp (user, "Require Quater") == 0 ||
+ strcmp (user, "Require Quarter") == 0) {
+ /* btw, note that I misspelled quarter before and
+ * thus this checks for Quater as well as Quarter to
+ * keep compatibility which is obviously important for
+ * something like this */
+ require_quarter = TRUE;
+ gtk_entry_set_text (GTK_ENTRY (entry), "");
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+set_text (GreeterItemInfo *info, const char *text)
+{
+ greeter_canvas_item_break_set_string (info,
+ text,
+ FALSE /* markup */,
+ info->data.text.real_max_width,
+ NULL /* width */,
+ NULL /* height */,
+ NULL /* canvas */,
+ info->item);
+}
+
+void
+greeter_item_pam_login (GtkEntry *entry, GreeterItemInfo *info)
+{
+ const char *str;
+ char *tmp;
+ GreeterItemInfo *error_info;
+
+ if (gtk_ok_button != NULL)
+ gtk_widget_set_sensitive (GTK_WIDGET (gtk_ok_button), FALSE);
+ if (gtk_start_again_button != NULL)
+ gtk_widget_set_sensitive (GTK_WIDGET (gtk_start_again_button), FALSE);
+
+ greeter_ignore_buttons (TRUE);
+
+ str = gtk_entry_get_text (GTK_ENTRY (entry));
+ if (greeter_probably_login_prompt &&
+ /* evilness */
+ evil (entry, str))
+ {
+ /* obviously being 100% reliable is not an issue for
+ this test */
+ gtk_entry_set_text (GTK_ENTRY (entry), "");
+ return;
+ }
+
+ if (greeter_probably_login_prompt &&
+ ve_string_empty (str) &&
+ greeter_item_timed_is_timed ())
+ {
+ /* timed interruption */
+ printf ("%c%c%c\n", STX, BEL, GDM_INTERRUPT_TIMED_LOGIN);
+ fflush (stdout);
+ return;
+ }
+
+ gtk_widget_set_sensitive (GTK_WIDGET (entry), FALSE);
+
+ /* clear the err_box */
+ if (err_box_clear_handler > 0)
+ {
+ g_source_remove (err_box_clear_handler);
+ err_box_clear_handler = 0;
+ }
+ error_info = greeter_lookup_id ("pam-error");
+ if (error_info) {
+ greeter_item_pam_error_set (FALSE);
+ set_text (error_info, "");
+ }
+
+ tmp = ve_locale_from_utf8 (str);
+ printf ("%c%s\n", STX, tmp);
+ fflush (stdout);
+ g_free (tmp);
+}
+
+static gboolean
+pam_key_release_event (GtkWidget *entry, GdkEventKey *event, gpointer data)
+{
+ GreeterItemInfo *entry_info = greeter_lookup_id ("user-pw-entry");
+
+ if (entry_info && entry_info->item &&
+ GNOME_IS_CANVAS_WIDGET (entry_info->item) &&
+ GTK_IS_ENTRY (GNOME_CANVAS_WIDGET (entry_info->item)->widget))
+ {
+ const char *login_string;
+ GtkWidget *entry = GNOME_CANVAS_WIDGET (entry_info->item)->widget;
+
+ if ((event->keyval == GDK_Tab ||
+ event->keyval == GDK_KP_Tab) &&
+ (event->state & (GDK_CONTROL_MASK|GDK_MOD1_MASK|GDK_SHIFT_MASK)) == 0)
+ {
+ greeter_item_pam_login (GTK_ENTRY (entry), entry_info);
+ return TRUE;
+ }
+
+ if (gtk_ok_button != NULL)
+ {
+ /*
+ * Set ok button to sensitive only if there are characters in
+ * the entry field
+ */
+ login_string = gtk_entry_get_text (GTK_ENTRY (entry));
+ if (login_string != NULL && login_string[0] != '\0')
+ gtk_widget_set_sensitive (GTK_WIDGET (gtk_ok_button), TRUE);
+ else
+ gtk_widget_set_sensitive (GTK_WIDGET (gtk_ok_button), FALSE);
+ }
+ }
+ return FALSE;
+}
+
+gboolean
+greeter_item_pam_setup (void)
+{
+ GreeterItemInfo *entry_info;
+
+ greeter_item_pam_error_set (FALSE);
+
+ entry_info = greeter_lookup_id ("user-pw-entry");
+ if (entry_info && entry_info->item &&
+ GNOME_IS_CANVAS_WIDGET (entry_info->item) &&
+ GTK_IS_ENTRY (GNOME_CANVAS_WIDGET (entry_info->item)->widget))
+ {
+ GtkWidget *entry = GNOME_CANVAS_WIDGET (entry_info->item)->widget;
+ gtk_widget_grab_focus (entry);
+
+ if ( ! DOING_GDM_DEVELOPMENT)
+ {
+ /* hack. For some reason if we leave it blank,
+ * we'll get a little bit of activity on first keystroke,
+ * this way we get rid of it, it will be cleared for the
+ * first prompt anyway. */
+ gtk_entry_set_text (GTK_ENTRY (entry), "...");
+
+ /* initially insensitive */
+ gtk_widget_set_sensitive (entry, FALSE);
+ }
+
+ g_signal_connect (entry, "activate",
+ G_CALLBACK (greeter_item_pam_login), entry_info);
+ g_signal_connect (G_OBJECT (entry), "key_release_event",
+ G_CALLBACK (pam_key_release_event), NULL);
+ }
+
+ return TRUE;
+}
+
+
+void
+greeter_item_pam_prompt (const char *message,
+ int entry_len,
+ gboolean entry_visible)
+{
+ GreeterItemInfo *conversation_info;
+ GreeterItemInfo *entry_info;
+ GtkWidget *entry;
+
+ conversation_info = greeter_lookup_id ("pam-prompt");
+ entry_info = greeter_lookup_id ("user-pw-entry");
+
+ if (conversation_info)
+ {
+ set_text (conversation_info, message);
+
+ /*
+ * Add Accessibility text for entry field.
+ * Might be nice to set ATK_RELATION_LABEL_FOR, LABELLED_BY between
+ * the label (pam-prompt) and the entry, but gdmgreeter doesn't use real
+ * GTK widgets for text fields. For now, just set the entry field's
+ * name.
+ */
+ if (entry_info != NULL)
+ {
+ GnomeCanvasWidget *item = GNOME_CANVAS_WIDGET (entry_info->item);
+ if (item != NULL)
+ {
+ GtkWidget *widget = item->widget;
+ if (widget != NULL)
+ {
+ AtkObject *atk_widget;
+ atk_widget = gtk_widget_get_accessible (widget);
+ if (atk_widget != NULL)
+ {
+ atk_object_set_name (atk_widget, message);
+ }
+ }
+ }
+ }
+ }
+
+ if (entry_info && entry_info->item &&
+ GNOME_IS_CANVAS_WIDGET (entry_info->item))
+ {
+ entry = GNOME_CANVAS_WIDGET (entry_info->item)->widget;
+
+ gtk_entry_set_visibility (GTK_ENTRY (entry), entry_visible);
+ gtk_widget_set_sensitive (GTK_WIDGET (entry), TRUE);
+ gtk_entry_set_max_length (GTK_ENTRY (entry), entry_len);
+ gtk_entry_set_text (GTK_ENTRY (entry), "");
+ gtk_widget_grab_focus (entry);
+ }
+
+ messages_to_give = FALSE;
+ replace_msg = TRUE;
+}
+
+void
+greeter_item_pam_message (const char *message)
+{
+ GreeterItemInfo *message_info;
+ char *oldtext;
+ char *newtext;
+
+ /* the user has not yet seen messages */
+ messages_to_give = TRUE;
+
+ message_info = greeter_lookup_id ("pam-message");
+
+ if (message_info)
+ {
+ /* HAAAAAAACK. Sometimes pam sends many many messages, SO
+ * we try to collect them until the next prompt or reset or
+ * whatnot */
+ if ( ! replace_msg &&
+ /* empty message is for clearing */
+ ! ve_string_empty (message))
+ {
+ g_object_get (G_OBJECT (message_info->item),
+ "text", &oldtext,
+ NULL);
+ if (strlen (oldtext) > 0)
+ {
+ newtext = g_strdup_printf ("%s\n%s", oldtext, message);
+ set_text (message_info, newtext);
+ g_free (newtext);
+ }
+ else
+ set_text (message_info, message);
+ }
+ else
+ set_text (message_info, message);
+ }
+ replace_msg = FALSE;
+}
+
+
+static gboolean
+error_clear (gpointer data)
+{
+ GreeterItemInfo *error_info = data;
+ err_box_clear_handler = 0;
+
+ set_text (error_info, "");
+ greeter_item_pam_error_set (FALSE);
+
+ return FALSE;
+}
+
+void
+greeter_item_pam_error (const char *message)
+{
+ GreeterItemInfo *error_info;
+
+ /* The message I got from pam had a silly newline
+ * in the beginning. That may make sense for a
+ * terminal based conversation, but it sucks for
+ * us, so skip it.
+ */
+ if (message[0] == '\n')
+ message++;
+
+ error_info = greeter_lookup_id ("pam-error");
+ if (error_info)
+ {
+ set_text (error_info, message);
+
+ if (err_box_clear_handler > 0)
+ g_source_remove (err_box_clear_handler);
+
+ if (strlen (message) == 0)
+ err_box_clear_handler = 0;
+ else
+ err_box_clear_handler = g_timeout_add (30000,
+ error_clear,
+ error_info);
+ greeter_item_pam_error_set (TRUE);
+ }
+}
+
+static GtkWidget *
+hig_dialog_new (GtkWindow *parent,
+ GtkDialogFlags flags,
+ GtkMessageType type,
+ GtkButtonsType buttons,
+ const gchar *primary_message,
+ const gchar *secondary_message)
+{
+ GtkWidget *dialog;
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (parent),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ type,
+ buttons,
+ "%s", primary_message);
+
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ "%s", secondary_message);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), "");
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+ gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 14);
+
+ return dialog;
+}
+
+void
+greeter_item_pam_leftover_messages (void)
+{
+ if (messages_to_give)
+ {
+ char *oldtext = NULL;
+ GreeterItemInfo *message_info;
+
+ message_info = greeter_lookup_id ("pam-message");
+
+ if (message_info != NULL)
+ {
+ g_object_get (G_OBJECT (message_info->item),
+ "text", &oldtext,
+ NULL);
+ }
+
+ if ( ! ve_string_empty (oldtext))
+ {
+ GtkWidget *dlg;
+
+ /* we should be now fine for focusing new windows */
+ gdm_wm_focus_new_windows (TRUE);
+
+ dlg = hig_dialog_new (NULL /* parent */,
+ GTK_DIALOG_MODAL /* flags */,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_OK,
+ oldtext,
+ "");
+ gtk_dialog_set_has_separator (GTK_DIALOG (dlg), FALSE);
+ gtk_window_set_modal (GTK_WINDOW (dlg), TRUE);
+ gdm_wm_center_window (GTK_WINDOW (dlg));
+
+ gdm_wm_no_login_focus_push ();
+ gtk_dialog_run (GTK_DIALOG (dlg));
+ gtk_widget_destroy (dlg);
+ gdm_wm_no_login_focus_pop ();
+ }
+ messages_to_give = FALSE;
+ }
+}
+
diff --git a/trunk/gui/greeter/greeter_item_pam.h b/trunk/gui/greeter/greeter_item_pam.h
new file mode 100644
index 00000000..0d1d3a6e
--- /dev/null
+++ b/trunk/gui/greeter/greeter_item_pam.h
@@ -0,0 +1,36 @@
+/* GDM - The GNOME Display Manager
+ * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
+ *
+ * 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 GREETER_ITEM_PAM_H
+#define GREETER_ITEM_PAM_H
+
+#include "greeter_item.h"
+
+gboolean greeter_item_pam_setup (void);
+void greeter_item_pam_prompt (const char *message,
+ int entry_len,
+ gboolean entry_visible);
+void greeter_item_pam_message (const char *message);
+void greeter_item_pam_error (const char *message);
+void greeter_item_pam_set_user (const char *user);
+void greeter_item_pam_leftover_messages (void);
+void greeter_item_pam_login (GtkEntry *entry, GreeterItemInfo *info);
+
+extern gchar *greeter_current_user;
+
+#endif
diff --git a/trunk/gui/greeter/greeter_item_timed.c b/trunk/gui/greeter/greeter_item_timed.c
new file mode 100644
index 00000000..ea6a50b6
--- /dev/null
+++ b/trunk/gui/greeter/greeter_item_timed.c
@@ -0,0 +1,156 @@
+/* GDM - The GNOME Display Manager
+ * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
+ *
+ * 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
+ */
+
+#include "config.h"
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+
+#include "gdm.h"
+#include "gdmconfig.h"
+
+#include "gdm-common.h"
+#include "gdm-socket-protocol.h"
+#include "gdm-daemon-config-keys.h"
+
+#include "greeter_parser.h"
+#include "greeter_configuration.h"
+#include "greeter_item_timed.h"
+
+extern gint gdm_timed_delay;
+
+static guint timed_handler_id = 0;
+
+static void
+greeter_item_timed_update (void)
+{
+ GreeterItemInfo *info;
+
+ info = greeter_lookup_id ("timed-label");
+ if (info != NULL)
+ {
+ greeter_item_update_text (info);
+ }
+}
+
+/*
+ * Timed Login: Timer
+ */
+
+static gboolean
+gdm_timer (gpointer data)
+{
+ greeter_item_timed_update ();
+ gdm_timed_delay--;
+ if (gdm_timed_delay <= 0)
+ {
+ /* timed interruption */
+ printf ("%c%c%c\n", STX, BEL, GDM_INTERRUPT_TIMED_LOGIN);
+ fflush (stdout);
+ }
+ return TRUE;
+}
+
+/*
+ * Timed Login: On GTK events, increase delay to at least 30
+ * seconds. Or the GDM_KEY_TIMED_LOGIN_DELAY, whichever is higher
+ */
+
+static gboolean
+gdm_timer_up_delay (GSignalInvocationHint *ihint,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer data)
+{
+ int timeddelay = gdm_config_get_int (GDM_KEY_TIMED_LOGIN_DELAY);
+
+ if (gdm_timed_delay < 30)
+ gdm_timed_delay = 30;
+ if (gdm_timed_delay < timeddelay)
+ gdm_timed_delay = timeddelay;
+ return TRUE;
+}
+
+gboolean
+greeter_item_timed_setup (void)
+{
+
+ /* if in timed mode, delay timeout on keyboard or menu activity */
+ if ( ! ve_string_empty (gdm_config_get_string (GDM_KEY_TIMED_LOGIN)))
+ {
+ guint sid;
+
+ g_type_class_ref (GTK_TYPE_MENU_ITEM);
+
+ sid = g_signal_lookup ("activate",
+ GTK_TYPE_MENU_ITEM);
+ g_signal_add_emission_hook (sid,
+ 0 /* detail */,
+ gdm_timer_up_delay,
+ NULL /* data */,
+ NULL /* destroy_notify */);
+
+ sid = g_signal_lookup ("key_press_event",
+ GTK_TYPE_WIDGET);
+ g_signal_add_emission_hook (sid,
+ 0 /* detail */,
+ gdm_timer_up_delay,
+ NULL /* data */,
+ NULL /* destroy_notify */);
+ sid = g_signal_lookup ("button_press_event",
+ GTK_TYPE_WIDGET);
+ g_signal_add_emission_hook (sid,
+ 0 /* detail */,
+ gdm_timer_up_delay,
+ NULL /* data */,
+ NULL /* destroy_notify */);
+ }
+
+ return TRUE;
+}
+
+void
+greeter_item_timed_start (void)
+{
+ int timeddelay = gdm_config_get_int (GDM_KEY_TIMED_LOGIN_DELAY);
+
+ if (timed_handler_id == 0 &&
+ gdm_config_get_bool (GDM_KEY_TIMED_LOGIN_ENABLE) &&
+ ! ve_string_empty (gdm_config_get_string (GDM_KEY_TIMED_LOGIN)) &&
+ timeddelay > 0)
+ {
+ gdm_timed_delay = timeddelay;
+ timed_handler_id = g_timeout_add (1000, gdm_timer, NULL);
+ }
+}
+
+void
+greeter_item_timed_stop (void)
+{
+ if (timed_handler_id != 0)
+ {
+ g_source_remove (timed_handler_id);
+ timed_handler_id = 0;
+ }
+}
+
+gboolean
+greeter_item_timed_is_timed (void)
+{
+ return timed_handler_id != 0;
+}
diff --git a/trunk/gui/greeter/greeter_item_timed.h b/trunk/gui/greeter/greeter_item_timed.h
new file mode 100644
index 00000000..bd544adc
--- /dev/null
+++ b/trunk/gui/greeter/greeter_item_timed.h
@@ -0,0 +1,29 @@
+/* GDM - The GNOME Display Manager
+ * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
+ *
+ * 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 GREETER_ITEM_TIMED_H
+#define GREETER_ITEM_TIMED_H
+
+#include "greeter_item.h"
+
+gboolean greeter_item_timed_setup (void);
+void greeter_item_timed_start (void);
+void greeter_item_timed_stop (void);
+gboolean greeter_item_timed_is_timed (void);
+
+#endif
diff --git a/trunk/gui/greeter/greeter_item_ulist.c b/trunk/gui/greeter/greeter_item_ulist.c
new file mode 100644
index 00000000..20cad3e4
--- /dev/null
+++ b/trunk/gui/greeter/greeter_item_ulist.c
@@ -0,0 +1,479 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * GDM - The GNOME Display Manager
+ * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
+ *
+ * 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
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <math.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+#include <librsvg/rsvg.h>
+
+#include "gdm.h"
+#include "gdmcommon.h"
+#include "gdmcomm.h"
+#include "gdmconfig.h"
+#include "gdmuser.h"
+
+#include "gdm-common.h"
+#include "gdm-socket-protocol.h"
+#include "gdm-daemon-config-keys.h"
+
+#include "greeter.h"
+#include "greeter_item_ulist.h"
+#include "greeter_parser.h"
+#include "greeter_configuration.h"
+#include "greeter_item.h"
+
+static GList *users = NULL;
+static GList *users_string = NULL;
+static GdkPixbuf *defface;
+static GHashTable *displays_hash = NULL;
+
+static GtkWidget *pam_entry = NULL;
+static GtkWidget *user_list = NULL;
+static gboolean selecting_user = FALSE;
+static gchar *selected_user = NULL;
+static int num_users = 0;
+
+enum
+{
+ GREETER_ULIST_ICON_COLUMN = 0,
+ GREETER_ULIST_LABEL_COLUMN,
+ GREETER_ULIST_LOGIN_COLUMN,
+ GREETER_ULIST_ACTIVE_COLUMN
+};
+
+/* Hide the userlist if there are no users displayed */
+void
+greeter_item_ulist_check_show_userlist (void)
+{
+ /*
+ * If the browser feature isn't enabled or if there are no users,
+ * then hide the rectangle used to contain the userlist. The
+ * userlist-rect id allows a rectangle to be defined with alpha
+ * behind the userlist that also goes away when the list is empty.
+ */
+ if (num_users == 0 || !gdm_config_get_bool (GDM_KEY_BROWSER)) {
+
+ GreeterItemInfo *urinfo = greeter_lookup_id ("userlist-rect");
+
+ if (user_list != NULL)
+ gtk_widget_hide (user_list);
+
+ if (urinfo) {
+ GnomeCanvasItem *item;
+
+ if (urinfo->group_item != NULL)
+ item = GNOME_CANVAS_ITEM (urinfo->group_item);
+ else
+ item = urinfo->item;
+
+ gnome_canvas_item_hide (item);
+ }
+ }
+}
+
+void
+greeter_item_ulist_unset_selected_user (void)
+{
+ GtkTreeSelection *selection;
+ if (user_list != NULL) {
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (user_list));
+ gtk_tree_selection_unselect_all (GTK_TREE_SELECTION (selection));
+ }
+
+ if (selected_user != NULL)
+ g_free (selected_user);
+ selected_user = NULL;
+}
+
+static int
+vector_len (char * const *v)
+{
+ int i;
+ if (v == NULL)
+ return 0;
+ for (i = 0; v[i] != NULL; i++)
+ ;
+ return i;
+}
+
+static void
+check_for_displays (void)
+{
+ char *ret;
+ char **vec;
+ char *auth_cookie = NULL;
+ int i;
+
+ /*
+ * Might be nice to move this call into read_config() so that it happens
+ * on the same socket call as reading the configuration.
+ */
+ ret = gdmcomm_call_gdm (GDM_SUP_ATTACHED_SERVERS, auth_cookie, "2.2.4.0", 5);
+ if (ve_string_empty (ret) || strncmp (ret, "OK ", 3) != 0) {
+ g_free (ret);
+ return;
+ }
+
+ vec = g_strsplit (&ret[3], ";", -1);
+ g_free (ret);
+ if (vec == NULL)
+ return;
+
+ if (displays_hash == NULL)
+ displays_hash = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ g_free);
+
+ for (i = 0; vec[i] != NULL; i++) {
+ char **rvec;
+
+ rvec = g_strsplit (vec[i], ",", -1);
+ if (rvec == NULL || vector_len (rvec) != 3)
+ continue;
+
+ g_hash_table_insert (displays_hash,
+ g_strdup (rvec[1]),
+ g_strdup (rvec[0]));
+
+ g_strfreev (rvec);
+ }
+
+ g_strfreev (vec);
+}
+
+static void
+gdm_greeter_users_init (void)
+{
+ gint size_of_users = 0;
+
+ defface = gdm_common_get_face (NULL,
+ gdm_config_get_string (GDM_KEY_DEFAULT_FACE),
+ gdm_config_get_int (GDM_KEY_MAX_ICON_WIDTH),
+ gdm_config_get_int (GDM_KEY_MAX_ICON_HEIGHT));
+ if (! defface) {
+ gdm_common_warning ("Can't open DefaultImage: %s!",
+ gdm_config_get_string (GDM_KEY_DEFAULT_FACE));
+ }
+
+ gdm_users_init (&users, &users_string, NULL, defface,
+ &size_of_users, GDM_IS_LOCAL, !DOING_GDM_DEVELOPMENT);
+}
+
+static void
+greeter_populate_user_list (GtkTreeModel *tm)
+{
+ GList *li;
+
+ for (li = users; li != NULL; li = li->next) {
+ GdmUser *usr = li->data;
+ GtkTreeIter iter = {0};
+ char *label;
+ char *name;
+ gboolean active;
+
+ if (usr->gecos && strcmp (usr->gecos, "") != 0) {
+ name = gdm_common_text_to_escaped_utf8 (usr->gecos);
+ } else {
+ name = gdm_common_text_to_escaped_utf8 (usr->login);
+ }
+
+ if (g_hash_table_lookup (displays_hash, usr->login))
+ active = TRUE;
+ else
+ active = FALSE;
+
+ if (active) {
+ label = g_strdup_printf ("<b>%s</b>\n <i><small>%s</small></i>",
+ name,
+ _("Already logged in"));
+ } else {
+ label = g_strdup_printf ("<b>%s</b>\n",
+ name);
+ }
+
+ g_free (name);
+
+ gtk_list_store_append (GTK_LIST_STORE (tm), &iter);
+ gtk_list_store_set (GTK_LIST_STORE (tm), &iter,
+ GREETER_ULIST_ICON_COLUMN, usr->picture,
+ GREETER_ULIST_LOGIN_COLUMN, usr->login,
+ GREETER_ULIST_LABEL_COLUMN, label,
+ GREETER_ULIST_ACTIVE_COLUMN, active,
+ -1);
+ g_free (label);
+ num_users++;
+ }
+}
+
+void
+greeter_item_ulist_select_user (gchar *login)
+{
+ printf ("%c%c%c%s\n", STX, BEL,
+ GDM_INTERRUPT_SELECT_USER, login);
+
+ fflush (stdout);
+}
+
+static void
+user_selected (GtkTreeSelection *selection, gpointer data)
+{
+ GtkTreeModel *tm = NULL;
+ GtkTreeIter iter = {0};
+
+ if (gtk_tree_selection_get_selected (selection, &tm, &iter)) {
+ char *login;
+
+ gtk_tree_model_get (tm, &iter, GREETER_ULIST_LOGIN_COLUMN,
+ &login, -1);
+ if (login != NULL) {
+ if (selecting_user && greeter_probably_login_prompt) {
+ gtk_entry_set_text (GTK_ENTRY (pam_entry), login);
+ }
+ if (selecting_user) {
+ GreeterItemInfo *pamlabel = greeter_lookup_id ("pam-message");
+ if (pamlabel == NULL) {
+ gdm_common_warning ("Theme broken: must have pam-message label!");
+ }
+ greeter_item_ulist_select_user (login);
+ if (selected_user != NULL)
+ g_free (selected_user);
+ selected_user = g_strdup (login);
+ }
+ }
+ }
+}
+
+static void
+browser_change_focus (GtkWidget *widget, GdkEventButton *event, gpointer data)
+{
+ gtk_widget_grab_focus (pam_entry);
+}
+
+static void
+greeter_generate_userlist (GtkWidget *tv, GreeterItemInfo *info)
+{
+ GtkTreeModel *tm;
+ GtkTreeViewColumn *column_one, *column_two;
+ GtkTreeSelection *selection;
+ GList *list, *li;
+
+ gdm_greeter_users_init ();
+
+ check_for_displays ();
+
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tv),
+ FALSE);
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tv));
+ gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE);
+ if (users != NULL) {
+ g_signal_connect (selection, "changed",
+ G_CALLBACK (user_selected),
+ NULL);
+
+ g_signal_connect (GTK_TREE_VIEW (tv), "button_release_event",
+ G_CALLBACK (browser_change_focus),
+ NULL);
+
+ tm = (GtkTreeModel *)gtk_list_store_new (4,
+ GDK_TYPE_PIXBUF,
+ G_TYPE_STRING,
+ G_TYPE_STRING,
+ G_TYPE_BOOLEAN);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (tv), tm);
+ column_one = gtk_tree_view_column_new_with_attributes (_("Icon"),
+ gtk_cell_renderer_pixbuf_new (),
+ "pixbuf", GREETER_ULIST_ICON_COLUMN,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (tv), column_one);
+
+ column_two = gtk_tree_view_column_new_with_attributes (_("Username"),
+ gtk_cell_renderer_text_new (),
+ "markup", GREETER_ULIST_LABEL_COLUMN,
+ NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (tv), column_two);
+
+ /* Only populate the user list if the browser is turned on */
+ if (gdm_config_get_bool (GDM_KEY_BROWSER))
+ greeter_populate_user_list (tm);
+
+ list = gtk_tree_view_column_get_cell_renderers (column_one);
+ for (li = list; li != NULL; li = li->next) {
+ GtkObject *cell = li->data;
+
+ if (info->data.list.icon_color != NULL)
+ g_object_set (cell, "cell-background",
+ info->data.list.icon_color, NULL);
+ }
+
+ list = gtk_tree_view_column_get_cell_renderers (column_two);
+ for (li = list; li != NULL; li = li->next) {
+ GtkObject *cell = li->data;
+
+ if (info->data.list.label_color != NULL)
+ g_object_set (cell, "background",
+ info->data.list.label_color, NULL);
+ }
+ }
+
+ /* we are done with the hash */
+ g_hash_table_destroy (displays_hash);
+ displays_hash = NULL;
+}
+
+static inline void
+force_no_tree_separators (GtkWidget *widget)
+{
+ gboolean first_time = TRUE;
+
+ if (first_time) {
+ gtk_rc_parse_string ("\n"
+ " style \"gdm-userlist-treeview-style\"\n"
+ " {\n"
+ " GtkTreeView::horizontal-separator=0\n"
+ " GtkTreeView::vertical-separator=0\n"
+ " }\n"
+ "\n"
+ " widget \"*.gdm-userlist-treeview\" style \"gdm-userlist-treeview-style\"\n"
+ "\n");
+ first_time = FALSE;
+ }
+
+ gtk_widget_set_name (widget, "gdm-userlist-treeview");
+}
+
+gboolean
+greeter_item_ulist_setup (void)
+{
+ GreeterItemInfo *info;
+
+ info = greeter_lookup_id ("user-pw-entry");
+ if (info && info->item &&
+ GNOME_IS_CANVAS_WIDGET (info->item) &&
+ GTK_IS_ENTRY (GNOME_CANVAS_WIDGET (info->item)->widget)) {
+ pam_entry = GNOME_CANVAS_WIDGET (info->item)->widget;
+ }
+
+ info = greeter_lookup_id ("userlist");
+
+ if (info && info->item &&
+ GNOME_IS_CANVAS_WIDGET (info->item)) {
+ GtkWidget *sw = GNOME_CANVAS_WIDGET (info->item)->widget;
+
+ if (GTK_IS_SCROLLED_WINDOW (sw) &&
+ GTK_IS_TREE_VIEW (GTK_BIN (sw)->child)) {
+ GtkRequisition req;
+ gdouble height;
+
+ user_list = GTK_BIN (sw)->child;
+
+ force_no_tree_separators (user_list);
+
+ greeter_generate_userlist (user_list, info);
+
+ /* Reset size of the widget canvas item so it
+ * is the same size as the userlist. This
+ * avoids the ugly white background displayed
+ * below the Face Browser when the list isn't
+ * as large as the rectangle defined in the
+ * GDM theme file.
+ */
+
+ gtk_widget_size_request (user_list, &req);
+ g_object_get (info->item, "height", &height, NULL);
+
+ if (req.height < height)
+ g_object_set (info->item, "height", (double)req.height, NULL);
+ }
+ }
+
+ return TRUE;
+}
+
+void
+greeter_item_ulist_enable (void)
+{
+ selecting_user = TRUE;
+ if (user_list != NULL)
+ gtk_widget_set_sensitive (user_list, TRUE);
+}
+
+void
+greeter_item_ulist_disable (void)
+{
+ selecting_user = FALSE;
+ if (user_list != NULL)
+ gtk_widget_set_sensitive (user_list, FALSE);
+}
+
+void
+greeter_item_ulist_set_user (const char *user)
+{
+ gboolean old_selecting_user = selecting_user;
+ GtkTreeSelection *selection;
+ GtkTreeIter iter = {0};
+ GtkTreeModel *tm = NULL;
+
+ if (user_list == NULL)
+ return;
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (user_list));
+ gtk_tree_selection_unselect_all (selection);
+
+ if (ve_string_empty (user))
+ return;
+
+ /* Make sure we don't set the pam_entry and pam label stuff,
+ this is programatic selection, not user selection */
+ selecting_user = FALSE;
+
+ tm = gtk_tree_view_get_model (GTK_TREE_VIEW (user_list));
+
+ if (gtk_tree_model_get_iter_first (tm, &iter)) {
+ do {
+ char *login;
+
+ gtk_tree_model_get (tm, &iter, GREETER_ULIST_LOGIN_COLUMN,
+ &login, -1);
+ if (login != NULL && strcmp (user, login) == 0) {
+ GtkTreePath *path = gtk_tree_model_get_path (tm, &iter);
+
+ gtk_tree_selection_select_iter (selection, &iter);
+ gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (user_list),
+ path, NULL,
+ FALSE, 0.0, 0.0);
+ gtk_tree_path_free (path);
+ break;
+ }
+
+ } while (gtk_tree_model_iter_next (tm, &iter));
+ }
+ selecting_user = old_selecting_user;
+}
diff --git a/trunk/gui/greeter/greeter_item_ulist.h b/trunk/gui/greeter/greeter_item_ulist.h
new file mode 100644
index 00000000..8bf2b568
--- /dev/null
+++ b/trunk/gui/greeter/greeter_item_ulist.h
@@ -0,0 +1,32 @@
+/* GDM - The GNOME Display Manager
+ * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
+ *
+ * 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 GREETER_ITEM_ULIST_H
+#define GREETER_ITEM_ULIST_H
+
+#include "greeter_item.h"
+
+gboolean greeter_item_ulist_setup (void);
+void greeter_item_ulist_enable (void);
+void greeter_item_ulist_disable (void);
+void greeter_item_ulist_set_user (const char *user);
+void greeter_item_ulist_unset_selected_user (void);
+void greeter_item_ulist_select_user (gchar *login);
+void greeter_item_ulist_check_show_userlist (void);
+
+#endif
diff --git a/trunk/gui/greeter/greeter_parser.c b/trunk/gui/greeter/greeter_parser.c
new file mode 100644
index 00000000..2a131fc0
--- /dev/null
+++ b/trunk/gui/greeter/greeter_parser.c
@@ -0,0 +1,1997 @@
+/* GDM - The GNOME Display Manager
+ * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
+ *
+ * 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
+ */
+
+#include "config.h"
+
+#include <gtk/gtk.h>
+#include <libxml/parser.h>
+#include <string.h>
+#include <stdlib.h>
+#include <librsvg/rsvg.h>
+#include <math.h>
+#include <locale.h>
+#include <glib/gi18n.h>
+#include <gdk/gdkx.h>
+#include <syslog.h>
+
+#include "gdmwm.h"
+#include "gdmcommon.h"
+#include "gdmconfig.h"
+
+#include "gdm-common.h"
+#include "gdm-daemon-config-keys.h"
+
+#include "greeter_configuration.h"
+#include "greeter_parser.h"
+#include "greeter_events.h"
+#include "gdm.h"
+
+/* FIXME: hack */
+extern GreeterItemInfo *welcome_string_info;
+
+/* evil globals */
+static char *file_search_path = NULL;
+static GList *button_stack = NULL;
+
+static GHashTable *pixbuf_hash = NULL;
+
+GHashTable *item_hash = NULL;
+GList *custom_items = NULL;
+
+static gboolean parse_items (xmlNodePtr node,
+ GList **items_out,
+ GreeterItemInfo *parent,
+ GError **error);
+
+static GdkPixbuf *
+load_pixbuf (const char *fname, GError **error)
+{
+ GdkPixbuf *pb;
+
+ if (pixbuf_hash == NULL)
+ pixbuf_hash = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ (GDestroyNotify)g_object_unref);
+ pb = g_hash_table_lookup (pixbuf_hash, fname);
+ if (pb != NULL)
+ return g_object_ref (pb);
+
+ pb = gdk_pixbuf_new_from_file (fname, error);
+ if G_UNLIKELY (pb == NULL)
+ return NULL;
+
+ g_hash_table_insert (pixbuf_hash, g_strdup (fname), g_object_ref (pb));
+
+ return pb;
+}
+
+GQuark
+greeter_parser_error_quark (void)
+{
+ static GQuark quark = 0;
+ if (!quark)
+ quark = g_quark_from_static_string ("greeter_parser_error");
+
+ return quark;
+}
+
+
+GreeterItemInfo *
+greeter_lookup_id (const char *id)
+{
+ GreeterItemInfo key;
+ GreeterItemInfo *info;
+
+ key.id = (char *)id;
+ info = g_hash_table_lookup (item_hash, &key);
+
+ return info;
+}
+
+static void
+parse_id (xmlNodePtr node,
+ GreeterItemInfo *info)
+{
+ xmlChar *prop;
+
+ prop = xmlGetProp (node, (const xmlChar *) "id");
+
+ if (prop)
+ {
+ info->id = g_strdup ((char *) prop);
+ g_hash_table_insert (item_hash, info, info);
+ xmlFree (prop);
+ }
+}
+
+/* Doesn't set the parts of rect that are not specified.
+ * If you want specific default values you need to fill them out
+ * in rect first
+ */
+static gboolean
+parse_pos (xmlNodePtr node,
+ GreeterItemInfo *info,
+ GError **error)
+{
+ xmlChar *prop;
+ char *p;
+
+ prop = xmlGetProp (node, (const xmlChar *) "anchor");
+ if (prop)
+ {
+ if (strcmp ((char *) prop, "center") == 0)
+ info->anchor = GTK_ANCHOR_CENTER;
+ else if (strcmp ((char *) prop, "c") == 0)
+ info->anchor = GTK_ANCHOR_CENTER;
+ else if (strcmp ((char *) prop, "nw") == 0)
+ info->anchor = GTK_ANCHOR_NW;
+ else if (strcmp ((char *) prop, "n") == 0)
+ info->anchor = GTK_ANCHOR_N;
+ else if (strcmp ((char *) prop, "ne") == 0)
+ info->anchor = GTK_ANCHOR_NE;
+ else if (strcmp ((char *) prop, "w") == 0)
+ info->anchor = GTK_ANCHOR_W;
+ else if (strcmp ((char *) prop, "e") == 0)
+ info->anchor = GTK_ANCHOR_E;
+ else if (strcmp ((char *) prop, "sw") == 0)
+ info->anchor = GTK_ANCHOR_SW;
+ else if (strcmp ((char *) prop, "s") == 0)
+ info->anchor = GTK_ANCHOR_S;
+ else if (strcmp ((char *) prop, "se") == 0)
+ info->anchor = GTK_ANCHOR_SE;
+ else
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "Unknown anchor type %s", prop);
+ xmlFree (prop);
+ return FALSE;
+ }
+ xmlFree (prop);
+ }
+
+
+ prop = xmlGetProp (node,(const xmlChar *) "x");
+ if (prop)
+ {
+ info->x = g_ascii_strtod ((char *) prop, &p);
+
+ if ((char *)prop == p)
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "Bad position specifier %s", prop);
+ xmlFree (prop);
+ return FALSE;
+ }
+
+ if (prop[0] == '-' || info->x < 0)
+ info->x_negative = TRUE;
+ else
+ info->x_negative = FALSE;
+
+ if (strchr ((char *) prop, '%') != NULL)
+ info->x_type = GREETER_ITEM_POS_RELATIVE;
+ else
+ info->x_type = GREETER_ITEM_POS_ABSOLUTE;
+ xmlFree (prop);
+ }
+
+ prop = xmlGetProp (node,(const xmlChar *) "y");
+ if (prop)
+ {
+ info->y = g_ascii_strtod ((char *) prop, &p);
+
+ if ((char *)prop == p)
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "Bad position specifier %s", prop);
+ xmlFree (prop);
+ return FALSE;
+ }
+
+ if (prop[0] == '-' || info->y < 0)
+ info->y_negative = TRUE;
+ else
+ info->y_negative = FALSE;
+
+ if (strchr ((char *) prop, '%') != NULL)
+ info->y_type = GREETER_ITEM_POS_RELATIVE;
+ else
+ info->y_type = GREETER_ITEM_POS_ABSOLUTE;
+ xmlFree (prop);
+ }
+
+ prop = xmlGetProp (node,(const xmlChar *) "width");
+ if (prop)
+ {
+ if (strcmp ((char *) prop, "box") == 0)
+ info->width_type = GREETER_ITEM_SIZE_BOX;
+ else if (strcmp ((char *) prop, "scale") == 0)
+ info->width_type = GREETER_ITEM_SIZE_SCALE;
+ else
+ {
+ info->width = g_ascii_strtod ((char *) prop, &p);
+
+ if ((char *)prop == p)
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "Bad size specifier %s", prop);
+ xmlFree (prop);
+ return FALSE;
+ }
+
+ if (strchr ((char *) prop, '%') != NULL)
+ info->width_type = GREETER_ITEM_SIZE_RELATIVE;
+ else
+ info->width_type = GREETER_ITEM_SIZE_ABSOLUTE;
+ }
+ xmlFree (prop);
+ }
+
+ prop = xmlGetProp (node,(const xmlChar *) "height");
+ if (prop)
+ {
+ if (strcmp ((char *) prop, "box") == 0)
+ info->height_type = GREETER_ITEM_SIZE_BOX;
+ else if (strcmp ((char *) prop, "scale") == 0)
+ info->height_type = GREETER_ITEM_SIZE_SCALE;
+ else
+ {
+ info->height = g_ascii_strtod ((char *) prop, &p);
+
+ if ((char *)prop == p)
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "Bad size specifier %s", prop);
+ xmlFree (prop);
+ return FALSE;
+ }
+
+ if (strchr ((char *) prop, '%') != NULL)
+ info->height_type = GREETER_ITEM_SIZE_RELATIVE;
+ else
+ info->height_type = GREETER_ITEM_SIZE_ABSOLUTE;
+ }
+ xmlFree (prop);
+ }
+
+ prop = xmlGetProp (node,(const xmlChar *) "expand");
+ if (prop)
+ {
+ if (strcmp ((char *) prop, "true") == 0)
+ {
+ info->expand = TRUE;
+ }
+ else if (strcmp ((char *) prop, "false") == 0)
+ {
+ info->expand = FALSE;
+ }
+ else
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "Bad expand spec %s", prop);
+ xmlFree (prop);
+ return FALSE;
+ }
+
+ xmlFree (prop);
+ }
+
+ return TRUE;
+}
+
+/* We pass the same arguments as to translated text, since we'll override it
+ * with translation score */
+static gboolean
+parse_stock (xmlNodePtr node,
+ GreeterItemInfo *info,
+ char **translated_text,
+ gint *translation_score,
+ GError **error)
+{
+ xmlChar *prop;
+
+ prop = xmlGetProp (node,(const xmlChar *) "type");
+ if (prop)
+ {
+ if (g_ascii_strcasecmp ((char *) prop, "language") == 0)
+ {
+ g_free (*translated_text);
+ *translated_text = g_strdup (_("_Language"));
+ }
+ else if (g_ascii_strcasecmp ((char *) prop, "session") == 0)
+ {
+ g_free (*translated_text);
+ *translated_text = g_strdup (_("_Session"));
+ }
+ else if (g_ascii_strcasecmp ((char *) prop, "system") == 0)
+ {
+ g_free (*translated_text);
+ *translated_text = g_strdup (_("_Actions"));
+ }
+ else if (g_ascii_strcasecmp ((char *) prop, "disconnect") == 0)
+ {
+ g_free (*translated_text);
+ *translated_text = g_strdup (_("D_isconnect"));
+ }
+ else if (g_ascii_strcasecmp ((char *) prop, "quit") == 0)
+ {
+ g_free (*translated_text);
+ *translated_text = g_strdup (_("_Quit"));
+ }
+ else if (g_ascii_strcasecmp ((char *) prop, "halt") == 0)
+ {
+ g_free (*translated_text);
+ *translated_text = g_strdup (_("Shut _Down"));
+ }
+ else if (g_ascii_strcasecmp ((char *) prop, "suspend") == 0)
+ {
+ g_free (*translated_text);
+ *translated_text = g_strdup (_("Sus_pend"));
+ }
+ else if (g_ascii_strcasecmp ((char *) prop, "reboot") == 0)
+ {
+ g_free (*translated_text);
+ *translated_text = g_strdup (_("_Restart"));
+ }
+ else if (g_ascii_strcasecmp ((char *) prop, "chooser") == 0)
+ {
+ g_free (*translated_text);
+ *translated_text = g_strdup (_("Remote Login via _XDMCP"));
+ }
+ else if (g_ascii_strcasecmp ((char *) prop, "config") == 0)
+ {
+ g_free (*translated_text);
+ *translated_text = g_strdup (_("Confi_gure"));
+ }
+ else if (g_ascii_strcasecmp ((char *) prop, "options") == 0)
+ {
+ g_free (*translated_text);
+ *translated_text = g_strdup (_("Op_tions"));
+ }
+ else if (g_ascii_strcasecmp ((char *) prop, "caps-lock-warning") == 0)
+ {
+ g_free (*translated_text);
+ *translated_text = g_strdup (_("Caps Lock is on."));
+ }
+ else if (g_ascii_strcasecmp ((char *) prop, "timed-label") == 0)
+ {
+ g_free (*translated_text);
+ *translated_text = g_strdup (_("User %u will login in %t"));
+ }
+ else if (g_ascii_strcasecmp ((char *) prop, "welcome-label") == 0)
+ {
+ /* FIXME: hack */
+ welcome_string_info = info;
+
+ g_free (*translated_text);
+ *translated_text = gdm_common_get_welcomemsg ();
+ }
+ /* FIXME: is this actually needed? */
+ else if (g_ascii_strcasecmp ((char *) prop, "username-label") == 0)
+ {
+ g_free (*translated_text);
+ *translated_text = g_strdup (_("Username:"));
+ }
+ else if (g_ascii_strcasecmp ((char *) prop, "ok") == 0)
+ {
+ g_free (*translated_text);
+ *translated_text = g_strdup (_("_OK"));
+ }
+ else if (g_ascii_strcasecmp ((char *) prop, "cancel") == 0)
+ {
+ g_free (*translated_text);
+ *translated_text = g_strdup (_("_Cancel"));
+ }
+ else if (g_ascii_strcasecmp ((char *) prop, "startagain") == 0)
+ {
+ g_free (*translated_text);
+ *translated_text = g_strdup (_("_Start Again"));
+ }
+ else
+ {
+ gboolean is_error = TRUE;
+ register int i = 0;
+ for (; i < GDM_CUSTOM_COMMAND_MAX; i++) {
+ gchar * key_string = NULL;
+ key_string = g_strdup_printf ("custom_cmd%d", i);
+ if (g_ascii_strcasecmp ((char *) prop, key_string) == 0) {
+ g_free (*translated_text);
+ g_free (key_string);
+ key_string = g_strdup_printf ("%s%d=", GDM_KEY_CUSTOM_CMD_LABEL_TEMPLATE, i);
+ *translated_text = g_strdup(gdm_config_get_string (key_string));
+ g_free (key_string);
+ is_error = FALSE;
+ break;
+ }
+ g_free (key_string);
+ }
+
+ if (is_error)
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "Bad stock label type");
+ xmlFree (prop);
+ return FALSE;
+ }
+ }
+
+ /* This is the very very very best "translation" */
+ *translation_score = -1;
+
+ xmlFree (prop);
+
+ return TRUE;
+ }
+ else
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "Stock type not specified");
+ return FALSE;
+ }
+}
+
+static void
+do_font_size_reduction (GreeterItemInfo *info)
+{
+ double size_reduction = 1.0;
+ int i;
+
+ if (gdm_wm_screen.width <= 800 &&
+ gdm_wm_screen.width > 640)
+ size_reduction = PANGO_SCALE_SMALL;
+ else if (gdm_wm_screen.width <= 640)
+ size_reduction = PANGO_SCALE_X_SMALL;
+
+ if (size_reduction < 0.99)
+ {
+ for (i = 0; i < GREETER_ITEM_STATE_MAX; i++)
+ {
+ if (info->data.text.fonts[i] != NULL)
+ {
+ int old_size = pango_font_description_get_size (info->data.text.fonts[i]);
+ pango_font_description_set_size (info->data.text.fonts[i], old_size * size_reduction);
+ }
+ }
+ }
+}
+
+
+static gboolean
+parse_canvasbutton (xmlNodePtr node,
+ GreeterItemInfo *info,
+ GError **error)
+{
+ xmlChar *prop;
+
+ prop = xmlGetProp (node,(const xmlChar *) "button");
+ if (prop)
+ {
+ if (strcmp ((char *) prop, "true") == 0)
+ {
+ info->canvasbutton = TRUE;
+ }
+ else if (strcmp ((char *) prop, "false") == 0)
+ {
+ info->canvasbutton = FALSE;
+ }
+ else
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "bad button spec %s", prop);
+ xmlFree (prop);
+ return FALSE;
+ }
+ xmlFree (prop);
+ }
+ return TRUE;
+}
+
+static gboolean
+parse_gtkbutton (xmlNodePtr node,
+ GreeterItemInfo *info,
+ GError **error)
+{
+ xmlNodePtr child;
+ char *translated_text = NULL;
+ gint translation_score = 1000;
+
+ child = node->children;
+
+ while (child)
+ {
+ if (strcmp ((char *) child->name, "pos") == 0)
+ {
+ if G_UNLIKELY (!parse_pos (child, info, error))
+ return FALSE;
+ }
+ else if (child->type == XML_ELEMENT_NODE &&
+ strcmp ((char *) child->name, "stock") == 0)
+ {
+ if G_UNLIKELY (!parse_stock (child, info, &translated_text, &translation_score, error))
+ return FALSE;
+ }
+
+ child = child->next;
+ }
+
+ if (translated_text == NULL)
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "A label must specify the text attribute");
+ return FALSE;
+ }
+
+ /* FIXME: evil hack to use internally translated strings */
+ if (translation_score == 999 &&
+ ! ve_string_empty (translated_text))
+ {
+ char *foo = g_strdup (_(translated_text));
+ g_free (translated_text);
+ translated_text = foo;
+ }
+
+ info->data.text.orig_text = translated_text;
+
+ return TRUE;
+}
+
+static gboolean
+parse_show (xmlNodePtr node,
+ GreeterItemInfo *info,
+ GError **error)
+{
+ xmlChar *prop;
+ char **argv = NULL;
+ int i;
+
+ prop = xmlGetProp (node,(const xmlChar *) "type");
+ if (prop != NULL)
+ {
+ g_free (info->show_type);
+ info->show_type = g_strdup ((char *) prop);
+ xmlFree (prop);
+ }
+
+ /* Note: subtype is deprecated, use type only */
+ prop = xmlGetProp (node,(const xmlChar *) "subtype");
+ if G_UNLIKELY (prop != NULL)
+ {
+ /* code for legacy uses of subtype only, are there any such
+ * themes out there? The Bluecurve was the one this was made
+ * for and bluecurve is NOT using it. */
+ if (info->show_type == NULL ||
+ strcmp (info->show_type, "system") == 0) {
+ g_free (info->show_type);
+ info->show_type = g_strdup ((char *) prop);
+ }
+ xmlFree (prop);
+ }
+
+ prop = xmlGetProp (node,(const xmlChar *) "min-screen-width");
+ if (prop != NULL)
+ {
+ g_warning ("minimum width is %d", info->minimum_required_screen_height);
+ info->minimum_required_screen_width = atoi ((char *) prop);
+ xmlFree (prop);
+ }
+
+ prop = xmlGetProp (node,(const xmlChar *) "min-screen-height");
+ if (prop != NULL)
+ {
+ info->minimum_required_screen_height = atoi ((char *) prop);
+ g_warning ("minimum height is %d", info->minimum_required_screen_height);
+ xmlFree (prop);
+ }
+
+ prop = xmlGetProp (node,(const xmlChar *) "modes");
+ if (prop != NULL)
+ {
+ if (strcmp ((char *) prop, "everywhere") == 0)
+ {
+ info->show_modes = GREETER_ITEM_SHOW_EVERYWHERE;
+ xmlFree (prop);
+ return TRUE;
+ }
+ else if (strcmp ((char *) prop, "nowhere") == 0)
+ {
+ info->show_modes = GREETER_ITEM_SHOW_NOWHERE;
+ xmlFree (prop);
+ return TRUE;
+ }
+
+ argv = g_strsplit ((char *) prop, ",", 0);
+ xmlFree (prop);
+ }
+ else
+ {
+ info->show_modes = GREETER_ITEM_SHOW_EVERYWHERE;
+ return TRUE;
+ }
+
+ info->show_modes = GREETER_ITEM_SHOW_NOWHERE;
+
+ if (argv != NULL)
+ {
+ for (i = 0; argv[i] != NULL; i++)
+ {
+ if (strcmp (argv[i], "console") == 0)
+ {
+ info->show_modes |= GREETER_ITEM_SHOW_CONSOLE;
+ }
+ else if (strcmp (argv[i], "console-fixed") == 0)
+ {
+ info->show_modes |= GREETER_ITEM_SHOW_CONSOLE_FIXED;
+ }
+ else if (strcmp (argv[i], "console-flexi") == 0)
+ {
+ info->show_modes |= GREETER_ITEM_SHOW_CONSOLE_FLEXI;
+ }
+ else if (strcmp (argv[i], "remote-flexi") == 0)
+ {
+ info->show_modes |= GREETER_ITEM_SHOW_REMOTE_FLEXI;
+ }
+ else if (strcmp (argv[i], "flexi") == 0)
+ {
+ info->show_modes |= GREETER_ITEM_SHOW_FLEXI;
+ }
+ else if (strcmp (argv[i], "remote") == 0)
+ {
+ info->show_modes |= GREETER_ITEM_SHOW_REMOTE;
+ }
+ }
+ g_strfreev (argv);
+ }
+ return TRUE;
+}
+
+static gboolean
+parse_fixed (xmlNodePtr node,
+ GreeterItemInfo *info,
+ GError **error)
+{
+ return parse_items (node,
+ &info->fixed_children,
+ info,
+ error);
+}
+
+static gboolean
+parse_box (xmlNodePtr node,
+ GreeterItemInfo *info,
+ GError **error)
+{
+ xmlChar *prop;
+ char *p;
+
+ prop = xmlGetProp (node,(const xmlChar *) "orientation");
+ if (prop)
+ {
+ if (strcmp ((char *) prop, "horizontal") == 0)
+ {
+ info->box_orientation = GTK_ORIENTATION_HORIZONTAL;
+ }
+ else if (strcmp ((char *) prop, "vertical") == 0)
+ {
+ info->box_orientation = GTK_ORIENTATION_VERTICAL;
+ }
+ else
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "Bad orientation %s", prop);
+ xmlFree (prop);
+ return FALSE;
+ }
+
+ xmlFree (prop);
+ }
+
+ prop = xmlGetProp (node,(const xmlChar *) "homogeneous");
+ if (prop)
+ {
+ if (strcmp ((char *) prop, "true") == 0)
+ {
+ info->box_homogeneous = TRUE;
+ }
+ else if (strcmp ((char *) prop, "false") == 0)
+ {
+ info->box_homogeneous = FALSE;
+ }
+ else
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "Bad homogenous spec %s", prop);
+ xmlFree (prop);
+ return FALSE;
+ }
+
+ xmlFree (prop);
+ }
+
+
+ prop = xmlGetProp (node,(const xmlChar *) "xpadding");
+ if (prop)
+ {
+ info->box_x_padding = g_ascii_strtod ((char *) prop, &p);
+
+ if G_UNLIKELY ((char *)prop == p)
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "Bad padding specification %s", prop);
+ xmlFree (prop);
+ return FALSE;
+ }
+ xmlFree (prop);
+ }
+
+ prop = xmlGetProp (node,(const xmlChar *) "ypadding");
+ if (prop)
+ {
+ info->box_y_padding = g_ascii_strtod ((char *) prop, &p);
+
+ if G_UNLIKELY ((char *)prop == p)
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "Bad padding specification %s", prop);
+ xmlFree (prop);
+ return FALSE;
+ }
+ xmlFree (prop);
+ }
+
+ prop = xmlGetProp (node,(const xmlChar *) "min-width");
+ if (prop)
+ {
+ info->box_min_width = g_ascii_strtod ((char *) prop, &p);
+
+ if G_UNLIKELY ((char *)prop == p)
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "Bad min-width specification %s", prop);
+ xmlFree (prop);
+ return FALSE;
+ }
+ xmlFree (prop);
+ }
+
+ prop = xmlGetProp (node,(const xmlChar *) "min-height");
+ if (prop)
+ {
+ info->box_min_height = g_ascii_strtod ((char *) prop, &p);
+
+ if G_UNLIKELY ((char *)prop == p)
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "Bad min-height specification %s", prop);
+ xmlFree (prop);
+ return FALSE;
+ }
+ xmlFree (prop);
+ }
+
+ prop = xmlGetProp (node,(const xmlChar *) "spacing");
+ if (prop)
+ {
+ info->box_spacing = g_ascii_strtod ((char *) prop, &p);
+
+ if G_UNLIKELY ((char *)prop == p)
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "Bad spacing specification %s", prop);
+ xmlFree (prop);
+ return FALSE;
+ }
+ xmlFree (prop);
+ }
+
+ return parse_items (node,
+ &info->box_children,
+ info,
+ error);
+
+}
+
+
+static gboolean
+parse_color (const char *str,
+ guint32 *col_out,
+ GError **error)
+{
+ guint32 col;
+ int i;
+ if G_UNLIKELY (str[0] != '#')
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "colors must start with #, %s is an invalid color", str);
+ return FALSE;
+ }
+ if G_UNLIKELY (strlen (str) != 7)
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "Colors must be on the format #xxxxxx, %s is an invalid color", str);
+ return FALSE;
+ }
+
+ col = 0;
+
+ for (i = 0; i < 6; i++)
+ col = (col << 4) | g_ascii_xdigit_value (str[i+1]);
+
+ *col_out = col;
+
+ return TRUE;
+}
+
+static gboolean
+parse_state_file_pixmap (xmlNodePtr node,
+ GreeterItemInfo *info,
+ GreeterItemState state,
+ GError **error)
+{
+ xmlChar *prop;
+ char *p;
+
+ info->have_state |= (1<<state);
+
+ prop = xmlGetProp (node,(const xmlChar *) "file");
+ if (prop)
+ {
+ if (g_path_is_absolute ((char *) prop))
+ info->data.pixmap.files[state] = g_strdup ((char *) prop);
+ else
+ info->data.pixmap.files[state] = g_build_filename (file_search_path,
+ (char *) prop,
+ NULL);
+
+ xmlFree (prop);
+ }
+
+ {
+ int i = 1;
+ char *altfile_prop_name = g_strdup_printf ("altfile%d", i);
+
+ prop = xmlGetProp (node,(const xmlChar *) altfile_prop_name);
+ while (prop)
+ {
+ char *filename = NULL;
+ if (g_path_is_absolute ((char *) prop))
+ filename = g_strdup ((char *) prop);
+ else
+ filename = g_build_filename (file_search_path,
+ (char *) prop,
+ NULL);
+
+ if (g_file_test (filename, G_FILE_TEST_EXISTS))
+ {
+ if (info->data.pixmap.files[state])
+ g_free (info->data.pixmap.files[state]);
+ info->data.pixmap.files[state] = filename;
+ }
+ xmlFree (prop);
+ g_free (altfile_prop_name);
+
+ i++;
+ altfile_prop_name = g_strdup_printf ("altfile%d", i);
+ prop = xmlGetProp (node,(const xmlChar *) altfile_prop_name);
+ }
+ g_free (altfile_prop_name);
+ }
+
+ prop = xmlGetProp (node,(const xmlChar *) "tint");
+ if (prop)
+ {
+ if (!parse_color ((char *) prop, &info->data.pixmap.tints[state], error))
+ return FALSE;
+ info->data.pixmap.have_tint |= (1<<state);
+ xmlFree (prop);
+ }
+
+ prop = xmlGetProp (node,(const xmlChar *) "alpha");
+ if (prop)
+ {
+ double alpha = g_ascii_strtod ((char *) prop, &p);
+
+ if G_UNLIKELY ((char *)prop == p)
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "Bad alpha specifier format %s", prop);
+ xmlFree (prop);
+ return FALSE;
+ }
+ xmlFree (prop);
+
+ if (alpha >= 1.0)
+ info->data.pixmap.alphas[state] = 0xff;
+ else if (alpha < 0)
+ info->data.pixmap.alphas[state] = 0;
+ else
+ info->data.pixmap.alphas[state] = floor (alpha * 0xff);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+parse_state_color_rect (xmlNodePtr node,
+ GreeterItemInfo *info,
+ GreeterItemState state,
+ GError **error)
+{
+ xmlChar *prop;
+ char *p;
+
+ info->have_state |= (1<<state);
+
+ prop = xmlGetProp (node,(const xmlChar *) "color");
+ if (prop)
+ {
+ if G_UNLIKELY (!parse_color ((char *) prop, &info->data.rect.colors[state], error))
+ return FALSE;
+ info->data.rect.have_color |= (1<<state);
+ xmlFree (prop);
+ }
+
+ prop = xmlGetProp (node,(const xmlChar *) "alpha");
+ if (prop)
+ {
+ double alpha = g_ascii_strtod ((char *) prop, &p);
+
+ if G_UNLIKELY ((char *)prop == p)
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "Bad alpha specifier format %s", prop);
+ xmlFree (prop);
+ return FALSE;
+ }
+ xmlFree (prop);
+
+ if (alpha >= 1.0)
+ info->data.rect.alphas[state] = 0xff;
+ else if (alpha < 0)
+ info->data.rect.alphas[state] = 0;
+ else
+ info->data.rect.alphas[state] = floor (alpha * 0xff);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+parse_color_list (xmlNodePtr node,
+ GreeterItemInfo *info,
+ GError **error)
+{
+ xmlChar *prop;
+ guint32 color;
+
+ prop = xmlGetProp (node,(const xmlChar *) "iconcolor");
+ if (prop)
+ {
+ if G_UNLIKELY (!parse_color ((char *) prop, &color, error)) {
+ info->data.list.icon_color = NULL;
+ return FALSE;
+ } else {
+ info->data.list.icon_color = g_strdup ((char *) prop);
+ }
+
+ xmlFree (prop);
+ }
+
+ prop = xmlGetProp (node,(const xmlChar *) "labelcolor");
+ if (prop)
+ {
+ if G_UNLIKELY (!parse_color ((char *) prop, &color, error)) {
+ info->data.list.label_color = NULL;
+ return FALSE;
+ } else {
+ info->data.list.label_color = g_strdup ((char *) prop);
+ }
+
+ xmlFree (prop);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+parse_pixmap (xmlNodePtr node,
+ gboolean svg,
+ GreeterItemInfo *info,
+ GError **error)
+{
+ xmlNodePtr child;
+ int i;
+
+ child = node->children;
+
+ while (child)
+ {
+ if (strcmp ((char *) child->name, "normal") == 0)
+ {
+ if G_UNLIKELY (!parse_state_file_pixmap (child, info, GREETER_ITEM_STATE_NORMAL, error))
+ return FALSE;
+ }
+ else if (strcmp ((char *) child->name, "prelight") == 0)
+ {
+ if G_UNLIKELY (!parse_state_file_pixmap (child, info, GREETER_ITEM_STATE_PRELIGHT, error))
+ return FALSE;
+ }
+ else if (strcmp ((char *) child->name, "active") == 0)
+ {
+ if G_UNLIKELY (!parse_state_file_pixmap (child, info, GREETER_ITEM_STATE_ACTIVE, error))
+ return FALSE;
+ }
+ else if (strcmp ((char *) child->name, "pos") == 0)
+ {
+ if G_UNLIKELY (!parse_pos (child, info, error))
+ return FALSE;
+ }
+ else if (strcmp ((char *) child->name, "fixed") == 0)
+ {
+ if G_UNLIKELY (!parse_fixed (child, info, error))
+ return FALSE;
+ }
+ else if (strcmp ((char *) child->name, "box") == 0)
+ {
+ if G_UNLIKELY (!parse_box (child, info, error))
+ return FALSE;
+ }
+ else if (strcmp ((char *) child->name, "show") == 0)
+ {
+ if G_UNLIKELY (!parse_show (child, info, error))
+ return FALSE;
+ }
+
+ child = child->next;
+ }
+
+ if G_UNLIKELY (!info->data.pixmap.files[GREETER_ITEM_STATE_NORMAL])
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "No filename specified for normal state");
+ return FALSE;
+ }
+
+ if (!svg)
+ {
+ for (i = 0; i < GREETER_ITEM_STATE_MAX; i++)
+ {
+ if (info->data.pixmap.files[i] != NULL)
+ {
+ info->data.pixmap.pixbufs[i] = load_pixbuf (info->data.pixmap.files[i], error);
+
+ if G_UNLIKELY (info->data.pixmap.pixbufs[i] == NULL)
+ return FALSE;
+ }
+ else
+ info->data.pixmap.pixbufs[i] = NULL;
+ }
+ }
+
+ return TRUE;
+}
+
+static gboolean
+parse_rect (xmlNodePtr node,
+ GreeterItemInfo *info,
+ GError **error)
+{
+ xmlNodePtr child;
+ int i;
+
+ child = node->children;
+
+ while (child)
+ {
+ if (strcmp ((char *) child->name, "normal") == 0)
+ {
+ if G_UNLIKELY (!parse_state_color_rect (child, info, GREETER_ITEM_STATE_NORMAL, error))
+ return FALSE;
+ }
+ else if (strcmp ((char *) child->name, "prelight") == 0)
+ {
+ if G_UNLIKELY (!parse_state_color_rect (child, info, GREETER_ITEM_STATE_PRELIGHT, error))
+ return FALSE;
+ }
+ else if (strcmp ((char *) child->name, "active") == 0)
+ {
+ if G_UNLIKELY (!parse_state_color_rect (child, info, GREETER_ITEM_STATE_ACTIVE, error))
+ return FALSE;
+ }
+ else if (strcmp ((char *) child->name, "pos") == 0)
+ {
+ if G_UNLIKELY (!parse_pos (child, info, error))
+ return FALSE;
+ }
+ else if (strcmp ((char *) child->name, "fixed") == 0)
+ {
+ if G_UNLIKELY (!parse_fixed (child, info, error))
+ return FALSE;
+ }
+ else if (strcmp ((char *) child->name, "box") == 0)
+ {
+ if G_UNLIKELY (!parse_box (child, info, error))
+ return FALSE;
+ }
+ else if (strcmp ((char *) child->name, "show") == 0)
+ {
+ if G_UNLIKELY (!parse_show (child, info, error))
+ return FALSE;
+ }
+
+ child = child->next;
+ }
+
+ for (i = 0; i < GREETER_ITEM_STATE_MAX; i++)
+ {
+ if ( ! (info->data.rect.have_color & (1<<i)))
+ continue;
+
+ info->data.rect.colors[i] = (info->data.rect.colors[i] << 8) | (guint) info->data.rect.alphas[i];
+ }
+
+ return TRUE;
+}
+
+
+static gboolean
+parse_state_text (xmlNodePtr node,
+ GreeterItemInfo *info,
+ GreeterItemState state,
+ GError **error)
+{
+ xmlChar *prop;
+ char *p;
+
+ info->have_state |= (1<<state);
+
+ prop = xmlGetProp (node,(const xmlChar *) "font");
+ if (prop)
+ {
+ info->data.text.fonts[state] = pango_font_description_from_string ((char *) prop);
+ if G_UNLIKELY (info->data.text.fonts[state] == NULL)
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "Bad font specification %s", prop);
+ xmlFree (prop);
+ return FALSE;
+ }
+ xmlFree (prop);
+ }
+
+ prop = xmlGetProp (node,(const xmlChar *) "color");
+ if (prop)
+ {
+ if G_UNLIKELY (!parse_color ((char *) prop, &info->data.text.colors[state], error))
+ return FALSE;
+ info->data.text.have_color |= (1<<state);
+ xmlFree (prop);
+ }
+
+ prop = xmlGetProp (node,(const xmlChar *) "alpha");
+ if (prop)
+ {
+ double alpha = g_ascii_strtod ((char *) prop, &p);
+
+ if G_UNLIKELY ((char *)prop == p)
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "Bad alpha specifier format %s", prop);
+ xmlFree (prop);
+ return FALSE;
+ }
+ xmlFree (prop);
+
+ if (alpha >= 1.0)
+ info->data.rect.alphas[state] = 0xff;
+ else if (alpha < 0)
+ info->data.rect.alphas[state] = 0;
+ else
+ info->data.rect.alphas[state] = floor (alpha * 0xff);
+ }
+
+ return TRUE;
+}
+
+static gint
+is_current_locale (const char *lang)
+{
+ const char * const *langs;
+ int score = 0;
+ int i;
+
+ langs = g_get_language_names ();
+
+ for (i = 0; langs[i] != NULL; i++)
+ {
+ if (strcmp (langs[i], lang) == 0)
+ return score;
+
+ score++;
+ }
+ return 1000;
+}
+
+static gboolean
+parse_translated_text (xmlNodePtr node,
+ char **translated_text,
+ gint *translation_score,
+ GError **error)
+{
+ xmlChar *text;
+ xmlChar *prop;
+ gint score;
+
+ prop = xmlNodeGetLang (node);
+ if (prop)
+ {
+ score = is_current_locale ((char *) prop);
+ xmlFree (prop);
+ } else
+ score = 999;
+
+ if (score >= *translation_score)
+ return TRUE;
+
+ text = xmlNodeGetContent (node);
+ if (text == NULL)
+ {
+ /* This is empty text */
+ *translation_score = score;
+ if (*translated_text)
+ g_free (*translated_text);
+ *translated_text = g_strdup ("");
+
+ return TRUE;
+ }
+
+ *translation_score = score;
+ if (*translated_text)
+ g_free (*translated_text);
+ *translated_text = g_strdup ((char *) text);
+
+ xmlFree (text);
+
+ return TRUE;
+}
+
+static gboolean
+parse_label_pos_extras (xmlNodePtr node,
+ GreeterItemInfo *info,
+ GError **error)
+{
+ xmlChar *prop;
+ char *p;
+
+ prop = xmlGetProp (node,(const xmlChar *) "max-width");
+ if (prop)
+ {
+ info->data.text.max_width = g_ascii_strtod ((char *) prop, &p);
+
+ if G_UNLIKELY ((char *)prop == p)
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "Bad max-width specification %s", prop);
+ xmlFree (prop);
+ return FALSE;
+ }
+ xmlFree (prop);
+ }
+
+ prop = xmlGetProp (node,(const xmlChar *) "max-screen-percent-width");
+ if (prop)
+ {
+ info->data.text.max_screen_percent_width = g_ascii_strtod ((char *) prop, &p);
+
+ if G_UNLIKELY ((char *)prop == p)
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "Bad max-screen-percent-width specification %s", prop);
+ xmlFree (prop);
+ return FALSE;
+ }
+ xmlFree (prop);
+ }
+
+ return TRUE;
+}
+
+
+static gboolean
+parse_label (xmlNodePtr node,
+ GreeterItemInfo *info,
+ GError **error)
+{
+ xmlNodePtr child;
+ int i;
+ char *translated_text = NULL;
+ gint translation_score = 1000;
+
+ child = node->children;
+ while (child)
+ {
+ if (strcmp ((char *) child->name, "normal") == 0)
+ {
+ if G_UNLIKELY (!parse_state_text (child, info, GREETER_ITEM_STATE_NORMAL, error))
+ return FALSE;
+ }
+ else if (strcmp ((char *) child->name, "prelight") == 0)
+ {
+ if G_UNLIKELY (!parse_state_text (child, info, GREETER_ITEM_STATE_PRELIGHT, error))
+ return FALSE;
+ }
+ else if (strcmp ((char *) child->name, "active") == 0)
+ {
+ if G_UNLIKELY (!parse_state_text (child, info, GREETER_ITEM_STATE_ACTIVE, error))
+ return FALSE;
+ }
+ else if (strcmp ((char *) child->name, "pos") == 0)
+ {
+ if G_UNLIKELY (!parse_pos (child, info, error))
+ return FALSE;
+ if G_UNLIKELY (!parse_label_pos_extras (child, info, error))
+ return FALSE;
+ }
+ else if (child->type == XML_ELEMENT_NODE &&
+ strcmp ((char *) child->name, "text") == 0)
+ {
+ if G_UNLIKELY (!parse_translated_text (child, &translated_text, &translation_score, error))
+ return FALSE;
+ }
+ else if (child->type == XML_ELEMENT_NODE &&
+ strcmp ((char *) child->name, "stock") == 0)
+ {
+ if G_UNLIKELY (!parse_stock (child, info, &translated_text, &translation_score, error))
+ return FALSE;
+ }
+ else if (strcmp ((char *) child->name, "show") == 0)
+ {
+ if G_UNLIKELY (!parse_show (child, info, error))
+ return FALSE;
+ }
+ else if (strcmp ((char *) child->name, "fixed") == 0 ||
+ strcmp ((char *) child->name, "box") == 0)
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "Label items cannot have children");
+ return FALSE;
+ }
+
+ child = child->next;
+ }
+
+ if (translated_text == NULL)
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "A label must specify the text attribute");
+ return FALSE;
+ }
+ /* FIXME: evil hack to use internally translated strings */
+ if (translation_score == 999 &&
+ ! ve_string_empty (translated_text))
+ {
+ char *foo = g_strdup (_(translated_text));
+ g_free (translated_text);
+ translated_text = foo;
+ }
+
+ for (i = 0; i < GREETER_ITEM_STATE_MAX; i++)
+ {
+ if ( ! (info->data.text.have_color & (1<<i)))
+ continue;
+
+ info->data.text.colors[i] = (info->data.text.colors[i] << 8) | (guint) info->data.text.alphas[i];
+ }
+
+ if (info->data.text.fonts[GREETER_ITEM_STATE_NORMAL] == NULL)
+ info->data.text.fonts[GREETER_ITEM_STATE_NORMAL] = pango_font_description_from_string ("Sans");
+
+ do_font_size_reduction (info);
+
+ info->data.text.orig_text = translated_text;
+
+ return TRUE;
+}
+
+static gboolean
+parse_listitem (xmlNodePtr node,
+ GreeterItemInfo *info,
+ GError **error)
+{
+ xmlNodePtr child;
+ xmlChar *prop;
+ GreeterItemListItem *li;
+ char *translated_text = NULL;
+ gint translation_score = 1000;
+
+ prop = xmlGetProp (node,(const xmlChar *) "id");
+
+ if G_LIKELY (prop)
+ {
+ li = g_new0 (GreeterItemListItem, 1);
+ li->id = g_strdup ((char *) prop);
+ xmlFree (prop);
+ }
+ else
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "Listitem id not specified");
+ return FALSE;
+ }
+
+ child = node->children;
+ while (child)
+ {
+ if (child->type == XML_ELEMENT_NODE &&
+ strcmp ((char *) child->name, "text") == 0)
+ {
+ if G_UNLIKELY ( ! parse_translated_text (child, &translated_text, &translation_score, error))
+ {
+ g_free (li->id);
+ g_free (li);
+ return FALSE;
+ }
+ }
+
+ child = child->next;
+ }
+
+ if G_UNLIKELY (translated_text == NULL)
+ {
+ g_free (li->id);
+ g_free (li);
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "A list item must specify the text attribute");
+ return FALSE;
+ }
+ li->text = translated_text;
+
+ info->data.list.items = g_list_append (info->data.list.items, li);
+
+ return TRUE;
+}
+
+static gboolean
+parse_list (xmlNodePtr node,
+ GreeterItemInfo *info,
+ GError **error)
+{
+ xmlNodePtr child;
+ xmlChar *prop;
+
+ info->data.list.combo_type = FALSE;
+ prop = xmlGetProp (node,(const xmlChar *) "combo");
+ if (prop)
+ {
+ if (strcmp ((char *) prop, "true") == 0)
+ {
+ info->data.list.combo_type = TRUE;
+ }
+ else if (strcmp ((char *) prop, "false") == 0)
+ {
+ info->data.list.combo_type = FALSE;
+ }
+ xmlFree (prop);
+ }
+
+ child = node->children;
+ while (child)
+ {
+ if (strcmp ((char *) child->name, "color") == 0)
+ {
+ if G_UNLIKELY (!parse_color_list (child, info, error))
+ return FALSE;
+ }
+ if (strcmp ((char *) child->name, "pos") == 0)
+ {
+ if G_UNLIKELY (!parse_pos (child, info, error))
+ return FALSE;
+ }
+ else if (strcmp ((char *) child->name, "show") == 0)
+ {
+ if G_UNLIKELY (!parse_show (child, info, error))
+ return FALSE;
+ }
+ else if (strcmp ((char *) child->name, "listitem") == 0)
+ {
+ if G_UNLIKELY ( ! parse_listitem (child, info, error))
+ return FALSE;
+ }
+ else if (strcmp ((char *) child->name, "fixed") == 0 ||
+ strcmp ((char *) child->name, "box") == 0)
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "List items cannot have children");
+ return FALSE;
+ }
+
+ child = child->next;
+ }
+
+ if ((strcmp (info->id, "userlist") == 0) && (info->data.list.combo_type == TRUE)) {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "userlist doest not support combo style");
+ return FALSE;
+ } else if (info->data.list.items != NULL) {
+
+ if G_UNLIKELY (strcmp (info->id, "userlist") == 0 ||
+ strcmp (info->id, "session") == 0 ||
+ strcmp (info->id, "language") == 0) {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "List of id userlist, session, and language cannot have custom list items");
+ return FALSE;
+ }
+ custom_items = g_list_append (custom_items, info);
+
+ } else if (strcmp (info->id, "session") == 0 ||
+ strcmp (info->id, "language") == 0) {
+ custom_items = g_list_append (custom_items, info);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+parse_entry (xmlNodePtr node,
+ GreeterItemInfo *info,
+ GError **error)
+{
+ xmlNodePtr child;
+
+ child = node->children;
+ while (child)
+ {
+ if (strcmp ((char *) child->name, "normal") == 0)
+ {
+ if G_UNLIKELY (!parse_state_text (child, info, GREETER_ITEM_STATE_NORMAL, error))
+ return FALSE;
+ }
+ else if (strcmp ((char *) child->name, "pos") == 0)
+ {
+ if G_UNLIKELY (!parse_pos (child, info, error))
+ return FALSE;
+ }
+ else if (strcmp ((char *) child->name, "show") == 0)
+ {
+ if G_UNLIKELY (!parse_show (child, info, error))
+ return FALSE;
+ }
+ else if (strcmp ((char *) child->name, "fixed") == 0 ||
+ strcmp ((char *) child->name, "box") == 0)
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "Entry items cannot have children");
+ return FALSE;
+ }
+
+ child = child->next;
+ }
+
+ do_font_size_reduction (info);
+
+ return TRUE;
+}
+
+static gboolean
+parse_items (xmlNodePtr node,
+ GList **items_out,
+ GreeterItemInfo *parent,
+ GError **error)
+{
+ xmlNodePtr child;
+ GList *items;
+ gboolean res;
+ xmlChar *type;
+ xmlChar *background;
+ GreeterItemInfo *info;
+ GreeterItemType item_type;
+
+ *items_out = NULL;
+
+ items = NULL;
+
+ child = node->children;
+ while (child)
+ {
+ if (child->type == XML_ELEMENT_NODE)
+ {
+ if G_UNLIKELY (strcmp ((char *) child->name, "item") != 0)
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "Found tag %s when looking for item", child->name);
+ return FALSE;
+ }
+
+ type = xmlGetProp (child, (const xmlChar *) "type");
+ if G_UNLIKELY (!type)
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "Items must specify their type");
+ return FALSE;
+ }
+
+ if (strcmp ((char *) type, "svg") == 0)
+ item_type = GREETER_ITEM_TYPE_SVG;
+ else if (strcmp ((char *) type, "pixmap") == 0)
+ item_type = GREETER_ITEM_TYPE_PIXMAP;
+ else if (strcmp ((char *) type, "rect") == 0)
+ item_type = GREETER_ITEM_TYPE_RECT;
+ else if (strcmp ((char *) type, "label") == 0)
+ item_type = GREETER_ITEM_TYPE_LABEL;
+ else if (strcmp ((char *) type, "entry") == 0)
+ item_type = GREETER_ITEM_TYPE_ENTRY;
+ else if (strcmp ((char *) type, "list") == 0)
+ item_type = GREETER_ITEM_TYPE_LIST;
+ else if (strcmp ((char *) type, "button") == 0)
+ item_type = GREETER_ITEM_TYPE_BUTTON;
+ else
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "Unknown item type %s", type);
+ xmlFree (type);
+ return FALSE;
+ }
+
+ xmlFree (type);
+
+ info = greeter_item_info_new (parent, item_type);
+
+ parse_id (child, info);
+ if G_UNLIKELY ( ! parse_canvasbutton (child, info, error))
+ return FALSE;
+
+ if (button_stack != NULL)
+ info->my_button = button_stack->data;
+ if (info->canvasbutton)
+ button_stack = g_list_prepend (button_stack, info);
+
+ switch (item_type)
+ {
+ case GREETER_ITEM_TYPE_SVG:
+ res = parse_pixmap (child, TRUE, info, error);
+ break;
+ case GREETER_ITEM_TYPE_PIXMAP:
+ res = parse_pixmap (child, FALSE, info, error);
+ break;
+ case GREETER_ITEM_TYPE_RECT:
+ res = parse_rect (child, info, error);
+ break;
+ case GREETER_ITEM_TYPE_LABEL:
+ res = parse_label (child, info, error);
+ break;
+ case GREETER_ITEM_TYPE_ENTRY:
+ res = parse_entry (child, info, error);
+ break;
+ case GREETER_ITEM_TYPE_LIST:
+ res = parse_list (child, info, error);
+ break;
+ case GREETER_ITEM_TYPE_BUTTON:
+ res = parse_gtkbutton (child, info, error);
+ break;
+ default:
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_SPEC,
+ "Bad item type");
+ res = FALSE;
+ }
+
+ if (info->canvasbutton)
+ button_stack = g_list_remove (button_stack, info);
+
+ background = xmlGetProp (child, (const xmlChar *) "background");
+ if G_UNLIKELY (background)
+ {
+ if (strcmp ((char *) background, "true") == 0)
+ {
+ info->background = TRUE;
+ }
+ else if (strcmp ((char *) background, "false") == 0)
+ {
+ info->background = FALSE;
+ }
+ xmlFree (background);
+ }
+
+ if G_UNLIKELY (!res)
+ return FALSE;
+
+ items = g_list_prepend (items, info);
+
+ }
+ child = child->next;
+ }
+
+ *items_out = g_list_reverse (items);
+ return TRUE;
+}
+
+static gboolean
+greeter_info_id_equal (GreeterItemInfo *a,
+ GreeterItemInfo *b)
+{
+ return g_str_equal (a->id, b->id);
+}
+
+static guint
+greeter_info_id_hash (GreeterItemInfo *key)
+{
+ return g_str_hash (key->id);
+}
+
+GreeterItemInfo *
+greeter_parse (const char *file, const char *datadir,
+ GnomeCanvas *canvas,
+ int width, int height, GError **error)
+{
+ GreeterItemInfo *root;
+ xmlDocPtr doc;
+ xmlNodePtr node;
+ xmlChar *prop;
+ gboolean res;
+ GList *items;
+
+ /* FIXME: EVIL! GLOBAL! */
+ g_free (file_search_path);
+ file_search_path = g_strdup (datadir);
+
+ if G_UNLIKELY (!g_file_test (file, G_FILE_TEST_EXISTS))
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_NO_FILE,
+ "Can't open file %s", file);
+ return NULL;
+ }
+
+
+ doc = xmlParseFile (file);
+ if G_UNLIKELY (doc == NULL)
+ {
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_XML,
+ "XML Parse error reading %s", file);
+ return NULL;
+ }
+
+ node = xmlDocGetRootElement (doc);
+ if G_UNLIKELY (node == NULL)
+ {
+ xmlFreeDoc (doc);
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_BAD_XML,
+ "Can't find the xml root node in file %s", file);
+ return NULL;
+ }
+
+ if G_UNLIKELY (strcmp ((char *) node->name, "greeter") != 0)
+ {
+ xmlFreeDoc (doc);
+ g_set_error (error,
+ GREETER_PARSER_ERROR,
+ GREETER_PARSER_ERROR_WRONG_TYPE,
+ "The file %s has the wrong xml type", file);
+ return NULL;
+ }
+
+ /*
+ * The gtk-theme property specifies a theme specific gtk-theme to use
+ */
+ prop = xmlGetProp (node, (const xmlChar *) "gtk-theme");
+ if (prop)
+ {
+ gchar *theme_dir;
+
+ /*
+ * It might be nice if we allowed this property to also supply a gtkrc file
+ * that could be included in the theme. Perhaps we should check first in
+ * the theme directory for a gtkrc file by the provided name and use that
+ * if found.
+ */
+ theme_dir = g_strdup_printf ("%s/%s", gtk_rc_get_theme_dir (), (char *) prop);
+ if (g_file_test (theme_dir, G_FILE_TEST_IS_DIR))
+ gdm_set_theme ((char *) prop);
+
+ xmlFree (prop);
+ }
+
+ item_hash = g_hash_table_new ((GHashFunc)greeter_info_id_hash,
+ (GEqualFunc)greeter_info_id_equal);
+
+
+ root = greeter_item_info_new (NULL, GREETER_ITEM_TYPE_RECT);
+ res = parse_items (node, &items, root, error);
+
+ /* Now we can whack the hash, we don't want to keep cached
+ pixbufs around anymore */
+ if (pixbuf_hash != NULL) {
+ g_hash_table_destroy (pixbuf_hash);
+ pixbuf_hash = NULL;
+ }
+
+ if G_UNLIKELY (!res)
+ {
+ welcome_string_info = NULL;
+
+ g_hash_table_destroy (item_hash);
+ item_hash = NULL;
+ g_list_free (custom_items);
+ custom_items = NULL;
+
+ g_list_free (button_stack);
+ button_stack = NULL;
+
+ g_list_foreach (items, (GFunc) greeter_item_info_free, NULL);
+ g_list_free (items);
+ items = NULL;
+
+ greeter_item_info_free (root);
+
+ xmlFreeDoc (doc);
+
+ return NULL;
+ }
+
+ xmlFreeDoc (doc);
+
+ root->fixed_children = items;
+
+ root->x = 0;
+ root->y = 0;
+ root->x_type = GREETER_ITEM_POS_ABSOLUTE;
+ root->y_type = GREETER_ITEM_POS_ABSOLUTE;
+
+ root->width = width;
+ root->height = height;
+ root->width_type = GREETER_ITEM_SIZE_ABSOLUTE;
+ root->width_type = GREETER_ITEM_SIZE_ABSOLUTE;
+
+ root->group_item = gnome_canvas_root (canvas);
+
+ return root;
+}
+
+const GList *
+greeter_custom_items (void)
+{
+ return custom_items;
+}
+
+static void
+hide_item (GreeterItemInfo *info, gpointer user_data)
+{
+ GnomeCanvasItem *item;
+ gboolean *found_background;
+
+ found_background = user_data;
+
+ if (info)
+ {
+ if (info->background)
+ {
+ *found_background = TRUE;
+ }
+ else {
+ item = info->item;
+ if (item) {
+ if (GNOME_IS_CANVAS_WIDGET (item)) {
+ gtk_widget_hide (GNOME_CANVAS_WIDGET (item)->widget);
+ }
+ else
+ gnome_canvas_item_hide (item);
+ }
+ if ((info->item_type == GREETER_ITEM_TYPE_ENTRY) &&
+ (info->data.text.menubar != NULL)) {
+ gtk_widget_hide (info->data.text.menubar);
+ }
+ }
+
+ g_list_foreach (info->fixed_children, (GFunc) hide_item, user_data);
+ g_list_foreach (info->box_children, (GFunc) hide_item, user_data);
+ }
+}
+
+gboolean
+greeter_show_only_background (GreeterItemInfo *root_item)
+{
+ gboolean found_background = FALSE;
+
+ hide_item (root_item, &found_background);
+
+ /* ensure root canvas is updated */
+ while (gtk_events_pending ())
+ gtk_main_iteration ();
+
+ return found_background;
+}
diff --git a/trunk/gui/greeter/greeter_parser.h b/trunk/gui/greeter/greeter_parser.h
new file mode 100644
index 00000000..b5021124
--- /dev/null
+++ b/trunk/gui/greeter/greeter_parser.h
@@ -0,0 +1,48 @@
+/* GDM - The GNOME Display Manager
+ * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
+ *
+ * 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 __GREETER_PARSER_H__
+#define __GREETER_PARSER_H__
+
+#include <libgnomecanvas/libgnomecanvas.h>
+#include "greeter_item.h"
+
+
+typedef enum
+{
+ GREETER_PARSER_ERROR_NO_FILE,
+ GREETER_PARSER_ERROR_BAD_XML,
+ GREETER_PARSER_ERROR_WRONG_TYPE,
+ GREETER_PARSER_ERROR_BAD_SPEC
+} GreeterParseError;
+
+#define GREETER_PARSER_ERROR greeter_parser_error_quark()
+GQuark greeter_parser_error_quark (void);
+
+GreeterItemInfo *greeter_parse (const char *file,
+ const char *data_dir,
+ GnomeCanvas *canvas,
+ int width,
+ int height,
+ GError **error);
+
+GreeterItemInfo *greeter_lookup_id (const char *id);
+const GList *greeter_custom_items (void);
+gboolean greeter_show_only_background (GreeterItemInfo *root_item);
+
+#endif /* __GREETER_PARSER_H__ */
diff --git a/trunk/gui/greeter/greeter_session.c b/trunk/gui/greeter/greeter_session.c
new file mode 100644
index 00000000..9820a119
--- /dev/null
+++ b/trunk/gui/greeter/greeter_session.c
@@ -0,0 +1,271 @@
+/* GDM - The GNOME Display Manager
+ * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
+ *
+ * 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
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <string.h>
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+
+#include "gdm.h"
+#include "gdmwm.h"
+#include "gdmcommon.h"
+#include "gdmconfig.h"
+#include "gdmsession.h"
+
+#include "gdm-common.h"
+#include "gdm-daemon-config-keys.h"
+
+#include "greeter.h"
+#include "greeter_session.h"
+#include "greeter_item_pam.h"
+#include "greeter_item_customlist.h"
+#include "greeter_configuration.h"
+#include "greeter_events.h"
+#include "greeter_parser.h"
+
+static GtkWidget *session_dialog;
+static GSList *session_group = NULL;
+extern GList *sessions;
+extern GHashTable *sessnames;
+extern gchar *default_session;
+extern char *current_session;
+extern gboolean session_dir_whacked_out;
+
+void
+greeter_set_session (char *session)
+{
+ g_free (current_session);
+ current_session = g_strdup (session);
+ greeter_custom_set_session (session);
+}
+
+void
+greeter_session_init (void)
+{
+ GtkWidget *w = NULL;
+ GtkWidget *hbox = NULL;
+ GtkWidget *main_vbox = NULL;
+ GtkWidget *vbox = NULL;
+ GtkWidget *cat_vbox = NULL;
+ GtkWidget *radio;
+ GtkWidget *dialog;
+ GtkWidget *button;
+ GList *tmp;
+ static GtkTooltips *tooltips = NULL;
+ GtkRequisition req;
+ char *s;
+ int num = 1;
+ char *label;
+
+ greeter_set_session (NULL);
+
+ session_dialog = dialog = gtk_dialog_new ();
+ if (tooltips == NULL)
+ tooltips = gtk_tooltips_new ();
+
+ gtk_dialog_add_button (GTK_DIALOG (dialog),
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL);
+
+ button = gtk_button_new_with_mnemonic (_("Change _Session"));
+ GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
+ gtk_widget_show (button);
+ gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button,
+ GTK_RESPONSE_OK);
+
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+ gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (dialog)->vbox), 2);
+ gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+ gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+
+ main_vbox = gtk_vbox_new (FALSE, 18);
+ gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 5);
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
+ main_vbox,
+ FALSE, FALSE, 0);
+
+ cat_vbox = gtk_vbox_new (FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (main_vbox),
+ cat_vbox,
+ FALSE, FALSE, 0);
+
+ s = g_strdup_printf ("<b>%s</b>", _("Sessions"));
+ w = gtk_label_new (s);
+ gtk_label_set_use_markup (GTK_LABEL (w), TRUE);
+ g_free (s);
+ gtk_misc_set_alignment (GTK_MISC (w), 0.0, 0.5);
+ gtk_box_pack_start (GTK_BOX (cat_vbox), w, FALSE, FALSE, 0);
+
+ hbox = gtk_hbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (cat_vbox),
+ hbox, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox),
+ gtk_label_new (" "),
+ FALSE, FALSE, 0);
+ vbox = gtk_vbox_new (FALSE, 6);
+ /* we will pack this later depending on size */
+
+ if (gdm_config_get_bool (GDM_KEY_SHOW_LAST_SESSION))
+ {
+ greeter_set_session (LAST_SESSION);
+
+ radio = gtk_radio_button_new_with_mnemonic (session_group, _("_Last session"));
+ g_object_set_data (G_OBJECT (radio),
+ SESSION_NAME,
+ LAST_SESSION);
+ session_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio));
+ gtk_tooltips_set_tip (tooltips, radio,
+ _("Log in using the session that you have used "
+ "last time you logged in"),
+ NULL);
+ gtk_box_pack_start (GTK_BOX (vbox), radio, FALSE, FALSE, 0);
+ gtk_widget_show (radio);
+ }
+
+ gdm_session_list_init ();
+
+ for (tmp = sessions; tmp != NULL; tmp = tmp->next)
+ {
+ GdmSession *session;
+ char *file;
+
+ file = (char *) tmp->data;
+ session = g_hash_table_lookup (sessnames, file);
+
+ if (num < 10 &&
+ (strcmp (file, GDM_SESSION_FAILSAFE_GNOME) != 0) &&
+ (strcmp (file, GDM_SESSION_FAILSAFE_XTERM) != 0))
+ label = g_strdup_printf ("_%d. %s", num, session->name);
+ else
+ label = g_strdup (session->name);
+ num++;
+
+ radio = gtk_radio_button_new_with_mnemonic (session_group, label);
+ g_free (label);
+ g_object_set_data_full (G_OBJECT (radio), SESSION_NAME,
+ file, (GDestroyNotify) g_free);
+ session_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (radio));
+ gtk_box_pack_start (GTK_BOX (vbox), radio, FALSE, FALSE, 0);
+ gtk_widget_show (radio);
+
+ if (! ve_string_empty (session->comment))
+ gtk_tooltips_set_tip
+ (tooltips, GTK_WIDGET (radio), session->comment, NULL);
+ }
+
+ gtk_widget_show_all (vbox);
+ gtk_widget_size_request (vbox, &req);
+
+ /* if too large */
+ if (req.height > 0.7 * gdm_wm_screen.height) {
+ GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL);
+ gtk_widget_set_size_request (sw,
+ req.width,
+ 0.7 * gdm_wm_screen.height);
+ gtk_scrolled_window_set_shadow_type
+ (GTK_SCROLLED_WINDOW (sw),
+ GTK_SHADOW_NONE);
+ gtk_scrolled_window_set_policy
+ (GTK_SCROLLED_WINDOW (sw),
+ GTK_POLICY_NEVER,
+ GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_add_with_viewport
+ (GTK_SCROLLED_WINDOW (sw), vbox);
+ gtk_widget_show (sw);
+ gtk_box_pack_start (GTK_BOX (hbox),
+ sw,
+ TRUE, TRUE, 0);
+ } else {
+ gtk_box_pack_start (GTK_BOX (hbox),
+ vbox,
+ TRUE, TRUE, 0);
+ }
+}
+
+/*
+ * The button with this handler appears in the F10 menu, so it
+ * cannot depend on callback data being passed in.
+ */
+static void
+greeter_session_handler (GreeterItemInfo *info,
+ gpointer user_data)
+{
+ GSList *tmp;
+ int ret;
+
+ /* Select the proper session */
+ tmp = session_group;
+ while (tmp != NULL)
+ {
+ GtkWidget *w = tmp->data;
+ const char *n;
+
+ n = g_object_get_data (G_OBJECT (w), SESSION_NAME);
+
+ if (n && strcmp (n, current_session) == 0)
+ {
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (w),
+ TRUE);
+ break;
+ }
+
+ tmp = tmp->next;
+ }
+
+ gtk_widget_show_all (session_dialog);
+
+ gdm_wm_center_window (GTK_WINDOW (session_dialog));
+
+ gdm_wm_no_login_focus_push ();
+ ret = gtk_dialog_run (GTK_DIALOG (session_dialog));
+ gdm_wm_no_login_focus_pop ();
+ gtk_widget_hide (session_dialog);
+
+ if (ret == GTK_RESPONSE_OK)
+ {
+ tmp = session_group;
+ while (tmp != NULL)
+ {
+ GtkWidget *w = tmp->data;
+ const char *n;
+
+ if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (w)))
+ {
+ n = g_object_get_data (G_OBJECT (w), SESSION_NAME);
+ greeter_set_session ((char *)n);
+ break;
+ }
+
+ tmp = tmp->next;
+ }
+ }
+}
+
+void
+greeter_item_session_setup ()
+{
+ greeter_item_register_action_callback ("session_button",
+ (ActionFunc)greeter_session_handler,
+ NULL);
+}
diff --git a/trunk/gui/greeter/greeter_session.h b/trunk/gui/greeter/greeter_session.h
new file mode 100644
index 00000000..43cf8f72
--- /dev/null
+++ b/trunk/gui/greeter/greeter_session.h
@@ -0,0 +1,26 @@
+/* GDM - The GNOME Display Manager
+ * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
+ *
+ * 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 __GREETER_SESSION_H__
+#define __GREETER_SESSION_H__
+
+void greeter_session_init (void);
+void greeter_item_session_setup (void);
+void greeter_set_session (char *session);
+
+#endif /* __GREETER_SESSION_H__ */
diff --git a/trunk/gui/greeter/greeter_system.c b/trunk/gui/greeter/greeter_system.c
new file mode 100644
index 00000000..65729c83
--- /dev/null
+++ b/trunk/gui/greeter/greeter_system.c
@@ -0,0 +1,594 @@
+/* GDM - The GNOME Display Manager
+ * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
+ *
+ * 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
+ */
+
+#include "config.h"
+
+#include <unistd.h>
+#include <string.h>
+
+#ifdef HAVE_CHKAUTHATTR
+#include <auth_attr.h>
+#include <secdb.h>
+#endif
+
+#include <gtk/gtk.h>
+#include <glib/gi18n.h>
+
+#include "gdm.h"
+#include "gdmcommon.h"
+#include "gdmconfig.h"
+#include "gdmwm.h"
+#include "misc.h"
+
+#include "gdm-common.h"
+#include "gdm-socket-protocol.h"
+#include "gdm-daemon-config-keys.h"
+
+#include "greeter.h"
+#include "greeter_configuration.h"
+#include "greeter_system.h"
+#include "greeter_item.h"
+#include "greeter_item_ulist.h"
+#include "greeter_parser.h"
+
+GtkWidget *dialog;
+extern gboolean GdmHaltFound;
+extern gboolean GdmRebootFound;
+extern gboolean *GdmCustomCmdsFound;
+extern gboolean GdmAnyCustomCmdsFound;
+extern gboolean GdmSuspendFound;
+extern gboolean GdmConfiguratorFound;
+
+/* doesn't check for executability, just for existance */
+static gboolean
+bin_exists (const char *command)
+{
+ char *bin;
+
+ if (ve_string_empty (command))
+ return FALSE;
+
+ /* Note, check only for existance, not for executability */
+ bin = ve_first_word (command);
+ if (bin != NULL &&
+ g_access (bin, F_OK) == 0) {
+ g_free (bin);
+ return TRUE;
+ } else {
+ g_free (bin);
+ return FALSE;
+ }
+}
+
+/*
+ * The buttons with these handlers appear in the F10 menu, so they
+ * cannot depend on callback data being passed in.
+ */
+static void
+query_greeter_restart_handler (void)
+{
+ if (gdm_wm_warn_dialog (_("Are you sure you want to restart the computer?"), "",
+ _("_Restart"), NULL, TRUE) == GTK_RESPONSE_YES) {
+ _exit (DISPLAY_REBOOT);
+ }
+}
+
+static void
+query_greeter_custom_cmd_handler (GtkWidget *widget, gpointer data)
+{
+ if (data) {
+ gint *cmd_id = (gint*)data;
+ gchar * key_string = g_strdup_printf ("%s%d=", GDM_KEY_CUSTOM_CMD_TEXT_TEMPLATE, *cmd_id);
+ if (gdm_wm_warn_dialog (gdm_config_get_string (key_string) , "",
+ GTK_STOCK_OK, NULL, TRUE) == GTK_RESPONSE_YES) {
+ printf ("%c%c%c%d\n", STX, BEL, GDM_INTERRUPT_CUSTOM_CMD, *cmd_id);
+ fflush (stdout);
+ }
+ g_free (key_string);
+ }
+}
+
+static void
+query_greeter_halt_handler (void)
+{
+ if (gdm_wm_warn_dialog (_("Are you sure you want to Shut Down the computer?"), "",
+ _("Shut _Down"), NULL, TRUE) == GTK_RESPONSE_YES) {
+ _exit (DISPLAY_HALT);
+ }
+}
+
+static void
+query_greeter_suspend_handler (void)
+{
+ if (gdm_wm_warn_dialog (_("Are you sure you want to suspend the computer?"), "",
+ _("_Suspend"), NULL, TRUE) == GTK_RESPONSE_YES) {
+ /* suspend interruption */
+ printf ("%c%c%c\n", STX, BEL, GDM_INTERRUPT_SUSPEND);
+ fflush (stdout);
+ }
+}
+
+static void
+greeter_restart_handler (void)
+{
+ _exit (DISPLAY_REBOOT);
+}
+
+static void
+greeter_custom_cmd_handler (gint cmd_id)
+{
+ printf ("%c%c%c%d\n", STX, BEL, GDM_INTERRUPT_CUSTOM_CMD, cmd_id);
+ fflush (stdout);
+}
+
+static void
+greeter_halt_handler (void)
+{
+ _exit (DISPLAY_HALT);
+}
+
+static void
+greeter_suspend_handler (void)
+{
+ printf ("%c%c%c\n", STX, BEL, GDM_INTERRUPT_SUSPEND);
+ fflush (stdout);
+}
+
+static void
+greeter_config_handler (void)
+{
+ greeter_item_ulist_disable ();
+
+ /* Make sure to unselect the user */
+ greeter_item_ulist_unset_selected_user ();
+
+ /* we should be now fine for focusing new windows */
+ gdm_wm_focus_new_windows (TRUE);
+
+ /* configure interruption */
+ printf ("%c%c%c\n", STX, BEL, GDM_INTERRUPT_CONFIGURE);
+ fflush (stdout);
+}
+
+static void
+greeter_chooser_handler (void)
+{
+ _exit (DISPLAY_RUN_CHOOSER);
+}
+
+static gboolean
+is_action_available (gchar *action)
+{
+ gchar **allowsyscmd = NULL;
+ const gchar *allowsyscmdval;
+ gboolean ret = FALSE;
+ int i;
+
+ allowsyscmdval = gdm_config_get_string (GDM_KEY_SYSTEM_COMMANDS_IN_MENU);
+ if (allowsyscmdval)
+ allowsyscmd = g_strsplit (allowsyscmdval, ";", 0);
+
+ if (allowsyscmd) {
+ for (i = 0; allowsyscmd[i] != NULL; i++) {
+ if (strcmp (allowsyscmd[i], action) == 0) {
+ ret = TRUE;
+ break;
+ }
+ }
+ }
+
+#ifdef HAVE_CHKAUTHATTR
+ if (ret == TRUE) {
+ gchar **rbackeys = NULL;
+ const gchar *rbackeysval;
+ const char *gdmuser;
+
+ gdmuser = gdm_config_get_string (GDM_KEY_USER);
+ rbackeysval = gdm_config_get_string (GDM_KEY_RBAC_SYSTEM_COMMAND_KEYS);
+ if (rbackeysval)
+ rbackeys = g_strsplit (rbackeysval, ";", 0);
+
+ if (rbackeys) {
+ for (i = 0; rbackeys[i] != NULL; i++) {
+ gchar **rbackey = g_strsplit (rbackeys[i], ":", 2);
+
+ if (! ve_string_empty (rbackey[0]) &&
+ ! ve_string_empty (rbackey[1]) &&
+ strcmp (rbackey[0], action) == 0) {
+
+ if (!chkauthattr (rbackey[1], gdmuser)) {
+ g_strfreev (rbackey);
+ ret = FALSE;
+ break;
+ }
+ }
+ g_strfreev (rbackey);
+ }
+ }
+ g_strfreev (rbackeys);
+ }
+#endif
+ g_strfreev (allowsyscmd);
+
+ return ret;
+}
+
+void
+greeter_system_append_system_menu (GtkWidget *menu)
+{
+ GtkWidget *w, *sep;
+ gint i = 0;
+
+ /* should never be allowed by the UI */
+ if ( ! gdm_config_get_bool (GDM_KEY_SYSTEM_MENU) ||
+ ve_string_empty (g_getenv ("GDM_IS_LOCAL")))
+ return;
+
+ if (gdm_config_get_bool (GDM_KEY_CHOOSER_BUTTON)) {
+ w = gtk_menu_item_new_with_mnemonic (_("Remote Login via _XDMCP..."));
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), w);
+ gtk_widget_show (GTK_WIDGET (w));
+ g_signal_connect (G_OBJECT (w), "activate",
+ G_CALLBACK (greeter_chooser_handler),
+ NULL);
+ }
+
+ /*
+ * Disable Configuration if using accessibility (AddGtkModules) since
+ * using it with accessibility causes a hang.
+ */
+ if (gdm_config_get_bool (GDM_KEY_CONFIG_AVAILABLE) &&
+ !gdm_config_get_bool (GDM_KEY_ADD_GTK_MODULES) &&
+ bin_exists (gdm_config_get_string (GDM_KEY_CONFIGURATOR))) {
+ w = gtk_menu_item_new_with_mnemonic (_("Confi_gure Login Manager..."));
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), w);
+ gtk_widget_show (GTK_WIDGET (w));
+ g_signal_connect (G_OBJECT (w), "activate",
+ G_CALLBACK (greeter_config_handler),
+ NULL);
+ }
+
+ if (GdmRebootFound || GdmHaltFound || GdmSuspendFound || GdmAnyCustomCmdsFound) {
+ sep = gtk_separator_menu_item_new ();
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), sep);
+ gtk_widget_show (sep);
+ }
+
+ if (GdmRebootFound && is_action_available ("REBOOT")) {
+ w = gtk_menu_item_new_with_mnemonic (_("_Restart"));
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), w);
+ gtk_widget_show (GTK_WIDGET (w));
+ g_signal_connect (G_OBJECT (w), "activate",
+ G_CALLBACK (query_greeter_restart_handler),
+ NULL);
+ }
+
+ if (GdmHaltFound && is_action_available ("HALT")) {
+ w = gtk_menu_item_new_with_mnemonic (_("Shut _Down"));
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), w);
+ gtk_widget_show (GTK_WIDGET (w));
+ g_signal_connect (G_OBJECT (w), "activate",
+ G_CALLBACK (query_greeter_halt_handler),
+ NULL);
+ }
+
+ if (GdmSuspendFound && is_action_available ("SUSPEND")) {
+ w = gtk_menu_item_new_with_mnemonic (_("Sus_pend"));
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), w);
+ gtk_widget_show (GTK_WIDGET (w));
+ g_signal_connect (G_OBJECT (w), "activate",
+ G_CALLBACK (query_greeter_suspend_handler),
+ NULL);
+ }
+
+ if (GdmAnyCustomCmdsFound && is_action_available ("CUSTOM_CMD")) {
+ for (i = 0; i < GDM_CUSTOM_COMMAND_MAX; i++) {
+ if (GdmCustomCmdsFound[i]){
+ gint * cmd_index = g_new0(gint, 1);
+ gchar * key_string = NULL;
+ *cmd_index = i;
+ key_string = g_strdup_printf ("%s%d=", GDM_KEY_CUSTOM_CMD_LABEL_TEMPLATE, i);
+ w = gtk_menu_item_new_with_mnemonic (gdm_config_get_string(key_string));
+ gtk_menu_shell_append (GTK_MENU_SHELL (menu), w);
+ gtk_widget_show (GTK_WIDGET (w));
+ g_signal_connect (G_OBJECT (w), "activate",
+ G_CALLBACK (query_greeter_custom_cmd_handler),
+ cmd_index);
+ g_free (key_string);
+ }
+ }
+ }
+
+}
+
+static gboolean
+radio_button_press_event (GtkWidget *widget,
+ GdkEventButton *event,
+ gpointer data)
+{
+ if (event->type == GDK_2BUTTON_PRESS) {
+ gtk_dialog_response (GTK_DIALOG(dialog), GTK_RESPONSE_OK);
+ }
+ return FALSE;
+}
+
+static void
+greeter_system_handler (GreeterItemInfo *info,
+ gpointer user_data)
+{
+ GtkWidget *w = NULL;
+ GtkWidget *hbox = NULL;
+ GtkWidget *main_vbox = NULL;
+ GtkWidget *vbox = NULL;
+ GtkWidget *cat_vbox = NULL;
+ GtkWidget *group_radio = NULL;
+ GtkWidget *halt_radio = NULL;
+ GtkWidget *suspend_radio = NULL;
+ GtkWidget *restart_radio = NULL;
+ GtkWidget **custom_cmds_radio = NULL;
+ GtkWidget *config_radio = NULL;
+ GtkWidget *chooser_radio = NULL;
+ gchar *s;
+ int ret;
+ gint i;
+ GSList *radio_group = NULL;
+ static GtkTooltips *tooltips = NULL;
+
+ /* should never be allowed by the UI */
+ if ( ! gdm_config_get_bool (GDM_KEY_SYSTEM_MENU) ||
+ ve_string_empty (g_getenv ("GDM_IS_LOCAL")))
+ return;
+
+ dialog = gtk_dialog_new ();
+ if (tooltips == NULL)
+ tooltips = gtk_tooltips_new ();
+ gtk_container_set_border_width (GTK_CONTAINER (dialog), 5);
+ gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+ gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+
+ main_vbox = gtk_vbox_new (FALSE, 18);
+ gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 5);
+ gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
+ main_vbox,
+ FALSE, FALSE, 0);
+
+ cat_vbox = gtk_vbox_new (FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (main_vbox),
+ cat_vbox,
+ FALSE, FALSE, 0);
+
+ s = g_strdup_printf ("<b>%s</b>",
+ _("Choose an Action"));
+ w = gtk_label_new (s);
+ gtk_label_set_use_markup (GTK_LABEL (w), TRUE);
+ g_free (s);
+ gtk_misc_set_alignment (GTK_MISC (w), 0.0, 0.5);
+ gtk_box_pack_start (GTK_BOX (cat_vbox), w, FALSE, FALSE, 0);
+
+ hbox = gtk_hbox_new (FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (cat_vbox),
+ hbox, FALSE, FALSE, 0);
+ gtk_box_pack_start (GTK_BOX (hbox),
+ gtk_label_new (" "),
+ FALSE, FALSE, 0);
+ vbox = gtk_vbox_new (FALSE, 6);
+ gtk_box_pack_start (GTK_BOX (hbox),
+ vbox,
+ TRUE, TRUE, 0);
+
+ if (GdmHaltFound) {
+ if (group_radio != NULL)
+ radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (group_radio));
+ halt_radio = gtk_radio_button_new_with_mnemonic (radio_group,
+ _("Shut _down the computer"));
+ group_radio = halt_radio;
+ gtk_tooltips_set_tip (tooltips, GTK_WIDGET (halt_radio),
+ _("Shut Down your computer so that "
+ "you may turn it off."),
+ NULL);
+ g_signal_connect (G_OBJECT(halt_radio), "button_press_event",
+ G_CALLBACK(radio_button_press_event), NULL);
+ gtk_box_pack_start (GTK_BOX (vbox),
+ halt_radio,
+ FALSE, FALSE, 4);
+ gtk_widget_show (halt_radio);
+ }
+
+ if (GdmRebootFound) {
+ if (group_radio != NULL)
+ radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (group_radio));
+ restart_radio = gtk_radio_button_new_with_mnemonic (radio_group,
+ _("_Restart the computer"));
+ group_radio = restart_radio;
+ gtk_tooltips_set_tip (tooltips, GTK_WIDGET (restart_radio),
+ _("Restart your computer"),
+ NULL);
+ g_signal_connect (G_OBJECT(restart_radio), "button_press_event",
+ G_CALLBACK(radio_button_press_event), NULL);
+ gtk_box_pack_start (GTK_BOX (vbox),
+ restart_radio,
+ FALSE, FALSE, 4);
+ gtk_widget_show (restart_radio);
+ }
+
+ if (GdmAnyCustomCmdsFound) {
+ custom_cmds_radio = g_new0 (GtkWidget*, GDM_CUSTOM_COMMAND_MAX);
+ for (i = 0; i < GDM_CUSTOM_COMMAND_MAX; i++) {
+ custom_cmds_radio[i] = NULL;
+ if (GdmCustomCmdsFound[i]){
+ gchar * key_string = NULL;
+ key_string = g_strdup_printf ("%s%d=", GDM_KEY_CUSTOM_CMD_LR_LABEL_TEMPLATE, i);
+ radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (group_radio));
+ custom_cmds_radio[i] = gtk_radio_button_new_with_mnemonic (radio_group,
+ gdm_config_get_string(key_string));
+ group_radio = custom_cmds_radio[i];
+ g_free (key_string);
+ key_string = g_strdup_printf ("%s%d=", GDM_KEY_CUSTOM_CMD_TOOLTIP_TEMPLATE, i);
+ gtk_tooltips_set_tip (tooltips, GTK_WIDGET (custom_cmds_radio[i]),
+ gdm_config_get_string(key_string),
+ NULL);
+ g_signal_connect (G_OBJECT(custom_cmds_radio[i]), "button_press_event",
+ G_CALLBACK(radio_button_press_event), NULL);
+ gtk_box_pack_start (GTK_BOX (vbox),
+ custom_cmds_radio[i],
+ FALSE, FALSE, 4);
+ gtk_widget_show (custom_cmds_radio[i]);
+ g_free (key_string);
+ }
+ }
+ }
+
+ if (GdmSuspendFound) {
+ if (group_radio != NULL)
+ radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (group_radio));
+ suspend_radio = gtk_radio_button_new_with_mnemonic (radio_group,
+ _("Sus_pend the computer"));
+ group_radio = suspend_radio;
+ gtk_tooltips_set_tip (tooltips, GTK_WIDGET (suspend_radio),
+ _("Suspend your computer"),
+ NULL);
+ g_signal_connect (G_OBJECT(suspend_radio), "button_press_event",
+ G_CALLBACK(radio_button_press_event), NULL);
+ gtk_box_pack_start (GTK_BOX (vbox),
+ suspend_radio,
+ FALSE, FALSE, 4);
+ gtk_widget_show (suspend_radio);
+ }
+
+ if (gdm_config_get_bool (GDM_KEY_CHOOSER_BUTTON)) {
+ if (group_radio != NULL)
+ radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (group_radio));
+ chooser_radio = gtk_radio_button_new_with_mnemonic (radio_group,
+ _("Run _XDMCP chooser"));
+ group_radio = chooser_radio;
+ gtk_tooltips_set_tip (tooltips, GTK_WIDGET (chooser_radio),
+ _("Run an XDMCP chooser which will allow "
+ "you to log into available remote "
+ "computers, if there are any."),
+ NULL);
+ g_signal_connect (G_OBJECT(chooser_radio), "button_press_event",
+ G_CALLBACK(radio_button_press_event), NULL);
+ gtk_box_pack_start (GTK_BOX (vbox),
+ chooser_radio,
+ FALSE, FALSE, 4);
+ gtk_widget_show (chooser_radio);
+ }
+
+ /*
+ * Disable Configuration if using accessibility (AddGtkModules) since
+ * using it with accessibility causes a hang.
+ */
+ if (gdm_config_get_bool (GDM_KEY_CONFIG_AVAILABLE) &&
+ !gdm_config_get_bool (GDM_KEY_ADD_GTK_MODULES) &&
+ bin_exists (gdm_config_get_string (GDM_KEY_CONFIGURATOR))) {
+ if (group_radio != NULL)
+ radio_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (group_radio));
+ config_radio = gtk_radio_button_new_with_mnemonic (radio_group,
+ _("Confi_gure the login manager"));
+ group_radio = config_radio;
+ gtk_tooltips_set_tip (tooltips, GTK_WIDGET (config_radio),
+ _("Configure GDM (this login manager). "
+ "This will require the root password."),
+ NULL);
+ g_signal_connect (G_OBJECT(config_radio), "button_press_event",
+ G_CALLBACK(radio_button_press_event), NULL);
+ gtk_box_pack_start (GTK_BOX (vbox),
+ config_radio,
+ FALSE, FALSE, 4);
+ gtk_widget_show (config_radio);
+ }
+
+ gtk_dialog_add_button (GTK_DIALOG (dialog),
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_CANCEL);
+
+ gtk_dialog_add_button (GTK_DIALOG (dialog),
+ GTK_STOCK_OK,
+ GTK_RESPONSE_OK);
+
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog),
+ GTK_RESPONSE_OK);
+
+ gtk_widget_show_all (dialog);
+ gdm_wm_center_window (GTK_WINDOW (dialog));
+
+ gdm_wm_no_login_focus_push ();
+ ret = gtk_dialog_run (GTK_DIALOG (dialog));
+ gdm_wm_no_login_focus_pop ();
+
+ if (ret != GTK_RESPONSE_OK)
+ {
+ gtk_widget_destroy (dialog);
+ return;
+ }
+
+ if (halt_radio != NULL && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (halt_radio)))
+ greeter_halt_handler ();
+ else if (restart_radio != NULL && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (restart_radio)))
+ greeter_restart_handler ();
+ else if (suspend_radio != NULL && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (suspend_radio)))
+ greeter_suspend_handler ();
+ else if (config_radio != NULL && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (config_radio)))
+ greeter_config_handler ();
+ else if (chooser_radio != NULL && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (chooser_radio)))
+ greeter_chooser_handler ();
+ else
+ for (i = 0; i < GDM_CUSTOM_COMMAND_MAX; i++) {
+ if (custom_cmds_radio[i] != NULL && gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (custom_cmds_radio[i])))
+ greeter_custom_cmd_handler (i);
+ }
+
+ gtk_widget_destroy (dialog);
+}
+
+
+void
+greeter_item_system_setup (void)
+{
+ gint i;
+
+ greeter_item_register_action_callback ("reboot_button",
+ (ActionFunc)query_greeter_restart_handler,
+ NULL);
+ greeter_item_register_action_callback ("halt_button",
+ (ActionFunc)query_greeter_halt_handler,
+ NULL);
+ greeter_item_register_action_callback ("suspend_button",
+ (ActionFunc)query_greeter_suspend_handler,
+ NULL);
+ greeter_item_register_action_callback ("system_button",
+ (ActionFunc)greeter_system_handler,
+ NULL);
+ greeter_item_register_action_callback ("config_button",
+ (ActionFunc)greeter_config_handler,
+ NULL);
+ greeter_item_register_action_callback ("chooser_button",
+ (ActionFunc)greeter_chooser_handler,
+ NULL);
+
+ for (i = 0; i < GDM_CUSTOM_COMMAND_MAX; i++) {
+ gint * cmd_index = g_new0(gint, 1);
+ gchar * key_string;
+ *cmd_index = i;
+ key_string = g_strdup_printf ("custom_cmd_button%d", i);
+ greeter_item_register_action_callback (key_string,
+ (ActionFunc)query_greeter_custom_cmd_handler,
+ cmd_index);
+ g_free (key_string);
+ }
+}
diff --git a/trunk/gui/greeter/greeter_system.h b/trunk/gui/greeter/greeter_system.h
new file mode 100644
index 00000000..2349345c
--- /dev/null
+++ b/trunk/gui/greeter/greeter_system.h
@@ -0,0 +1,29 @@
+/* GDM - The GNOME Display Manager
+ * Copyright (C) 1998, 1999, 2000 Martin K. Petersen <mkp@mkp.net>
+ *
+ * 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 __GREETER_SYSTEM_H__
+#define __GREETER_SYSTEM_H__
+
+#include "greeter_item.h"
+#include "greeter_events.h"
+
+void greeter_item_system_setup (void);
+void greeter_system_append_system_menu (GtkWidget *menu);
+
+#endif
+
diff --git a/trunk/gui/greeter/themes/.cvsignore b/trunk/gui/greeter/themes/.cvsignore
new file mode 100644
index 00000000..22a4e729
--- /dev/null
+++ b/trunk/gui/greeter/themes/.cvsignore
@@ -0,0 +1,3 @@
+Makefile
+Makefile.in
+
diff --git a/trunk/gui/greeter/themes/Makefile.am b/trunk/gui/greeter/themes/Makefile.am
new file mode 100644
index 00000000..85df4a1b
--- /dev/null
+++ b/trunk/gui/greeter/themes/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = circles happygnome happygnome-list
diff --git a/trunk/gui/greeter/themes/circles/.cvsignore b/trunk/gui/greeter/themes/circles/.cvsignore
new file mode 100644
index 00000000..d09a03b4
--- /dev/null
+++ b/trunk/gui/greeter/themes/circles/.cvsignore
@@ -0,0 +1,3 @@
+Makefile
+Makefile.in
+GdmGreeterTheme.desktop
diff --git a/trunk/gui/greeter/themes/circles/GdmGreeterTheme.desktop.in b/trunk/gui/greeter/themes/circles/GdmGreeterTheme.desktop.in
new file mode 100644
index 00000000..b5699ab1
--- /dev/null
+++ b/trunk/gui/greeter/themes/circles/GdmGreeterTheme.desktop.in
@@ -0,0 +1,11 @@
+# This is not really a .desktop file like the rest, but it's useful to treat
+# it as such
+
+[GdmGreeterTheme]
+Encoding=UTF-8
+Greeter=circles.xml
+_Name=Circles
+_Description=Theme with blue circles
+_Author=Bond, James Bond
+_Copyright=(c) 2002 Bond, James Bond
+Screenshot=screenshot.png
diff --git a/trunk/gui/greeter/themes/circles/Makefile.am b/trunk/gui/greeter/themes/circles/Makefile.am
new file mode 100644
index 00000000..0e8fa065
--- /dev/null
+++ b/trunk/gui/greeter/themes/circles/Makefile.am
@@ -0,0 +1,19 @@
+circlesdir = $(datadir)/gdm/themes/circles
+circles_DATA = \
+ GdmGreeterTheme.desktop \
+ circles.xml \
+ background.svg \
+ flower.png \
+ help.png \
+ options.png \
+ screenshot.png
+
+circles_in_files = \
+ GdmGreeterTheme.desktop.in
+
+@INTLTOOL_DESKTOP_RULE@
+
+EXTRA_DIST = $(circles_DATA) $(circles_in_files)
+
+clean-local:
+ /bin/rm -f GdmGreeterTheme.desktop
diff --git a/trunk/gui/greeter/themes/circles/background.svg b/trunk/gui/greeter/themes/circles/background.svg
new file mode 100644
index 00000000..11abc4f4
--- /dev/null
+++ b/trunk/gui/greeter/themes/circles/background.svg
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 9.0, SVG Export Plug-In -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20000303 Stylable//EN" "http://www.w3.org/TR/2000/03/WD-SVG-20000303/DTD/svg-20000303-stylable.dtd" [
+ <!ENTITY st0 "fill:url(#aigrd1);stroke:none;">
+ <!ENTITY st1 "fill:url(#aigrd3);stroke:none;">
+ <!ENTITY st2 "fill:url(#aigrd2);stroke:none;">
+ <!ENTITY st3 "fill-rule:nonzero;clip-rule:nonzero;fill:#2A569D;stroke:#000000;stroke-miterlimit:4;">
+ <!ENTITY st4 "stroke:none;">
+]>
+<svg width="508.104pt" height="383.717pt" viewBox="0 0 508.104 383.717" xml:space="preserve">
+ <g id="Layer_x0020_1" style="&st3;">
+ <g id="middle">
+ <linearGradient id="aigrd1" gradientUnits="userSpaceOnUse" x1="237.2617" y1="24.7095" x2="237.2617" y2="371.207">
+ <stop offset="0" style="stop-color:#4E77B9"/>
+ <stop offset="1" style="stop-color:#6E8CBE"/>
+ </linearGradient>
+ <path style="&st0;" d="M59.227,357.212c27.481,9.066,56.985,13.994,87.696,13.994c148.221,0,268.375-114.698,268.375-256.189c0-31.789-6.073-62.221-17.16-90.308C249.869,104.206,131.168,219.909,59.227,357.212z"/>
+ </g>
+ <linearGradient id="aigrd2" gradientUnits="userSpaceOnUse" x1="277.0767" y1="0" x2="277.0766" y2="383.7178">
+ <stop offset="0" style="stop-color:#335EA2"/>
+ <stop offset="1" style="stop-color:#6D8BBD"/>
+ </linearGradient>
+ <path id="lower_x0020_right" style="&st2;" d="M447.704,0c-16.859,7.792-33.389,16.037-49.566,24.709c11.087,28.087,17.16,58.52,17.16,90.308c0,141.491-120.154,256.189-268.375,256.189c-30.71,0-60.214-4.928-87.696-13.994
+ c-4.584,8.749-8.979,17.585-13.178,26.505h462.056V0h-60.4z"/>
+ <g id="upper_x0020_left">
+ <linearGradient id="aigrd3" gradientUnits="userSpaceOnUse" x1="199.0684" y1="0" x2="199.0683" y2="357.2129">
+ <stop offset="0" style="stop-color:#436FB6"/>
+ <stop offset="1" style="stop-color:#305CA3"/>
+ </linearGradient>
+ <path style="&st1;" d="M398.137,24.709C394.798,16.252,391.011,8.005,386.791,0H0v329.44c18.309,11.454,38.174,20.827,59.227,27.772c71.942-137.304,190.642-253.007,338.911-332.503z"/>
+ </g>
+ <g id="bottom_x0020_small">
+ <path style="&st4;" d="M0,329.44v54.277h46.048c4.2-8.92,8.594-17.756,13.178-26.505C38.174,350.267,18.309,340.894,0,329.44z"/>
+ </g>
+ <g id="top_x0020_small">
+ <path style="&st4;" d="M447.704,0h-60.913c4.221,8.005,8.008,16.252,11.347,24.709C414.315,16.037,430.844,7.792,447.704,0z"/>
+ </g>
+ </g>
+</svg>
diff --git a/trunk/gui/greeter/themes/circles/circles.xml b/trunk/gui/greeter/themes/circles/circles.xml
new file mode 100644
index 00000000..a39b6639
--- /dev/null
+++ b/trunk/gui/greeter/themes/circles/circles.xml
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE greeter SYSTEM "greeter.dtd">
+<greeter>
+ <item type="svg" background="true">
+ <normal file="background.svg"/>
+ <pos x="0" y="0" width="100%" height="-75"/>
+ </item>
+ <item type="rect" background="true">
+ <normal color="#000000"/>
+ <pos x="0" y="-75" width="100%" height="75"/>
+ <fixed>
+ <item type="rect" background="true">
+ <normal color="#ffffff"/>
+ <pos x="0" y="4" width="100%" height="100%"/>
+ <box orientation="horizontal" spacing="10" xpadding="10" ypadding="10">
+ <item type="button" id="options_button" button="true">
+ <pos y="5" width="80" height="50"/>
+ <stock type="options"/>
+ </item>
+ <item type="list" id="language" combo="true">
+ <pos x="25" y="10" height="40" width="300"/>
+ </item>
+ <item type="list" id="session" combo="true">
+ <pos x="50" y="10" height="40" width="300"/>
+ </item>
+ </box>
+ </item>
+ </fixed>
+ </item>
+ <item type="rect" id="userlist-rect">
+ <normal color="#FFFFFF" alpha="0.5" font="Sans 14"/>
+ <pos anchor="nw" x="0" y="0" width="box" height="box"/>
+ <box orientation="vertical" min-width="440" max-width="440" min-height="100"
+ xpadding="4" ypadding="4" spacing="0">
+ <item type="list" id="userlist">
+ <pos anchor="nw" x="0" y="0" height="550" width="440"/>
+ <color iconcolor="#ACBFDD" labelcolor="#ACBFDD"/>
+ </item>
+ </box>
+ </item>
+
+ <item type="pixmap" background="true">
+ <normal file="flower.png"/>
+ <pos x="100%" y="100%" anchor="se"/>
+ </item>
+ <item type="label" id="clock">
+ <normal color="#000000" font="Sans 12"/>
+ <pos x="-20" y="-37" anchor="e"/>
+ <text>%c</text>
+ </item>
+
+ <item type="rect">
+ <show type="timed"/>
+ <normal color="#FFFFFF" alpha="0.5"/>
+ <pos anchor="c" x="50%" y="25%" width="box" height="box"/>
+ <box orientation="vertical" min-width="400" xpadding="10" ypadding="5" spacing="0">
+ <item type="label" id="timed-label">
+ <normal color="#000000" font="Sans 12"/>
+ <pos x="50%" anchor="n"/>
+ <!-- Stock label for: User %s will login in %d seconds -->
+ <stock type="timed-label"/>
+ </item>
+ </box>
+ </item>
+
+ <item type="rect">
+ <normal color="#FFFFFF" alpha="0.5"/>
+ <pos anchor="c" x="50%" y="50%" width="box" height="box"/>
+ <box orientation="vertical" min-width="340" xpadding="30" ypadding="30" spacing="10">
+ <item type="label">
+ <pos anchor="n" x="50%"/>
+ <normal color="#000000" font="Sans 14"/>
+ <!-- Stock label for: Welcome to %h -->
+ <stock type="welcome-label"/>
+ </item>
+ <item type="label" id="pam-prompt">
+ <pos anchor="nw" x="10%"/>
+ <normal color="#000000" font="Sans 12"/>
+ <!-- Stock label for: Username: -->
+ <stock type="username-label"/>
+ </item>
+ <item type="rect">
+ <normal color="#000000"/>
+ <pos anchor="n" x="50%" height="24" width="80%"/>
+ <fixed>
+ <item type="entry" id="user-pw-entry">
+ <normal color="#000000" font="Sans 12"/>
+ <pos anchor="nw" x="1" y="1" height="-2" width="-2"/>
+ </item>
+ </fixed>
+ </item>
+ <item type="button" id="ok_button">
+ <pos anchor="n" x="50%" height="32" width="50%"/>
+ <stock type="ok"/>
+ </item>
+ <item type="button" id="cancel_button">
+ <pos anchor="n" x="50%" height="32" width="50%"/>
+ <stock type="startagain"/>
+ </item>
+ <item type="label" id="pam-message">
+ <pos anchor="n" x="50%"/>
+ <normal color="#000000" font="Sans 12"/>
+ <text></text>
+ </item>
+ </box>
+ <fixed>
+ <item type="label" id="pam-error">
+ <pos anchor="n" x="50%" y="110%"/>
+ <normal color="#000000" font="Sans 12"/>
+ <text></text>
+ </item>
+ </fixed>
+ </item>
+</greeter>
+
+
diff --git a/trunk/gui/greeter/themes/circles/flower.png b/trunk/gui/greeter/themes/circles/flower.png
new file mode 100644
index 00000000..92d25f32
--- /dev/null
+++ b/trunk/gui/greeter/themes/circles/flower.png
Binary files differ
diff --git a/trunk/gui/greeter/themes/circles/help.png b/trunk/gui/greeter/themes/circles/help.png
new file mode 100644
index 00000000..b38b48a6
--- /dev/null
+++ b/trunk/gui/greeter/themes/circles/help.png
Binary files differ
diff --git a/trunk/gui/greeter/themes/circles/options.png b/trunk/gui/greeter/themes/circles/options.png
new file mode 100644
index 00000000..3c08e02d
--- /dev/null
+++ b/trunk/gui/greeter/themes/circles/options.png
Binary files differ
diff --git a/trunk/gui/greeter/themes/circles/screenshot.png b/trunk/gui/greeter/themes/circles/screenshot.png
new file mode 100644
index 00000000..7120b03d
--- /dev/null
+++ b/trunk/gui/greeter/themes/circles/screenshot.png
Binary files differ
diff --git a/trunk/gui/greeter/themes/happygnome-list/.cvsignore b/trunk/gui/greeter/themes/happygnome-list/.cvsignore
new file mode 100644
index 00000000..d09a03b4
--- /dev/null
+++ b/trunk/gui/greeter/themes/happygnome-list/.cvsignore
@@ -0,0 +1,3 @@
+Makefile
+Makefile.in
+GdmGreeterTheme.desktop
diff --git a/trunk/gui/greeter/themes/happygnome-list/GdmGreeterTheme.desktop.in b/trunk/gui/greeter/themes/happygnome-list/GdmGreeterTheme.desktop.in
new file mode 100644
index 00000000..908c6c7e
--- /dev/null
+++ b/trunk/gui/greeter/themes/happygnome-list/GdmGreeterTheme.desktop.in
@@ -0,0 +1,11 @@
+# This is not really a .desktop file like the rest, but it's useful to treat
+# it as such
+
+[GdmGreeterTheme]
+Encoding=UTF-8
+Greeter=happygnome.xml
+_Name=Happy GNOME with Browser
+_Description=GNOME Art variation of Circles with a Face Browser
+_Author=GNOME Artists
+_Copyright=(c) 2002 GNOME
+Screenshot=screenshot.png
diff --git a/trunk/gui/greeter/themes/happygnome-list/Makefile.am b/trunk/gui/greeter/themes/happygnome-list/Makefile.am
new file mode 100644
index 00000000..42ba140f
--- /dev/null
+++ b/trunk/gui/greeter/themes/happygnome-list/Makefile.am
@@ -0,0 +1,18 @@
+happygnomedir = $(datadir)/gdm/themes/happygnome-list
+happygnome_DATA = \
+ GdmGreeterTheme.desktop \
+ happygnome.xml \
+ background.svg \
+ gnome-logo.svg \
+ options.png \
+ screenshot.png
+
+happygnome_in_files = \
+ GdmGreeterTheme.desktop.in
+
+@INTLTOOL_DESKTOP_RULE@
+
+EXTRA_DIST = $(happygnome_DATA) $(happygnome_in_files)
+
+clean-local:
+ /bin/rm -f GdmGreeterTheme.desktop
diff --git a/trunk/gui/greeter/themes/happygnome-list/background.svg b/trunk/gui/greeter/themes/happygnome-list/background.svg
new file mode 100644
index 00000000..11abc4f4
--- /dev/null
+++ b/trunk/gui/greeter/themes/happygnome-list/background.svg
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 9.0, SVG Export Plug-In -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20000303 Stylable//EN" "http://www.w3.org/TR/2000/03/WD-SVG-20000303/DTD/svg-20000303-stylable.dtd" [
+ <!ENTITY st0 "fill:url(#aigrd1);stroke:none;">
+ <!ENTITY st1 "fill:url(#aigrd3);stroke:none;">
+ <!ENTITY st2 "fill:url(#aigrd2);stroke:none;">
+ <!ENTITY st3 "fill-rule:nonzero;clip-rule:nonzero;fill:#2A569D;stroke:#000000;stroke-miterlimit:4;">
+ <!ENTITY st4 "stroke:none;">
+]>
+<svg width="508.104pt" height="383.717pt" viewBox="0 0 508.104 383.717" xml:space="preserve">
+ <g id="Layer_x0020_1" style="&st3;">
+ <g id="middle">
+ <linearGradient id="aigrd1" gradientUnits="userSpaceOnUse" x1="237.2617" y1="24.7095" x2="237.2617" y2="371.207">
+ <stop offset="0" style="stop-color:#4E77B9"/>
+ <stop offset="1" style="stop-color:#6E8CBE"/>
+ </linearGradient>
+ <path style="&st0;" d="M59.227,357.212c27.481,9.066,56.985,13.994,87.696,13.994c148.221,0,268.375-114.698,268.375-256.189c0-31.789-6.073-62.221-17.16-90.308C249.869,104.206,131.168,219.909,59.227,357.212z"/>
+ </g>
+ <linearGradient id="aigrd2" gradientUnits="userSpaceOnUse" x1="277.0767" y1="0" x2="277.0766" y2="383.7178">
+ <stop offset="0" style="stop-color:#335EA2"/>
+ <stop offset="1" style="stop-color:#6D8BBD"/>
+ </linearGradient>
+ <path id="lower_x0020_right" style="&st2;" d="M447.704,0c-16.859,7.792-33.389,16.037-49.566,24.709c11.087,28.087,17.16,58.52,17.16,90.308c0,141.491-120.154,256.189-268.375,256.189c-30.71,0-60.214-4.928-87.696-13.994
+ c-4.584,8.749-8.979,17.585-13.178,26.505h462.056V0h-60.4z"/>
+ <g id="upper_x0020_left">
+ <linearGradient id="aigrd3" gradientUnits="userSpaceOnUse" x1="199.0684" y1="0" x2="199.0683" y2="357.2129">
+ <stop offset="0" style="stop-color:#436FB6"/>
+ <stop offset="1" style="stop-color:#305CA3"/>
+ </linearGradient>
+ <path style="&st1;" d="M398.137,24.709C394.798,16.252,391.011,8.005,386.791,0H0v329.44c18.309,11.454,38.174,20.827,59.227,27.772c71.942-137.304,190.642-253.007,338.911-332.503z"/>
+ </g>
+ <g id="bottom_x0020_small">
+ <path style="&st4;" d="M0,329.44v54.277h46.048c4.2-8.92,8.594-17.756,13.178-26.505C38.174,350.267,18.309,340.894,0,329.44z"/>
+ </g>
+ <g id="top_x0020_small">
+ <path style="&st4;" d="M447.704,0h-60.913c4.221,8.005,8.008,16.252,11.347,24.709C414.315,16.037,430.844,7.792,447.704,0z"/>
+ </g>
+ </g>
+</svg>
diff --git a/trunk/gui/greeter/themes/happygnome-list/gnome-logo.svg b/trunk/gui/greeter/themes/happygnome-list/gnome-logo.svg
new file mode 100644
index 00000000..bdde1d1e
--- /dev/null
+++ b/trunk/gui/greeter/themes/happygnome-list/gnome-logo.svg
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="us-ascii" ?>
+<!-- Generator: Adobe Illustrator 9.0, SVG Export Plug-In -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20000303 Stylable//EN" "http://www.w3.org/TR/2000/03/WD-SVG-20000303/DTD/svg-20000303-stylable.dtd" [
+ <!ENTITY st0 "fill-rule:nonzero;clip-rule:nonzero;stroke:#000000;stroke-miterlimit:4;">
+ <!ENTITY st1 "stroke:none;">
+]>
+<svg width="95.991pt" height="150.915pt" viewBox="0 0 95.991 150.915" xml:space="preserve">
+ <g id="Layer_x0020_1" style="&st0;">
+ <g style="&st1;">
+ <g>
+ <g>
+ <path d="M86.068,0C61.466,0,56.851,35.041,70.691,35.041C84.529,35.041,110.671,0,86.068,0z"/>
+ <path d="M45.217,30.699c7.369,0.45,15.454-28.122,1.604-26.325c-13.845,1.797-8.976,25.875-1.604,26.325z"/>
+ <path d="M11.445,48.453c5.241-2.307,0.675-24.872-8.237-18.718c-8.908,6.155,2.996,21.024,8.237,18.718z"/>
+ <path d="M26.212,36.642c6.239-1.272,6.581-26.864-4.545-22.273c-11.128,4.592-1.689,23.547,4.545,22.273z"/>
+ <path id="newshape" d="M58.791,93.913c1.107,8.454-6.202,12.629-13.36,7.179C22.644,83.743,83.16,75.088,79.171,51.386c-3.311-19.674-63.676-13.617-70.55,17.167C3.968,89.374,27.774,118.26,52.614,118.26c12.22,0,26.315-11.034,28.952-25.012
+ c2.014-10.659-23.699-6.388-22.775,0.665z"/>
+ </g>
+ </g>
+ <g>
+ <path d="M17.718,132.165l-1.49,2.857c-0.418-0.374-1.064-0.746-1.937-1.115c-0.873-0.369-1.623-0.555-2.25-0.555c-1.964,0-3.514,0.668-4.65,2.004c-1.137,1.337-1.705,3.127-1.705,5.37c0,2.135,0.557,3.841,1.671,5.117c1.114,1.276,2.63,1.915,4.549,1.915
+ c1.264,0,2.305-0.346,3.124-1.037v-3.932h-2.781v-3.031h6.344v8.958c-0.847,0.692-1.938,1.231-3.271,1.618s-2.661,0.58-3.981,0.58c-2.868,0-5.142-0.941-6.822-2.824s-2.52-4.369-2.52-7.459c0-3.092,0.914-5.604,2.743-7.536c1.828-1.933,4.289-2.899,7.382-2.899
+ c2.192,0,4.057,0.656,5.594,1.969z"/>
+ <path d="M34.892,150.853l-9.719-12.688v12.406h-3.406V130.54h1.719l9.438,12.094V130.54h3.406v20.313h-1.438z"/>
+ <path d="M39.487,140.392c0-2.852,0.781-5.264,2.345-7.236c1.563-1.973,3.652-2.959,6.268-2.959c2.881,0,5.082,0.893,6.604,2.679c1.522,1.786,2.283,4.292,2.283,7.517c0,3.227-0.795,5.786-2.385,7.682c-1.592,1.895-3.85,2.842-6.775,2.842
+ c-2.688,0-4.75-0.938-6.186-2.814s-2.153-4.447-2.153-7.709z M43.175,140.392c0,2.342,0.396,4.155,1.19,5.439c0.793,1.285,1.947,1.928,3.461,1.928c1.779,0,3.136-0.629,4.07-1.887c0.936-1.257,1.402-3.084,1.402-5.48c0-4.692-1.732-7.039-5.199-7.039
+ c-1.587,0-2.805,0.636-3.653,1.906c-0.849,1.271-1.272,2.982-1.272,5.133z"/>
+ <path d="M78.831,150.571h-3.438l-2.094-10.781l-4.031,11.063h-1.281L63.94,139.79l-2.141,10.781h-3.438l4.031-20.031h1.875l4.359,13.5l4.234-13.5h1.875l4.094,20.031z"/>
+ <path d="M84.569,133.696v4.688h6.438v3.031h-6.438v6h9.063v3.156H81.006V130.54h12.625v3.156h-9.063z"/>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/trunk/gui/greeter/themes/happygnome-list/happygnome.xml b/trunk/gui/greeter/themes/happygnome-list/happygnome.xml
new file mode 100644
index 00000000..ba92210c
--- /dev/null
+++ b/trunk/gui/greeter/themes/happygnome-list/happygnome.xml
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE greeter SYSTEM "greeter.dtd">
+<greeter>
+ <item type="svg" background="true">
+ <normal file="background.svg"/>
+ <pos x="0" y="0" width="100%" height="-75"/>
+ </item>
+ <item type="rect" background="true">
+ <normal color="#000000"/>
+ <pos x="0" y="-75" width="100%" height="75"/>
+ <fixed>
+ <item type="rect" background="true">
+ <normal color="#ffffff"/>
+ <pos x="0" y="4" width="100%" height="100%"/>
+ <box orientation="horizontal" spacing="10" xpadding="10" ypadding="10">
+ <item type="button" id="options_button">
+ <pos width="100" height="50" />
+ <stock type="options"/>
+ </item>
+ <item type="list" id="language" combo="true">
+ <pos x="25" y="5" height="40" width="300"/>
+ </item>
+ <item type="list" id="session" combo="true">
+ <pos x="50" y="5" height="40" width="300"/>
+ </item>
+ </box>
+ </item>
+ </fixed>
+ </item>
+ <item type="svg" background="true">
+ <normal file="gnome-logo.svg"/>
+ <pos x="-12" y="-12" width="30" height="47" anchor="se" />
+ </item>
+ <item type="label" id="clock">
+ <normal color="#000000" font="Sans 12"/>
+ <pos x="-80" y="-37" anchor="e"/>
+ <text>%c</text>
+ </item>
+
+ <item type="rect" id="caps-lock-warning">
+ <normal color="#FFFFFF" alpha="0.5"/>
+ <pos anchor="c" x="75%" y="75%" width="box" height="box"/>
+ <box orientation="vertical" min-width="400" xpadding="10" ypadding="5" spacing="0">
+ <item type="label">
+ <normal color="#000000" font="Sans 12"/>
+ <pos x="50%" anchor="n"/>
+ <!-- Stock label for: You've got capslock on! -->
+ <stock type="caps-lock-warning"/>
+ </item>
+ </box>
+ </item>
+
+ <item type="rect">
+ <show type="timed"/>
+ <normal color="#FFFFFF" alpha="0.5"/>
+ <pos anchor="c" x="75%" y="25%" width="box" height="box"/>
+ <box orientation="vertical" min-width="400" xpadding="10" ypadding="5" spacing="0">
+ <item type="label" id="timed-label">
+ <normal color="#000000" font="Sans 12"/>
+ <pos x="50%" anchor="n"/>
+ <!-- Stock label for: User %s will login in %d seconds -->
+ <stock type="timed-label"/>
+ </item>
+ </box>
+ </item>
+
+ <item type="rect" id="userlist-rect">
+ <normal color="#FFFFFF" alpha="0.5" font="Sans 14"/>
+ <pos anchor="c" x="25%" y="50%" width="box" height="box"/>
+ <box orientation="vertical" min-width="440" max-width="440" min-height="100" xpadding="4" ypadding="4" spacing="0">
+ <item type="list" id="userlist">
+ <pos anchor="nw" x="0" y="0" height="550" width="440"/>
+ <color iconcolor="#ACBFDD" labelcolor="#ACBFDD"/>
+ </item>
+ </box>
+ </item>
+
+ <item type="rect">
+ <normal color="#FFFFFF" alpha="0.5"/>
+ <pos anchor="c" x="75%" y="50%" width="box" height="box"/>
+ <box orientation="vertical" min-width="340" xpadding="30" ypadding="30" spacing="10">
+ <item type="label">
+ <pos anchor="n" x="50%"/>
+ <normal color="#000000" font="Sans 18"/>
+ <!-- Stock label for: Welcome to %h -->
+ <stock type="welcome-label"/>
+ </item>
+ <item type="label" id="pam-prompt">
+ <pos anchor="nw" x="10%"/>
+ <normal color="#000000" font="Sans 12"/>
+ <!-- Stock label for: Username: -->
+ <stock type="username-label"/>
+ </item>
+ <item type="rect">
+ <normal color="#000000"/>
+ <pos anchor="n" x="50%" height="24" width="80%"/>
+ <fixed>
+ <item type="entry" id="user-pw-entry">
+ <normal color="#000000" font="Sans 12"/>
+ <pos anchor="nw" x="1" y="1" height="-2" width="-2"/>
+ </item>
+ </fixed>
+ </item>
+ <item type="button" id="ok_button">
+ <pos anchor="n" x="50%" height="32" width="50%"/>
+ <stock type="ok"/>
+ </item>
+ <item type="button" id="cancel_button">
+ <pos anchor="n" x="50%" height="32" width="50%"/>
+ <stock type="startagain"/>
+ </item>
+ <item type="label" id="pam-message">
+ <pos anchor="n" x="50%"/>
+ <normal color="#000000" font="Sans 12"/>
+ <text></text>
+ </item>
+ </box>
+ <fixed>
+ <item type="label" id="pam-error">
+ <pos anchor="n" x="50%" y="110%"/>
+ <normal color="#000000" font="Sans 12"/>
+ <text></text>
+ </item>
+ </fixed>
+ </item>
+</greeter>
+
+
diff --git a/trunk/gui/greeter/themes/happygnome-list/options.png b/trunk/gui/greeter/themes/happygnome-list/options.png
new file mode 100644
index 00000000..431813fa
--- /dev/null
+++ b/trunk/gui/greeter/themes/happygnome-list/options.png
Binary files differ
diff --git a/trunk/gui/greeter/themes/happygnome-list/screenshot.png b/trunk/gui/greeter/themes/happygnome-list/screenshot.png
new file mode 100644
index 00000000..0e9390fc
--- /dev/null
+++ b/trunk/gui/greeter/themes/happygnome-list/screenshot.png
Binary files differ
diff --git a/trunk/gui/greeter/themes/happygnome/.cvsignore b/trunk/gui/greeter/themes/happygnome/.cvsignore
new file mode 100644
index 00000000..d09a03b4
--- /dev/null
+++ b/trunk/gui/greeter/themes/happygnome/.cvsignore
@@ -0,0 +1,3 @@
+Makefile
+Makefile.in
+GdmGreeterTheme.desktop
diff --git a/trunk/gui/greeter/themes/happygnome/GdmGreeterTheme.desktop.in b/trunk/gui/greeter/themes/happygnome/GdmGreeterTheme.desktop.in
new file mode 100644
index 00000000..d95ac06d
--- /dev/null
+++ b/trunk/gui/greeter/themes/happygnome/GdmGreeterTheme.desktop.in
@@ -0,0 +1,11 @@
+# This is not really a .desktop file like the rest, but it's useful to treat
+# it as such
+
+[GdmGreeterTheme]
+Encoding=UTF-8
+Greeter=happygnome.xml
+_Name=Happy GNOME
+_Description=GNOME Art variation of Circles
+_Author=GNOME Artists
+_Copyright=(c) 2002 GNOME
+Screenshot=screenshot.png
diff --git a/trunk/gui/greeter/themes/happygnome/Makefile.am b/trunk/gui/greeter/themes/happygnome/Makefile.am
new file mode 100644
index 00000000..19981eb7
--- /dev/null
+++ b/trunk/gui/greeter/themes/happygnome/Makefile.am
@@ -0,0 +1,18 @@
+happygnomedir = $(datadir)/gdm/themes/happygnome
+happygnome_DATA = \
+ GdmGreeterTheme.desktop \
+ happygnome.xml \
+ background.svg \
+ gnome-logo.svg \
+ options.png \
+ screenshot.png
+
+happygnome_in_files = \
+ GdmGreeterTheme.desktop.in
+
+@INTLTOOL_DESKTOP_RULE@
+
+EXTRA_DIST = $(happygnome_DATA) $(happygnome_in_files)
+
+clean-local:
+ /bin/rm -f GdmGreeterTheme.desktop
diff --git a/trunk/gui/greeter/themes/happygnome/background.svg b/trunk/gui/greeter/themes/happygnome/background.svg
new file mode 100644
index 00000000..11abc4f4
--- /dev/null
+++ b/trunk/gui/greeter/themes/happygnome/background.svg
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<!-- Generator: Adobe Illustrator 9.0, SVG Export Plug-In -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20000303 Stylable//EN" "http://www.w3.org/TR/2000/03/WD-SVG-20000303/DTD/svg-20000303-stylable.dtd" [
+ <!ENTITY st0 "fill:url(#aigrd1);stroke:none;">
+ <!ENTITY st1 "fill:url(#aigrd3);stroke:none;">
+ <!ENTITY st2 "fill:url(#aigrd2);stroke:none;">
+ <!ENTITY st3 "fill-rule:nonzero;clip-rule:nonzero;fill:#2A569D;stroke:#000000;stroke-miterlimit:4;">
+ <!ENTITY st4 "stroke:none;">
+]>
+<svg width="508.104pt" height="383.717pt" viewBox="0 0 508.104 383.717" xml:space="preserve">
+ <g id="Layer_x0020_1" style="&st3;">
+ <g id="middle">
+ <linearGradient id="aigrd1" gradientUnits="userSpaceOnUse" x1="237.2617" y1="24.7095" x2="237.2617" y2="371.207">
+ <stop offset="0" style="stop-color:#4E77B9"/>
+ <stop offset="1" style="stop-color:#6E8CBE"/>
+ </linearGradient>
+ <path style="&st0;" d="M59.227,357.212c27.481,9.066,56.985,13.994,87.696,13.994c148.221,0,268.375-114.698,268.375-256.189c0-31.789-6.073-62.221-17.16-90.308C249.869,104.206,131.168,219.909,59.227,357.212z"/>
+ </g>
+ <linearGradient id="aigrd2" gradientUnits="userSpaceOnUse" x1="277.0767" y1="0" x2="277.0766" y2="383.7178">
+ <stop offset="0" style="stop-color:#335EA2"/>
+ <stop offset="1" style="stop-color:#6D8BBD"/>
+ </linearGradient>
+ <path id="lower_x0020_right" style="&st2;" d="M447.704,0c-16.859,7.792-33.389,16.037-49.566,24.709c11.087,28.087,17.16,58.52,17.16,90.308c0,141.491-120.154,256.189-268.375,256.189c-30.71,0-60.214-4.928-87.696-13.994
+ c-4.584,8.749-8.979,17.585-13.178,26.505h462.056V0h-60.4z"/>
+ <g id="upper_x0020_left">
+ <linearGradient id="aigrd3" gradientUnits="userSpaceOnUse" x1="199.0684" y1="0" x2="199.0683" y2="357.2129">
+ <stop offset="0" style="stop-color:#436FB6"/>
+ <stop offset="1" style="stop-color:#305CA3"/>
+ </linearGradient>
+ <path style="&st1;" d="M398.137,24.709C394.798,16.252,391.011,8.005,386.791,0H0v329.44c18.309,11.454,38.174,20.827,59.227,27.772c71.942-137.304,190.642-253.007,338.911-332.503z"/>
+ </g>
+ <g id="bottom_x0020_small">
+ <path style="&st4;" d="M0,329.44v54.277h46.048c4.2-8.92,8.594-17.756,13.178-26.505C38.174,350.267,18.309,340.894,0,329.44z"/>
+ </g>
+ <g id="top_x0020_small">
+ <path style="&st4;" d="M447.704,0h-60.913c4.221,8.005,8.008,16.252,11.347,24.709C414.315,16.037,430.844,7.792,447.704,0z"/>
+ </g>
+ </g>
+</svg>
diff --git a/trunk/gui/greeter/themes/happygnome/gnome-logo.svg b/trunk/gui/greeter/themes/happygnome/gnome-logo.svg
new file mode 100644
index 00000000..bdde1d1e
--- /dev/null
+++ b/trunk/gui/greeter/themes/happygnome/gnome-logo.svg
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="us-ascii" ?>
+<!-- Generator: Adobe Illustrator 9.0, SVG Export Plug-In -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20000303 Stylable//EN" "http://www.w3.org/TR/2000/03/WD-SVG-20000303/DTD/svg-20000303-stylable.dtd" [
+ <!ENTITY st0 "fill-rule:nonzero;clip-rule:nonzero;stroke:#000000;stroke-miterlimit:4;">
+ <!ENTITY st1 "stroke:none;">
+]>
+<svg width="95.991pt" height="150.915pt" viewBox="0 0 95.991 150.915" xml:space="preserve">
+ <g id="Layer_x0020_1" style="&st0;">
+ <g style="&st1;">
+ <g>
+ <g>
+ <path d="M86.068,0C61.466,0,56.851,35.041,70.691,35.041C84.529,35.041,110.671,0,86.068,0z"/>
+ <path d="M45.217,30.699c7.369,0.45,15.454-28.122,1.604-26.325c-13.845,1.797-8.976,25.875-1.604,26.325z"/>
+ <path d="M11.445,48.453c5.241-2.307,0.675-24.872-8.237-18.718c-8.908,6.155,2.996,21.024,8.237,18.718z"/>
+ <path d="M26.212,36.642c6.239-1.272,6.581-26.864-4.545-22.273c-11.128,4.592-1.689,23.547,4.545,22.273z"/>
+ <path id="newshape" d="M58.791,93.913c1.107,8.454-6.202,12.629-13.36,7.179C22.644,83.743,83.16,75.088,79.171,51.386c-3.311-19.674-63.676-13.617-70.55,17.167C3.968,89.374,27.774,118.26,52.614,118.26c12.22,0,26.315-11.034,28.952-25.012
+ c2.014-10.659-23.699-6.388-22.775,0.665z"/>
+ </g>
+ </g>
+ <g>
+ <path d="M17.718,132.165l-1.49,2.857c-0.418-0.374-1.064-0.746-1.937-1.115c-0.873-0.369-1.623-0.555-2.25-0.555c-1.964,0-3.514,0.668-4.65,2.004c-1.137,1.337-1.705,3.127-1.705,5.37c0,2.135,0.557,3.841,1.671,5.117c1.114,1.276,2.63,1.915,4.549,1.915
+ c1.264,0,2.305-0.346,3.124-1.037v-3.932h-2.781v-3.031h6.344v8.958c-0.847,0.692-1.938,1.231-3.271,1.618s-2.661,0.58-3.981,0.58c-2.868,0-5.142-0.941-6.822-2.824s-2.52-4.369-2.52-7.459c0-3.092,0.914-5.604,2.743-7.536c1.828-1.933,4.289-2.899,7.382-2.899
+ c2.192,0,4.057,0.656,5.594,1.969z"/>
+ <path d="M34.892,150.853l-9.719-12.688v12.406h-3.406V130.54h1.719l9.438,12.094V130.54h3.406v20.313h-1.438z"/>
+ <path d="M39.487,140.392c0-2.852,0.781-5.264,2.345-7.236c1.563-1.973,3.652-2.959,6.268-2.959c2.881,0,5.082,0.893,6.604,2.679c1.522,1.786,2.283,4.292,2.283,7.517c0,3.227-0.795,5.786-2.385,7.682c-1.592,1.895-3.85,2.842-6.775,2.842
+ c-2.688,0-4.75-0.938-6.186-2.814s-2.153-4.447-2.153-7.709z M43.175,140.392c0,2.342,0.396,4.155,1.19,5.439c0.793,1.285,1.947,1.928,3.461,1.928c1.779,0,3.136-0.629,4.07-1.887c0.936-1.257,1.402-3.084,1.402-5.48c0-4.692-1.732-7.039-5.199-7.039
+ c-1.587,0-2.805,0.636-3.653,1.906c-0.849,1.271-1.272,2.982-1.272,5.133z"/>
+ <path d="M78.831,150.571h-3.438l-2.094-10.781l-4.031,11.063h-1.281L63.94,139.79l-2.141,10.781h-3.438l4.031-20.031h1.875l4.359,13.5l4.234-13.5h1.875l4.094,20.031z"/>
+ <path d="M84.569,133.696v4.688h6.438v3.031h-6.438v6h9.063v3.156H81.006V130.54h12.625v3.156h-9.063z"/>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/trunk/gui/greeter/themes/happygnome/happygnome.xml b/trunk/gui/greeter/themes/happygnome/happygnome.xml
new file mode 100644
index 00000000..2d0d539f
--- /dev/null
+++ b/trunk/gui/greeter/themes/happygnome/happygnome.xml
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE greeter SYSTEM "greeter.dtd">
+<greeter>
+ <item type="svg" background="true">
+ <normal file="background.svg"/>
+ <pos x="0" y="0" width="100%" height="-75"/>
+ </item>
+ <item type="rect" background="true">
+ <normal color="#000000"/>
+ <pos x="0" y="-75" width="100%" height="75"/>
+ <fixed>
+ <item type="rect" background="true">
+ <normal color="#ffffff"/>
+ <pos x="0" y="4" width="100%" height="100%"/>
+ <box orientation="horizontal" spacing="10" xpadding="10" ypadding="10">
+ <item type="button" id="options_button">
+ <pos width="100" height="50" />
+ <stock type="options"/>
+ </item>
+ <item type="list" id="language" combo="true">
+ <pos x="25" y="5" height="40" width="300"/>
+ </item>
+ <item type="list" id="session" combo="true">
+ <pos x="50" y="5" height="40" width="300"/>
+ </item>
+ </box>
+ </item>
+ </fixed>
+ </item>
+ <item type="rect" id="userlist-rect">
+ <normal color="#FFFFFF" alpha="0.5" font="Sans 14"/>
+ <pos anchor="nw" x="0" y="0" width="box" height="box"/>
+ <box orientation="vertical" min-width="440" max-width="440" min-height="100"
+ xpadding="4" ypadding="4" spacing="0">
+ <item type="list" id="userlist">
+ <pos anchor="nw" x="0" y="0" height="550" width="440"/>
+ <color iconcolor="#ACBFDD" labelcolor="#ACBFDD"/>
+ </item>
+ </box>
+ </item>
+ <item type="svg" background="true">
+ <normal file="gnome-logo.svg"/>
+ <pos x="-12" y="-12" width="30" height="47" anchor="se" />
+ </item>
+ <item type="label" id="clock">
+ <normal color="#000000" font="Sans 12"/>
+ <pos x="-80" y="-37" anchor="e"/>
+ <text>%c</text>
+ </item>
+
+ <item type="rect" id="caps-lock-warning">
+ <normal color="#FFFFFF" alpha="0.5"/>
+ <pos anchor="c" x="50%" y="75%" width="box" height="box"/>
+ <box orientation="vertical" min-width="400" xpadding="10" ypadding="5" spacing="0">
+ <item type="label">
+ <normal color="#000000" font="Sans 12"/>
+ <pos x="50%" anchor="n"/>
+ <!-- Stock label for: You've got capslock on! -->
+ <stock type="caps-lock-warning"/>
+ </item>
+ </box>
+ </item>
+
+ <item type="rect">
+ <show type="timed"/>
+ <normal color="#FFFFFF" alpha="0.5"/>
+ <pos anchor="c" x="50%" y="25%" width="box" height="box"/>
+ <box orientation="vertical" min-width="400" xpadding="10" ypadding="5" spacing="0">
+ <item type="label" id="timed-label">
+ <normal color="#000000" font="Sans 12"/>
+ <pos x="50%" anchor="n"/>
+ <!-- Stock label for: User %s will login in %d seconds -->
+ <stock type="timed-label"/>
+ </item>
+ </box>
+ </item>
+
+ <item type="rect">
+ <normal color="#FFFFFF" alpha="0.5"/>
+ <pos anchor="c" x="50%" y="50%" width="box" height="box"/>
+ <box orientation="vertical" min-width="340" xpadding="30" ypadding="30" spacing="10">
+ <item type="label">
+ <pos anchor="n" x="50%"/>
+ <normal color="#000000" font="Sans 14"/>
+ <!-- Stock label for: Welcome to %h -->
+ <stock type="welcome-label"/>
+ </item>
+ <item type="label" id="pam-prompt">
+ <pos anchor="nw" x="10%"/>
+ <normal color="#000000" font="Sans 12"/>
+ <!-- Stock label for: Username: -->
+ <stock type="username-label"/>
+ </item>
+ <item type="rect">
+ <normal color="#000000"/>
+ <pos anchor="n" x="50%" height="24" width="80%"/>
+ <fixed>
+ <item type="entry" id="user-pw-entry">
+ <normal color="#000000" font="Sans 12"/>
+ <pos anchor="nw" x="1" y="1" height="-2" width="-2"/>
+ </item>
+ </fixed>
+ </item>
+ <item type="button" id="ok_button">
+ <pos anchor="n" x="50%" height="32" width="50%"/>
+ <stock type="ok"/>
+ </item>
+ <item type="button" id="cancel_button">
+ <pos anchor="n" x="50%" height="32" width="50%"/>
+ <stock type="startagain"/>
+ </item>
+ <item type="label" id="pam-message">
+ <pos anchor="n" x="50%"/>
+ <normal color="#000000" font="Sans 12"/>
+ <text></text>
+ </item>
+ </box>
+ <fixed>
+ <item type="label" id="pam-error">
+ <pos anchor="n" x="50%" y="110%"/>
+ <normal color="#000000" font="Sans 12"/>
+ <text></text>
+ </item>
+ </fixed>
+ </item>
+</greeter>
+
+
diff --git a/trunk/gui/greeter/themes/happygnome/options.png b/trunk/gui/greeter/themes/happygnome/options.png
new file mode 100644
index 00000000..431813fa
--- /dev/null
+++ b/trunk/gui/greeter/themes/happygnome/options.png
Binary files differ
diff --git a/trunk/gui/greeter/themes/happygnome/screenshot.png b/trunk/gui/greeter/themes/happygnome/screenshot.png
new file mode 100644
index 00000000..a31c9875
--- /dev/null
+++ b/trunk/gui/greeter/themes/happygnome/screenshot.png
Binary files differ