? out.diff
Index: configure.ac
===================================================================
RCS file: /cvs/gnome/gdm2/configure.ac,v
retrieving revision 1.68
diff -u -p -r1.68 configure.ac
--- configure.ac	4 Sep 2006 21:09:30 -0000	1.68
+++ configure.ac	6 Sep 2006 06:35:12 -0000
@@ -844,6 +844,9 @@ AC_SUBST(GDMPREFETCH)
 AC_SUBST(GDMPREFETCHLIST)
 AC_SUBST(GDMPREFETCHCMD)
 
+GDM_SCRATCH_DIR="${localstatedir}/lib/gdm"
+AC_DEFINE_UNQUOTED(GDM_SCRATCH_DIR, "$GDM_SCRATCH_DIR", [GDM scratch dir])
+
 AC_ARG_ENABLE(secureremote,
   [  --enable-secureremote=[yes/no]  Enable to offer a secure X connection through ssh  [default=no]],,
   enable_secureremote=no)
Index: config/gdm.conf.in
===================================================================
RCS file: /cvs/gnome/gdm2/config/gdm.conf.in,v
retrieving revision 1.157
diff -u -p -r1.157 gdm.conf.in
--- config/gdm.conf.in	3 Aug 2006 17:36:26 -0000	1.157
+++ config/gdm.conf.in	6 Sep 2006 06:35:16 -0000
@@ -491,6 +491,9 @@ GraphicalThemeRand=false
 # list of libraries, one per line, and load each library in the file.
 PreFetchProgram=@GDMPREFETCHCMD@
 
+# Set to true to show the domain login GUI elements.
+#ShowDomain=false
+
 # The chooser is what's displayed when a user wants an indirect XDMCP session,
 # or selects Run XDMCP chooser from the system menu
 [chooser]
