diff --git a/gdm-domain-logon.patch b/gdm-domain-logon.patch new file mode 100644 index 0000000..6bdf7c2 --- /dev/null +++ b/gdm-domain-logon.patch @@ -0,0 +1,1996 @@ +Index: gui/simple-greeter/gdm-simple-greeter.schemas.in +=================================================================== +--- gui/simple-greeter/gdm-simple-greeter.schemas.in (revision 6548) ++++ gui/simple-greeter/gdm-simple-greeter.schemas.in (working copy) +@@ -92,6 +92,18 @@ + + + ++ /schemas/apps/gdm/simple-greeter/recent-domains ++ /apps/gdm/simple-greeter/recent-domains ++ gdm-simple-greeter ++ list ++ string ++ [] ++ ++ Recently selected domains ++ Set to a list of login domains to be shown by default at the login window. ++ ++ ++ + /schemas/apps/gdm/simple-greeter/wm_use_compiz + /apps/gdm/simple-greeter/wm_use_compiz + gdm-simple-greeter +Index: gui/simple-greeter/gdm-domain-option-widget.c +=================================================================== +--- gui/simple-greeter/gdm-domain-option-widget.c (revision 0) ++++ gui/simple-greeter/gdm-domain-option-widget.c (revision 0) +@@ -0,0 +1,379 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- ++ * ++ * Copyright (C) 2008 Hans Petter Jansson ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * Written by: Hans Petter Jansson ++ * ++ */ ++ ++#include "config.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "gdm-profile.h" ++#include "gdm-domain-option-widget.h" ++#include "gdm-recent-option-widget.h" ++#include "gdm-domain-chooser-dialog.h" ++#include "gdm-domain-provider.h" ++ ++#define GDM_DOMAIN_OPTION_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_DOMAIN_OPTION_WIDGET, GdmDomainOptionWidgetPrivate)) ++ ++struct GdmDomainOptionWidgetPrivate ++{ ++ GtkWidget *dialog; ++ GdmDomainProvider *domain_provider; ++}; ++ ++enum { ++ DOMAIN_ACTIVATED, ++ NUMBER_OF_SIGNALS ++}; ++ ++static guint signals [NUMBER_OF_SIGNALS] = { 0, }; ++ ++static void gdm_domain_option_widget_class_init (GdmDomainOptionWidgetClass *klass); ++static void gdm_domain_option_widget_init (GdmDomainOptionWidget *domain_option_widget); ++static void gdm_domain_option_widget_finalize (GObject *object); ++static void gdm_domain_option_widget_hide_dialog (GdmDomainOptionWidget *widget); ++ ++G_DEFINE_TYPE (GdmDomainOptionWidget, gdm_domain_option_widget, GDM_TYPE_RECENT_OPTION_WIDGET) ++ ++static gchar * ++convert_domain_name_to_display (const gchar *domain_name) ++{ ++ gchar *utf8_name; ++ gchar *normalized_name; ++ ++ utf8_name = g_locale_to_utf8 (domain_name, -1, NULL, NULL, NULL); ++ if (!utf8_name) ++ return NULL; ++ ++ normalized_name = g_utf8_strdown (utf8_name, -1); ++ g_free (utf8_name); ++ ++ return normalized_name; ++} ++ ++static void ++gdm_domain_option_widget_set_domain_from_dialog (GdmDomainOptionWidget *widget) ++{ ++ char *domain_name; ++ ++ domain_name = gdm_domain_chooser_dialog_get_current_domain_name (GDM_DOMAIN_CHOOSER_DIALOG (widget->priv->dialog)); ++ gdm_domain_option_widget_set_current_domain_name (widget, domain_name); ++ g_free (domain_name); ++} ++ ++static void ++on_dialog_response (GtkDialog *dialog, ++ int response_id, ++ GdmDomainOptionWidget *widget) ++{ ++ switch (response_id) { ++ case GTK_RESPONSE_OK: ++ gdm_domain_option_widget_set_domain_from_dialog (widget); ++ break; ++ ++ default: ++ break; ++ } ++ ++ gdm_domain_option_widget_hide_dialog (widget); ++} ++ ++static void ++gdm_domain_option_widget_hide_dialog (GdmDomainOptionWidget *widget) ++{ ++ gtk_widget_destroy (widget->priv->dialog); ++ widget->priv->dialog = NULL; ++} ++ ++static void ++create_dialog (GdmDomainOptionWidget *widget) ++{ ++ gdm_profile_start (NULL); ++ ++ g_assert (widget->priv->dialog == NULL); ++ ++ widget->priv->dialog = gdm_domain_chooser_dialog_new (); ++ ++ gdm_profile_end (NULL); ++} ++ ++static void ++gdm_domain_option_widget_show_dialog (GdmDomainOptionWidget *widget, ++ const char *active_item_id) ++{ ++ if (widget->priv->dialog == NULL) { ++ create_dialog (widget); ++ } ++ ++ g_signal_connect (GTK_DIALOG (widget->priv->dialog), ++ "response", ++ G_CALLBACK (on_dialog_response), ++ widget); ++ ++ gtk_widget_show_all (GTK_WIDGET (widget->priv->dialog)); ++ ++ gdm_domain_chooser_dialog_set_current_domain_name (GDM_DOMAIN_CHOOSER_DIALOG (GDM_DOMAIN_OPTION_WIDGET (widget)->priv->dialog), ++ active_item_id); ++} ++ ++static gint ++find_domain_name_in_list (GdmDomainOptionWidget *domain_option_widget, const gchar *domain_name) ++{ ++ GdmDomainOptionWidgetPrivate *priv = domain_option_widget->priv; ++ GList *domain_list; ++ GList *domain_list_item; ++ gint result = -1; ++ ++ domain_list = gdm_domain_provider_peek_domains (priv->domain_provider); ++ domain_list_item = g_list_find_custom (domain_list, domain_name, (GCompareFunc) g_strcasecmp); ++ ++ if (domain_list_item) ++ result = g_list_position (domain_list, domain_list_item); ++ ++ return result; ++} ++ ++static gboolean ++gdm_domain_option_widget_lookup_item (GdmRecentOptionWidget *domain_option_widget, ++ const char *id, ++ char **name, ++ char **comment) ++{ ++ gchar *display_name; ++ ++ if (!find_domain_name_in_list (GDM_DOMAIN_OPTION_WIDGET (domain_option_widget), id)) ++ return FALSE; ++ ++ display_name = convert_domain_name_to_display (id); ++ if (!display_name) ++ return FALSE; ++ ++ if (name) ++ *name = g_strdup (display_name); ++ if (comment) ++ *comment = g_strdup (display_name); ++ ++ g_free (display_name); ++ return TRUE; ++} ++ ++static void ++gdm_domain_option_widget_activated (GdmOptionWidget *widget) ++{ ++ char *active_item_id; ++ ++ active_item_id = gdm_option_widget_get_active_item (GDM_OPTION_WIDGET (widget)); ++ if (active_item_id == NULL) { ++ return; ++ } ++ ++ if (strcmp (active_item_id, "__other") == 0) { ++ active_item_id = gdm_option_widget_get_default_item (widget); ++ gdm_domain_option_widget_set_current_domain_name (GDM_DOMAIN_OPTION_WIDGET (widget), active_item_id); ++ gdm_domain_option_widget_show_dialog (GDM_DOMAIN_OPTION_WIDGET (widget), active_item_id); ++ } ++ ++ g_signal_emit (G_OBJECT (widget), signals [DOMAIN_ACTIVATED], 0); ++ ++ g_free (active_item_id); ++} ++ ++static void ++gdm_domain_option_widget_class_init (GdmDomainOptionWidgetClass *klass) ++{ ++ GObjectClass *object_class = G_OBJECT_CLASS (klass); ++ GdmOptionWidgetClass *option_widget_class = GDM_OPTION_WIDGET_CLASS (klass); ++ ++ object_class->finalize = gdm_domain_option_widget_finalize; ++ ++ option_widget_class->activated = gdm_domain_option_widget_activated; ++ ++ signals [DOMAIN_ACTIVATED] = g_signal_new ("domain-activated", ++ G_TYPE_FROM_CLASS (object_class), ++ G_SIGNAL_RUN_FIRST, ++ G_STRUCT_OFFSET (GdmDomainOptionWidgetClass, domain_activated), ++ NULL, ++ NULL, ++ g_cclosure_marshal_VOID__VOID, ++ G_TYPE_NONE, ++ 0); ++ ++ g_type_class_add_private (klass, sizeof (GdmDomainOptionWidgetPrivate)); ++} ++ ++static void ++populate_widget (GdmDomainOptionWidget *domain_option_widget) ++{ ++ GdmDomainOptionWidgetPrivate *priv = domain_option_widget->priv; ++ GdmOptionWidget *option_widget = GDM_OPTION_WIDGET (domain_option_widget); ++ GList *domain_list; ++ GList *l; ++ gchar *current_domain_name; ++ ++ domain_list = gdm_domain_provider_peek_domains (priv->domain_provider); ++ ++ current_domain_name = gdm_domain_option_widget_get_current_domain_name (domain_option_widget); ++ gdm_option_widget_remove_all_items (option_widget); ++ ++ for (l = domain_list; l; l = g_list_next (l)) { ++ const gchar *domain_name = l->data; ++ gchar *display_name; ++ ++ display_name = convert_domain_name_to_display (domain_name); ++ if (!display_name) ++ continue; ++ ++ gdm_option_widget_add_item (option_widget, ++ domain_name, ++ display_name, ++ display_name, ++ GDM_OPTION_WIDGET_POSITION_MIDDLE); ++ g_free (display_name); ++ } ++ ++ if (current_domain_name) { ++ gdm_domain_option_widget_set_current_domain_name (domain_option_widget, current_domain_name); ++ g_free (current_domain_name); ++ } ++} ++ ++static void ++gdm_domain_option_widget_init (GdmDomainOptionWidget *domain_option_widget) ++{ ++ GdmDomainOptionWidgetPrivate *priv; ++ GdmOptionWidget *option_widget = GDM_OPTION_WIDGET (domain_option_widget); ++ GError *error = NULL; ++ ++ priv = domain_option_widget->priv = GDM_DOMAIN_OPTION_WIDGET_GET_PRIVATE (domain_option_widget); ++ ++ priv->domain_provider = gdm_get_domain_provider (); ++ g_signal_connect_swapped (priv->domain_provider, "changed", ++ (GCallback) populate_widget, domain_option_widget); ++ ++ gdm_option_widget_add_item (option_widget, ++ "__local", ++ _("Local login"), ++ _("Log in to the local computer."), ++ GDM_OPTION_WIDGET_POSITION_TOP); ++ ++ gdm_option_widget_add_item (option_widget, ++ "__other", ++ _("Other..."), ++ _("Choose a domain from the " ++ "full list of available domains."), ++ GDM_OPTION_WIDGET_POSITION_BOTTOM); ++ ++ gdm_option_widget_set_default_item (option_widget, "__local"); ++ ++ populate_widget (domain_option_widget); ++ ++ gdm_recent_option_widget_set_gconf_key (GDM_RECENT_OPTION_WIDGET (domain_option_widget), ++ "/apps/gdm/simple-greeter/recent-domains", ++ gdm_domain_option_widget_lookup_item, ++ &error); ++ ++ if (error != NULL) { ++ g_warning ("Could not read recent domains from gconf: %s", ++ error->message); ++ g_error_free (error); ++ } ++} ++ ++static void ++gdm_domain_option_widget_finalize (GObject *object) ++{ ++ GdmDomainOptionWidgetPrivate *priv; ++ GdmDomainOptionWidget *domain_option_widget; ++ ++ g_return_if_fail (object != NULL); ++ g_return_if_fail (GDM_IS_DOMAIN_OPTION_WIDGET (object)); ++ ++ domain_option_widget = GDM_DOMAIN_OPTION_WIDGET (object); ++ priv = domain_option_widget->priv; ++ ++ g_return_if_fail (priv != NULL); ++ ++ if (priv->dialog != NULL) { ++ gtk_widget_destroy (priv->dialog); ++ } ++ ++ g_signal_handlers_disconnect_by_func (priv->domain_provider, populate_widget, domain_option_widget); ++ ++ G_OBJECT_CLASS (gdm_domain_option_widget_parent_class)->finalize (object); ++} ++ ++GtkWidget * ++gdm_domain_option_widget_new (void) ++{ ++ GObject *object; ++ ++ object = g_object_new (GDM_TYPE_DOMAIN_OPTION_WIDGET, ++ "label-text", _("_Domain:"), ++ "icon-name", "preferences-system-network", ++ "max-item-count", 16, ++ NULL); ++ ++ return GTK_WIDGET (object); ++} ++ ++char * ++gdm_domain_option_widget_get_current_domain_name (GdmDomainOptionWidget *widget) ++{ ++ char *active_item_id; ++ ++ active_item_id = gdm_option_widget_get_active_item (GDM_OPTION_WIDGET (widget)); ++ if (active_item_id == NULL) { ++ return NULL; ++ } ++ ++ if (strcmp (active_item_id, "__other") == 0) { ++ g_free (active_item_id); ++ return NULL; ++ } ++ ++ return active_item_id; ++} ++ ++void ++gdm_domain_option_widget_set_current_domain_name (GdmDomainOptionWidget *widget, ++ const char *domain_name) ++{ ++ g_return_if_fail (GDM_IS_DOMAIN_OPTION_WIDGET (widget)); ++ ++ if (domain_name != NULL && ++ !gdm_option_widget_lookup_item (GDM_OPTION_WIDGET (widget), ++ domain_name, NULL, NULL, NULL)) { ++ gdm_recent_option_widget_add_item (GDM_RECENT_OPTION_WIDGET (widget), ++ domain_name); ++ } ++ ++ gdm_option_widget_set_active_item (GDM_OPTION_WIDGET (widget), domain_name); ++} +Index: gui/simple-greeter/gdm-domain-option-widget.h +=================================================================== +--- gui/simple-greeter/gdm-domain-option-widget.h (revision 0) ++++ gui/simple-greeter/gdm-domain-option-widget.h (revision 0) +@@ -0,0 +1,59 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- ++ * ++ * Copyright (C) 2008 Hans Petter Jansson ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * Written by: Hans Petter Jansson ++ */ ++ ++#ifndef __GDM_DOMAIN_OPTION_WIDGET_H ++#define __GDM_DOMAIN_OPTION_WIDGET_H ++ ++#include ++#include "gdm-recent-option-widget.h" ++ ++G_BEGIN_DECLS ++ ++#define GDM_TYPE_DOMAIN_OPTION_WIDGET (gdm_domain_option_widget_get_type ()) ++#define GDM_DOMAIN_OPTION_WIDGET(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_DOMAIN_OPTION_WIDGET, GdmDomainOptionWidget)) ++#define GDM_DOMAIN_OPTION_WIDGET_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_DOMAIN_OPTION_WIDGET, GdmDomainOptionWidgetClass)) ++#define GDM_IS_DOMAIN_OPTION_WIDGET(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_DOMAIN_OPTION_WIDGET)) ++#define GDM_IS_DOMAIN_OPTION_WIDGET_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_DOMAIN_OPTION_WIDGET)) ++#define GDM_DOMAIN_OPTION_WIDGET_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_DOMAIN_OPTION_WIDGET, GdmDomainOptionWidgetClass)) ++ ++typedef struct GdmDomainOptionWidgetPrivate GdmDomainOptionWidgetPrivate; ++ ++typedef struct ++{ ++ GdmRecentOptionWidget parent; ++ GdmDomainOptionWidgetPrivate *priv; ++} GdmDomainOptionWidget; ++ ++typedef struct ++{ ++ GdmRecentOptionWidgetClass parent_class; ++ ++ void (* domain_activated) (GdmDomainOptionWidget *widget); ++} GdmDomainOptionWidgetClass; ++ ++GType gdm_domain_option_widget_get_type (void); ++GtkWidget * gdm_domain_option_widget_new (void); ++ ++char * gdm_domain_option_widget_get_current_domain_name (GdmDomainOptionWidget *widget); ++void gdm_domain_option_widget_set_current_domain_name (GdmDomainOptionWidget *widget, ++ const char *domain_name); ++ ++#endif /* __GDM_DOMAIN_OPTION_WIDGET_H */ +Index: gui/simple-greeter/gdm-domain-chooser-dialog.c +=================================================================== +--- gui/simple-greeter/gdm-domain-chooser-dialog.c (revision 0) ++++ gui/simple-greeter/gdm-domain-chooser-dialog.c (revision 0) +@@ -0,0 +1,207 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- ++ * ++ * Copyright (C) 2008 Hans Petter Jansson ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * Written by: Hans Petter Jansson ++ */ ++ ++#include "config.h" ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "gdm-domain-chooser-widget.h" ++#include "gdm-domain-chooser-dialog.h" ++ ++#define GDM_DOMAIN_CHOOSER_DIALOG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_DOMAIN_CHOOSER_DIALOG, GdmDomainChooserDialogPrivate)) ++ ++struct GdmDomainChooserDialogPrivate ++{ ++ GtkWidget *chooser_widget; ++}; ++ ++ ++static void gdm_domain_chooser_dialog_class_init (GdmDomainChooserDialogClass *klass); ++static void gdm_domain_chooser_dialog_init (GdmDomainChooserDialog *domain_chooser_dialog); ++static void gdm_domain_chooser_dialog_finalize (GObject *object); ++ ++G_DEFINE_TYPE (GdmDomainChooserDialog, gdm_domain_chooser_dialog, GTK_TYPE_DIALOG) ++ ++char * ++gdm_domain_chooser_dialog_get_current_domain_name (GdmDomainChooserDialog *dialog) ++{ ++ char *domain_name; ++ ++ g_return_val_if_fail (GDM_IS_DOMAIN_CHOOSER_DIALOG (dialog), NULL); ++ ++ domain_name = gdm_domain_chooser_widget_get_current_domain_name (GDM_DOMAIN_CHOOSER_WIDGET (dialog->priv->chooser_widget)); ++ ++ return domain_name; ++} ++ ++void ++gdm_domain_chooser_dialog_set_current_domain_name (GdmDomainChooserDialog *dialog, ++ const char *domain_name) ++{ ++ g_return_if_fail (GDM_IS_DOMAIN_CHOOSER_DIALOG (dialog)); ++ ++ gdm_domain_chooser_widget_set_current_domain_name (GDM_DOMAIN_CHOOSER_WIDGET (dialog->priv->chooser_widget), domain_name); ++} ++ ++static void ++gdm_domain_chooser_dialog_size_request (GtkWidget *widget, ++ GtkRequisition *requisition) ++{ ++ int screen_w; ++ int screen_h; ++ GtkRequisition child_requisition; ++ ++ if (GTK_WIDGET_CLASS (gdm_domain_chooser_dialog_parent_class)->size_request) { ++ GTK_WIDGET_CLASS (gdm_domain_chooser_dialog_parent_class)->size_request (widget, requisition); ++ } ++ ++ screen_w = gdk_screen_get_width (gtk_widget_get_screen (widget)); ++ screen_h = gdk_screen_get_height (gtk_widget_get_screen (widget)); ++ ++ gtk_widget_get_child_requisition (GTK_BIN (widget)->child, &child_requisition); ++ *requisition = child_requisition; ++ ++ requisition->width += 2 * GTK_CONTAINER (widget)->border_width; ++ requisition->height += 2 * GTK_CONTAINER (widget)->border_width; ++ ++ requisition->width = MIN (requisition->width, .50 * screen_w); ++ requisition->height = MIN (requisition->height, .80 * screen_h); ++} ++ ++static void ++gdm_domain_chooser_dialog_realize (GtkWidget *widget) ++{ ++ GdmDomainChooserDialog *chooser_dialog; ++ GdkWindow *root_window; ++ GdkCursor *cursor; ++ ++ root_window = gdk_screen_get_root_window (gdk_screen_get_default ()); ++ cursor = gdk_cursor_new (GDK_WATCH); ++ gdk_window_set_cursor (root_window, cursor); ++ gdk_cursor_unref (cursor); ++ ++ chooser_dialog = GDM_DOMAIN_CHOOSER_DIALOG (widget); ++ ++ gtk_widget_show (chooser_dialog->priv->chooser_widget); ++ ++ GTK_WIDGET_CLASS (gdm_domain_chooser_dialog_parent_class)->realize (widget); ++ ++ cursor = gdk_cursor_new (GDK_LEFT_PTR); ++ gdk_window_set_cursor (root_window, cursor); ++ gdk_cursor_unref (cursor); ++} ++ ++static void ++gdm_domain_chooser_dialog_class_init (GdmDomainChooserDialogClass *klass) ++{ ++ GObjectClass *object_class = G_OBJECT_CLASS (klass); ++ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); ++ ++ object_class->finalize = gdm_domain_chooser_dialog_finalize; ++ widget_class->size_request = gdm_domain_chooser_dialog_size_request; ++ widget_class->realize = gdm_domain_chooser_dialog_realize; ++ ++ g_type_class_add_private (klass, sizeof (GdmDomainChooserDialogPrivate)); ++} ++ ++static gboolean ++respond (GdmDomainChooserDialog *dialog) ++{ ++ gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); ++ return FALSE; ++} ++ ++static void ++queue_response (GdmDomainChooserDialog *dialog) ++{ ++ g_idle_add ((GSourceFunc) respond, dialog); ++} ++ ++static void ++gdm_domain_chooser_dialog_init (GdmDomainChooserDialog *dialog) ++{ ++ ++ dialog->priv = GDM_DOMAIN_CHOOSER_DIALOG_GET_PRIVATE (dialog); ++ ++ dialog->priv->chooser_widget = gdm_domain_chooser_widget_new (); ++ gdm_chooser_widget_set_hide_inactive_items (GDM_CHOOSER_WIDGET (dialog->priv->chooser_widget), ++ FALSE); ++ ++ gdm_domain_chooser_widget_set_current_domain_name (GDM_DOMAIN_CHOOSER_WIDGET (dialog->priv->chooser_widget), ++ "__local"); ++ gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), dialog->priv->chooser_widget); ++ ++ g_signal_connect_swapped (G_OBJECT (dialog->priv->chooser_widget), ++ "activated", G_CALLBACK (queue_response), ++ dialog); ++ ++ gtk_dialog_add_buttons (GTK_DIALOG (dialog), ++ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, ++ GTK_STOCK_OK, GTK_RESPONSE_OK, ++ NULL); ++ ++ gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE); ++ gtk_container_set_border_width (GTK_CONTAINER (dialog), 12); ++ gtk_container_set_border_width (GTK_CONTAINER (dialog->priv->chooser_widget), 5); ++ gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER_ALWAYS); ++ gtk_window_set_default_size (GTK_WINDOW (dialog), 512, 440); ++ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); ++} ++ ++static void ++gdm_domain_chooser_dialog_finalize (GObject *object) ++{ ++ GdmDomainChooserDialog *domain_chooser_dialog; ++ ++ g_return_if_fail (object != NULL); ++ g_return_if_fail (GDM_IS_DOMAIN_CHOOSER_DIALOG (object)); ++ ++ domain_chooser_dialog = GDM_DOMAIN_CHOOSER_DIALOG (object); ++ ++ g_return_if_fail (domain_chooser_dialog->priv != NULL); ++ ++ G_OBJECT_CLASS (gdm_domain_chooser_dialog_parent_class)->finalize (object); ++} ++ ++GtkWidget * ++gdm_domain_chooser_dialog_new (void) ++{ ++ GObject *object; ++ ++ object = g_object_new (GDM_TYPE_DOMAIN_CHOOSER_DIALOG, ++ "icon-name", "preferences-system-network", ++ "title", _("Domains"), ++ "border-width", 8, ++ "modal", TRUE, ++ NULL); ++ ++ return GTK_WIDGET (object); ++} +Index: gui/simple-greeter/gdm-domain-chooser-dialog.h +=================================================================== +--- gui/simple-greeter/gdm-domain-chooser-dialog.h (revision 0) ++++ gui/simple-greeter/gdm-domain-chooser-dialog.h (revision 0) +@@ -0,0 +1,60 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- ++ * ++ * Copyright (C) 2008 Hans Petter Jansson ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * Written by: Hans Petter Jansson ++ */ ++ ++#ifndef __GDM_DOMAIN_CHOOSER_DIALOG_H ++#define __GDM_DOMAIN_CHOOSER_DIALOG_H ++ ++#include ++#include ++ ++G_BEGIN_DECLS ++ ++#define GDM_TYPE_DOMAIN_CHOOSER_DIALOG (gdm_domain_chooser_dialog_get_type ()) ++#define GDM_DOMAIN_CHOOSER_DIALOG(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_DOMAIN_CHOOSER_DIALOG, GdmDomainChooserDialog)) ++#define GDM_DOMAIN_CHOOSER_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_DOMAIN_CHOOSER_DIALOG, GdmDomainChooserDialogClass)) ++#define GDM_IS_DOMAIN_CHOOSER_DIALOG(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_DOMAIN_CHOOSER_DIALOG)) ++#define GDM_IS_DOMAIN_CHOOSER_DIALOG_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_DOMAIN_CHOOSER_DIALOG)) ++#define GDM_DOMAIN_CHOOSER_DIALOG_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_DOMAIN_CHOOSER_DIALOG, GdmDomainChooserDialogClass)) ++ ++typedef struct GdmDomainChooserDialogPrivate GdmDomainChooserDialogPrivate; ++ ++typedef struct ++{ ++ GtkDialog parent; ++ GdmDomainChooserDialogPrivate *priv; ++} GdmDomainChooserDialog; ++ ++typedef struct ++{ ++ GtkDialogClass parent_class; ++} GdmDomainChooserDialogClass; ++ ++GType gdm_domain_chooser_dialog_get_type (void); ++ ++GtkWidget * gdm_domain_chooser_dialog_new (void); ++ ++char * gdm_domain_chooser_dialog_get_current_domain_name (GdmDomainChooserDialog *dialog); ++void gdm_domain_chooser_dialog_set_current_domain_name (GdmDomainChooserDialog *dialog, ++ const char *domain_name); ++ ++G_END_DECLS ++ ++#endif /* __GDM_DOMAIN_CHOOSER_DIALOG_H */ +Index: gui/simple-greeter/gdm-domain-chooser-widget.c +=================================================================== +--- gui/simple-greeter/gdm-domain-chooser-widget.c (revision 0) ++++ gui/simple-greeter/gdm-domain-chooser-widget.c (revision 0) +@@ -0,0 +1,237 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- ++ * ++ * Copyright (C) 2008 Hans Petter Jansson ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * Written by: Hans Petter Jansson ++ */ ++ ++#include "config.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "gdm-domain-chooser-widget.h" ++#include "gdm-chooser-widget.h" ++#include "gdm-domain-provider.h" ++ ++#define GDM_DOMAIN_CHOOSER_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_DOMAIN_CHOOSER_WIDGET, GdmDomainChooserWidgetPrivate)) ++ ++struct GdmDomainChooserWidgetPrivate ++{ ++ GdmDomainProvider *domain_provider; ++}; ++ ++static void gdm_domain_chooser_widget_class_init (GdmDomainChooserWidgetClass *klass); ++static void gdm_domain_chooser_widget_init (GdmDomainChooserWidget *domain_chooser_widget); ++static void gdm_domain_chooser_widget_finalize (GObject *object); ++ ++G_DEFINE_TYPE (GdmDomainChooserWidget, gdm_domain_chooser_widget, GDM_TYPE_CHOOSER_WIDGET) ++ ++#if 0 ++ ++enum { ++ CHOOSER_LIST_TITLE_COLUMN = 0, ++ CHOOSER_LIST_TRANSLATED_COLUMN, ++ CHOOSER_LIST_DOMAIN_COLUMN ++}; ++ ++#endif ++ ++static gchar * ++convert_domain_name_to_display (const gchar *domain_name) ++{ ++ gchar *utf8_name; ++ gchar *normalized_name; ++ ++ utf8_name = g_locale_to_utf8 (domain_name, -1, NULL, NULL, NULL); ++ if (!utf8_name) ++ return NULL; ++ ++ normalized_name = g_utf8_strdown (utf8_name, -1); ++ g_free (utf8_name); ++ ++ return normalized_name; ++} ++ ++char * ++gdm_domain_chooser_widget_get_current_domain_name (GdmDomainChooserWidget *widget) ++{ ++ char *domain_name; ++ ++ g_return_val_if_fail (GDM_IS_DOMAIN_CHOOSER_WIDGET (widget), NULL); ++ ++ domain_name = gdm_chooser_widget_get_selected_item (GDM_CHOOSER_WIDGET (widget)); ++ ++ if (domain_name == NULL) { ++ domain_name = g_strdup ("__local"); ++ } ++ ++ return domain_name; ++} ++ ++void ++gdm_domain_chooser_widget_set_current_domain_name (GdmDomainChooserWidget *widget, ++ const char *domain_name) ++{ ++ g_return_if_fail (GDM_IS_DOMAIN_CHOOSER_WIDGET (widget)); ++ ++ if (domain_name == NULL) { ++ gdm_chooser_widget_set_selected_item (GDM_CHOOSER_WIDGET (widget), ++ NULL); ++ return; ++ } ++ ++ gdm_chooser_widget_set_selected_item (GDM_CHOOSER_WIDGET (widget), ++ domain_name); ++} ++ ++static void ++populate_widget (GdmDomainChooserWidget *domain_chooser_widget) ++{ ++ GdmDomainChooserWidgetPrivate *priv = domain_chooser_widget->priv; ++ GdmChooserWidget *chooser_widget = GDM_CHOOSER_WIDGET (domain_chooser_widget); ++ GList *domain_list; ++ GList *l; ++ gchar *current_domain_name; ++ ++ domain_list = gdm_domain_provider_peek_domains (priv->domain_provider); ++ ++ current_domain_name = gdm_domain_chooser_widget_get_current_domain_name (domain_chooser_widget); ++ gdm_chooser_widget_remove_all_items (chooser_widget); ++ ++ for (l = domain_list; l; l = g_list_next (l)) { ++ const gchar *domain_name = l->data; ++ gchar *display_name; ++ ++ display_name = convert_domain_name_to_display (domain_name); ++ if (!display_name) ++ continue; ++ ++ gdm_chooser_widget_add_item (chooser_widget, ++ domain_name, ++ NULL, ++ display_name, ++ display_name, ++ 0, ++ FALSE, ++ FALSE); ++ ++ g_free (display_name); ++ } ++ ++ gdm_chooser_widget_add_item (chooser_widget, ++ "__local", ++ NULL, ++ _("Local login"), ++ _("Log in to the local computer."), ++ 0, ++ FALSE, ++ TRUE); ++ ++ gdm_domain_chooser_widget_set_current_domain_name (domain_chooser_widget, current_domain_name); ++} ++ ++static void ++gdm_domain_chooser_widget_dispose (GObject *object) ++{ ++ G_OBJECT_CLASS (gdm_domain_chooser_widget_parent_class)->dispose (object); ++} ++ ++static void ++gdm_domain_chooser_widget_realize (GtkWidget *widget) ++{ ++ GdmDomainChooserWidget *chooser; ++ ++ chooser = GDM_DOMAIN_CHOOSER_WIDGET (widget); ++ ++ GTK_WIDGET_CLASS (gdm_domain_chooser_widget_parent_class)->realize (widget); ++} ++ ++static void ++gdm_domain_chooser_widget_class_init (GdmDomainChooserWidgetClass *klass) ++{ ++ GObjectClass *object_class = G_OBJECT_CLASS (klass); ++ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); ++ ++ object_class->dispose = gdm_domain_chooser_widget_dispose; ++ object_class->finalize = gdm_domain_chooser_widget_finalize; ++ widget_class->realize = gdm_domain_chooser_widget_realize; ++ ++ g_type_class_add_private (klass, sizeof (GdmDomainChooserWidgetPrivate)); ++} ++ ++static void ++gdm_domain_chooser_widget_init (GdmDomainChooserWidget *domain_chooser_widget) ++{ ++ GdmDomainChooserWidgetPrivate *priv; ++ ++ priv = domain_chooser_widget->priv = GDM_DOMAIN_CHOOSER_WIDGET_GET_PRIVATE (domain_chooser_widget); ++ ++ priv->domain_provider = gdm_get_domain_provider (); ++ g_signal_connect_swapped (priv->domain_provider, "changed", ++ (GCallback) populate_widget, domain_chooser_widget); ++ ++ populate_widget (domain_chooser_widget); ++ ++ gdm_chooser_widget_set_separator_position (GDM_CHOOSER_WIDGET (domain_chooser_widget), ++ GDM_CHOOSER_WIDGET_POSITION_TOP); ++} ++ ++static void ++gdm_domain_chooser_widget_finalize (GObject *object) ++{ ++ GdmDomainChooserWidgetPrivate *priv; ++ GdmDomainChooserWidget *domain_chooser_widget; ++ ++ g_return_if_fail (object != NULL); ++ g_return_if_fail (GDM_IS_DOMAIN_CHOOSER_WIDGET (object)); ++ ++ domain_chooser_widget = GDM_DOMAIN_CHOOSER_WIDGET (object); ++ priv = domain_chooser_widget->priv; ++ ++ g_return_if_fail (priv != NULL); ++ ++ g_signal_handlers_disconnect_by_func (priv->domain_provider, populate_widget, domain_chooser_widget); ++ ++ G_OBJECT_CLASS (gdm_domain_chooser_widget_parent_class)->finalize (object); ++} ++ ++GtkWidget * ++gdm_domain_chooser_widget_new (void) ++{ ++ GObject *object; ++ ++ object = g_object_new (GDM_TYPE_DOMAIN_CHOOSER_WIDGET, ++ "inactive-text", _("_Domains:"), ++ "active-text", _("_Domain:"), ++ NULL); ++ ++ return GTK_WIDGET (object); ++} +Index: gui/simple-greeter/gdm-domain-chooser-widget.h +=================================================================== +--- gui/simple-greeter/gdm-domain-chooser-widget.h (revision 0) ++++ gui/simple-greeter/gdm-domain-chooser-widget.h (revision 0) +@@ -0,0 +1,59 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- ++ * ++ * Copyright (C) 2008 Hans Petter Jansson ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * Written by: Hans Petter Jansson ++ */ ++ ++#ifndef __GDM_DOMAIN_CHOOSER_WIDGET_H ++#define __GDM_DOMAIN_CHOOSER_WIDGET_H ++ ++#include ++#include "gdm-chooser-widget.h" ++ ++G_BEGIN_DECLS ++ ++#define GDM_TYPE_DOMAIN_CHOOSER_WIDGET (gdm_domain_chooser_widget_get_type ()) ++#define GDM_DOMAIN_CHOOSER_WIDGET(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_DOMAIN_CHOOSER_WIDGET, GdmDomainChooserWidget)) ++#define GDM_DOMAIN_CHOOSER_WIDGET_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_DOMAIN_CHOOSER_WIDGET, GdmDomainChooserWidgetClass)) ++#define GDM_IS_DOMAIN_CHOOSER_WIDGET(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_DOMAIN_CHOOSER_WIDGET)) ++#define GDM_IS_DOMAIN_CHOOSER_WIDGET_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_DOMAIN_CHOOSER_WIDGET)) ++#define GDM_DOMAIN_CHOOSER_WIDGET_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_DOMAIN_CHOOSER_WIDGET, GdmDomainChooserWidgetClass)) ++ ++typedef struct GdmDomainChooserWidgetPrivate GdmDomainChooserWidgetPrivate; ++ ++typedef struct ++{ ++ GdmChooserWidget parent; ++ GdmDomainChooserWidgetPrivate *priv; ++} GdmDomainChooserWidget; ++ ++typedef struct ++{ ++ GdmChooserWidgetClass parent_class; ++} GdmDomainChooserWidgetClass; ++ ++GType gdm_domain_chooser_widget_get_type (void); ++GtkWidget * gdm_domain_chooser_widget_new (void); ++ ++char * gdm_domain_chooser_widget_get_current_domain_name (GdmDomainChooserWidget *widget); ++void gdm_domain_chooser_widget_set_current_domain_name (GdmDomainChooserWidget *widget, ++ const char *lang_name); ++ ++G_END_DECLS ++ ++#endif /* __GDM_DOMAIN_CHOOSER_WIDGET_H */ +Index: gui/simple-greeter/gdm-domain-provider.c +=================================================================== +--- gui/simple-greeter/gdm-domain-provider.c (revision 0) ++++ gui/simple-greeter/gdm-domain-provider.c (revision 0) +@@ -0,0 +1,478 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- ++ * ++ * Copyright (C) 2008 Hans Petter Jansson ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * Written by: Hans Petter Jansson ++ */ ++ ++#include "config.h" ++ ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++ ++#include ++#include ++#include ++ ++#include "gdm-domain-provider.h" ++ ++#define QUERY_TIMEOUT_S 30 ++#define N_DOMAINS_MAX 128 ++#define BUFFER_READ_MAX 256 ++ ++#define GDM_DOMAIN_PROVIDER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_DOMAIN_PROVIDER, GdmDomainProviderPrivate)) ++ ++typedef enum ++{ ++ STATE_IDLE, ++ STATE_QUERY_SEPARATOR, ++ STATE_QUERY_DOMAINS ++} ++State; ++ ++enum ++{ ++ CHANGED, ++ NUMBER_OF_SIGNALS ++}; ++ ++typedef void (*CmdEndFunc) (GdmDomainProvider *domain_provider, gchar *output, gint status); ++ ++struct GdmDomainProviderPrivate ++{ ++ gchar *separator; ++ GList *domains; ++ ++ State state; ++ guint something_changed : 1; ++ ++ GIOChannel *cmd_channel; ++ GString *cmd_output_string; ++ GPid cmd_pid; ++ CmdEndFunc cmd_end_func; ++ ++ guint callback_id; ++}; ++ ++static void gdm_domain_provider_class_init (GdmDomainProviderClass *klass); ++static void gdm_domain_provider_init (GdmDomainProvider *domain_provider); ++static void gdm_domain_provider_finalize (GObject *object); ++ ++static void get_separator_begin (GdmDomainProvider *domain_provider); ++ ++static GdmDomainProvider *global_domain_provider = NULL; ++static guint signals [NUMBER_OF_SIGNALS] = { 0, }; ++ ++G_DEFINE_TYPE (GdmDomainProvider, gdm_domain_provider, G_TYPE_OBJECT) ++ ++static gint ++compare_strings (const gchar *string_a, const gchar *string_b) ++{ ++ gint result = 0; ++ ++ if (string_a) { ++ if (string_b) { ++ result = g_ascii_strcasecmp (string_a, string_b); ++ } else { ++ result = -1; ++ } ++ } else if (string_b) { ++ result = 1; ++ } ++ ++ return result; ++} ++ ++static gint ++compare_string_lists (GList *list_a, GList *list_b) ++{ ++ gint result = 0; ++ ++ for (;;) { ++ if (list_a == NULL) { ++ if (list_b != NULL) ++ result = 1; ++ break; ++ } else if (list_b == NULL) { ++ result = -1; ++ break; ++ } ++ ++ result = g_ascii_strcasecmp (list_a->data, list_b->data); ++ if (result != 0) ++ break; ++ ++ list_a = g_list_next (list_a); ++ list_b = g_list_next (list_b); ++ } ++ ++ return result; ++} ++ ++static gint ++cmd_cleanup (GdmDomainProvider *domain_provider, gchar **output) ++{ ++ GdmDomainProviderPrivate *priv = domain_provider->priv; ++ gint cmd_status = 0; ++ gchar *cmd_output; ++ ++ /* When idle, callback_id represents the timeout until we run the next ++ * series of queries. Otherwise, it represents the GIOChannel watch. */ ++ ++ if (priv->callback_id) ++ g_source_remove (priv->callback_id); ++ priv->callback_id = 0; ++ priv->cmd_channel = NULL; ++ ++ if (priv->state == STATE_IDLE) ++ return 0; ++ ++ priv->state = STATE_IDLE; ++ ++ waitpid (priv->cmd_pid, &cmd_status, 0); ++ g_spawn_close_pid (priv->cmd_pid); ++ ++ cmd_output = g_string_free (priv->cmd_output_string, FALSE); ++ priv->cmd_output_string = NULL; ++ ++ if (output) ++ *output = cmd_output; ++ else ++ g_free (cmd_output); ++ ++ return WEXITSTATUS (cmd_status); ++} ++ ++static gboolean ++cmd_handle_output (GIOChannel *channel, GIOCondition condition, gpointer data) ++{ ++ GdmDomainProvider *domain_provider = data; ++ GdmDomainProviderPrivate *priv = domain_provider->priv; ++ gchar buf [BUFFER_READ_MAX]; ++ gsize bytes_read; ++ GIOStatus status; ++ ++ g_assert (priv->cmd_output_string != NULL); ++ g_assert (priv->state != STATE_IDLE); ++ ++ status = g_io_channel_read_chars (channel, buf, BUFFER_READ_MAX, &bytes_read, NULL); ++ ++ if (bytes_read < 1) { ++ gchar *cmd_output; ++ gint cmd_status; ++ ++ cmd_status = cmd_cleanup (domain_provider, &cmd_output); ++ ++ if (priv->cmd_end_func) { ++ CmdEndFunc cmd_end_func = priv->cmd_end_func; ++ priv->cmd_end_func = NULL; ++ ++ cmd_end_func (domain_provider, cmd_output, cmd_status); ++ } ++ ++ /* cmd_cleanup () removes the watch for us */ ++ return TRUE; ++ } ++ ++ g_string_append_len (priv->cmd_output_string, buf, bytes_read); ++ return TRUE; ++} ++ ++static gboolean ++async_spawn_and_read (GdmDomainProvider *domain_provider, ++ const gchar * const *spawn_args, ++ CmdEndFunc end_func) ++{ ++ GdmDomainProviderPrivate *priv = domain_provider->priv; ++ gint cmd_stdout_fd; ++ ++ g_assert (priv->state == STATE_IDLE); ++ ++ /* NOTE: The GLib docs don't say if g_spawn_async_with_pipes () can actually cause ++ * spawn_args to be written to. We assume that won't happen. */ ++ ++ if (!g_spawn_async_with_pipes ("/", ++ (gchar **) spawn_args, ++ NULL, ++ 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 */, ++ &priv->cmd_pid, ++ NULL /* &cmd_stdin_fd */, ++ &cmd_stdout_fd, ++ NULL /* &cmd_stderr_fd */, ++ NULL)) ++ return FALSE; ++ ++ priv->cmd_end_func = end_func; ++ priv->cmd_output_string = g_string_new (""); ++ ++ fcntl (cmd_stdout_fd, F_SETFL, O_NONBLOCK); ++ ++ priv->cmd_channel = g_io_channel_unix_new (cmd_stdout_fd); ++ g_io_channel_set_encoding (priv->cmd_channel, NULL, NULL); ++ g_io_channel_set_close_on_unref (priv->cmd_channel, TRUE); ++ priv->callback_id = g_io_add_watch (priv->cmd_channel, ++ G_IO_IN | G_IO_HUP, ++ cmd_handle_output, ++ domain_provider); ++ g_io_channel_unref (priv->cmd_channel); /* Watch holds remaining ref */ ++ ++ return TRUE; ++} ++ ++static gboolean ++idle_end (GdmDomainProvider *domain_provider) ++{ ++ cmd_cleanup (domain_provider, NULL); ++ ++ /* Next state */ ++ ++ get_separator_begin (domain_provider); ++ ++ /* cmd_cleanup () removes the callback for us */ ++ return TRUE; ++} ++ ++static void ++idle_begin (GdmDomainProvider *domain_provider) ++{ ++ GdmDomainProviderPrivate *priv = domain_provider->priv; ++ ++ if (priv->something_changed) { ++ /* Emit changed signal */ ++ ++ g_signal_emit (G_OBJECT (domain_provider), signals [CHANGED], 0); ++ priv->something_changed = FALSE; ++ } ++ ++ g_timeout_add_seconds (QUERY_TIMEOUT_S, (GSourceFunc) idle_end, domain_provider); ++ priv->state = STATE_IDLE; ++} ++ ++static void ++get_domains_end (GdmDomainProvider *domain_provider, gchar *output, gint status) ++{ ++ GdmDomainProviderPrivate *priv = domain_provider->priv; ++ GList *domains = NULL; ++ GList *old_domains; ++ ++ if (status == 0 && output != NULL && *output) { ++ gchar **tokens; ++ gint i; ++ ++ tokens = g_strsplit_set (output, "\n\r", N_DOMAINS_MAX); ++ ++ g_qsort_with_data (tokens, ++ g_strv_length (tokens), ++ sizeof (gchar *), ++ (GCompareDataFunc) g_ascii_strcasecmp, ++ NULL); ++ ++ for (i = 0; tokens [i]; i++) { ++ /* Ensure no blank entries */ ++ if (!strlen (tokens [i])) ++ continue; ++ ++ domains = g_list_prepend (domains, tokens [i]); ++ } ++ ++ g_free (tokens); ++ ++ domains = g_list_reverse (domains); ++ } ++ ++ old_domains = priv->domains; ++ priv->domains = domains; ++ ++ if (compare_string_lists (domains, old_domains) != 0) ++ priv->something_changed = TRUE; ++ ++ g_list_foreach (old_domains, (GFunc) g_free, NULL); ++ g_list_free (old_domains); ++ ++ /* Next state */ ++ ++ idle_begin (domain_provider); ++} ++ ++static void ++get_domains_begin (GdmDomainProvider *domain_provider) ++{ ++ GdmDomainProviderPrivate *priv = domain_provider->priv; ++ const gchar * const cmd_args [] = { "wbinfo", "--all-domains", NULL }; ++ ++ if (async_spawn_and_read (domain_provider, cmd_args, get_domains_end)) ++ priv->state = STATE_QUERY_DOMAINS; ++ else ++ idle_begin (domain_provider); ++} ++ ++static void ++get_separator_end (GdmDomainProvider *domain_provider, gchar *output, gint status) ++{ ++ GdmDomainProviderPrivate *priv = domain_provider->priv; ++ gchar *separator = NULL; ++ gchar *old_separator; ++ ++ if (status == 0 && output != NULL) { ++ gchar *p0; ++ ++ p0 = strchr (output, '\n'); ++ if (!p0) ++ p0 = strchr (output, '\r'); ++ ++ if (p0 && p0 != output) { ++ *p0 = 0; ++ separator = g_strdup (output); ++ } ++ } ++ ++ old_separator = priv->separator; ++ priv->separator = separator; ++ ++ if (compare_strings (separator, old_separator)) ++ priv->something_changed = TRUE; ++ ++ g_free (old_separator); ++ ++ /* Next state */ ++ ++ if (priv->separator) ++ get_domains_begin (domain_provider); ++ else ++ idle_begin (domain_provider); ++} ++ ++static void ++get_separator_begin (GdmDomainProvider *domain_provider) ++{ ++ GdmDomainProviderPrivate *priv = domain_provider->priv; ++ const gchar * const cmd_args [] = { "wbinfo", "--separator", NULL }; ++ ++ if (async_spawn_and_read (domain_provider, cmd_args, get_separator_end)) ++ priv->state = STATE_QUERY_SEPARATOR; ++ else ++ idle_begin (domain_provider); ++} ++ ++static void ++gdm_domain_provider_class_init (GdmDomainProviderClass *klass) ++{ ++ GObjectClass *object_class = G_OBJECT_CLASS (klass); ++ ++ object_class->finalize = gdm_domain_provider_finalize; ++ ++ signals [CHANGED] = g_signal_new ("changed", ++ G_TYPE_FROM_CLASS (object_class), ++ G_SIGNAL_RUN_FIRST, ++ G_STRUCT_OFFSET (GdmDomainProviderClass, changed), ++ NULL, ++ NULL, ++ g_cclosure_marshal_VOID__VOID, ++ G_TYPE_NONE, ++ 0); ++ ++ g_type_class_add_private (klass, sizeof (GdmDomainProviderPrivate)); ++} ++ ++static void ++gdm_domain_provider_init (GdmDomainProvider *domain_provider) ++{ ++ GdmDomainProviderPrivate *priv; ++ ++ priv = domain_provider->priv = GDM_DOMAIN_PROVIDER_GET_PRIVATE (domain_provider); ++ ++ priv->state = STATE_IDLE; ++ ++ /* Start the state machine */ ++ get_separator_begin (domain_provider); ++} ++ ++static void ++gdm_domain_provider_finalize (GObject *object) ++{ ++ GdmDomainProvider *domain_provider; ++ ++ g_return_if_fail (object != NULL); ++ g_return_if_fail (GDM_IS_DOMAIN_PROVIDER (object)); ++ ++ domain_provider = GDM_DOMAIN_PROVIDER (object); ++ ++ /* Stop the state machine */ ++ cmd_cleanup (domain_provider, NULL); ++ ++ G_OBJECT_CLASS (gdm_domain_provider_parent_class)->finalize (object); ++} ++ ++/* --- * ++ * API * ++ * --- */ ++ ++GdmDomainProvider * ++gdm_get_domain_provider (void) ++{ ++ if (!global_domain_provider) ++ global_domain_provider = g_object_new (GDM_TYPE_DOMAIN_PROVIDER, NULL); ++ ++ return global_domain_provider; ++} ++ ++gboolean ++gdm_domain_provider_is_domain_logon_enabled (GdmDomainProvider *domain_provider) ++{ ++ GdmDomainProviderPrivate *priv; ++ ++ g_return_val_if_fail (GDM_IS_DOMAIN_PROVIDER (domain_provider), FALSE); ++ ++ priv = domain_provider->priv; ++ ++ return priv->separator ? TRUE : FALSE; ++} ++ ++const gchar * ++gdm_domain_provider_peek_separator (GdmDomainProvider *domain_provider) ++{ ++ GdmDomainProviderPrivate *priv; ++ ++ g_return_val_if_fail (GDM_IS_DOMAIN_PROVIDER (domain_provider), NULL); ++ ++ priv = domain_provider->priv; ++ ++ return priv->separator; ++} ++ ++GList * ++gdm_domain_provider_peek_domains (GdmDomainProvider *domain_provider) ++{ ++ GdmDomainProviderPrivate *priv; ++ ++ g_return_val_if_fail (GDM_IS_DOMAIN_PROVIDER (domain_provider), NULL); ++ ++ priv = domain_provider->priv; ++ ++ return priv->domains; ++} +Index: gui/simple-greeter/gdm-domain-provider.h +=================================================================== +--- gui/simple-greeter/gdm-domain-provider.h (revision 0) ++++ gui/simple-greeter/gdm-domain-provider.h (revision 0) +@@ -0,0 +1,61 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- ++ * ++ * Copyright (C) 2008 Hans Petter Jansson ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ * Written by: Hans Petter Jansson ++ */ ++ ++#ifndef __GDM_DOMAIN_PROVIDER_H ++#define __GDM_DOMAIN_PROVIDER_H ++ ++#include ++ ++G_BEGIN_DECLS ++ ++#define GDM_TYPE_DOMAIN_PROVIDER (gdm_domain_provider_get_type ()) ++#define GDM_DOMAIN_PROVIDER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_DOMAIN_PROVIDER, GdmDomainProvider)) ++#define GDM_DOMAIN_PROVIDER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_DOMAIN_PROVIDER, GdmDomainProviderClass)) ++#define GDM_IS_DOMAIN_PROVIDER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_DOMAIN_PROVIDER)) ++#define GDM_IS_DOMAIN_PROVIDER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_DOMAIN_PROVIDER)) ++#define GDM_DOMAIN_PROVIDER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_DOMAIN_PROVIDER, GdmDomainProviderClass)) ++ ++typedef struct GdmDomainProviderPrivate GdmDomainProviderPrivate; ++ ++typedef struct ++{ ++ GObject parent; ++ GdmDomainProviderPrivate *priv; ++} GdmDomainProvider; ++ ++typedef struct ++{ ++ GObjectClass parent_class; ++ ++ void (* changed) (GdmDomainProvider *domain_provider); ++} GdmDomainProviderClass; ++ ++GType gdm_domain_provider_get_type (void); ++ ++GdmDomainProvider * gdm_get_domain_provider (void); ++ ++gboolean gdm_domain_provider_is_domain_logon_enabled (GdmDomainProvider *domain_provider); ++const gchar * gdm_domain_provider_peek_separator (GdmDomainProvider *domain_provider); ++GList * gdm_domain_provider_peek_domains (GdmDomainProvider *domain_provider); ++ ++G_END_DECLS ++ ++#endif /* __GDM_DOMAIN_PROVIDER_H */ +Index: gui/simple-greeter/gdm-greeter-panel.c +=================================================================== +--- gui/simple-greeter/gdm-greeter-panel.c (revision 6548) ++++ gui/simple-greeter/gdm-greeter-panel.c (working copy) +@@ -40,6 +40,7 @@ + #include "gdm-language-option-widget.h" + #include "gdm-layout-option-widget.h" + #include "gdm-session-option-widget.h" ++#include "gdm-domain-option-widget.h" + #include "gdm-profile.h" + + #include "na-tray.h" +@@ -58,6 +59,7 @@ struct GdmGreeterPanelPrivate + GtkWidget *language_option_widget; + GtkWidget *layout_option_widget; + GtkWidget *session_option_widget; ++ GtkWidget *domain_option_widget; + + char *default_session_name; + char *default_language_name; +@@ -72,6 +74,7 @@ enum { + LANGUAGE_SELECTED, + LAYOUT_SELECTED, + SESSION_SELECTED, ++ DOMAIN_SELECTED, + NUMBER_OF_SIGNALS + }; + +@@ -451,6 +454,17 @@ gdm_greeter_panel_class_init (GdmGreeter + G_TYPE_NONE, + 1, G_TYPE_STRING); + ++ signals[DOMAIN_SELECTED] = ++ g_signal_new ("domain-selected", ++ G_TYPE_FROM_CLASS (object_class), ++ G_SIGNAL_RUN_LAST, ++ G_STRUCT_OFFSET (GdmGreeterPanelClass, domain_selected), ++ NULL, ++ NULL, ++ g_cclosure_marshal_VOID__STRING, ++ G_TYPE_NONE, ++ 1, G_TYPE_STRING); ++ + g_object_class_install_property (object_class, + PROP_MONITOR, + g_param_spec_int ("monitor", +@@ -521,6 +535,24 @@ on_session_activated (GdmSessionOptionWi + } + + static void ++on_domain_activated (GdmDomainOptionWidget *widget, ++ GdmGreeterPanel *panel) ++{ ++ ++ char *domain; ++ ++ domain = gdm_domain_option_widget_get_current_domain_name (GDM_DOMAIN_OPTION_WIDGET (panel->priv->domain_option_widget)); ++ ++ if (domain == NULL) { ++ return; ++ } ++ ++ g_signal_emit (panel, signals[DOMAIN_SELECTED], 0, domain); ++ ++ g_free (domain); ++} ++ ++static void + gdm_greeter_panel_init (GdmGreeterPanel *panel) + { + NaTray *tray; +@@ -581,6 +613,12 @@ gdm_greeter_panel_init (GdmGreeterPanel + G_CALLBACK (on_session_activated), panel); + gtk_box_pack_start (GTK_BOX (panel->priv->option_hbox), panel->priv->session_option_widget, FALSE, FALSE, 6); + ++ panel->priv->domain_option_widget = gdm_domain_option_widget_new (); ++ g_signal_connect (G_OBJECT (panel->priv->domain_option_widget), ++ "domain-activated", ++ G_CALLBACK (on_domain_activated), panel); ++ gtk_box_pack_start (GTK_BOX (panel->priv->option_hbox), panel->priv->domain_option_widget, FALSE, FALSE, 6); ++ + spacer = gtk_label_new (""); + gtk_box_pack_start (GTK_BOX (panel->priv->option_hbox), spacer, TRUE, TRUE, 6); + gtk_widget_show (spacer); +@@ -643,6 +681,7 @@ gdm_greeter_panel_show_user_options (Gdm + gtk_widget_show (panel->priv->session_option_widget); + gtk_widget_show (panel->priv->language_option_widget); + gtk_widget_show (panel->priv->layout_option_widget); ++ gtk_widget_hide (panel->priv->domain_option_widget); + } + + void +@@ -651,6 +690,7 @@ gdm_greeter_panel_hide_user_options (Gdm + gtk_widget_hide (panel->priv->session_option_widget); + gtk_widget_hide (panel->priv->language_option_widget); + gtk_widget_hide (panel->priv->layout_option_widget); ++ gtk_widget_show (panel->priv->domain_option_widget); + + g_debug ("GdmGreeterPanel: activating default layout"); + gdm_layout_activate (NULL); +@@ -730,3 +770,20 @@ gdm_greeter_panel_set_default_session_na + gdm_option_widget_set_default_item (GDM_OPTION_WIDGET (panel->priv->session_option_widget), + session_name); + } ++ ++void ++gdm_greeter_panel_set_default_domain_name (GdmGreeterPanel *panel, ++ const char *domain_name) ++{ ++ g_return_if_fail (GDM_IS_GREETER_PANEL (panel)); ++ ++ if (domain_name != NULL && ++ !gdm_option_widget_lookup_item (GDM_OPTION_WIDGET (panel->priv->domain_option_widget), ++ domain_name, NULL, NULL, NULL)) { ++ g_warning ("Default domain is not available"); ++ return; ++ } ++ ++ gdm_option_widget_set_default_item (GDM_OPTION_WIDGET (panel->priv->domain_option_widget), ++ domain_name); ++} +Index: gui/simple-greeter/gdm-greeter-panel.h +=================================================================== +--- gui/simple-greeter/gdm-greeter-panel.h (revision 6548) ++++ gui/simple-greeter/gdm-greeter-panel.h (working copy) +@@ -53,6 +53,9 @@ typedef struct + + void (* session_selected) (GdmGreeterPanel *panel, + const char *text); ++ ++ void (* domain_selected) (GdmGreeterPanel *panel, ++ const char *text); + } GdmGreeterPanelClass; + + GType gdm_greeter_panel_get_type (void); +@@ -70,6 +73,8 @@ void gdm_greeter_panel + const char *layout_name); + void gdm_greeter_panel_set_default_session_name (GdmGreeterPanel *panel, + const char *session_name); ++void gdm_greeter_panel_set_default_domain_name (GdmGreeterPanel *panel, ++ const char *domain_name); + G_END_DECLS + + #endif /* __GDM_GREETER_PANEL_H */ +Index: gui/simple-greeter/gdm-greeter-session.c +=================================================================== +--- gui/simple-greeter/gdm-greeter-session.c (revision 6548) ++++ gui/simple-greeter/gdm-greeter-session.c (working copy) +@@ -38,6 +38,8 @@ + #include "gdm-greeter-panel.h" + #include "gdm-greeter-login-window.h" + ++#include "gdm-domain-provider.h" ++ + #include "gdm-profile.h" + + #define GDM_GREETER_SESSION_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_GREETER_SESSION, GdmGreeterSessionPrivate)) +@@ -48,6 +50,9 @@ struct GdmGreeterSessionPrivate + + GtkWidget *login_window; + GtkWidget *panel; ++ ++ char *user; ++ char *domain; + }; + + enum { +@@ -62,6 +67,33 @@ G_DEFINE_TYPE (GdmGreeterSession, gdm_gr + + static gpointer session_object = NULL; + ++static char * ++maybe_prepend_domain_to_user (GdmGreeterSession *session, const char *user) ++{ ++ char *domain_and_user = NULL; ++ const char *separator; ++ ++ separator = gdm_domain_provider_peek_separator (gdm_get_domain_provider ()); ++ ++ if (user) { ++ if (separator) { ++ /* The user string may already contain a domain, so we look for the ++ * separator and prepend ours only if it's not already there. */ ++ ++ if (session->priv->domain && !strstr (user, separator)) ++ domain_and_user = g_strconcat (session->priv->domain, ++ separator, ++ user, ++ NULL); ++ } ++ ++ if (!domain_and_user) ++ domain_and_user = g_strdup (user); ++ } ++ ++ return domain_and_user; ++} ++ + static void + on_info (GdmGreeterClient *client, + const char *text, +@@ -140,6 +172,16 @@ on_default_session_name_changed (GdmGree + } + + static void ++on_selected_domain_changed (GdmGreeterClient *client, ++ const char *text, ++ GdmGreeterSession *session) ++{ ++ g_debug ("GdmGreeterSession: selected domain changed: %s", text); ++ gdm_greeter_panel_set_default_domain_name (GDM_GREETER_PANEL (session->priv->panel), ++ text); ++} ++ ++static void + on_timed_login_requested (GdmGreeterClient *client, + const char *text, + int delay, +@@ -198,8 +240,14 @@ on_begin_verification_for_user (GdmGreet + const char *username, + GdmGreeterSession *session) + { ++ char *domain_and_user; ++ ++ domain_and_user = maybe_prepend_domain_to_user (session, username); ++ + gdm_greeter_client_call_begin_verification_for_user (session->priv->client, +- username); ++ domain_and_user); ++ ++ g_free (domain_and_user); + } + + static void +@@ -236,13 +284,46 @@ on_select_layout (GdmGreeterSession + } + + static void ++on_select_domain (GdmGreeterSession *session, ++ const char *text) ++{ ++ char *domain_and_user; ++ ++ g_free (session->priv->domain); ++ session->priv->domain = NULL; ++ ++ if (text && strcmp (text, "__local") && strcmp (text, "__other")) ++ session->priv->domain = g_strdup (text); ++ ++ domain_and_user = maybe_prepend_domain_to_user (session, session->priv->user); ++ ++ gdm_greeter_client_call_select_user (session->priv->client, ++ domain_and_user); ++ ++ g_free (domain_and_user); ++} ++ ++static void + on_select_user (GdmGreeterLoginWindow *login_window, + const char *text, + GdmGreeterSession *session) + { ++ char *domain_and_user; ++ + gdm_greeter_panel_show_user_options (GDM_GREETER_PANEL (session->priv->panel)); ++ ++ g_free (session->priv->user); ++ session->priv->user = NULL; ++ ++ if (text) ++ session->priv->user = g_strdup (text); ++ ++ domain_and_user = maybe_prepend_domain_to_user (session, text); ++ + gdm_greeter_client_call_select_user (session->priv->client, +- text); ++ domain_and_user); ++ ++ g_free (domain_and_user); + } + + static void +@@ -300,6 +381,11 @@ toggle_panel (GdmGreeterSession *session + G_CALLBACK (on_select_session), + session); + ++ g_signal_connect_swapped (session->priv->panel, ++ "domain-selected", ++ G_CALLBACK (on_select_domain), ++ session); ++ + gtk_widget_show (session->priv->panel); + } else { + gtk_widget_destroy (session->priv->panel); +@@ -522,6 +608,10 @@ gdm_greeter_session_init (GdmGreeterSess + G_CALLBACK (on_selected_user_changed), + session); + g_signal_connect (session->priv->client, ++ "selected-domain-changed", ++ G_CALLBACK (on_selected_domain_changed), ++ session); ++ g_signal_connect (session->priv->client, + "default-language-name-changed", + G_CALLBACK (on_default_language_name_changed), + session); +@@ -563,6 +653,9 @@ gdm_greeter_session_finalize (GObject *o + + g_return_if_fail (greeter_session->priv != NULL); + ++ g_free (greeter_session->priv->user); ++ g_free (greeter_session->priv->domain); ++ + G_OBJECT_CLASS (gdm_greeter_session_parent_class)->finalize (object); + } + +Index: gui/simple-greeter/gdm-chooser-widget.c +=================================================================== +--- gui/simple-greeter/gdm-chooser-widget.c (revision 6548) ++++ gui/simple-greeter/gdm-chooser-widget.c (working copy) +@@ -2105,6 +2105,20 @@ gdm_chooser_widget_remove_item (GdmChoos + move_cursor_to_top (widget); + } + ++void ++gdm_chooser_widget_remove_all_items (GdmChooserWidget *widget) ++{ ++ widget->priv->number_of_rows_with_images = 0; ++ widget->priv->number_of_rows_with_status = 0; ++ widget->priv->number_of_separated_rows = 0; ++ widget->priv->number_of_normal_rows = 0; ++ ++ gtk_list_store_clear (widget->priv->list_store); ++ ++ update_separator_visibility (widget); ++ move_cursor_to_top (widget); ++} ++ + gboolean + gdm_chooser_widget_lookup_item (GdmChooserWidget *widget, + const char *id, +Index: gui/simple-greeter/Makefile.am +=================================================================== +--- gui/simple-greeter/Makefile.am (revision 6548) ++++ gui/simple-greeter/Makefile.am (working copy) +@@ -136,6 +136,14 @@ test_greeter_panel_SOURCES = \ + gdm-sessions.c \ + gdm-session-option-widget.h \ + gdm-session-option-widget.c \ ++ gdm-domain-chooser-dialog.h \ ++ gdm-domain-chooser-dialog.c \ ++ gdm-domain-chooser-widget.h \ ++ gdm-domain-chooser-widget.c \ ++ gdm-domain-option-widget.h \ ++ gdm-domain-option-widget.c \ ++ gdm-domain-provider.h \ ++ gdm-domain-provider.c \ + $(NULL) + + test_greeter_panel_LDADD = \ +@@ -313,12 +321,20 @@ gdm_simple_greeter_SOURCES = \ + gdm-language-chooser-dialog.c \ + gdm-language-option-widget.h \ + gdm-language-option-widget.c \ ++ gdm-domain-chooser-dialog.h \ ++ gdm-domain-chooser-dialog.c \ ++ gdm-domain-chooser-widget.h \ ++ gdm-domain-chooser-widget.c \ ++ gdm-domain-option-widget.h \ ++ gdm-domain-option-widget.c \ + gdm-sessions.h \ + gdm-sessions.c \ + gdm-session-option-widget.h \ + gdm-session-option-widget.c \ + gdm-user-chooser-widget.h \ + gdm-user-chooser-widget.c \ ++ gdm-domain-provider.h \ ++ gdm-domain-provider.c \ + $(NULL) + + gdm_simple_greeter_LDADD = \ +Index: gui/simple-greeter/gdm-chooser-widget.h +=================================================================== +--- gui/simple-greeter/gdm-chooser-widget.h (revision 6548) ++++ gui/simple-greeter/gdm-chooser-widget.h (working copy) +@@ -96,6 +96,8 @@ void gdm_chooser_widget_update_i + void gdm_chooser_widget_remove_item (GdmChooserWidget *widget, + const char *id); + ++void gdm_chooser_widget_remove_all_items (GdmChooserWidget *widget); ++ + gboolean gdm_chooser_widget_lookup_item (GdmChooserWidget *widget, + const char *id, + GdkPixbuf **image, diff --git a/gdm.changes b/gdm.changes index 354dd36..9c7a199 100644 --- a/gdm.changes +++ b/gdm.changes @@ -1,3 +1,14 @@ +------------------------------------------------------------------- +Mon Oct 6 15:45:07 CEST 2008 - sbrabec@suse.cz + +- Conflict with other branding providers (FATE#304881). + +------------------------------------------------------------------- +Fri Sep 26 01:52:16 CDT 2008 - hpj@novell.com + +- Add gdm-domain-logon.patch, which implements an Active Directory + domain logon selector using wbinfo. + ------------------------------------------------------------------- Sat Sep 20 14:46:06 CEST 2008 - vuntz@novell.com diff --git a/gdm.spec b/gdm.spec index 0a28810..a9952ba 100644 --- a/gdm.spec +++ b/gdm.spec @@ -56,7 +56,7 @@ PreReq: %insserv_prereq License: GPL v2 or later Group: System/GUI/GNOME Version: 2.23.92 -Release: 5 +Release: 6 Summary: The GNOME 2.x Display Manager Source: %{name}-%{version}.tar.bz2 Source1: gdm.pamd @@ -73,6 +73,7 @@ Patch5: gdm-2.23.92-gsd-path.patch Patch6: gdm-desktop-session-env-pam.patch # PATCH-FIX-OPENSUSE gdm-suse-xsession.patch vuntz@novell.com -- Use the /etc/X11/xdm/* scripts Patch7: gdm-suse-xsession.patch +Patch8: gdm-domain-logon.patch Patch28: gdm-X_SERVER.patch # PATCH-SUSE: enable SELinux Patch60: gdm-selinux.patch @@ -106,6 +107,7 @@ License: GPL v2 or later Summary: The GNOME 2.x Display Manager Group: System/GUI/GNOME Provides: %{name}-branding = %{version} +Conflicts: otherproviders(%{name}-branding) Supplements: packageand(branding-upstream:%{name}) #BRAND: Provide two equal files - /usr/share/gdm/defaults.conf and #BRAND: factory-defaults.conf with default configuration of gdm. @@ -136,6 +138,7 @@ Authors: %patch5 -p1 %patch6 -p1 %patch7 -p1 +%patch8 %patch28 %patch60 @@ -243,6 +246,11 @@ fi %files lang -f %{name}.lang %changelog +* Mon Oct 06 2008 sbrabec@suse.cz +- Conflict with other branding providers (FATE#304881). +* Fri Sep 26 2008 hpj@novell.com +- Add gdm-domain-logon.patch, which implements an Active Directory + domain logon selector using wbinfo. * Sat Sep 20 2008 vuntz@novell.com - Add gdm-suse-xsession.patch, which is similar to the gdm-xdm-sessions.patch we have with GDM <= 2.20: it makes GDM