diff --git a/gui/simple-greeter/Makefile.am b/gui/simple-greeter/Makefile.am index bba7a4a..d652961 100644 --- a/gui/simple-greeter/Makefile.am +++ b/gui/simple-greeter/Makefile.am @@ -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 = \ diff --git a/gui/simple-greeter/gdm-chooser-widget.c b/gui/simple-greeter/gdm-chooser-widget.c index f0298c6..4894eee 100644 --- a/gui/simple-greeter/gdm-chooser-widget.c +++ b/gui/simple-greeter/gdm-chooser-widget.c @@ -2105,6 +2105,20 @@ gdm_chooser_widget_remove_item (GdmChooserWidget *widget, 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, diff --git a/gui/simple-greeter/gdm-chooser-widget.h b/gui/simple-greeter/gdm-chooser-widget.h index b73d1bb..b70016c 100644 --- a/gui/simple-greeter/gdm-chooser-widget.h +++ b/gui/simple-greeter/gdm-chooser-widget.h @@ -96,6 +96,8 @@ void gdm_chooser_widget_update_item (GdmChooserWidget * 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/gui/simple-greeter/gdm-domain-chooser-dialog.c b/gui/simple-greeter/gdm-domain-chooser-dialog.c new file mode 100644 index 0000000..f577b65 --- /dev/null +++ b/gui/simple-greeter/gdm-domain-chooser-dialog.c @@ -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); +} diff --git a/gui/simple-greeter/gdm-domain-chooser-dialog.h b/gui/simple-greeter/gdm-domain-chooser-dialog.h new file mode 100644 index 0000000..f11f183 --- /dev/null +++ b/gui/simple-greeter/gdm-domain-chooser-dialog.h @@ -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 */ diff --git a/gui/simple-greeter/gdm-domain-chooser-widget.c b/gui/simple-greeter/gdm-domain-chooser-widget.c new file mode 100644 index 0000000..1d8b113 --- /dev/null +++ b/gui/simple-greeter/gdm-domain-chooser-widget.c @@ -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); +} diff --git a/gui/simple-greeter/gdm-domain-chooser-widget.h b/gui/simple-greeter/gdm-domain-chooser-widget.h new file mode 100644 index 0000000..4ba9d18 --- /dev/null +++ b/gui/simple-greeter/gdm-domain-chooser-widget.h @@ -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 */ diff --git a/gui/simple-greeter/gdm-domain-option-widget.c b/gui/simple-greeter/gdm-domain-option-widget.c new file mode 100644 index 0000000..31e76e2 --- /dev/null +++ b/gui/simple-greeter/gdm-domain-option-widget.c @@ -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", + (GdmRecentOptionLookupItemFunc) 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); +} diff --git a/gui/simple-greeter/gdm-domain-option-widget.h b/gui/simple-greeter/gdm-domain-option-widget.h new file mode 100644 index 0000000..4913ede --- /dev/null +++ b/gui/simple-greeter/gdm-domain-option-widget.h @@ -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 */ diff --git a/gui/simple-greeter/gdm-domain-provider.c b/gui/simple-greeter/gdm-domain-provider.c new file mode 100644 index 0000000..2924291 --- /dev/null +++ b/gui/simple-greeter/gdm-domain-provider.c @@ -0,0 +1,536 @@ +/* -*- 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, /* Next state: STATE_QUERY_SEPARATOR */ + STATE_QUERY_SEPARATOR, /* Next state: STATE_QUERY_OWN_DOMAIN or STATE_IDLE */ + STATE_QUERY_OWN_DOMAIN, /* Next state: STATE_QUERY_TRUSTED_DOMAINS or STATE_IDLE */ + STATE_QUERY_TRUSTED_DOMAINS, /* Next state: STATE_IDLE */ +} +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; + + gchar *domains_output; + + 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; + + g_free (priv->domains_output); + priv->domains_output = NULL; + + if (priv->something_changed) { + /* Emit changed signal */ + + g_signal_emit (G_OBJECT (domain_provider), signals [CHANGED], 0); + priv->something_changed = FALSE; + } + + priv->callback_id = g_timeout_add_seconds (QUERY_TIMEOUT_S, (GSourceFunc) idle_end, domain_provider); + priv->state = STATE_IDLE; +} + +static void +get_trusted_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; + + if (priv->domains_output) { + output = g_realloc (output, strlen (output) + strlen (priv->domains_output) + 1); + strcat (output, priv->domains_output); + } + + 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; + + /* Ensure no duplicates */ + if (i > 0 && !g_ascii_strcasecmp (tokens [i], tokens [i - 1])) + continue; + + /* Ensure no builtin */ + if (!g_ascii_strcasecmp (tokens [i], "BUILTIN")) + continue; + + /* Ensure no local host name */ + if (!g_ascii_strcasecmp (tokens [i], g_get_host_name ())) + continue; + + domains = g_list_prepend (domains, tokens [i]); + } + + g_free (tokens); + + domains = g_list_reverse (domains); + } + + g_free (output); + + 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_trusted_domains_begin (GdmDomainProvider *domain_provider) +{ + GdmDomainProviderPrivate *priv = domain_provider->priv; + const gchar * const cmd_args [] = { "wbinfo", "--trusted-domains", NULL }; + + if (async_spawn_and_read (domain_provider, cmd_args, get_trusted_domains_end)) + priv->state = STATE_QUERY_TRUSTED_DOMAINS; + else + idle_begin (domain_provider); +} + +static void +get_own_domain_end (GdmDomainProvider *domain_provider, gchar *output, gint status) +{ + GdmDomainProviderPrivate *priv = domain_provider->priv; + + if (status == 0 && output != NULL && *output) + priv->domains_output = output; + + /* Next state */ + + get_trusted_domains_begin (domain_provider); +} + +static void +get_own_domain_begin (GdmDomainProvider *domain_provider) +{ + GdmDomainProviderPrivate *priv = domain_provider->priv; + const gchar * const cmd_args [] = { "wbinfo", "--own-domain", NULL }; + + if (async_spawn_and_read (domain_provider, cmd_args, get_own_domain_end)) + priv->state = STATE_QUERY_OWN_DOMAIN; + 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, *p1; + + p0 = strchr (output, '\n'); + p1 = strchr (output, '\r'); + if (!p0 || (p1 && p1 < p0)) + p0 = p1; + + if (p0 && p0 != output) { + *p0 = 0; + separator = output; + } else { + g_free (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_own_domain_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; + GdmDomainProviderPrivate *priv; + + g_return_if_fail (object != NULL); + g_return_if_fail (GDM_IS_DOMAIN_PROVIDER (object)); + + domain_provider = GDM_DOMAIN_PROVIDER (object); + priv = domain_provider->priv; + + /* Stop the state machine */ + cmd_cleanup (domain_provider, NULL); + + g_free (priv->domains_output); + priv->domains_output = 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; +} diff --git a/gui/simple-greeter/gdm-domain-provider.h b/gui/simple-greeter/gdm-domain-provider.h new file mode 100644 index 0000000..6a318ff --- /dev/null +++ b/gui/simple-greeter/gdm-domain-provider.h @@ -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 */ diff --git a/gui/simple-greeter/gdm-greeter-panel.c b/gui/simple-greeter/gdm-greeter-panel.c index 50478c5..825f0c5 100644 --- a/gui/simple-greeter/gdm-greeter-panel.c +++ b/gui/simple-greeter/gdm-greeter-panel.c @@ -40,6 +40,7 @@ #include "gdm-layout-option-widget.h" #include "gdm-session-option-widget.h" #include "gdm-timer.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; GdmTimer *animation_timer; double progress; @@ -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 (GdmGreeterPanelClass *klass) 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 (GdmSessionOptionWidget *widget, } 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 *panel) 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 (GdmGreeterPanel *panel) 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_show (panel->priv->domain_option_widget); } void @@ -651,18 +690,26 @@ gdm_greeter_panel_hide_user_options (GdmGreeterPanel *panel) 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); } void +gdm_greeter_panel_set_domain_enabled (GdmGreeterPanel *panel, gboolean enabled) +{ + gtk_widget_set_sensitive (panel->priv->domain_option_widget, enabled); +} + +void gdm_greeter_panel_reset (GdmGreeterPanel *panel) { gdm_greeter_panel_set_default_language_name (panel, NULL); gdm_greeter_panel_set_default_layout_name (panel, NULL); gdm_greeter_panel_set_default_session_name (panel, NULL); gdm_greeter_panel_hide_user_options (panel); + gdm_greeter_panel_set_domain_enabled (panel, TRUE); } void @@ -730,3 +777,20 @@ gdm_greeter_panel_set_default_session_name (GdmGreeterPanel *panel, 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); +} diff --git a/gui/simple-greeter/gdm-greeter-panel.h b/gui/simple-greeter/gdm-greeter-panel.h index 07cca3f..6079569 100644 --- a/gui/simple-greeter/gdm-greeter-panel.h +++ b/gui/simple-greeter/gdm-greeter-panel.h @@ -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); @@ -64,12 +67,16 @@ void gdm_greeter_panel_show_user_options (GdmGree void gdm_greeter_panel_hide_user_options (GdmGreeterPanel *panel); void gdm_greeter_panel_reset (GdmGreeterPanel *panel); +void gdm_greeter_panel_set_domain_enabled (GdmGreeterPanel *panel, gboolean enabled); + void gdm_greeter_panel_set_default_language_name (GdmGreeterPanel *panel, const char *language_name); void gdm_greeter_panel_set_default_layout_name (GdmGreeterPanel *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 */ diff --git a/gui/simple-greeter/gdm-greeter-session.c b/gui/simple-greeter/gdm-greeter-session.c index 83375b2..251e7c8 100644 --- a/gui/simple-greeter/gdm-greeter-session.c +++ b/gui/simple-greeter/gdm-greeter-session.c @@ -38,6 +38,8 @@ #include "gdm-greeter-panel.h" #include "gdm-greeter-login-window.h" +#include "gdm-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,11 @@ struct GdmGreeterSessionPrivate GtkWidget *login_window; GtkWidget *panel; + + char *user; + char *domain; + + gint n_info_queries; }; enum { @@ -62,6 +69,33 @@ G_DEFINE_TYPE (GdmGreeterSession, gdm_greeter_session, G_TYPE_OBJECT) 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, @@ -99,6 +133,10 @@ on_reset (GdmGreeterClient *client, gdm_greeter_panel_reset (GDM_GREETER_PANEL (session->priv->panel)); gdm_greeter_login_window_reset (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window)); + + session->priv->n_info_queries = 0; + if (session->priv->panel) + gdm_greeter_panel_set_domain_enabled (GDM_GREETER_PANEL (session->priv->panel), TRUE); } static void @@ -174,6 +212,9 @@ on_secret_info_query (GdmGreeterClient *client, { g_debug ("GdmGreeterSession: Secret info query: %s", text); + if (session->priv->panel) + gdm_greeter_panel_set_domain_enabled (GDM_GREETER_PANEL (session->priv->panel), FALSE); + gdm_greeter_login_window_secret_info_query (GDM_GREETER_LOGIN_WINDOW (session->priv->login_window), text); } @@ -198,8 +239,14 @@ on_begin_verification_for_user (GdmGreeterLoginWindow *login_window, 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 @@ -207,8 +254,21 @@ on_query_answer (GdmGreeterLoginWindow *login_window, const char *text, GdmGreeterSession *session) { + gchar *temp; + + if (session->priv->n_info_queries == 0) + temp = maybe_prepend_domain_to_user (session, text); + else + temp = g_strdup (text); + + if (session->priv->panel) + gdm_greeter_panel_set_domain_enabled (GDM_GREETER_PANEL (session->priv->panel), FALSE); + gdm_greeter_client_call_answer_query (session->priv->client, - text); + temp); + + g_free (temp); + session->priv->n_info_queries++; } static void @@ -236,13 +296,39 @@ on_select_layout (GdmGreeterSession *session, } 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); +} + +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 @@ -251,6 +337,10 @@ on_cancelled (GdmGreeterLoginWindow *login_window, { gdm_greeter_panel_hide_user_options (GDM_GREETER_PANEL (session->priv->panel)); gdm_greeter_client_call_cancel (session->priv->client); + + session->priv->n_info_queries = 0; + if (session->priv->panel) + gdm_greeter_panel_set_domain_enabled (GDM_GREETER_PANEL (session->priv->panel), TRUE); } static void @@ -300,6 +390,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); @@ -542,6 +637,8 @@ gdm_greeter_session_init (GdmGreeterSession *session) G_CALLBACK (on_user_authorized), session); + session->priv->n_info_queries = 0; + /* We want to listen for panel mnemonics even if the * login window is focused, so we intercept them here. */ @@ -563,6 +660,9 @@ gdm_greeter_session_finalize (GObject *object) 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); } diff --git a/gui/simple-greeter/gdm-simple-greeter.schemas.in b/gui/simple-greeter/gdm-simple-greeter.schemas.in index 55b441f..450cb22 100644 --- a/gui/simple-greeter/gdm-simple-greeter.schemas.in +++ b/gui/simple-greeter/gdm-simple-greeter.schemas.in @@ -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 --- gdm-2.24.0/po/POTFILES.in +++ gdm-2.24.0/po/POTFILES.in @@ -63,6 +63,9 @@ gui/simple-greeter/gdm-cell-renderer-timer.c gui/simple-greeter/gdm-chooser-widget.c gui/simple-greeter/gdm-clock-widget.c +gui/simple-greeter/gdm-domain-chooser-dialog.c +gui/simple-greeter/gdm-domain-chooser-widget.c +gui/simple-greeter/gdm-domain-option-widget.c gui/simple-greeter/gdm-greeter-login-window.c gui/simple-greeter/gdm-greeter-login-window.c gui/simple-greeter/gdm-greeter-login-window.glade