Index: daemon/gdm.h
===================================================================
RCS file: /cvs/gnome/gdm2/daemon/gdm.h,v
retrieving revision 1.218
diff -u -p -r1.218 gdm.h
--- daemon/gdm.h	24 Aug 2006 03:47:43 -0000	1.218
+++ daemon/gdm.h	6 Sep 2006 06:35:16 -0000
@@ -384,6 +384,8 @@ enum {
 #define GDM_KEY_GRAPHICAL_THEME_DIR "greeter/GraphicalThemeDir=" DATADIR "/gdm/themes/"
 #define GDM_KEY_GRAPHICAL_THEMED_COLOR "greeter/GraphicalThemedColor=#76848F"
 
+#define GDM_KEY_SHOW_DOMAIN "greeter/ShowDomain=false"
+
 #define GDM_KEY_INFO_MSG_FILE "greeter/InfoMsgFile="
 #define GDM_KEY_INFO_MSG_FONT "greeter/InfoMsgFont="
 
@@ -725,6 +727,7 @@ void		gdm_final_cleanup	(void);
 #define GDM_NOTIFY_TIMED_LOGIN_DELAY "TimedLoginDelay" /* <seconds> */
 #define GDM_NOTIFY_TIMED_LOGIN_ENABLE "TimedLoginEnable" /* <true/false as int> */
 #define GDM_NOTIFY_DISALLOW_TCP "DisallowTCP" /* <true/false as int> */
+#define GDM_NOTIFY_SHOW_DOMAIN "ShowDomain" /* <trye/false as int> */
 #define GDM_NOTIFY_SOUND_ON_LOGIN_FILE "SoundOnLoginFile" /* <sound file> */
 #define GDM_NOTIFY_SOUND_ON_LOGIN_SUCCESS_FILE "SoundOnLoginSuccessFile" /* <sound file> */
 #define GDM_NOTIFY_SOUND_ON_LOGIN_FAILURE_FILE "SoundOnLoginFailureFile" /* <sound file> */
Index: daemon/verify-pam.c
===================================================================
RCS file: /cvs/gnome/gdm2/daemon/verify-pam.c,v
retrieving revision 1.99
diff -u -p -r1.99 verify-pam.c
--- daemon/verify-pam.c	9 Jun 2006 21:07:41 -0000	1.99
+++ daemon/verify-pam.c	6 Sep 2006 06:35:17 -0000
@@ -57,6 +57,8 @@ static char *tmp_PAM_USER = NULL;
 
 /* this is another hack */
 static gboolean did_we_ask_for_password = FALSE;
+static gboolean is_account_disabled = FALSE;
+static gboolean is_account_expired = FALSE;
 
 static char *selected_user = NULL;
 
@@ -430,6 +432,7 @@ perhaps_translate_message (const char *m
 		g_hash_table_insert (hash, "You are required to change your password immediately (password aged)", _("You are required to change your password immediately (password aged)"));
 		g_hash_table_insert (hash, "You are required to change your password immediately (root enforced)", _("You are required to change your password immediately (root enforced)"));
 		g_hash_table_insert (hash, "Your account has expired; please contact your system administrator", _("Your account has expired; please contact your system administrator"));
+		g_hash_table_insert (hash, "Your account is disabled. Please contact your system administrator", _("Your account is disabled. Please contact your system administrator"));
 		g_hash_table_insert (hash, "No password supplied", _("No password supplied"));
 		g_hash_table_insert (hash, "Password unchanged", _("Password unchanged"));
 		g_hash_table_insert (hash, "Can not get username", _("Can not get username"));
@@ -502,8 +505,9 @@ gdm_verify_pam_conv (int num_msg, struct
     
     for (replies = 0; replies < num_msg; replies++) {
 	gboolean islogin = FALSE;
-	const char *m = msg[replies]->msg;
-	m = perhaps_translate_message (m);
+	const char *m_untranslated = msg[replies]->msg;
+	const char *m;
+	m = perhaps_translate_message (m_untranslated);
 	
 	switch (msg[replies]->msg_style) {
 	    
@@ -589,6 +593,12 @@ gdm_verify_pam_conv (int num_msg, struct
 	    
 	case PAM_ERROR_MSG:
 	    /* PAM sent a message that should displayed to the user */
+
+	    if (strstr (m_untranslated, "account is disabled"))
+		is_account_disabled = TRUE;
+	    else if (strstr (m_untranslated, "account has expired"))
+		is_account_expired = TRUE;
+
 	    gdm_slave_greeter_ctl_no_ret (GDM_ERRDLG, m);
 	    reply[replies].resp_retcode = PAM_SUCCESS;
 	    reply[replies].resp = NULL;
@@ -1125,7 +1135,11 @@ authenticate_again:
 		    /* Only give this message if we actually asked for
 		       password, otherwise it would be silly to say that
 		       the password may have been wrong */
-		    if (did_we_ask_for_password) {
+		    if (is_account_disabled) {
+			    basemsg = _("\nYour account has been disabled.");
+		    } else if (is_account_expired) {
+			    basemsg = _("\nYour account has expired.");
+		    } else if (did_we_ask_for_password) {
 			    basemsg = _("\nIncorrect username or password.  "
 					"Letters must be typed in the correct "
 					"case.");
@@ -1134,7 +1148,7 @@ authenticate_again:
 					"Letters must be typed in the correct "
 					"case.");
 		    }
-		    if (is_capslock) {
+		    if (is_capslock && !is_account_disabled && !is_account_expired) {
 			    msg = g_strconcat (basemsg, "  ",
 					       _("Caps Lock is on."),
 					       NULL);
@@ -1250,6 +1264,8 @@ gdm_verify_setup_user (GdmDisplay *d, co
 
     /* Start authentication session */
     did_we_ask_for_password = FALSE;
+    is_account_disabled = FALSE;
+    is_account_expired = FALSE;
     if ((pamerr = pam_authenticate (pamh, null_tok)) != PAM_SUCCESS) {
 	    if (gdm_slave_action_pending ()) {
 		    gdm_error (_("Couldn't authenticate user"));
Index: gui/greeter/greeter.c
===================================================================
RCS file: /cvs/gnome/gdm2/gui/greeter/greeter.c,v
retrieving revision 1.130
diff -u -p -r1.130 greeter.c
--- gui/greeter/greeter.c	8 Aug 2006 15:24:05 -0000	1.130
+++ gui/greeter/greeter.c	6 Sep 2006 06:35:18 -0000
@@ -121,6 +121,53 @@ get_random_theme ()
     return theme;
 }
 
+static gchar *errdlg_message = NULL;
+
+static void
+show_errdlg_messages (void)
+{
+    gchar *tmp;
+    GtkWidget *dlg;
+
+    if (!errdlg_message)
+	return;
+
+    /* we should be now fine for focusing new windows */
+    gdm_wm_focus_new_windows (TRUE);
+
+    tmp = ve_locale_to_utf8 (errdlg_message);
+    dlg = ve_hig_dialog_new (NULL /* parent */,
+			     GTK_DIALOG_MODAL /* flags */,
+			     GTK_MESSAGE_ERROR,
+			     GTK_BUTTONS_OK,
+			     tmp,
+			     "");
+    g_free (tmp);
+    g_free (errdlg_message);
+    errdlg_message = NULL;
+
+    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 ();
+}
+
+static void
+append_errdlg_message (const gchar *message)
+{
+    if (errdlg_message) {
+	gchar *tmp;
+
+	tmp = g_strjoin ("\n\n", errdlg_message, message, NULL);
+	g_free (errdlg_message);
+	errdlg_message = tmp;
+    } else {
+	errdlg_message = g_strdup (message);
+    }
+}
+
 static gboolean
 greeter_ctrl_handler (GIOChannel *source,
 		      GIOCondition cond,
@@ -184,6 +231,8 @@ process_operation (guchar       op_code,
 	break;
 
     case GDM_PROMPT:
+	show_errdlg_messages ();
+
 	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),
@@ -205,6 +254,8 @@ process_operation (guchar       op_code,
 	break;
 
     case GDM_NOECHO:
+	show_errdlg_messages ();
+
 	tmp = ve_locale_to_utf8 (args);
 
 	if (tmp != NULL && strcmp (tmp, _("Password:")) == 0)
@@ -217,6 +268,8 @@ process_operation (guchar       op_code,
 	break;
 
     case GDM_MSG:
+	show_errdlg_messages ();
+
 	tmp = ve_locale_to_utf8 (args);
 	greeter_item_pam_message (tmp);
 	g_free (tmp);
@@ -225,6 +278,8 @@ process_operation (guchar       op_code,
 	break;
 
     case GDM_ERRBOX:
+	show_errdlg_messages ();
+
 	tmp = ve_locale_to_utf8 (args);
 	greeter_item_pam_error (tmp);
 	g_free (tmp);
@@ -234,30 +289,17 @@ process_operation (guchar       op_code,
 	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 = ve_hig_dialog_new (NULL /* parent */,
-				 GTK_DIALOG_MODAL /* flags */,
-				 GTK_MESSAGE_ERROR,
-				 GTK_BUTTONS_OK,
-				 tmp,
-				 "");
+	append_errdlg_message (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:
+	show_errdlg_messages ();
+
 	tmp = ve_locale_to_utf8 (args);
 	session = gdm_session_lookup (tmp);
 	g_free (tmp);
@@ -274,6 +316,8 @@ process_operation (guchar       op_code,
 	break;
 
     case GDM_LANG:
+	show_errdlg_messages ();
+
 	language = greeter_language_get_language (args);
 	if (greeter_language_get_save_language () == GTK_RESPONSE_CANCEL)
 	    printf ("%c%s\n", STX, GDM_RESPONSE_CANCEL);
@@ -284,6 +328,8 @@ process_operation (guchar       op_code,
 	break;
 
     case GDM_SSESS:
+	show_errdlg_messages ();
+
 	if (gdm_get_save_session () == GTK_RESPONSE_YES)
 	  printf ("%cY\n", STX);
 	else
@@ -293,6 +339,8 @@ process_operation (guchar       op_code,
 	break;
 
     case GDM_SLANG:
+	show_errdlg_messages ();
+
 	if (greeter_language_get_save_language () == GTK_RESPONSE_YES)
 	    printf ("%cY\n", STX);
 	else
@@ -325,6 +373,8 @@ process_operation (guchar       op_code,
 	break;
 
     case GDM_QUIT:
+	show_errdlg_messages ();
+
 	greeter_item_timed_stop ();
 
 	if (require_quarter) {
@@ -429,6 +479,8 @@ process_operation (guchar       op_code,
 	break;
 
     case GDM_SAVEDIE:
+	show_errdlg_messages ();
+
 	/* Set busy cursor */
 	gdm_common_setup_cursor (GDK_WATCH);
 
@@ -448,6 +500,8 @@ process_operation (guchar       op_code,
 	break;
 	
     default:
+	show_errdlg_messages ();
+
 	gdm_common_fail_greeter ("Unexpected greeter command received: '%c'", op_code);
 	break;
     }
@@ -773,6 +827,7 @@ gdm_read_config (void)
 	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_SHOW_DOMAIN);
 
 	/* Keys not to include in reread_config */
 	gdm_config_get_string (GDM_KEY_SESSION_DESKTOP_DIR);
@@ -832,7 +887,8 @@ greeter_reread_config (int sig, gpointer
 	    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_ALLOW_REMOTE_ROOT) ||
+	    gdm_config_reload_bool   (GDM_KEY_SHOW_DOMAIN)) {
 
 		/* Set busy cursor */
 		gdm_common_setup_cursor (GDK_WATCH);
Index: gui/greeter/greeter.h
===================================================================
RCS file: /cvs/gnome/gdm2/gui/greeter/greeter.h,v
retrieving revision 1.10
diff -u -p -r1.10 greeter.h
--- gui/greeter/greeter.h	6 Oct 2005 21:30:26 -0000	1.10
+++ gui/greeter/greeter.h	6 Sep 2006 06:35:18 -0000
@@ -27,6 +27,9 @@ extern GtkWidget *window;
 
 extern gboolean greeter_probably_login_prompt;
 
+extern gboolean  greeter_can_do_domain_login;
+extern gchar    *greeter_domain_separator;
+
 void greeter_ignore_buttons (gboolean val);
 
 #endif
Index: gui/greeter/greeter_canvas_item.c
===================================================================
RCS file: /cvs/gnome/gdm2/gui/greeter/greeter_canvas_item.c,v
retrieving revision 1.39
diff -u -p -r1.39 greeter_canvas_item.c
--- gui/greeter/greeter_canvas_item.c	3 Aug 2006 02:32:39 -0000	1.39
+++ gui/greeter/greeter_canvas_item.c	6 Sep 2006 06:35:20 -0000
@@ -20,6 +20,8 @@
 
 #include <math.h>
 #include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
 #include <gtk/gtk.h>
 #include <glib/gi18n.h>
 #include <librsvg/rsvg.h>
@@ -34,6 +36,10 @@
 #include "greeter_canvas_item.h"
 #include "greeter_configuration.h"
 #include "greeter_canvas_text.h"
+#include "greeter_parser.h"
+
+#define WBINFO_DOMAINS_MAX 64
+#define WBINFO_READ_MAX    256
 
 static void
 apply_tint (GdkPixbuf *pixbuf, guint32 tint_color)
@@ -249,6 +255,189 @@ greeter_item_run_button_action_callback 
 	gtk_widget_grab_focus (entry);
 }
 
+gboolean    greeter_can_do_domain_login = FALSE;
+gchar      *greeter_domain_separator    = NULL;
+
+gboolean    greeter_wbinfo_was_run      = FALSE;
+gboolean    greeter_wbinfo_is_running   = FALSE;
+GPid        greeter_wbinfo_pid;
+GIOChannel *greeter_wbinfo_channel;
+GString    *greeter_wbinfo_output;
+
+static void
+wbinfo_end (void)
+{
+	GreeterItemInfo  *domain_entry_item_info;
+	GtkWidget        *domain_entry  = NULL;
+	gint              wbinfo_status = 0;
+	gchar            *wbinfo_output;
+	GtkListStore     *domain_list_store;
+	gchar           **tokens        = NULL;
+	gchar            *own_domain    = NULL;
+	gint              select_index  = 0;
+	GtkTreeIter       iter;
+	const gchar      *text;
+	gint              i;
+
+	if (!greeter_wbinfo_is_running)
+		return;
+
+	greeter_wbinfo_is_running = FALSE;
+	waitpid (greeter_wbinfo_pid, &wbinfo_status, 0);
+	g_spawn_close_pid (greeter_wbinfo_pid);
+
+	wbinfo_output = g_string_free (greeter_wbinfo_output, FALSE);
+
+	domain_entry_item_info = greeter_lookup_id ("domain-entry");
+	if (domain_entry_item_info && domain_entry_item_info->item &&
+	    GNOME_IS_CANVAS_WIDGET (domain_entry_item_info->item)) {
+		domain_entry = GNOME_CANVAS_WIDGET (domain_entry_item_info->item)->widget;
+	} else {
+		g_free (wbinfo_output);
+		return;
+	}
+
+	/* Set up the domain store model */
+
+	domain_list_store = gtk_list_store_new (1, G_TYPE_STRING);
+
+	/* The "local login" entry */
+
+	gtk_list_store_append (domain_list_store, &iter);
+	gtk_list_store_set (domain_list_store, &iter,
+			    0, _("<Local>"),
+			    -1);
+
+	/* Process wbinfo output, if any */
+
+	if (WEXITSTATUS (wbinfo_status) == 0 && wbinfo_output && *wbinfo_output) {
+		/* The first line of output should be the domain separator,
+		 * and any remaining lines are trusted domains. */
+		tokens = g_strsplit_set (wbinfo_output, "\n\r", WBINFO_DOMAINS_MAX + 1);
+	}
+
+	g_free (wbinfo_output);
+	g_free (greeter_domain_separator);
+	greeter_domain_separator = NULL;
+
+	if (tokens && tokens [0]) {
+		greeter_can_do_domain_login = TRUE;
+		greeter_domain_separator = g_strdup (tokens [0]);
+
+		own_domain = tokens [1];
+
+		/* Generate a sorted list of domains for the domain selector combo. */
+
+		g_qsort_with_data (&tokens [1],
+				   g_strv_length (tokens) - 1,
+				   sizeof (gchar *),
+				   (GCompareDataFunc) g_ascii_strcasecmp,
+				   NULL);
+
+		for (i = 1; tokens [i]; i++) {
+			/* Ensure no blank entries */
+			if (!strlen (tokens [i]))
+				continue;
+
+			gtk_list_store_append (domain_list_store, &iter);
+			gtk_list_store_set (domain_list_store, &iter,
+					    0, tokens [i],
+					    -1);
+
+			if (tokens [i] == own_domain)
+				select_index = i;
+		}
+
+	} else {
+		greeter_can_do_domain_login = FALSE;
+	}
+
+	if (tokens)
+		g_strfreev (tokens);
+
+	/* Assign model and default selection to widget */
+
+	gtk_combo_box_set_model (GTK_COMBO_BOX (domain_entry),
+				 GTK_TREE_MODEL (domain_list_store));
+	gtk_combo_box_entry_set_text_column (GTK_COMBO_BOX_ENTRY (domain_entry), 0);
+
+	/* Default to our own domain, but only if the entry was empty */
+	text = gtk_entry_get_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (domain_entry))));
+	if (!text || !*text)
+		gtk_combo_box_set_active (GTK_COMBO_BOX (domain_entry), select_index);
+
+	g_object_unref (domain_list_store);
+}
+
+static gboolean
+wbinfo_on_output (GIOChannel *channel, GIOCondition condition, gpointer data)
+{
+	gchar     buf [WBINFO_READ_MAX];
+	gsize     bytes_read;
+	GIOStatus status;
+
+	status = g_io_channel_read_chars (channel, buf, WBINFO_READ_MAX, &bytes_read, NULL);
+
+	if (bytes_read < 1) {
+		wbinfo_end ();
+		return FALSE;
+	}
+
+	g_string_append_len (greeter_wbinfo_output, buf, bytes_read);
+	return TRUE;
+}
+
+static void
+wbinfo_begin (void)
+{
+	gchar *wbinfo_args [] = { "wbinfo", "--separator", "--own-domain", "--trusted-domains", NULL };
+	gchar *wbinfo_env  [] = { NULL };
+	gint  wbinfo_stdout_fd;
+
+	if (greeter_wbinfo_was_run)
+		return;
+
+	greeter_wbinfo_was_run = TRUE;
+
+	/* Lame guess, in case winbind isn't running, but gets started later. This
+	 * is a workaround for testing and broken systems. */
+	greeter_domain_separator = g_strdup ("\\");
+
+	if (!g_spawn_async_with_pipes ("/",
+				       wbinfo_args,
+				       wbinfo_env,
+				       G_SPAWN_SEARCH_PATH | G_SPAWN_STDERR_TO_DEV_NULL |
+				       G_SPAWN_DO_NOT_REAP_CHILD,
+				       NULL /* child setup function */,
+				       NULL /* child setup user_data */,
+				       &greeter_wbinfo_pid,
+				       NULL /* &wbinfo_stdin_fd */,
+				       &wbinfo_stdout_fd,
+				       NULL /* &wbinfo_stderr_fd */,
+				       NULL))
+		return;
+
+	greeter_wbinfo_is_running = TRUE;
+	greeter_wbinfo_output = g_string_new ("");
+
+	fcntl (wbinfo_stdout_fd, F_SETFL, O_NONBLOCK);
+
+	greeter_wbinfo_channel = g_io_channel_unix_new (wbinfo_stdout_fd);
+	g_io_channel_set_encoding (greeter_wbinfo_channel, NULL, NULL);
+	g_io_channel_set_close_on_unref (greeter_wbinfo_channel, TRUE);
+	g_io_add_watch (greeter_wbinfo_channel, G_IO_IN | G_IO_HUP, wbinfo_on_output, NULL);
+	g_io_channel_unref (greeter_wbinfo_channel);  /* Watch holds remaining ref */
+}
+
+static gboolean
+deselect_entry_text (GtkEntry *entry)
+{
+  gtk_editable_select_region (GTK_EDITABLE (entry), 0, 0);
+  gtk_editable_set_position (GTK_EDITABLE (entry), -1);
+
+  return FALSE;
+}
+
 void
 greeter_item_create_canvas_item (GreeterItemInfo *item)
 {
@@ -490,6 +679,48 @@ greeter_item_create_canvas_item (Greeter
 
     /* cursor blinking is evil on remote displays, don't do it forever */
     gdm_common_setup_blinking_entry (entry);
+
+    break;
+
+  case GREETER_ITEM_TYPE_COMBO_BOX_ENTRY:
+    entry = gtk_combo_box_entry_new ();
+
+    gtk_widget_set_name (entry, "domain-entry");
+
+    gtk_entry_set_has_frame (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (entry))), FALSE);
+    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);
+
+    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 (gtk_bin_get_child (GTK_BIN (entry)));
+
+    /* Recall the last used domain */
+    if (g_file_get_contents (GDM_SCRATCH_DIR "/last_domain", &text, NULL, NULL)) {
+      GtkWidget *temp_entry;
+
+      temp_entry = gtk_bin_get_child (GTK_BIN (entry));
+
+      gtk_entry_set_text (GTK_ENTRY (temp_entry), text);
+
+      /* The set text gets selected. It looks bad. Avoid that. */
+      g_idle_add_full (G_PRIORITY_LOW, (GSourceFunc) deselect_entry_text, temp_entry, NULL);
+
+      g_free (text);
+    }
+
+    /* Query wbinfo */
+    wbinfo_begin ();
 
     break;
 
Index: gui/greeter/greeter_configuration.h
===================================================================
RCS file: /cvs/gnome/gdm2/gui/greeter/greeter_configuration.h,v
retrieving revision 1.22
diff -u -p -r1.22 greeter_configuration.h
--- gui/greeter/greeter_configuration.h	19 Apr 2005 02:57:56 -0000	1.22
+++ gui/greeter/greeter_configuration.h	6 Sep 2006 06:35:20 -0000
@@ -62,6 +62,7 @@ extern gchar *GdmSoundOnLoginFailureFile
 extern gboolean GdmSoundOnLoginReady;
 extern gboolean GdmSoundOnLoginSuccess;
 extern gboolean GdmSoundOnLoginFailure;
+extern gboolean GdmShowDomain;
 
 extern gboolean GDM_IS_LOCAL;
 extern gboolean DOING_GDM_DEVELOPMENT;
Index: gui/greeter/greeter_item.c
===================================================================
RCS file: /cvs/gnome/gdm2/gui/greeter/greeter_item.c,v
retrieving revision 1.30
diff -u -p -r1.30 greeter_item.c
--- gui/greeter/greeter_item.c	27 Apr 2006 02:10:16 -0000	1.30
+++ gui/greeter/greeter_item.c	6 Sep 2006 06:35:20 -0000
@@ -209,6 +209,10 @@ greeter_item_is_visible (GreeterItemInfo
        strcmp (info->show_type, "suspend") == 0))
 	  return FALSE;
 
+  if ( ! gdm_config_get_bool (GDM_KEY_SHOW_DOMAIN) &&
+	g_str_has_prefix (info->show_type, "domain"))
+	  return FALSE;
+
   if (( ! gdm_config_get_bool (GDM_KEY_TIMED_LOGIN_ENABLE) ||
           ve_string_empty (gdm_config_get_string (GDM_KEY_TIMED_LOGIN))) &&
       (info->show_type != NULL &&
Index: gui/greeter/greeter_item.h
===================================================================
RCS file: /cvs/gnome/gdm2/gui/greeter/greeter_item.h,v
retrieving revision 1.18
diff -u -p -r1.18 greeter_item.h
--- gui/greeter/greeter_item.h	27 Apr 2006 02:10:16 -0000	1.18
+++ gui/greeter/greeter_item.h	6 Sep 2006 06:35:20 -0000
@@ -47,7 +47,8 @@ enum _GreeterItemType {
   GREETER_ITEM_TYPE_LABEL,
   GREETER_ITEM_TYPE_ENTRY,
   GREETER_ITEM_TYPE_LIST,
-  GREETER_ITEM_TYPE_BUTTON
+  GREETER_ITEM_TYPE_BUTTON,
+  GREETER_ITEM_TYPE_COMBO_BOX_ENTRY
 };
 
 /* Make sure to adjust the bitfield in the structure if
@@ -147,7 +148,7 @@ struct _GreeterItemInfo {
   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)
+#define GREETER_ITEM_TYPE_IS_TEXT(info) ((info)->item_type == GREETER_ITEM_TYPE_LABEL || (info)->item_type == GREETER_ITEM_TYPE_ENTRY || (info)->item_type == GREETER_ITEM_TYPE_COMBO_BOX_ENTRY)
 	  struct {
 		  guint8 alphas[GREETER_ITEM_STATE_MAX];
 		  guint32 colors[GREETER_ITEM_STATE_MAX];
Index: gui/greeter/greeter_item_pam.c
===================================================================
RCS file: /cvs/gnome/gdm2/gui/greeter/greeter_item_pam.c,v
retrieving revision 1.39
diff -u -p -r1.39 greeter_item_pam.c
--- gui/greeter/greeter_item_pam.c	9 Jun 2006 21:07:42 -0000	1.39
+++ gui/greeter/greeter_item_pam.c	6 Sep 2006 06:35:20 -0000
@@ -36,6 +36,7 @@
 #include "gdm.h"
 #include "gdmwm.h"
 #include "gdmcommon.h"
+#include "gdmconfig.h"
 
 static gboolean messages_to_give = FALSE;
 static gboolean replace_msg = TRUE;
@@ -115,11 +116,29 @@ set_text (GreeterItemInfo *info, const c
 					      info->item);
 }
 
+static void
+domain_entry_set_sensitive (gboolean sensitive)
+{
+  if (gdm_config_get_bool (GDM_KEY_SHOW_DOMAIN))
+    {
+      GreeterItemInfo *domain_entry_item_info;
+      GtkWidget       *domain_entry = NULL;
+
+      domain_entry_item_info = greeter_lookup_id ("domain-entry");
+      if (domain_entry_item_info && domain_entry_item_info->item &&
+	GNOME_IS_CANVAS_WIDGET (domain_entry_item_info->item))
+	  domain_entry = GNOME_CANVAS_WIDGET (domain_entry_item_info->item)->widget;
+
+      if (domain_entry)
+	  gtk_widget_set_sensitive (domain_entry, sensitive);
+    }
+}
+
 void
 greeter_item_pam_login (GtkEntry *entry, GreeterItemInfo *info)
 {
   const char *str;
-  char *tmp;
+  char *tmp, *tmp2;
   GreeterItemInfo *error_info;
 
   greeter_ignore_buttons (TRUE);
@@ -146,6 +165,7 @@ greeter_item_pam_login (GtkEntry *entry,
     }
   
   gtk_widget_set_sensitive (GTK_WIDGET (entry), FALSE);
+  domain_entry_set_sensitive (FALSE);
 
   /* clear the err_box */
   if (err_box_clear_handler > 0)
@@ -160,6 +180,33 @@ greeter_item_pam_login (GtkEntry *entry,
   }
   
   tmp = ve_locale_from_utf8 (str);
+
+  /* Prepend the domain if applicable */
+  if (greeter_probably_login_prompt && gdm_config_get_bool (GDM_KEY_SHOW_DOMAIN))
+    {
+      GreeterItemInfo *domain_entry_item_info;
+      GtkWidget       *domain_entry = NULL;
+
+      domain_entry_item_info = greeter_lookup_id ("domain-entry");
+      if (domain_entry_item_info && domain_entry_item_info->item &&
+	  GNOME_IS_CANVAS_WIDGET (domain_entry_item_info->item))
+	domain_entry = GNOME_CANVAS_WIDGET (domain_entry_item_info->item)->widget;
+
+      if (domain_entry && (str = gtk_combo_box_get_active_text (GTK_COMBO_BOX (domain_entry))) && *str &&
+	  strcmp (str, _("<Local>")))
+        {
+	  g_file_set_contents (GDM_SCRATCH_DIR "/last_domain", str, strlen (str), NULL);
+
+	  tmp2 = g_strdup_printf ("%s%s%s", str, greeter_domain_separator, tmp);
+	  g_free (tmp);
+	  tmp = tmp2;
+        }
+      else
+	{
+	  g_remove (GDM_SCRATCH_DIR "/last_domain");
+	}
+    }
+
   printf ("%c%s\n", STX, tmp);
   fflush (stdout);
   g_free (tmp);
@@ -213,6 +260,7 @@ greeter_item_pam_setup (void)
 
           /* initially insensitive */
           gtk_widget_set_sensitive (entry, FALSE);
+	  domain_entry_set_sensitive (FALSE);
 	}
 
       g_signal_connect (entry, "activate",
@@ -252,6 +300,9 @@ greeter_item_pam_prompt (const char *mes
       gtk_entry_set_max_length (GTK_ENTRY (entry), entry_len);
       gtk_entry_set_text (GTK_ENTRY (entry), "");
       gtk_widget_grab_focus (entry);
+
+      /* Domain selector should only be accessed when entering the user name */
+      domain_entry_set_sensitive (entry_visible);
     }
 
   messages_to_give = FALSE;
Index: gui/greeter/greeter_parser.c
===================================================================
RCS file: /cvs/gnome/gdm2/gui/greeter/greeter_parser.c,v
retrieving revision 1.48
diff -u -p -r1.48 greeter_parser.c
--- gui/greeter/greeter_parser.c	3 Aug 2006 02:32:39 -0000	1.48
+++ gui/greeter/greeter_parser.c	6 Sep 2006 06:35:20 -0000
@@ -394,6 +394,11 @@ parse_stock (xmlNodePtr node,
 	  g_free (*translated_text);
 	  *translated_text = g_strdup (_("Username:"));
 	}
+      else if (g_ascii_strcasecmp ((char *) prop, "domain-label") == 0)
+        {
+	  g_free (*translated_text);
+	  *translated_text = g_strdup (_("Domain:"));
+	}
       else if (g_ascii_strcasecmp ((char *) prop, "ok") == 0)
         {
 	  g_free (*translated_text);
@@ -1552,6 +1557,15 @@ parse_entry (xmlNodePtr        node,
 }
 
 static gboolean
+parse_combo_box_entry (xmlNodePtr        node,
+		       GreeterItemInfo  *info,
+		       GError         **error)
+{
+	/* A ComboBoxEntry is just an Entry with a dropdown list */
+	return parse_entry (node, info, error);
+}
+
+static gboolean
 parse_items (xmlNodePtr  node,
 	     GList     **items_out,
 	     GreeterItemInfo *parent,
@@ -1606,6 +1620,8 @@ parse_items (xmlNodePtr  node,
 	      item_type = GREETER_ITEM_TYPE_LIST;
 	    else if (strcmp ((char *) type, "button") == 0)
 	      item_type = GREETER_ITEM_TYPE_BUTTON;
+	    else if (strcmp ((char *) type, "combo-box-entry") == 0)
+	      item_type = GREETER_ITEM_TYPE_COMBO_BOX_ENTRY;
 	    else
 	      {
 		g_set_error (error,
@@ -1649,6 +1665,9 @@ parse_items (xmlNodePtr  node,
 		break;
 	      case GREETER_ITEM_TYPE_BUTTON:
 		res = parse_gtkbutton (child, info, error);
+		break;
+	      case GREETER_ITEM_TYPE_COMBO_BOX_ENTRY:
+	        res = parse_combo_box_entry (child, info, error);
 		break;
 	      default:
 		g_set_error (error,
