diff --git a/2-new-chooser-widget.patch b/2-new-chooser-widget.patch new file mode 100644 index 0000000..0f175f1 --- /dev/null +++ b/2-new-chooser-widget.patch @@ -0,0 +1,1739 @@ +From 675a2a355ef15825b5998adc89a69d0958a0e2c0 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Thu, 13 Dec 2007 10:06:26 -0500 +Subject: [PATCH] Add new chooser widget + Since it takes a lot of code to deal with the whole model/view + split of a tree view, it's probably better to abstract that + work out into one unified "chooser" widget. + +--- + gui/simple-greeter/gdm-chooser-widget.c | 1607 +++++++++++++++++++++++++++++++ + gui/simple-greeter/gdm-chooser-widget.h | 102 ++ + 2 files changed, 1709 insertions(+), 0 deletions(-) + create mode 100644 gui/simple-greeter/gdm-chooser-widget.c + create mode 100644 gui/simple-greeter/gdm-chooser-widget.h + +diff --git a/gui/simple-greeter/gdm-chooser-widget.c b/gui/simple-greeter/gdm-chooser-widget.c +new file mode 100644 +index 0000000..64186a2 +--- /dev/null ++++ b/gui/simple-greeter/gdm-chooser-widget.c +@@ -0,0 +1,1607 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- ++ * ++ * Copyright (C) 2007 Ray Strode ++ * Copyright (C) 2007 William Jon McCann ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ */ ++ ++#include "config.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include "gdm-chooser-widget.h" ++ ++#define GDM_CHOOSER_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_CHOOSER_WIDGET, GdmChooserWidgetPrivate)) ++ ++#ifndef GDM_CHOOSER_WIDGET_DEFAULT_ICON_SIZE ++#define GDM_CHOOSER_WIDGET_DEFAULT_ICON_SIZE 64 ++#endif ++ ++typedef enum { ++ GDM_CHOOSER_WIDGET_STATE_GROWN = 0, ++ GDM_CHOOSER_WIDGET_STATE_GROWING, ++ GDM_CHOOSER_WIDGET_STATE_SHRINKING, ++ GDM_CHOOSER_WIDGET_STATE_SHRUNK, ++} GdmChooserWidgetState; ++ ++struct GdmChooserWidgetPrivate ++{ ++ GtkWidget *frame; ++ GtkWidget *frame_alignment; ++ GtkWidget *scrolled_window; ++ ++ GtkWidget *items_view; ++ GtkListStore *list_store; ++ ++ GtkTreeModelFilter *model_filter; ++ GtkTreeModelSort *model_sorter; ++ ++ GdkPixbuf *is_in_use_pixbuf; ++ ++ GtkTreeRowReference *active_row; ++ GtkTreeRowReference *separator_row; ++ GtkTreeRowReference *top_edge_row; /* Only around for shrink */ ++ GtkTreeRowReference *bottom_edge_row; /* animations */ ++ ++ GtkTreeViewColumn *is_in_use_column; ++ GtkTreeViewColumn *image_column; ++ ++ char *inactive_text; ++ char *active_text; ++ char *in_use_message; ++ ++ gint number_of_normal_rows; ++ gint number_of_separated_rows; ++ gint number_of_in_use_rows; ++ gint number_of_rows_with_images; ++ ++ guint update_idle_id; ++ guint animation_timeout_id; ++ ++ guint32 should_hide_inactive_items : 1; ++ ++ GdmChooserWidgetPosition separator_position; ++ GdmChooserWidgetState state; ++ ++}; ++ ++enum { ++ PROP_0, ++ PROP_INACTIVE_TEXT, ++ PROP_ACTIVE_TEXT ++}; ++ ++enum { ++ ACTIVATED = 0, ++ DEACTIVATED, ++ NUMBER_OF_SIGNALS ++}; ++ ++static guint signals[NUMBER_OF_SIGNALS]; ++ ++static void gdm_chooser_widget_class_init (GdmChooserWidgetClass *klass); ++static void gdm_chooser_widget_init (GdmChooserWidget *chooser_widget); ++static void gdm_chooser_widget_finalize (GObject *object); ++ ++G_DEFINE_TYPE (GdmChooserWidget, gdm_chooser_widget, GTK_TYPE_ALIGNMENT) ++enum { ++ CHOOSER_IMAGE_COLUMN = 0, ++ CHOOSER_NAME_COLUMN, ++ CHOOSER_COMMENT_COLUMN, ++ CHOOSER_ITEM_IS_IN_USE_COLUMN, ++ CHOOSER_ITEM_IS_SEPARATED_COLUMN, ++ CHOOSER_ITEM_IS_VISIBLE_COLUMN, ++ CHOOSER_ID_COLUMN, ++ NUMBER_OF_CHOOSER_COLUMNS ++}; ++ ++static gboolean ++find_item (GdmChooserWidget *widget, ++ const char *id, ++ GtkTreeIter *iter) ++{ ++ GtkTreeModel *model; ++ gboolean found_item; ++ ++ g_assert (GDM_IS_CHOOSER_WIDGET (widget)); ++ g_assert (id != NULL); ++ ++ found_item = FALSE; ++ model = GTK_TREE_MODEL (widget->priv->list_store); ++ ++ if (!gtk_tree_model_get_iter_first (model, iter)) { ++ return FALSE; ++ } ++ ++ do { ++ char *item_id; ++ ++ ++ gtk_tree_model_get (model, iter, ++ CHOOSER_ID_COLUMN, &item_id, -1); ++ ++ g_assert (item_id != NULL); ++ ++ if (strcmp (id, item_id) == 0) { ++ found_item = TRUE; ++ } ++ g_free (item_id); ++ ++ } while (!found_item && gtk_tree_model_iter_next (model, iter)); ++ ++ return found_item; ++} ++ ++static char * ++get_active_item_id (GdmChooserWidget *widget, ++ GtkTreeIter *iter) ++{ ++ char *item_id; ++ GtkTreeModel *model; ++ GtkTreePath *path; ++ ++ g_return_val_if_fail (GDM_IS_CHOOSER_WIDGET (widget), NULL); ++ ++ model = GTK_TREE_MODEL (widget->priv->list_store); ++ item_id = NULL; ++ ++ if (widget->priv->active_row == NULL) { ++ return NULL; ++ } ++ ++ path = gtk_tree_row_reference_get_path (widget->priv->active_row); ++ if (gtk_tree_model_get_iter (model, iter, path)) { ++ gtk_tree_model_get (model, iter, ++ CHOOSER_ID_COLUMN, &item_id, -1); ++ }; ++ gtk_tree_path_free (path); ++ ++ return item_id; ++} ++ ++char * ++gdm_chooser_widget_get_active_item (GdmChooserWidget *widget) ++{ ++ GtkTreeIter iter; ++ ++ return get_active_item_id (widget, &iter); ++} ++ ++static void ++activate_from_item_id (GdmChooserWidget *widget, ++ const char *item_id) ++{ ++ GtkTreeModel *model; ++ GtkTreePath *path; ++ GtkTreeIter iter; ++ ++ model = GTK_TREE_MODEL (widget->priv->list_store); ++ path = NULL; ++ ++ if (find_item (widget, item_id, &iter)) { ++ GtkTreePath *child_path; ++ ++ child_path = gtk_tree_model_get_path (model, &iter); ++ path = gtk_tree_model_sort_convert_child_path_to_path (widget->priv->model_sorter, child_path); ++ gtk_tree_path_free (child_path); ++ } ++ ++ if (path == NULL) { ++ return; ++ } ++ ++ gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (widget->priv->items_view), ++ path, ++ NULL, ++ TRUE, ++ 0.5, ++ 0.0); ++ ++ gtk_tree_view_set_cursor (GTK_TREE_VIEW (widget->priv->items_view), ++ path, ++ NULL, ++ FALSE); ++ ++ gtk_tree_view_row_activated (GTK_TREE_VIEW (widget->priv->items_view), ++ path, ++ NULL); ++ gtk_tree_path_free (path); ++} ++ ++static void ++set_frame_text (GdmChooserWidget *widget, ++ const char *text) ++{ ++ GtkWidget *label; ++ ++ label = gtk_frame_get_label_widget (GTK_FRAME (widget->priv->frame)); ++ ++ if (text == NULL && label != NULL) { ++ gtk_frame_set_label_widget (GTK_FRAME (widget->priv->frame), ++ NULL); ++ gtk_alignment_set_padding (GTK_ALIGNMENT (widget->priv->frame_alignment), ++ 0, 0, 0, 0); ++ } else if (text != NULL && label == NULL) { ++ label = gtk_label_new (""); ++ gtk_label_set_mnemonic_widget (GTK_LABEL (label), ++ widget->priv->items_view); ++ gtk_widget_show (label); ++ gtk_frame_set_label_widget (GTK_FRAME (widget->priv->frame), ++ label); ++ gtk_alignment_set_padding (GTK_ALIGNMENT (widget->priv->frame_alignment), ++ 6, 0, 12, 0); ++ } ++ ++ if (label != NULL && text != NULL) { ++ char *markup; ++ markup = g_strdup_printf ("%s", text); ++ gtk_label_set_markup_with_mnemonic (GTK_LABEL (label), markup); ++ g_free (markup); ++ } ++} ++ ++static void ++translate_base_path_to_sorted_path (GdmChooserWidget *widget, ++ GtkTreePath **path) ++{ ++ GtkTreePath *filtered_path; ++ GtkTreePath *sorted_path; ++ ++ filtered_path = ++ gtk_tree_model_filter_convert_child_path_to_path (widget->priv->model_filter, *path); ++ sorted_path = gtk_tree_model_sort_convert_child_path_to_path (widget->priv->model_sorter, ++ filtered_path); ++ gtk_tree_path_free (filtered_path); ++ ++ gtk_tree_path_free (*path); ++ *path = sorted_path; ++} ++ ++static gboolean ++shrink_edge_toward_active_row (GdmChooserWidget *widget, ++ GtkTreeRowReference **edge_row) ++{ ++ GtkTreeModel *model; ++ GtkTreePath *active_path; ++ GtkTreePath *edge_path; ++ GtkTreeIter edge_iter; ++ gboolean edge_is_hidden; ++ int relative_position; ++ ++ model = GTK_TREE_MODEL (widget->priv->list_store); ++ ++ active_path = gtk_tree_row_reference_get_path (widget->priv->active_row); ++ translate_base_path_to_sorted_path (widget, &active_path); ++ ++ g_assert (*edge_row != NULL); ++ edge_path = gtk_tree_row_reference_get_path (*edge_row); ++ g_assert (edge_path != NULL); ++ relative_position = gtk_tree_path_compare (edge_path, active_path); ++ if (relative_position != 0 && ++ gtk_tree_model_get_iter (GTK_TREE_MODEL (widget->priv->model_sorter), ++ &edge_iter, edge_path)) { ++ GtkTreeIter filtered_iter; ++ GtkTreeIter iter; ++ ++ if (relative_position < 0) { ++ gtk_tree_path_next (edge_path); ++ } else { ++ gtk_tree_path_prev (edge_path); ++ } ++ gtk_tree_row_reference_free (*edge_row); ++ ++ *edge_row = gtk_tree_row_reference_new (GTK_TREE_MODEL (widget->priv->model_sorter), ++ edge_path); ++ ++ gtk_tree_model_sort_convert_iter_to_child_iter (widget->priv->model_sorter, ++ &filtered_iter, &edge_iter); ++ gtk_tree_model_filter_convert_iter_to_child_iter (widget->priv->model_filter, ++ &iter, &filtered_iter); ++ gtk_list_store_set (GTK_LIST_STORE (widget->priv->list_store), ++ &iter, CHOOSER_ITEM_IS_VISIBLE_COLUMN, FALSE, -1); ++ ++ edge_is_hidden = FALSE; ++ } else { ++ edge_is_hidden = TRUE; ++ } ++ gtk_tree_path_free (active_path); ++ gtk_tree_path_free (edge_path); ++ ++ return edge_is_hidden; ++} ++ ++static gboolean ++iterate_animation (GdmChooserWidget *widget) ++{ ++ gboolean is_done; ++ ++ if (widget->priv->state == GDM_CHOOSER_WIDGET_STATE_SHRINKING) { ++ if (widget->priv->top_edge_row != NULL) { ++ is_done = shrink_edge_toward_active_row (widget, ++ &widget->priv->top_edge_row); ++ } ++ ++ if (widget->priv->bottom_edge_row != NULL) { ++ is_done = is_done && ++ shrink_edge_toward_active_row (widget, ++ &widget->priv->bottom_edge_row); ++ } ++ } else { ++ GtkTreePath *path; ++ GtkTreeIter iter; ++ gboolean is_visible; ++ ++ path = gtk_tree_path_new_first (); ++ ++ do { ++ if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (widget->priv->list_store), ++ &iter, path)) { ++ is_done = TRUE; ++ break; ++ } ++ ++ gtk_tree_model_get (GTK_TREE_MODEL (widget->priv->list_store), ++ &iter, CHOOSER_ITEM_IS_VISIBLE_COLUMN, ++ &is_visible, -1); ++ ++ if (is_visible) { ++ gtk_tree_path_next (path); ++ } else { ++ gtk_list_store_set (GTK_LIST_STORE (widget->priv->list_store), ++ &iter, CHOOSER_ITEM_IS_VISIBLE_COLUMN, ++ TRUE, -1); ++ } ++ } while (is_visible); ++ ++ gtk_tree_path_free (path); ++ } ++ ++ return is_done != TRUE; ++} ++ ++static void ++stop_animation (GdmChooserWidget *widget) ++{ ++ if (widget->priv->animation_timeout_id == 0) { ++ return; ++ } ++ ++ gtk_tree_row_reference_free (widget->priv->top_edge_row); ++ widget->priv->top_edge_row = NULL; ++ ++ gtk_tree_row_reference_free (widget->priv->bottom_edge_row); ++ widget->priv->bottom_edge_row = NULL; ++ ++ widget->priv->animation_timeout_id = 0; ++ gtk_widget_set_sensitive (GTK_WIDGET (widget), TRUE); ++} ++ ++static void ++start_animation (GdmChooserWidget *widget) ++{ ++ GtkTreePath *edge_path; ++ int number_of_visible_rows; ++ int number_of_rows; ++ ++ if (widget->priv->animation_timeout_id != 0) { ++ g_source_remove (widget->priv->animation_timeout_id); ++ } ++ ++ number_of_visible_rows = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (widget->priv->model_sorter), NULL); ++ number_of_rows = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (widget->priv->list_store), NULL); ++ ++ if (widget->priv->state == GDM_CHOOSER_WIDGET_STATE_SHRINKING) { ++ if (number_of_visible_rows <= 1) { ++ widget->priv->state = GDM_CHOOSER_WIDGET_STATE_SHRUNK; ++ return; ++ } ++ ++ edge_path = gtk_tree_path_new_first (); ++ widget->priv->top_edge_row = gtk_tree_row_reference_new (GTK_TREE_MODEL (widget->priv->model_sorter), ++ edge_path); ++ gtk_tree_path_free (edge_path); ++ ++ edge_path = gtk_tree_path_new_from_indices (number_of_visible_rows - 1, -1); ++ ++ widget->priv->bottom_edge_row = gtk_tree_row_reference_new (GTK_TREE_MODEL (widget->priv->model_sorter), ++ edge_path); ++ gtk_tree_path_free (edge_path); ++ ++ g_assert (widget->priv->top_edge_row != NULL && widget->priv->bottom_edge_row != NULL); ++ } ++ ++ if (widget->priv->state == GDM_CHOOSER_WIDGET_STATE_GROWING) { ++ if (number_of_visible_rows >= number_of_rows) { ++ widget->priv->state = GDM_CHOOSER_WIDGET_STATE_GROWN; ++ return; ++ } ++ } ++ ++ gtk_widget_set_sensitive (GTK_WIDGET (widget), FALSE); ++ ++ /* FIXME: The 4 here is abitrary. We should really keep track of the time we start and ++ * hide enough rows to catch up to where we should be each time through ++ */ ++ widget->priv->animation_timeout_id = ++ g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE, ++ 1000 / (4 * number_of_rows), ++ (GSourceFunc) iterate_animation, ++ widget, (GDestroyNotify) stop_animation); ++} ++ ++static void ++gdm_chooser_widget_grow (GdmChooserWidget *widget) ++{ ++ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (widget->priv->scrolled_window), ++ GTK_SHADOW_ETCHED_IN); ++ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (widget->priv->scrolled_window), ++ GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); ++ gtk_alignment_set (GTK_ALIGNMENT (widget->priv->frame_alignment), ++ 0.0, 0.0, 1.0, 1.0); ++ ++ set_frame_text (widget, widget->priv->inactive_text); ++ ++ widget->priv->state = GDM_CHOOSER_WIDGET_STATE_GROWING; ++ start_animation (widget); ++} ++ ++static void ++move_cursor_to_top (GdmChooserWidget *widget) ++{ ++ GtkTreeModel *model; ++ GtkTreePath *path; ++ GtkTreeIter iter; ++ ++ model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget->priv->items_view)); ++ path = gtk_tree_path_new_first (); ++ if (gtk_tree_model_get_iter (model, &iter, path)) { ++ gtk_tree_view_set_cursor (GTK_TREE_VIEW (widget->priv->items_view), ++ path, ++ NULL, ++ FALSE); ++ } ++ gtk_tree_path_free (path); ++} ++ ++static gboolean ++clear_selection (GdmChooserWidget *widget) ++{ ++ GtkTreeSelection *selection; ++ ++ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget->priv->items_view)); ++ gtk_tree_selection_unselect_all (selection); ++ ++ return FALSE; ++} ++ ++static void ++gdm_chooser_widget_shrink (GdmChooserWidget *widget) ++{ ++ g_assert (widget->priv->should_hide_inactive_items == TRUE); ++ ++ set_frame_text (widget, widget->priv->active_text); ++ ++ gtk_alignment_set (GTK_ALIGNMENT (widget->priv->frame_alignment), ++ 0.0, 0.0, 1.0, 0.0); ++ ++ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (widget->priv->scrolled_window), ++ GTK_POLICY_NEVER, GTK_POLICY_NEVER); ++ ++ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (widget->priv->scrolled_window), ++ GTK_SHADOW_ETCHED_OUT); ++ ++ clear_selection (widget); ++ widget->priv->state = GDM_CHOOSER_WIDGET_STATE_SHRINKING; ++ start_animation (widget); ++} ++ ++static void ++activate_from_row (GdmChooserWidget *widget, ++ GtkTreeRowReference *row) ++{ ++ g_assert (row != NULL); ++ g_assert (gtk_tree_row_reference_valid (row)); ++ ++ if (widget->priv->active_row != NULL) { ++ gtk_tree_row_reference_free (widget->priv->active_row); ++ widget->priv->active_row = NULL; ++ } ++ ++ widget->priv->active_row = gtk_tree_row_reference_copy (row); ++ g_signal_emit (widget, signals[ACTIVATED], 0); ++ ++ if (widget->priv->should_hide_inactive_items) { ++ gdm_chooser_widget_shrink (widget); ++ } ++} ++ ++static void ++deactivate (GdmChooserWidget *widget) ++{ ++ if (widget->priv->active_row == NULL) { ++ return; ++ } ++ ++ gtk_tree_row_reference_free (widget->priv->active_row); ++ widget->priv->active_row = NULL; ++ ++ g_signal_emit (widget, signals[DEACTIVATED], 0, NULL, NULL); ++ ++ if (widget->priv->state != GDM_CHOOSER_WIDGET_STATE_GROWN) { ++ gdm_chooser_widget_grow (widget); ++ } ++} ++ ++static void ++activate_selected_item (GdmChooserWidget *widget) ++{ ++ GtkTreeRowReference *row; ++ GtkTreeSelection *selection; ++ GtkTreeModel *model; ++ GtkTreeModel *sort_model; ++ GtkTreeIter sorted_iter; ++ gboolean is_already_active; ++ ++ row = NULL; ++ model = GTK_TREE_MODEL (widget->priv->list_store); ++ is_already_active = FALSE; ++ ++ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget->priv->items_view)); ++ if (gtk_tree_selection_get_selected (selection, &sort_model, &sorted_iter)) { ++ GtkTreePath *sorted_path; ++ GtkTreePath *filtered_path; ++ GtkTreePath *base_path; ++ ++ g_assert (sort_model == GTK_TREE_MODEL (widget->priv->model_sorter)); ++ ++ sorted_path = gtk_tree_model_get_path (sort_model, &sorted_iter); ++ filtered_path = ++ gtk_tree_model_sort_convert_path_to_child_path (widget->priv->model_sorter, ++ sorted_path); ++ gtk_tree_path_free (sorted_path); ++ base_path = ++ gtk_tree_model_filter_convert_path_to_child_path (widget->priv->model_filter, ++ filtered_path); ++ ++ if (widget->priv->active_row != NULL) { ++ GtkTreePath *active_path; ++ ++ active_path = gtk_tree_row_reference_get_path (widget->priv->active_row); ++ ++ if (gtk_tree_path_compare (base_path, active_path) == 0) { ++ is_already_active = TRUE; ++ } ++ gtk_tree_path_free (active_path); ++ } ++ g_assert (base_path != NULL); ++ row = gtk_tree_row_reference_new (model, base_path); ++ gtk_tree_path_free (base_path); ++ } ++ ++ if (!is_already_active) { ++ activate_from_row (widget, row); ++ } else { ++ deactivate (widget); ++ } ++ gtk_tree_row_reference_free (row); ++} ++ ++void ++gdm_chooser_widget_set_active_item (GdmChooserWidget *widget, ++ const char *id) ++{ ++ g_return_if_fail (GDM_IS_CHOOSER_WIDGET (widget)); ++ ++ if (id != NULL) { ++ activate_from_item_id (widget, id); ++ } else { ++ deactivate (widget); ++ } ++} ++ ++static void ++gdm_chooser_widget_set_property (GObject *object, ++ guint prop_id, ++ const GValue *value, ++ GParamSpec *pspec) ++{ ++ GdmChooserWidget *self; ++ ++ self = GDM_CHOOSER_WIDGET (object); ++ ++ switch (prop_id) { ++ ++ case PROP_INACTIVE_TEXT: ++ g_free (self->priv->inactive_text); ++ self->priv->inactive_text = g_value_dup_string (value); ++ ++ if (self->priv->active_row == NULL) { ++ set_frame_text (self, self->priv->inactive_text); ++ } ++ break; ++ ++ case PROP_ACTIVE_TEXT: ++ g_free (self->priv->active_text); ++ self->priv->active_text = g_value_dup_string (value); ++ ++ if (self->priv->active_row != NULL) { ++ set_frame_text (self, self->priv->active_text); ++ } ++ break; ++ ++ default: ++ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); ++ break; ++ } ++} ++ ++static void ++gdm_chooser_widget_get_property (GObject *object, ++ guint prop_id, ++ GValue *value, ++ GParamSpec *pspec) ++{ ++ GdmChooserWidget *self; ++ ++ self = GDM_CHOOSER_WIDGET (object); ++ ++ switch (prop_id) { ++ case PROP_INACTIVE_TEXT: ++ g_value_set_string (value, self->priv->inactive_text); ++ break; ++ ++ case PROP_ACTIVE_TEXT: ++ g_value_set_string (value, self->priv->active_text); ++ break; ++ default: ++ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); ++ break; ++ } ++} ++ ++static GObject * ++gdm_chooser_widget_constructor (GType type, ++ guint n_construct_properties, ++ GObjectConstructParam *construct_properties) ++{ ++ GdmChooserWidget *chooser_widget; ++ GdmChooserWidgetClass *klass; ++ ++ klass = GDM_CHOOSER_WIDGET_CLASS (g_type_class_peek (GDM_TYPE_CHOOSER_WIDGET)); ++ ++ chooser_widget = GDM_CHOOSER_WIDGET (G_OBJECT_CLASS (gdm_chooser_widget_parent_class)->constructor (type, ++ n_construct_properties, ++ construct_properties)); ++ ++ return G_OBJECT (chooser_widget); ++} ++ ++static void ++gdm_chooser_widget_dispose (GObject *object) ++{ ++ GdmChooserWidget *widget; ++ ++ widget = GDM_CHOOSER_WIDGET (object); ++ ++ if (widget->priv->separator_row != NULL) { ++ gtk_tree_row_reference_free (widget->priv->separator_row); ++ widget->priv->separator_row = NULL; ++ } ++ ++ if (widget->priv->active_row != NULL) { ++ gtk_tree_row_reference_free (widget->priv->active_row); ++ widget->priv->active_row = NULL; ++ } ++ ++ if (widget->priv->inactive_text != NULL) { ++ g_free (widget->priv->inactive_text); ++ widget->priv->inactive_text = NULL; ++ } ++ ++ if (widget->priv->active_text != NULL) { ++ g_free (widget->priv->active_text); ++ widget->priv->active_text = NULL; ++ } ++ ++ if (widget->priv->in_use_message != NULL) { ++ g_free (widget->priv->in_use_message); ++ widget->priv->in_use_message = NULL; ++ } ++ ++ G_OBJECT_CLASS (gdm_chooser_widget_parent_class)->dispose (object); ++} ++ ++static gboolean ++gdm_chooser_widget_focus_in (GtkWidget *widget, ++ GdkEventFocus *event) ++{ ++ GdmChooserWidget *chooser; ++ chooser = GDM_CHOOSER_WIDGET (widget); ++ ++ gtk_widget_grab_focus (chooser->priv->items_view); ++ ++ return FALSE; ++} ++ ++static void ++gdm_chooser_widget_size_request (GtkWidget *widget, ++ GtkRequisition *requisition) ++{ ++ GdmChooserWidget *chooser; ++ ++ chooser = GDM_CHOOSER_WIDGET (widget); ++ ++ GTK_WIDGET_CLASS (gdm_chooser_widget_parent_class)->size_request (widget, requisition); ++ ++ /* XXX: this hack makes the scrolled window behave the way we want in ++ * the login window. The login window is special because it always ++ * tries to hug the widgets as tightly as possible. Normally, this ++ * "tight hug" makes the scrolled_window get squeezed into nothing (if ++ * POLICY_AUTOMATIC) If we use POLICY_NEVER then the scrolled window ++ * gets the right size but can't have a scrollbar (which sort of ++ * defeats the point I guess) ++ */ ++ requisition->height -= chooser->priv->scrolled_window->requisition.height; ++ chooser->priv->scrolled_window->requisition.height = chooser->priv->items_view->requisition.height; ++ chooser->priv->scrolled_window->requisition.height += chooser->priv->scrolled_window->style->ythickness * 2; ++ chooser->priv->scrolled_window->requisition.height += GTK_CONTAINER (chooser->priv->scrolled_window)->border_width * 2; ++ requisition->height += chooser->priv->scrolled_window->requisition.height; ++} ++ ++#ifdef BUILD_ALLOCATION_HACK ++static gint ++compare_allocation_height (GdmChooserWidget *widget_a, ++ GdmChooserWidget *widget_b) ++{ ++ return GTK_WIDGET (widget_a)->allocation.height - GTK_WIDGET (widget_b)->allocation.height; ++} ++ ++static void ++renegotiate_allocation (GtkContainer *container, ++ GdmChooserWidgetClass *klass) ++{ ++ GList *children; ++ GList *choosers; ++ GList *tmp; ++ int total_allocation; ++ int number_of_choosers; ++ ++ if (klass->size_negotiation_handler == 0) { ++ return; ++ } ++ klass->size_negotiation_handler = 0; ++ g_signal_handlers_disconnect_by_func (container, renegotiate_allocation, klass); ++ ++ children = gtk_container_get_children (container); ++ ++ total_allocation = 0; ++ number_of_choosers = 0; ++ choosers = NULL; ++ for (tmp = children; tmp != NULL; tmp = tmp->next) { ++ GdmChooserWidget *widget; ++ ++ if (!GDM_IS_CHOOSER_WIDGET (tmp->data)) { ++ continue; ++ } ++ ++ widget = GDM_CHOOSER_WIDGET (tmp->data); ++ ++ total_allocation += GTK_WIDGET (widget)->allocation.height; ++ choosers = g_list_insert_sorted (choosers, widget, (GCompareFunc) compare_allocation_height); ++ number_of_choosers++; ++ } ++ total_allocation = MIN (total_allocation, GTK_WIDGET (container)->allocation.height); ++ ++ for (tmp = choosers; tmp != NULL; tmp = tmp->next) { ++ GdmChooserWidget *widget; ++ GtkAllocation allocation; ++ ++ g_assert (GDM_IS_CHOOSER_WIDGET (tmp->data)); ++ ++ widget = GDM_CHOOSER_WIDGET (tmp->data); ++ ++ allocation = GTK_WIDGET (widget)->allocation; ++ ++ GTK_WIDGET (widget)->allocation.height = MIN (GTK_WIDGET (widget)->requisition.height, ++ total_allocation / number_of_choosers); ++ ++ total_allocation -= allocation.height; ++ ++ number_of_choosers--; ++ } ++ g_list_free (children); ++} ++ ++static void ++gdm_chooser_widget_size_allocate (GtkWidget *widget, ++ GtkAllocation *allocation) ++{ ++ GdmChooserWidgetClass *klass; ++ ++ klass = GDM_CHOOSER_WIDGET_GET_CLASS (widget); ++ ++ GTK_WIDGET_CLASS (gdm_chooser_widget_parent_class)->size_allocate (widget, allocation); ++ ++ /* XXX: Vbox isn't too smart about divving up allocations when there isn't enough room to go around. ++ * Since we may have more than one chooser widget in a vbox, we redistribute space between the choosers ++ * (if one chooser gets lots of space and another gets no space, give some up) ++ */ ++ if (allocation->height == 1 && klass->size_negotiation_handler == 0) { ++ GtkWidget *parent; ++ ++ parent = gtk_widget_get_parent (widget); ++ klass->size_negotiation_handler = g_signal_connect (parent, "size-allocate", ++ G_CALLBACK (renegotiate_allocation), ++ klass); ++ } ++} ++#endif ++ ++static void ++gdm_chooser_widget_class_init (GdmChooserWidgetClass *klass) ++{ ++ GObjectClass *object_class = G_OBJECT_CLASS (klass); ++ GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); ++ ++ object_class->get_property = gdm_chooser_widget_get_property; ++ object_class->set_property = gdm_chooser_widget_set_property; ++ object_class->constructor = gdm_chooser_widget_constructor; ++ object_class->dispose = gdm_chooser_widget_dispose; ++ object_class->finalize = gdm_chooser_widget_finalize; ++ widget_class->focus_in_event = gdm_chooser_widget_focus_in; ++ widget_class->size_request = gdm_chooser_widget_size_request; ++#ifdef BUILD_ALLOCATION_HACK ++ widget_class->size_allocate = gdm_chooser_widget_size_allocate; ++#endif ++ ++ signals [ACTIVATED] = g_signal_new ("activated", ++ G_TYPE_FROM_CLASS (object_class), ++ G_SIGNAL_RUN_LAST, ++ G_STRUCT_OFFSET (GdmChooserWidgetClass, activated), ++ NULL, ++ NULL, ++ g_cclosure_marshal_VOID__VOID, ++ G_TYPE_NONE, ++ 0); ++ ++ signals [DEACTIVATED] = g_signal_new ("deactivated", ++ G_TYPE_FROM_CLASS (object_class), ++ G_SIGNAL_RUN_LAST, ++ G_STRUCT_OFFSET (GdmChooserWidgetClass, deactivated), ++ NULL, ++ NULL, ++ g_cclosure_marshal_VOID__VOID, ++ G_TYPE_NONE, ++ 0); ++ ++ g_object_class_install_property (object_class, ++ PROP_INACTIVE_TEXT, ++ g_param_spec_string ("inactive-text", ++ _("Inactive Text"), ++ _("The text to use in the label if the " ++ "user hasn't picked an item yet"), ++ NULL, ++ (G_PARAM_READWRITE | ++ G_PARAM_CONSTRUCT))); ++ g_object_class_install_property (object_class, ++ PROP_ACTIVE_TEXT, ++ g_param_spec_string ("active-text", ++ _("Active Text"), ++ _("The text to use in the label if the " ++ "user has picked an item"), ++ NULL, ++ (G_PARAM_READWRITE | ++ G_PARAM_CONSTRUCT))); ++ ++ g_type_class_add_private (klass, sizeof (GdmChooserWidgetPrivate)); ++} ++ ++static void ++on_row_activated (GtkTreeView *tree_view, ++ GtkTreePath *tree_path, ++ GtkTreeViewColumn *tree_column, ++ GdmChooserWidget *widget) ++{ ++ activate_selected_item (widget); ++} ++ ++static gboolean ++path_is_separator (GdmChooserWidget *widget, ++ GtkTreeModel *model, ++ GtkTreePath *path) ++{ ++ GtkTreePath *base_path; ++ GtkTreePath *filtered_path; ++ GtkTreePath *sorted_path; ++ GtkTreePath *separator_path; ++ gboolean is_separator; ++ ++ if (widget->priv->separator_row == NULL) { ++ return FALSE; ++ } ++ ++ base_path = gtk_tree_row_reference_get_path (widget->priv->separator_row); ++ separator_path = base_path; ++ filtered_path = NULL; ++ sorted_path = NULL; ++ ++ if (model != GTK_TREE_MODEL (widget->priv->list_store)) { ++ filtered_path = gtk_tree_model_filter_convert_child_path_to_path (widget->priv->model_filter, base_path); ++ separator_path = filtered_path; ++ ++ gtk_tree_path_free (base_path); ++ base_path = NULL; ++ } ++ ++ if (filtered_path != NULL && model != GTK_TREE_MODEL (widget->priv->model_filter)) { ++ sorted_path = gtk_tree_model_sort_convert_child_path_to_path (widget->priv->model_sorter, filtered_path); ++ separator_path = sorted_path; ++ ++ gtk_tree_path_free (filtered_path); ++ filtered_path = NULL; ++ } ++ ++ if ((separator_path != NULL) && ++ gtk_tree_path_compare (path, separator_path) == 0) { ++ is_separator = TRUE; ++ } else { ++ is_separator = FALSE; ++ } ++ gtk_tree_path_free (separator_path); ++ ++ return is_separator; ++} ++ ++static int ++compare_item (GtkTreeModel *model, ++ GtkTreeIter *a, ++ GtkTreeIter *b, ++ gpointer data) ++{ ++ GdmChooserWidget *widget; ++ char *name_a; ++ char *name_b; ++ gboolean is_separate_a; ++ gboolean is_separate_b; ++ int result; ++ int direction; ++ GtkTreeIter *separator_iter; ++ ++ g_assert (GDM_IS_CHOOSER_WIDGET (data)); ++ ++ widget = GDM_CHOOSER_WIDGET (data); ++ ++ separator_iter = NULL; ++ if (widget->priv->separator_row != NULL) { ++ ++ GtkTreePath *path_a; ++ GtkTreePath *path_b; ++ ++ path_a = gtk_tree_model_get_path (model, a); ++ path_b = gtk_tree_model_get_path (model, b); ++ ++ if (path_is_separator (widget, model, path_a)) { ++ separator_iter = a; ++ } else if (path_is_separator (widget, model, path_b)) { ++ separator_iter = b; ++ } ++ ++ gtk_tree_path_free (path_a); ++ gtk_tree_path_free (path_b); ++ } ++ ++ name_a = NULL; ++ is_separate_a = FALSE; ++ if (separator_iter != a) { ++ gtk_tree_model_get (model, a, ++ CHOOSER_NAME_COLUMN, &name_a, ++ CHOOSER_ITEM_IS_SEPARATED_COLUMN, &is_separate_a, ++ -1); ++ } ++ ++ char *id; ++ name_b = NULL; ++ is_separate_b = FALSE; ++ if (separator_iter != b) { ++ gtk_tree_model_get (model, b, ++ CHOOSER_NAME_COLUMN, &name_b, ++ CHOOSER_ID_COLUMN, &id, ++ CHOOSER_ITEM_IS_SEPARATED_COLUMN, &is_separate_b, ++ -1); ++ } ++ ++ if (widget->priv->separator_position == GDM_CHOOSER_WIDGET_POSITION_TOP) { ++ direction = -1; ++ } else { ++ direction = 1; ++ } ++ ++ if (separator_iter == b) { ++ result = is_separate_a? 1 : -1; ++ result *= direction; ++ } else if (separator_iter == a) { ++ result = is_separate_b? -1 : 1; ++ result *= direction; ++ } else if (is_separate_b == is_separate_a) { ++ result = g_utf8_collate (name_a, name_b); ++ } else { ++ result = is_separate_a - is_separate_b; ++ result *= direction; ++ } ++ ++ g_free (name_a); ++ g_free (name_b); ++ ++ return result; ++} ++ ++static void ++name_cell_data_func (GtkTreeViewColumn *tree_column, ++ GtkCellRenderer *cell, ++ GtkTreeModel *model, ++ GtkTreeIter *iter, ++ GdmChooserWidget *widget) ++{ ++ gboolean is_in_use; ++ char *name; ++ char *markup; ++ ++ name = NULL; ++ gtk_tree_model_get (model, ++ iter, ++ CHOOSER_ITEM_IS_IN_USE_COLUMN, &is_in_use, ++ CHOOSER_NAME_COLUMN, &name, ++ -1); ++ ++ if (is_in_use) { ++ markup = g_strdup_printf ("%s\n" ++ "%s", ++ name, widget->priv->in_use_message); ++ } else { ++ markup = g_strdup_printf ("%s", name); ++ } ++ g_free (name); ++ ++ g_object_set (cell, "markup", markup, NULL); ++ g_free (markup); ++} ++ ++static void ++check_cell_data_func (GtkTreeViewColumn *tree_column, ++ GtkCellRenderer *cell, ++ GtkTreeModel *model, ++ GtkTreeIter *iter, ++ GdmChooserWidget *widget) ++{ ++ gboolean is_in_use; ++ GdkPixbuf *pixbuf; ++ ++ gtk_tree_model_get (model, ++ iter, ++ CHOOSER_ITEM_IS_IN_USE_COLUMN, &is_in_use, ++ -1); ++ ++ if (is_in_use) { ++ pixbuf = widget->priv->is_in_use_pixbuf; ++ } else { ++ pixbuf = NULL; ++ } ++ ++ g_object_set (cell, "pixbuf", pixbuf, NULL); ++} ++ ++static GdkPixbuf * ++get_is_in_use_pixbuf (GdmChooserWidget *widget) ++{ ++ GtkIconTheme *theme; ++ GdkPixbuf *pixbuf; ++ ++ theme = gtk_icon_theme_get_default (); ++ pixbuf = gtk_icon_theme_load_icon (theme, ++ "emblem-default", ++ GDM_CHOOSER_WIDGET_DEFAULT_ICON_SIZE / 3, ++ 0, ++ NULL); ++ ++ return pixbuf; ++} ++ ++static gboolean ++separator_func (GtkTreeModel *model, ++ GtkTreeIter *iter, ++ gpointer data) ++{ ++ GdmChooserWidget *widget; ++ GtkTreePath *path; ++ gboolean is_separator; ++ ++ g_assert (GDM_IS_CHOOSER_WIDGET (data)); ++ ++ widget = GDM_CHOOSER_WIDGET (data); ++ ++ g_assert (widget->priv->separator_row != NULL); ++ ++ path = gtk_tree_model_get_path (model, iter); ++ ++ is_separator = path_is_separator (widget, model, path); ++ ++ gtk_tree_path_free (path); ++ ++ return is_separator; ++} ++ ++static void ++add_separator (GdmChooserWidget *widget) ++{ ++ GtkTreeIter iter; ++ GtkTreeModel *model; ++ GtkTreePath *path; ++ ++ g_assert (widget->priv->separator_row == NULL); ++ ++ model = GTK_TREE_MODEL (widget->priv->list_store); ++ ++ gtk_list_store_insert_with_values (widget->priv->list_store, ++ &iter, 0, ++ CHOOSER_ID_COLUMN, "-", -1); ++ path = gtk_tree_model_get_path (model, &iter); ++ widget->priv->separator_row = ++ gtk_tree_row_reference_new (model, path); ++ gtk_tree_path_free (path); ++} ++ ++static gboolean ++update_column_visibility (GdmChooserWidget *widget) ++{ ++ if (widget->priv->number_of_rows_with_images > 0) { ++ gtk_tree_view_column_set_visible (widget->priv->image_column, ++ TRUE); ++ } else { ++ gtk_tree_view_column_set_visible (widget->priv->image_column, ++ FALSE); ++ } ++ if (widget->priv->number_of_in_use_rows > 0) { ++ gtk_tree_view_column_set_visible (widget->priv->is_in_use_column, ++ TRUE); ++ } else { ++ gtk_tree_view_column_set_visible (widget->priv->is_in_use_column, ++ FALSE); ++ } ++ ++ return FALSE; ++} ++ ++static void ++clear_canceled_visibility_update (GdmChooserWidget *widget) ++{ ++ widget->priv->update_idle_id = 0; ++} ++ ++static void ++queue_column_visibility_update (GdmChooserWidget *widget) ++{ ++ if (widget->priv->update_idle_id == 0) { ++ widget->priv->update_idle_id = ++ g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, ++ (GSourceFunc) ++ update_column_visibility, widget, ++ (GDestroyNotify) ++ clear_canceled_visibility_update); ++ } ++} ++ ++static void ++on_row_changed (GtkTreeModel *model, ++ GtkTreePath *path, ++ GtkTreeIter *iter, ++ GdmChooserWidget *widget) ++{ ++ queue_column_visibility_update (widget); ++} ++ ++static void ++add_frame (GdmChooserWidget *widget) ++{ ++ widget->priv->frame = gtk_frame_new (NULL); ++ gtk_frame_set_shadow_type (GTK_FRAME (widget->priv->frame), ++ GTK_SHADOW_NONE); ++ gtk_widget_show (widget->priv->frame); ++ gtk_container_add (GTK_CONTAINER (widget), widget->priv->frame); ++ ++ widget->priv->frame_alignment = gtk_alignment_new (0.5, 0.5, 1.0, 1.0); ++ gtk_widget_show (widget->priv->frame_alignment); ++ gtk_container_add (GTK_CONTAINER (widget->priv->frame), ++ widget->priv->frame_alignment); ++} ++ ++static gboolean ++on_button_release (GtkTreeView *items_view, ++ GdkEventButton *event, ++ GdmChooserWidget *widget) ++{ ++ GtkTreeModel *model; ++ GtkTreeIter iter; ++ GtkTreeSelection *selection; ++ ++ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget->priv->items_view)); ++ if (gtk_tree_selection_get_selected (selection, &model, &iter)) { ++ GtkTreePath *path; ++ ++ path = gtk_tree_model_get_path (model, &iter); ++ gtk_tree_view_row_activated (GTK_TREE_VIEW (items_view), ++ path, NULL); ++ gtk_tree_path_free (path); ++ } ++ ++ return FALSE; ++} ++ ++static void ++gdm_chooser_widget_init (GdmChooserWidget *widget) ++{ ++ GtkTreeViewColumn *column; ++ GtkTreeSelection *selection; ++ GtkCellRenderer *renderer; ++ ++ widget->priv = GDM_CHOOSER_WIDGET_GET_PRIVATE (widget); ++ ++ gtk_alignment_set_padding (GTK_ALIGNMENT (widget), 6, 0, 12, 0); ++ ++ add_frame (widget); ++ ++ widget->priv->scrolled_window = gtk_scrolled_window_new (NULL, NULL); ++ ++ gtk_scrolled_window_set_vadjustment (GTK_SCROLLED_WINDOW (widget->priv->scrolled_window), ++ NULL); ++ gtk_scrolled_window_set_hadjustment (GTK_SCROLLED_WINDOW (widget->priv->scrolled_window), ++ NULL); ++ gtk_widget_show (widget->priv->scrolled_window); ++ gtk_container_add (GTK_CONTAINER (widget->priv->frame_alignment), ++ widget->priv->scrolled_window); ++ ++ widget->priv->items_view = gtk_tree_view_new (); ++ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (widget->priv->items_view), ++ FALSE); ++ g_signal_connect (widget->priv->items_view, ++ "row-activated", ++ G_CALLBACK (on_row_activated), ++ widget); ++ ++ /* hack to make single-click activate work ++ */ ++ g_signal_connect_after (widget->priv->items_view, ++ "button-release-event", ++ G_CALLBACK (on_button_release), ++ widget); ++ ++ gtk_widget_show (widget->priv->items_view); ++ gtk_container_add (GTK_CONTAINER (widget->priv->scrolled_window), ++ widget->priv->items_view); ++ ++ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget->priv->items_view)); ++ gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE); ++ ++ g_assert (NUMBER_OF_CHOOSER_COLUMNS == 7); ++ widget->priv->list_store = gtk_list_store_new (NUMBER_OF_CHOOSER_COLUMNS, ++ GDK_TYPE_PIXBUF, ++ G_TYPE_STRING, ++ G_TYPE_STRING, ++ G_TYPE_BOOLEAN, ++ G_TYPE_BOOLEAN, ++ G_TYPE_BOOLEAN, ++ G_TYPE_STRING); ++ ++ widget->priv->model_filter = GTK_TREE_MODEL_FILTER (gtk_tree_model_filter_new (GTK_TREE_MODEL (widget->priv->list_store), NULL)); ++ ++ gtk_tree_model_filter_set_visible_column (widget->priv->model_filter, ++ CHOOSER_ITEM_IS_VISIBLE_COLUMN); ++ g_signal_connect (G_OBJECT (widget->priv->model_filter), "row-changed", ++ G_CALLBACK (on_row_changed), widget); ++ ++ widget->priv->model_sorter = GTK_TREE_MODEL_SORT (gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (widget->priv->model_filter))); ++ ++ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (widget->priv->model_sorter), ++ CHOOSER_ID_COLUMN, ++ compare_item, ++ widget, NULL); ++ ++ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (widget->priv->model_sorter), ++ CHOOSER_ID_COLUMN, ++ GTK_SORT_ASCENDING); ++ gtk_tree_view_set_model (GTK_TREE_VIEW (widget->priv->items_view), ++ GTK_TREE_MODEL (widget->priv->model_sorter)); ++ gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (widget->priv->items_view), ++ separator_func, ++ widget, NULL); ++ ++ /* IMAGE COLUMN */ ++ renderer = gtk_cell_renderer_pixbuf_new (); ++ column = gtk_tree_view_column_new (); ++ gtk_tree_view_column_pack_start (column, renderer, FALSE); ++ gtk_tree_view_append_column (GTK_TREE_VIEW (widget->priv->items_view), column); ++ widget->priv->image_column = column; ++ ++ gtk_tree_view_column_set_attributes (column, ++ renderer, ++ "pixbuf", CHOOSER_IMAGE_COLUMN, ++ NULL); ++ ++ g_object_set (renderer, ++ "width", GDM_CHOOSER_WIDGET_DEFAULT_ICON_SIZE, ++ "xalign", 1.0, ++ NULL); ++ ++ /* NAME COLUMN */ ++ renderer = gtk_cell_renderer_text_new (); ++ column = gtk_tree_view_column_new (); ++ gtk_tree_view_column_pack_start (column, renderer, FALSE); ++ gtk_tree_view_append_column (GTK_TREE_VIEW (widget->priv->items_view), column); ++ gtk_tree_view_column_set_cell_data_func (column, ++ renderer, ++ (GtkTreeCellDataFunc) name_cell_data_func, ++ widget, ++ NULL); ++ ++ gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (widget->priv->items_view), ++ CHOOSER_COMMENT_COLUMN); ++ ++ /* IN USE COLUMN */ ++ renderer = gtk_cell_renderer_pixbuf_new (); ++ column = gtk_tree_view_column_new (); ++ gtk_tree_view_column_pack_start (column, renderer, FALSE); ++ gtk_tree_view_append_column (GTK_TREE_VIEW (widget->priv->items_view), column); ++ widget->priv->is_in_use_column = column; ++ ++ gtk_tree_view_column_set_cell_data_func (column, ++ renderer, ++ (GtkTreeCellDataFunc) check_cell_data_func, ++ widget, ++ NULL); ++ widget->priv->is_in_use_pixbuf = get_is_in_use_pixbuf (widget); ++ ++ g_object_set (renderer, ++ "width", GDM_CHOOSER_WIDGET_DEFAULT_ICON_SIZE, ++ NULL); ++ ++ add_separator (widget); ++ ++ queue_column_visibility_update (widget); ++ gdm_chooser_widget_grow (widget); ++} ++ ++static void ++gdm_chooser_widget_finalize (GObject *object) ++{ ++ GdmChooserWidget *widget; ++ ++ g_return_if_fail (object != NULL); ++ g_return_if_fail (GDM_IS_CHOOSER_WIDGET (object)); ++ ++ widget = GDM_CHOOSER_WIDGET (object); ++ ++ g_return_if_fail (widget->priv != NULL); ++ ++ G_OBJECT_CLASS (gdm_chooser_widget_parent_class)->finalize (object); ++} ++ ++GtkWidget * ++gdm_chooser_widget_new (const char *inactive_text, ++ const char *active_text) ++{ ++ GObject *object; ++ ++ object = g_object_new (GDM_TYPE_CHOOSER_WIDGET, ++ "inactive-text", inactive_text, ++ "active-text", active_text, NULL); ++ ++ return GTK_WIDGET (object); ++} ++ ++void ++gdm_chooser_widget_add_item (GdmChooserWidget *widget, ++ const char *id, ++ GdkPixbuf *image, ++ const char *name, ++ const char *comment, ++ gboolean in_use, ++ gboolean keep_separate) ++{ ++ gboolean is_visible; ++ ++ g_return_if_fail (GDM_IS_CHOOSER_WIDGET (widget)); ++ ++ if (keep_separate) { ++ widget->priv->number_of_separated_rows++; ++ } else { ++ widget->priv->number_of_normal_rows++; ++ } ++ ++ if (in_use) { ++ widget->priv->number_of_in_use_rows++; ++ } ++ ++ if (image != NULL) { ++ widget->priv->number_of_rows_with_images++; ++ } ++ ++ is_visible = widget->priv->active_row == NULL; ++ ++ gtk_list_store_insert_with_values (widget->priv->list_store, ++ NULL, 0, ++ CHOOSER_IMAGE_COLUMN, image, ++ CHOOSER_NAME_COLUMN, name, ++ CHOOSER_COMMENT_COLUMN, comment, ++ CHOOSER_ITEM_IS_IN_USE_COLUMN, in_use, ++ CHOOSER_ITEM_IS_SEPARATED_COLUMN, keep_separate, ++ CHOOSER_ITEM_IS_VISIBLE_COLUMN, is_visible, ++ CHOOSER_ID_COLUMN, id, ++ -1); ++ ++ move_cursor_to_top (widget); ++} ++ ++void ++gdm_chooser_widget_remove_item (GdmChooserWidget *widget, ++ const char *id) ++{ ++ GtkTreeModel *model; ++ GtkTreeIter iter; ++ GdkPixbuf *image; ++ gboolean is_separate; ++ gboolean is_in_use; ++ ++ g_return_if_fail (GDM_IS_CHOOSER_WIDGET (widget)); ++ ++ model = GTK_TREE_MODEL (widget->priv->list_store); ++ ++ if (!find_item (widget, id, &iter)) { ++ g_critical ("Tried to remove non-existing item from chooser"); ++ return; ++ } ++ ++ is_separate = FALSE; ++ gtk_tree_model_get (model, &iter, ++ CHOOSER_IMAGE_COLUMN, &image, ++ CHOOSER_ITEM_IS_IN_USE_COLUMN, &is_in_use, ++ CHOOSER_ITEM_IS_SEPARATED_COLUMN, &is_separate, ++ -1); ++ ++ if (image != NULL) { ++ widget->priv->number_of_rows_with_images--; ++ g_object_unref (image); ++ } ++ ++ if (is_in_use) { ++ widget->priv->number_of_in_use_rows--; ++ } ++ ++ if (is_separate) { ++ widget->priv->number_of_separated_rows--; ++ } else { ++ widget->priv->number_of_normal_rows--; ++ } ++ ++ gtk_list_store_remove (widget->priv->list_store, &iter); ++ ++ move_cursor_to_top (widget); ++} ++ ++gboolean ++gdm_chooser_widget_lookup_item (GdmChooserWidget *widget, ++ const char *id, ++ GdkPixbuf **image, ++ char **name, ++ char **comment, ++ gboolean *is_in_use, ++ gboolean *is_separate) ++{ ++ GtkTreeModel *model; ++ GtkTreeIter iter; ++ char *active_item_id; ++ ++ g_return_val_if_fail (GDM_IS_CHOOSER_WIDGET (widget), FALSE); ++ g_return_val_if_fail (id != NULL, FALSE); ++ ++ active_item_id = get_active_item_id (widget, &iter); ++ ++ if (active_item_id == NULL || strcmp (active_item_id, id) != 0) { ++ g_free (active_item_id); ++ ++ if (!find_item (widget, id, &iter)) { ++ return FALSE; ++ } ++ } ++ g_free (active_item_id); ++ ++ gtk_tree_model_get (model, &iter, ++ CHOOSER_IMAGE_COLUMN, image, ++ CHOOSER_NAME_COLUMN, name, ++ CHOOSER_ITEM_IS_IN_USE_COLUMN, is_in_use, ++ CHOOSER_ITEM_IS_SEPARATED_COLUMN, is_separate, ++ -1); ++ ++ return TRUE; ++} ++ ++void ++gdm_chooser_widget_set_item_in_use (GdmChooserWidget *widget, ++ const char *id, ++ gboolean is_in_use) ++{ ++ GtkTreeIter iter; ++ ++ g_return_if_fail (GDM_IS_CHOOSER_WIDGET (widget)); ++ ++ if (!find_item (widget, id, &iter)) { ++ return; ++ } ++ ++ gtk_list_store_set (widget->priv->list_store, &iter, ++ CHOOSER_ITEM_IS_IN_USE_COLUMN, is_in_use, -1); ++} ++ ++void ++gdm_chooser_widget_set_in_use_message (GdmChooserWidget *widget, ++ const char *message) ++{ ++ g_return_if_fail (GDM_IS_CHOOSER_WIDGET (widget)); ++ ++ g_free (widget->priv->in_use_message); ++ widget->priv->in_use_message = g_strdup (message); ++} ++ ++void ++gdm_chooser_widget_set_separator_position (GdmChooserWidget *widget, ++ GdmChooserWidgetPosition position) ++{ ++ g_return_if_fail (GDM_IS_CHOOSER_WIDGET (widget)); ++ ++ if (widget->priv->separator_position != position) { ++ widget->priv->separator_position = position; ++ } ++ ++ gtk_tree_model_filter_refilter (widget->priv->model_filter); ++} ++ ++void ++gdm_chooser_widget_set_hide_inactive_items (GdmChooserWidget *widget, ++ gboolean should_hide) ++{ ++ widget->priv->should_hide_inactive_items = should_hide; ++ ++ if (should_hide && ++ (widget->priv->state != GDM_CHOOSER_WIDGET_STATE_SHRUNK ++ || widget->priv->state != GDM_CHOOSER_WIDGET_STATE_SHRINKING) && ++ widget->priv->active_row != NULL) { ++ gdm_chooser_widget_shrink (widget); ++ } else if (!should_hide && ++ (widget->priv->state != GDM_CHOOSER_WIDGET_STATE_GROWN ++ || widget->priv->state != GDM_CHOOSER_WIDGET_STATE_GROWING)) { ++ gdm_chooser_widget_grow (widget); ++ } ++} +diff --git a/gui/simple-greeter/gdm-chooser-widget.h b/gui/simple-greeter/gdm-chooser-widget.h +new file mode 100644 +index 0000000..9a5581f +--- /dev/null ++++ b/gui/simple-greeter/gdm-chooser-widget.h +@@ -0,0 +1,102 @@ ++/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- ++ * ++ * Copyright (C) 2007 Ray Strode ++ * Copyright (C) 2007 William Jon McCann ++ * ++ * This program is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with this program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ * ++ */ ++ ++#ifndef __GDM_CHOOSER_WIDGET_H ++#define __GDM_CHOOSER_WIDGET_H ++ ++#include ++#include ++ ++G_BEGIN_DECLS ++ ++#define GDM_TYPE_CHOOSER_WIDGET (gdm_chooser_widget_get_type ()) ++#define GDM_CHOOSER_WIDGET(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_CHOOSER_WIDGET, GdmChooserWidget)) ++#define GDM_CHOOSER_WIDGET_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_CHOOSER_WIDGET, GdmChooserWidgetClass)) ++#define GDM_IS_CHOOSER_WIDGET(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_CHOOSER_WIDGET)) ++#define GDM_IS_CHOOSER_WIDGET_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_CHOOSER_WIDGET)) ++#define GDM_CHOOSER_WIDGET_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_CHOOSER_WIDGET, GdmChooserWidgetClass)) ++ ++typedef struct GdmChooserWidgetPrivate GdmChooserWidgetPrivate; ++ ++typedef struct ++{ ++ GtkAlignment parent; ++ GdmChooserWidgetPrivate *priv; ++} GdmChooserWidget; ++ ++typedef struct ++{ ++ GtkAlignmentClass parent_class; ++ ++ void (* activated) (GdmChooserWidget *widget); ++ void (* deactivated) (GdmChooserWidget *widget); ++ ++#ifdef BUILD_ALLOCATION_HACK ++ gulong size_negotiation_handler; ++#endif ++} GdmChooserWidgetClass; ++ ++typedef enum { ++ GDM_CHOOSER_WIDGET_POSITION_TOP = 0, ++ GDM_CHOOSER_WIDGET_POSITION_BOTTOM, ++} GdmChooserWidgetPosition; ++ ++GType gdm_chooser_widget_get_type (void); ++GtkWidget * gdm_chooser_widget_new (const char *unactive_label, ++ const char *active_label); ++ ++void gdm_chooser_widget_add_item (GdmChooserWidget *widget, ++ const char *id, ++ GdkPixbuf *image, ++ const char *name, ++ const char *comment, ++ gboolean is_in_use, ++ gboolean keep_separate); ++ ++void gdm_chooser_widget_remove_item (GdmChooserWidget *widget, ++ const char *id); ++ ++gboolean gdm_chooser_widget_lookup_item (GdmChooserWidget *widget, ++ const char *id, ++ GdkPixbuf **image, ++ char **name, ++ char **comment, ++ gboolean *is_in_use, ++ gboolean *is_separate); ++ ++char * gdm_chooser_widget_get_active_item (GdmChooserWidget *widget); ++void gdm_chooser_widget_set_active_item (GdmChooserWidget *widget, ++ const char *item); ++ ++void gdm_chooser_widget_set_item_in_use (GdmChooserWidget *widget, ++ const char *id, ++ gboolean is_in_use); ++ ++void gdm_chooser_widget_set_in_use_message (GdmChooserWidget *widget, ++ const char *message); ++ ++void gdm_chooser_widget_set_separator_position (GdmChooserWidget *widget, ++ GdmChooserWidgetPosition position); ++void gdm_chooser_widget_set_hide_inactive_items (GdmChooserWidget *widget, ++ gboolean should_hide); ++G_END_DECLS ++ ++#endif /* __GDM_CHOOSER_WIDGET_H */ +-- +1.5.3.6 + diff --git a/3-switch-user-chooser-over.patch b/3-switch-user-chooser-over.patch new file mode 100644 index 0000000..5e1d8c2 --- /dev/null +++ b/3-switch-user-chooser-over.patch @@ -0,0 +1,880 @@ +From 1a8e5634ea780869574072ce5d4b33048fb35698 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Thu, 13 Dec 2007 10:12:30 -0500 +Subject: [PATCH] Change user-chooser-widget over to use new chooser widget + +--- + gui/simple-greeter/Makefile.am | 10 + + gui/simple-greeter/gdm-user-chooser-widget.c | 600 ++------------------------ + gui/simple-greeter/gdm-user-chooser-widget.h | 11 +- + 3 files changed, 59 insertions(+), 562 deletions(-) + +diff --git a/gui/simple-greeter/Makefile.am b/gui/simple-greeter/Makefile.am +index a403f24..836c620 100644 +--- a/gui/simple-greeter/Makefile.am ++++ b/gui/simple-greeter/Makefile.am +@@ -45,6 +45,8 @@ test_greeter_login_window_SOURCES = \ + test-greeter-login-window.c \ + gdm-greeter-login-window.h \ + gdm-greeter-login-window.c \ ++ gdm-chooser-widget.h \ ++ gdm-chooser-widget.c \ + gdm-user-chooser-widget.h \ + gdm-user-chooser-widget.c \ + gdm-user-chooser-dialog.h \ +@@ -86,6 +88,8 @@ test_language_chooser_LDADD = \ + + test_session_chooser_SOURCES = \ + test-session-chooser.c \ ++ gdm-chooser-widget.h \ ++ gdm-chooser-widget.c \ + gdm-session-chooser-widget.h \ + gdm-session-chooser-widget.c \ + gdm-session-chooser-dialog.h \ +@@ -98,6 +102,8 @@ test_session_chooser_LDADD = \ + + test_user_chooser_SOURCES = \ + test-user-chooser.c \ ++ gdm-chooser-widget.h \ ++ gdm-chooser-widget.c \ + gdm-user-chooser-widget.h \ + gdm-user-chooser-widget.c \ + gdm-user-chooser-dialog.h \ +@@ -131,6 +137,8 @@ libexec_PROGRAMS = \ + + gdm_simple_greeter_SOURCES = \ + greeter-main.c \ ++ gdm-chooser-widget.h \ ++ gdm-chooser-widget.c \ + gdm-greeter-client.h \ + gdm-greeter-client.c \ + gdm-greeter-session.h \ +@@ -145,6 +153,8 @@ gdm_simple_greeter_SOURCES = \ + gdm-greeter-panel.c \ + gdm-greeter-background.h \ + gdm-greeter-background.c \ ++ gdm-session-chooser-widget.h \ ++ gdm-session-chooser-widget.c \ + gdm-user-chooser-widget.h \ + gdm-user-chooser-widget.c \ + gdm-user-manager.h \ +diff --git a/gui/simple-greeter/gdm-user-chooser-widget.c b/gui/simple-greeter/gdm-user-chooser-widget.c +index e8c0cdc..b8a9bb7 100644 +--- a/gui/simple-greeter/gdm-user-chooser-widget.c ++++ b/gui/simple-greeter/gdm-user-chooser-widget.c +@@ -1,6 +1,7 @@ + /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2007 William Jon McCann ++ * Copyright (C) 2007 Ray Strode + * + * 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 +@@ -47,61 +48,23 @@ enum { + + struct GdmUserChooserWidgetPrivate + { +- GtkWidget *treeview; +- +- GtkTreeModel *real_model; +- GtkTreeModel *filter_model; +- GtkTreeModel *sort_model; +- + GdmUserManager *manager; + + GdkPixbuf *logged_in_pixbuf; +- char *chosen_user; +- gboolean show_only_chosen; +- gboolean show_other_user; +- gboolean show_guest_user; + +- guint populate_id; ++ guint show_other_user : 1; ++ guint show_guest_user : 1; + }; + + enum { + PROP_0, + }; + +-enum { +- USER_CHOSEN, +- LAST_SIGNAL +-}; +- +-static guint signals [LAST_SIGNAL] = { 0, }; +- + static void gdm_user_chooser_widget_class_init (GdmUserChooserWidgetClass *klass); + static void gdm_user_chooser_widget_init (GdmUserChooserWidget *user_chooser_widget); + static void gdm_user_chooser_widget_finalize (GObject *object); + +-G_DEFINE_TYPE (GdmUserChooserWidget, gdm_user_chooser_widget, GTK_TYPE_VBOX) +- +-enum { +- CHOOSER_LIST_PIXBUF_COLUMN = 0, +- CHOOSER_LIST_NAME_COLUMN, +- CHOOSER_LIST_TOOLTIP_COLUMN, +- CHOOSER_LIST_IS_LOGGED_IN_COLUMN, +- CHOOSER_LIST_ID_COLUMN +-}; +- +-void +-gdm_user_chooser_widget_set_show_only_chosen (GdmUserChooserWidget *widget, +- gboolean show_only) +-{ +- g_return_if_fail (GDM_IS_USER_CHOOSER_WIDGET (widget)); +- +- if (widget->priv->show_only_chosen != show_only) { +- widget->priv->show_only_chosen = show_only; +- if (widget->priv->filter_model != NULL) { +- gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (widget->priv->filter_model)); +- } +- } +-} ++G_DEFINE_TYPE (GdmUserChooserWidget, gdm_user_chooser_widget, GDM_TYPE_CHOOSER_WIDGET) + + void + gdm_user_chooser_widget_set_show_other_user (GdmUserChooserWidget *widget, +@@ -111,9 +74,6 @@ gdm_user_chooser_widget_set_show_other_user (GdmUserChooserWidget *widget, + + if (widget->priv->show_other_user != show_user) { + widget->priv->show_other_user = show_user; +- if (widget->priv->filter_model != NULL) { +- gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (widget->priv->filter_model)); +- } + } + } + +@@ -125,122 +85,15 @@ gdm_user_chooser_widget_set_show_guest_user (GdmUserChooserWidget *widget, + + if (widget->priv->show_guest_user != show_user) { + widget->priv->show_guest_user = show_user; +- if (widget->priv->filter_model != NULL) { +- gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (widget->priv->filter_model)); +- } + } + } + + char * + gdm_user_chooser_widget_get_chosen_user_name (GdmUserChooserWidget *widget) + { +- char *user_name; +- + g_return_val_if_fail (GDM_IS_USER_CHOOSER_WIDGET (widget), NULL); + +- user_name = NULL; +- if (widget->priv->chosen_user != NULL) { +- user_name = g_strdup (widget->priv->chosen_user); +- } +- +- return user_name; +-} +- +-static void +-activate_name (GdmUserChooserWidget *widget, +- const char *name) +-{ +- GtkTreeModel *model; +- GtkTreeIter iter; +- GtkTreePath *path; +- +- path = NULL; +- +- model = widget->priv->real_model; +- +- if (name != NULL && gtk_tree_model_get_iter_first (model, &iter)) { +- +- do { +- char *id; +- gboolean found; +- +- id = NULL; +- gtk_tree_model_get (model, +- &iter, +- CHOOSER_LIST_ID_COLUMN, &id, +- -1); +- if (id == NULL) { +- continue; +- } +- +- found = (strcmp (id, name) == 0); +- +- if (found) { +- path = gtk_tree_model_get_path (model, &iter); +- break; +- } +- +- } while (gtk_tree_model_iter_next (model, &iter)); +- } +- +- if (path != NULL) { +- gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (widget->priv->treeview), +- path, +- NULL, +- TRUE, +- 0.5, +- 0.0); +- gtk_tree_view_set_cursor (GTK_TREE_VIEW (widget->priv->treeview), +- path, +- NULL, +- FALSE); +- +- gtk_tree_view_row_activated (GTK_TREE_VIEW (widget->priv->treeview), +- path, +- NULL); +- gtk_tree_path_free (path); +- } +-} +- +-static void +-choose_user_id (GdmUserChooserWidget *widget, +- const char *id) +-{ +- +- g_debug ("GdmUserChooserWidget: Selection changed from:'%s' to:'%s'", +- widget->priv->chosen_user ? widget->priv->chosen_user : "", +- id ? id : ""); +- +- g_free (widget->priv->chosen_user); +- widget->priv->chosen_user = g_strdup (id); +- +- gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (widget->priv->filter_model)); +-} +- +-static void +-choose_selected_user (GdmUserChooserWidget *widget) +-{ +- char *id; +- GtkTreeSelection *selection; +- GtkTreeModel *model; +- GtkTreeIter iter; +- +- id = NULL; +- +- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget->priv->treeview)); +- if (gtk_tree_selection_get_selected (selection, &model, &iter)) { +- gtk_tree_model_get (model, &iter, CHOOSER_LIST_ID_COLUMN, &id, -1); +- } +- +- choose_user_id (widget, id); +-} +- +-static void +-clear_selection (GdmUserChooserWidget *widget) +-{ +- GtkTreeSelection *selection; +- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget->priv->treeview)); +- gtk_tree_selection_unselect_all (selection); ++ return gdm_chooser_widget_get_active_item (GDM_CHOOSER_WIDGET (widget)); + } + + void +@@ -249,14 +102,18 @@ gdm_user_chooser_widget_set_chosen_user_name (GdmUserChooserWidget *widget, + { + g_return_if_fail (GDM_IS_USER_CHOOSER_WIDGET (widget)); + +- if (name == NULL) { +- clear_selection (widget); +- choose_user_id (widget, NULL); +- } else { +- activate_name (widget, name); +- } ++ gdm_chooser_widget_set_active_item (GDM_CHOOSER_WIDGET (widget), name); + } + ++void ++gdm_user_chooser_widget_set_show_only_chosen (GdmUserChooserWidget *widget, ++ gboolean show_only) { ++ g_return_if_fail (GDM_IS_USER_CHOOSER_WIDGET (widget)); ++ ++ gdm_chooser_widget_set_hide_inactive_items (GDM_CHOOSER_WIDGET (widget), ++ show_only); ++ ++} + static void + gdm_user_chooser_widget_set_property (GObject *object, + guint prop_id, +@@ -315,55 +172,22 @@ gdm_user_chooser_widget_dispose (GObject *object) + + widget = GDM_USER_CHOOSER_WIDGET (object); + +- g_free (widget->priv->chosen_user); +- widget->priv->chosen_user = NULL; +- + G_OBJECT_CLASS (gdm_user_chooser_widget_parent_class)->dispose (object); + } + + static void + gdm_user_chooser_widget_class_init (GdmUserChooserWidgetClass *klass) + { +- GObjectClass *object_class = G_OBJECT_CLASS (klass); +- ++ GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->get_property = gdm_user_chooser_widget_get_property; + object_class->set_property = gdm_user_chooser_widget_set_property; + object_class->constructor = gdm_user_chooser_widget_constructor; + object_class->dispose = gdm_user_chooser_widget_dispose; + object_class->finalize = gdm_user_chooser_widget_finalize; + +- signals [USER_CHOSEN] = g_signal_new ("user-chosen", +- G_TYPE_FROM_CLASS (object_class), +- G_SIGNAL_RUN_LAST, +- G_STRUCT_OFFSET (GdmUserChooserWidgetClass, user_chosen), +- NULL, +- NULL, +- g_cclosure_marshal_VOID__VOID, +- G_TYPE_NONE, +- 0); +- + g_type_class_add_private (klass, sizeof (GdmUserChooserWidgetPrivate)); + } + +-static void +-on_selection_changed (GtkTreeSelection *selection, +- GdmUserChooserWidget *widget) +-{ +-} +- +-static void +-on_row_activated (GtkTreeView *tree_view, +- GtkTreePath *tree_path, +- GtkTreeViewColumn *tree_column, +- GdmUserChooserWidget *widget) +-{ +- choose_selected_user (widget); +- +- g_signal_emit (widget, signals[USER_CHOSEN], 0); +- +- clear_selection (widget); +-} +- + static GdkPixbuf * + get_pixbuf_for_user (GdmUserChooserWidget *widget, + const char *username) +@@ -394,107 +218,37 @@ get_logged_in_pixbuf (GdmUserChooserWidget *widget) + } + + static gboolean +-populate_model (GdmUserChooserWidget *widget) ++add_special_users (GdmUserChooserWidget *widget) + { +- GtkTreeIter iter; + GdkPixbuf *pixbuf; + + widget->priv->logged_in_pixbuf = get_logged_in_pixbuf (widget); + + pixbuf = get_pixbuf_for_user (widget, NULL); + +- /* Add some fake entries */ +- gtk_list_store_append (GTK_LIST_STORE (widget->priv->real_model), &iter); +- gtk_list_store_set (GTK_LIST_STORE (widget->priv->real_model), &iter, +- CHOOSER_LIST_PIXBUF_COLUMN, pixbuf, +- CHOOSER_LIST_NAME_COLUMN, _("Other..."), +- CHOOSER_LIST_TOOLTIP_COLUMN, _("Choose a different account"), +- CHOOSER_LIST_IS_LOGGED_IN_COLUMN, FALSE, +- CHOOSER_LIST_ID_COLUMN, GDM_USER_CHOOSER_USER_OTHER, +- -1); +- +- gtk_list_store_append (GTK_LIST_STORE (widget->priv->real_model), &iter); +- gtk_list_store_set (GTK_LIST_STORE (widget->priv->real_model), &iter, +- CHOOSER_LIST_PIXBUF_COLUMN, pixbuf, +- CHOOSER_LIST_NAME_COLUMN, _("Guest"), +- CHOOSER_LIST_TOOLTIP_COLUMN, _("Login as a temporary guest"), +- CHOOSER_LIST_IS_LOGGED_IN_COLUMN, FALSE, +- CHOOSER_LIST_ID_COLUMN, GDM_USER_CHOOSER_USER_GUEST, +- -1); +- ++ gdm_chooser_widget_add_item (GDM_CHOOSER_WIDGET (widget), ++ GDM_USER_CHOOSER_USER_OTHER, ++ pixbuf, _("Other..."), ++ _("Choose a different account"), FALSE, ++ TRUE); ++ ++ gdm_chooser_widget_add_item (GDM_CHOOSER_WIDGET (widget), ++ GDM_USER_CHOOSER_USER_GUEST, ++ pixbuf, _("Guest"), ++ _("Login as a temporary guest"), FALSE, ++ TRUE); + if (pixbuf != NULL) { + g_object_unref (pixbuf); + } + +- widget->priv->populate_id = 0; + return FALSE; + } + +-static int +-compare_user_names (char *name_a, +- char *name_b, +- char *id_a, +- char *id_b) +-{ +- +- if (id_a == NULL) { +- return 1; +- } else if (id_b == NULL) { +- return -1; +- } +- +- if (strcmp (id_a, "__other") == 0) { +- return 1; +- } else if (strcmp (id_b, "__other") == 0) { +- return -1; +- } else if (strcmp (id_a, "__guest") == 0) { +- return 1; +- } else if (strcmp (id_b, "__guest") == 0) { +- return -1; +- } +- +- if (name_a == NULL) { +- return 1; +- } else if (name_b == NULL) { +- return -1; +- } +- +- return g_utf8_collate (name_a, name_b); +-} +- +-static int +-compare_user (GtkTreeModel *model, +- GtkTreeIter *a, +- GtkTreeIter *b, +- gpointer user_data) +-{ +- char *name_a; +- char *name_b; +- char *id_a; +- char *id_b; +- int result; +- +- gtk_tree_model_get (model, a, CHOOSER_LIST_NAME_COLUMN, &name_a, -1); +- gtk_tree_model_get (model, b, CHOOSER_LIST_NAME_COLUMN, &name_b, -1); +- gtk_tree_model_get (model, a, CHOOSER_LIST_ID_COLUMN, &id_a, -1); +- gtk_tree_model_get (model, b, CHOOSER_LIST_ID_COLUMN, &id_b, -1); +- +- result = compare_user_names (name_a, name_b, id_a, id_b); +- +- g_free (name_a); +- g_free (name_b); +- g_free (id_a); +- g_free (id_b); +- +- return result; +-} +- + static void + on_user_added (GdmUserManager *manager, + GdmUser *user, + GdmUserChooserWidget *widget) + { +- GtkTreeIter iter; + GdkPixbuf *pixbuf; + char *tooltip; + +@@ -502,18 +256,13 @@ on_user_added (GdmUserManager *manager, + + pixbuf = gdm_user_render_icon (user, GTK_WIDGET (widget), ICON_SIZE); + +- tooltip = g_strdup_printf ("%s: %s", +- _("Short Name"), ++ tooltip = g_strdup_printf (_("Log in as %s"), + gdm_user_get_user_name (user)); + +- gtk_list_store_append (GTK_LIST_STORE (widget->priv->real_model), &iter); +- gtk_list_store_set (GTK_LIST_STORE (widget->priv->real_model), &iter, +- CHOOSER_LIST_PIXBUF_COLUMN, pixbuf, +- CHOOSER_LIST_NAME_COLUMN, gdm_user_get_real_name (user), +- CHOOSER_LIST_TOOLTIP_COLUMN, tooltip, +- CHOOSER_LIST_IS_LOGGED_IN_COLUMN, gdm_user_get_num_sessions (user) > 0, +- CHOOSER_LIST_ID_COLUMN, gdm_user_get_user_name (user), +- -1); ++ gdm_chooser_widget_add_item (GDM_CHOOSER_WIDGET (widget), ++ gdm_user_get_user_name (user), ++ pixbuf, gdm_user_get_real_name (user), ++ tooltip, FALSE, FALSE); + g_free (tooltip); + + if (pixbuf != NULL) { +@@ -526,41 +275,14 @@ on_user_removed (GdmUserManager *manager, + GdmUser *user, + GdmUserChooserWidget *widget) + { +- GtkTreeIter iter; +- gboolean found; + const char *user_name; + + g_debug ("GdmUserChooserWidget: User removed: %s", gdm_user_get_user_name (user)); + +- found = FALSE; +- + user_name = gdm_user_get_user_name (user); + +- if (gtk_tree_model_get_iter_first (widget->priv->real_model, &iter)) { +- +- do { +- char *id; +- +- id = NULL; +- gtk_tree_model_get (widget->priv->real_model, +- &iter, +- CHOOSER_LIST_ID_COLUMN, &id, +- -1); +- if (id == NULL) { +- continue; +- } +- +- found = (strcmp (id, user_name) == 0); +- +- if (found) { +- break; +- } +- +- } while (gtk_tree_model_iter_next (widget->priv->real_model, &iter)); +- } +- if (found) { +- gtk_list_store_remove (GTK_LIST_STORE (widget->priv->real_model), &iter); +- } ++ gdm_chooser_widget_remove_item (GDM_CHOOSER_WIDGET (widget), ++ user_name); + } + + static void +@@ -568,162 +290,28 @@ on_user_is_logged_in_changed (GdmUserManager *manager, + GdmUser *user, + GdmUserChooserWidget *widget) + { +- GtkTreeIter iter; +- gboolean found; + const char *user_name; + gboolean is_logged_in; + + g_debug ("GdmUserChooserWidget: User logged in changed: %s", gdm_user_get_user_name (user)); + +- found = FALSE; +- + user_name = gdm_user_get_user_name (user); + is_logged_in = gdm_user_get_num_sessions (user) > 0; + +- if (gtk_tree_model_get_iter_first (widget->priv->real_model, &iter)) { +- +- do { +- char *id; +- +- id = NULL; +- gtk_tree_model_get (widget->priv->real_model, +- &iter, +- CHOOSER_LIST_ID_COLUMN, &id, +- -1); +- if (id == NULL) { +- continue; +- } +- +- found = (strcmp (id, user_name) == 0); +- +- if (found) { +- break; +- } +- +- } while (gtk_tree_model_iter_next (widget->priv->real_model, &iter)); +- } +- +- if (found) { +- gtk_list_store_set (GTK_LIST_STORE (widget->priv->real_model), +- &iter, +- CHOOSER_LIST_IS_LOGGED_IN_COLUMN, is_logged_in, +- -1); +- } +-} +- +-static gboolean +-user_visible_cb (GtkTreeModel *model, +- GtkTreeIter *iter, +- GdmUserChooserWidget *widget) +-{ +- char *id; +- gboolean ret; +- +- ret = FALSE; +- +- id = NULL; +- gtk_tree_model_get (model, iter, CHOOSER_LIST_ID_COLUMN, &id, -1); +- if (id == NULL) { +- goto out; +- } +- +- /* if a user is chosen */ +- if (widget->priv->chosen_user != NULL +- && widget->priv->show_only_chosen) { +- +- ret = (strcmp (id, widget->priv->chosen_user) == 0); +- goto out; +- } +- +- if (! widget->priv->show_other_user +- && strcmp (id, GDM_USER_CHOOSER_USER_OTHER) == 0) { +- ret = FALSE; +- goto out; +- } +- if (! widget->priv->show_guest_user +- && strcmp (id, GDM_USER_CHOOSER_USER_GUEST) == 0) { +- ret = FALSE; +- goto out; +- } +- +- ret = TRUE; +- +- out: +- g_free (id); +- +- return ret; +-} +- +-static void +-name_cell_data_func (GtkTreeViewColumn *tree_column, +- GtkCellRenderer *cell, +- GtkTreeModel *model, +- GtkTreeIter *iter, +- GdmUserChooserWidget *widget) +-{ +- gboolean logged_in; +- char *name; +- char *markup; +- +- name = NULL; +- gtk_tree_model_get (model, +- iter, +- CHOOSER_LIST_IS_LOGGED_IN_COLUMN, &logged_in, +- CHOOSER_LIST_NAME_COLUMN, &name, +- -1); +- +- if (logged_in) { +- markup = g_strdup_printf ("%s\n%s", +- name, +- _("Currently logged in")); +- } else { +- markup = g_strdup_printf ("%s", name); +- } +- +- g_object_set (cell, +- "markup", markup, +- NULL); +- +- g_free (markup); +- g_free (name); +-} +- +-static void +-check_cell_data_func (GtkTreeViewColumn *tree_column, +- GtkCellRenderer *cell, +- GtkTreeModel *model, +- GtkTreeIter *iter, +- GdmUserChooserWidget *widget) +-{ +- gboolean logged_in; +- GdkPixbuf *pixbuf; +- +- gtk_tree_model_get (model, +- iter, +- CHOOSER_LIST_IS_LOGGED_IN_COLUMN, &logged_in, +- -1); +- +- if (logged_in) { +- pixbuf = widget->priv->logged_in_pixbuf; +- } else { +- pixbuf = NULL; +- } +- +- g_object_set (cell, +- "pixbuf", pixbuf, +- NULL); ++ gdm_chooser_widget_set_item_in_use (GDM_CHOOSER_WIDGET (widget), ++ user_name, is_logged_in); + } + + static void + gdm_user_chooser_widget_init (GdmUserChooserWidget *widget) + { +- GtkWidget *scrolled; +- GtkTreeViewColumn *column; +- GtkTreeSelection *selection; +- GtkCellRenderer *renderer; +- + widget->priv = GDM_USER_CHOOSER_WIDGET_GET_PRIVATE (widget); + ++ gdm_chooser_widget_set_separator_position (GDM_CHOOSER_WIDGET (widget), ++ GDM_CHOOSER_WIDGET_POSITION_BOTTOM); ++ gdm_chooser_widget_set_in_use_message (GDM_CHOOSER_WIDGET (widget), ++ _("Currently logged in")); ++ + widget->priv->manager = gdm_user_manager_ref_default (); + g_signal_connect (widget->priv->manager, + "user-added", +@@ -738,103 +326,7 @@ gdm_user_chooser_widget_init (GdmUserChooserWidget *widget) + G_CALLBACK (on_user_is_logged_in_changed), + widget); + +- scrolled = gtk_scrolled_window_new (NULL, NULL); +- gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled), +- GTK_SHADOW_IN); +- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), +- GTK_POLICY_NEVER, +- GTK_POLICY_AUTOMATIC); +- gtk_box_pack_start (GTK_BOX (widget), scrolled, TRUE, TRUE, 0); +- +- widget->priv->treeview = gtk_tree_view_new (); +- gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (widget->priv->treeview), FALSE); +- +- g_signal_connect (widget->priv->treeview, +- "row-activated", +- G_CALLBACK (on_row_activated), +- widget); +- gtk_container_add (GTK_CONTAINER (scrolled), widget->priv->treeview); +- +- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget->priv->treeview)); +- gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); +- g_signal_connect (selection, "changed", +- G_CALLBACK (on_selection_changed), +- widget); +- +- widget->priv->real_model = (GtkTreeModel *)gtk_list_store_new (5, +- GDK_TYPE_PIXBUF, +- G_TYPE_STRING, +- G_TYPE_STRING, +- G_TYPE_BOOLEAN, +- G_TYPE_STRING); +- +- widget->priv->filter_model = gtk_tree_model_filter_new (widget->priv->real_model, NULL); +- +- gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (widget->priv->filter_model), +- (GtkTreeModelFilterVisibleFunc) user_visible_cb, +- widget, +- NULL); +- +- widget->priv->sort_model = gtk_tree_model_sort_new_with_model (widget->priv->filter_model); +- +- gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (widget->priv->sort_model), +- CHOOSER_LIST_NAME_COLUMN, +- compare_user, +- NULL, NULL); +- +- gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (widget->priv->sort_model), +- CHOOSER_LIST_NAME_COLUMN, +- GTK_SORT_ASCENDING); +- +- gtk_tree_view_set_model (GTK_TREE_VIEW (widget->priv->treeview), widget->priv->sort_model); +- +- /* CHECK COLUMN */ +- renderer = gtk_cell_renderer_pixbuf_new (); +- column = gtk_tree_view_column_new (); +- gtk_tree_view_column_pack_start (column, renderer, FALSE); +- gtk_tree_view_append_column (GTK_TREE_VIEW (widget->priv->treeview), column); +- gtk_tree_view_column_set_cell_data_func (column, +- renderer, +- (GtkTreeCellDataFunc) check_cell_data_func, +- widget, +- NULL); +- g_object_set (renderer, +- "width", 96, +- "yalign", 0.5, +- "xalign", 0.5, +- NULL); +- +- /* FACE COLUMN */ +- renderer = gtk_cell_renderer_pixbuf_new (); +- column = gtk_tree_view_column_new (); +- gtk_tree_view_column_pack_start (column, renderer, FALSE); +- gtk_tree_view_append_column (GTK_TREE_VIEW (widget->priv->treeview), column); +- +- gtk_tree_view_column_set_attributes (column, +- renderer, +- "pixbuf", CHOOSER_LIST_PIXBUF_COLUMN, +- NULL); +- +- g_object_set (renderer, +- "width", 64, +- "yalign", 0.5, +- "xalign", 1.0, +- NULL); +- +- /* NAME COLUMN */ +- renderer = gtk_cell_renderer_text_new (); +- column = gtk_tree_view_column_new (); +- gtk_tree_view_column_pack_start (column, renderer, FALSE); +- gtk_tree_view_append_column (GTK_TREE_VIEW (widget->priv->treeview), column); +- gtk_tree_view_column_set_cell_data_func (column, +- renderer, +- (GtkTreeCellDataFunc) name_cell_data_func, +- widget, +- NULL); +- +- gtk_tree_view_set_tooltip_column (GTK_TREE_VIEW (widget->priv->treeview), CHOOSER_LIST_TOOLTIP_COLUMN); +- +- widget->priv->populate_id = g_idle_add ((GSourceFunc)populate_model, widget); ++ add_special_users (widget); + } + + static void +@@ -849,10 +341,6 @@ gdm_user_chooser_widget_finalize (GObject *object) + + g_return_if_fail (widget->priv != NULL); + +- if (widget->priv->populate_id > 0) { +- g_source_remove (widget->priv->populate_id); +- } +- + G_OBJECT_CLASS (gdm_user_chooser_widget_parent_class)->finalize (object); + } + +@@ -862,6 +350,8 @@ gdm_user_chooser_widget_new (void) + GObject *object; + + object = g_object_new (GDM_TYPE_USER_CHOOSER_WIDGET, ++ "inactive-text", _("_Users:"), ++ "active-text", _("_User:"), + NULL); + + return GTK_WIDGET (object); +diff --git a/gui/simple-greeter/gdm-user-chooser-widget.h b/gui/simple-greeter/gdm-user-chooser-widget.h +index 9c1ef6f..a117fb3 100644 +--- a/gui/simple-greeter/gdm-user-chooser-widget.h ++++ b/gui/simple-greeter/gdm-user-chooser-widget.h +@@ -22,7 +22,8 @@ + #define __GDM_USER_CHOOSER_WIDGET_H + + #include +-#include ++ ++#include "gdm-chooser-widget.h" + + G_BEGIN_DECLS + +@@ -37,16 +38,13 @@ typedef struct GdmUserChooserWidgetPrivate GdmUserChooserWidgetPrivate; + + typedef struct + { +- GtkVBox parent; ++ GdmChooserWidget parent; + GdmUserChooserWidgetPrivate *priv; + } GdmUserChooserWidget; + + typedef struct + { +- GtkVBoxClass parent_class; +- +- /* signals */ +- void (* user_chosen) (GdmUserChooserWidget *widget); ++ GdmChooserWidgetClass parent_class; + } GdmUserChooserWidgetClass; + + #define GDM_USER_CHOOSER_USER_OTHER "__other" +@@ -64,7 +62,6 @@ void gdm_user_chooser_widget_set_show_other_user (GdmUs + gboolean show_other); + void gdm_user_chooser_widget_set_show_guest_user (GdmUserChooserWidget *widget, + gboolean show_other); +- + G_END_DECLS + + #endif /* __GDM_USER_CHOOSER_WIDGET_H */ +-- +1.5.3.6 + diff --git a/4-switch-session-chooser-over.patch b/4-switch-session-chooser-over.patch new file mode 100644 index 0000000..9ed3a0c --- /dev/null +++ b/4-switch-session-chooser-over.patch @@ -0,0 +1,522 @@ +From 62276dc527e60a27f951cf73ad8de3fb1c8ced8a Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Thu, 13 Dec 2007 10:14:33 -0500 +Subject: [PATCH] Change session-chooser-widget over to use new chooser widget + +--- + gui/simple-greeter/gdm-session-chooser-widget.c | 352 +++-------------------- + gui/simple-greeter/gdm-session-chooser-widget.h | 15 +- + 2 files changed, 50 insertions(+), 317 deletions(-) + +diff --git a/gui/simple-greeter/gdm-session-chooser-widget.c b/gui/simple-greeter/gdm-session-chooser-widget.c +index 7763da7..849be94 100644 +--- a/gui/simple-greeter/gdm-session-chooser-widget.c ++++ b/gui/simple-greeter/gdm-session-chooser-widget.c +@@ -1,6 +1,7 @@ + /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2007 William Jon McCann ++ * Copyright (C) 2007 Ray Strode + * + * 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 +@@ -34,6 +35,7 @@ + #include + + #include "gdm-session-chooser-widget.h" ++#include "gdm-chooser-widget.h" + + enum { + DESKTOP_ENTRY_NO_DISPLAY = 1 << 0, +@@ -54,34 +56,18 @@ typedef struct _GdmChooserSession { + + struct GdmSessionChooserWidgetPrivate + { +- GtkWidget *treeview; +- + GHashTable *available_sessions; +- char *current_session; + }; + + enum { + PROP_0, + }; + +-enum { +- SESSION_ACTIVATED, +- LAST_SIGNAL +-}; +- +-static guint signals [LAST_SIGNAL] = { 0, }; +- + static void gdm_session_chooser_widget_class_init (GdmSessionChooserWidgetClass *klass); + static void gdm_session_chooser_widget_init (GdmSessionChooserWidget *session_chooser_widget); + static void gdm_session_chooser_widget_finalize (GObject *object); + +-G_DEFINE_TYPE (GdmSessionChooserWidget, gdm_session_chooser_widget, GTK_TYPE_VBOX) +- +-enum { +- CHOOSER_LIST_NAME_COLUMN = 0, +- CHOOSER_LIST_COMMENT_COLUMN, +- CHOOSER_LIST_ID_COLUMN +-}; ++G_DEFINE_TYPE (GdmSessionChooserWidget, gdm_session_chooser_widget, GDM_TYPE_CHOOSER_WIDGET) + + static void + chooser_session_free (GdmChooserSession *session) +@@ -101,89 +87,28 @@ chooser_session_free (GdmChooserSession *session) + char * + gdm_session_chooser_widget_get_current_session_name (GdmSessionChooserWidget *widget) + { +- char *session_name; +- + g_return_val_if_fail (GDM_IS_SESSION_CHOOSER_WIDGET (widget), NULL); +- +- session_name = NULL; +- if (widget->priv->current_session != NULL) { +- session_name = g_strdup (widget->priv->current_session); +- } +- +- return session_name; ++ return gdm_chooser_widget_get_active_item (GDM_CHOOSER_WIDGET (widget)); + } + +-static void +-select_name (GdmSessionChooserWidget *widget, +- const char *name) ++void ++gdm_session_chooser_widget_set_current_session_name (GdmSessionChooserWidget *widget, ++ const char *name) + { +- GtkTreeModel *model; +- GtkTreeIter iter; +- GtkTreePath *path; +- +- path = NULL; +- +- model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget->priv->treeview)); +- +- if (name != NULL && gtk_tree_model_get_iter_first (model, &iter)) { +- +- do { +- GdmChooserSession *session; +- char *id; +- gboolean found; +- +- session = NULL; +- id = NULL; +- gtk_tree_model_get (model, +- &iter, +- CHOOSER_LIST_ID_COLUMN, &id, +- -1); +- if (id != NULL) { +- session = g_hash_table_lookup (widget->priv->available_sessions, id); +- g_free (id); +- } +- +- found = (session != NULL +- && session->filename != NULL +- && strcmp (session->filename, name) == 0); +- +- if (found) { +- path = gtk_tree_model_get_path (model, &iter); +- break; +- } +- +- } while (gtk_tree_model_iter_next (model, &iter)); +- } ++ g_return_if_fail (GDM_IS_SESSION_CHOOSER_WIDGET (widget)); + +- if (path != NULL) { +- gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (widget->priv->treeview), +- path, +- gtk_tree_view_get_column (GTK_TREE_VIEW (widget->priv->treeview), 0), +- TRUE, 0.5, 0.0); +- gtk_tree_view_set_cursor (GTK_TREE_VIEW (widget->priv->treeview), +- path, +- NULL, +- FALSE); +- +- gtk_tree_path_free (path); +- } ++ gdm_chooser_widget_set_active_item (GDM_CHOOSER_WIDGET (widget), ++ name); + } + + void +-gdm_session_chooser_widget_set_current_session_name (GdmSessionChooserWidget *widget, +- const char *name) ++gdm_session_chooser_widget_set_show_only_chosen (GdmSessionChooserWidget *widget, ++ gboolean show_only) + { +- GtkTreeSelection *selection; +- + g_return_if_fail (GDM_IS_SESSION_CHOOSER_WIDGET (widget)); + +- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget->priv->treeview)); +- +- if (name == NULL) { +- gtk_tree_selection_unselect_all (selection); +- } else { +- select_name (widget, name); +- } ++ gdm_chooser_widget_set_hide_inactive_items (GDM_CHOOSER_WIDGET (widget), ++ show_only); + } + + static void +@@ -249,9 +174,6 @@ gdm_session_chooser_widget_dispose (GObject *object) + widget->priv->available_sessions = NULL; + } + +- g_free (widget->priv->current_session); +- widget->priv->current_session = NULL; +- + G_OBJECT_CLASS (gdm_session_chooser_widget_parent_class)->dispose (object); + } + +@@ -266,39 +188,9 @@ gdm_session_chooser_widget_class_init (GdmSessionChooserWidgetClass *klass) + object_class->dispose = gdm_session_chooser_widget_dispose; + object_class->finalize = gdm_session_chooser_widget_finalize; + +- signals [SESSION_ACTIVATED] = g_signal_new ("session-activated", +- G_TYPE_FROM_CLASS (object_class), +- G_SIGNAL_RUN_LAST, +- G_STRUCT_OFFSET (GdmSessionChooserWidgetClass, session_activated), +- NULL, +- NULL, +- g_cclosure_marshal_VOID__VOID, +- G_TYPE_NONE, +- 0); +- + g_type_class_add_private (klass, sizeof (GdmSessionChooserWidgetPrivate)); + } + +-static void +-on_session_selected (GtkTreeSelection *selection, +- GdmSessionChooserWidget *widget) +-{ +- GtkTreeModel *model = NULL; +- GtkTreeIter iter = {0}; +- char *id; +- +- id = NULL; +- +- if (gtk_tree_selection_get_selected (selection, &model, &iter)) { +- gtk_tree_model_get (model, &iter, CHOOSER_LIST_ID_COLUMN, &id, -1); +- } +- +- g_free (widget->priv->current_session); +- widget->priv->current_session = g_strdup (id); +- +- g_free (id); +-} +- + /* adapted from gnome-menus desktop-entries.c */ + static guint + get_flags_from_key_file (GKeyFile *key_file, +@@ -460,21 +352,13 @@ collect_sessions (GdmSessionChooserWidget *widget) + } + + static void +-on_row_activated (GtkTreeView *tree_view, +- GtkTreePath *tree_path, +- GtkTreeViewColumn *tree_column, +- GdmSessionChooserWidget *widget) +-{ +- g_signal_emit (widget, signals[SESSION_ACTIVATED], 0); +-} +- +-static void +-add_session_to_model (const char *name, +- GdmChooserSession *session, +- GdmSessionChooserWidget *widget) ++add_session (const char *name, ++ GdmChooserSession *session, ++ GdmSessionChooserWidget *widget) + { +- GtkTreeModel *model; +- GtkTreeIter iter; ++ g_assert (name != NULL); ++ g_assert (session != NULL); ++ g_assert (GDM_IS_SESSION_CHOOSER_WIDGET (widget)); + + if (session->flags & DESKTOP_ENTRY_NO_DISPLAY + || session->flags & DESKTOP_ENTRY_HIDDEN +@@ -483,197 +367,43 @@ add_session_to_model (const char *name, + g_debug ("Not adding session to list: %s", session->filename); + } + +- model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget->priv->treeview)); +- +- gtk_list_store_append (GTK_LIST_STORE (model), &iter); +- gtk_list_store_set (GTK_LIST_STORE (model), +- &iter, +- CHOOSER_LIST_NAME_COLUMN, session->translated_name, +- CHOOSER_LIST_COMMENT_COLUMN, session->translated_comment, +- CHOOSER_LIST_ID_COLUMN, name, +- -1); ++ gdm_chooser_widget_add_item (GDM_CHOOSER_WIDGET (widget), name, ++ NULL, session->translated_name, ++ session->translated_comment, FALSE, FALSE); + } + + static void +-populate_model (GdmSessionChooserWidget *widget, +- GtkTreeModel *model) ++add_available_sessions (GdmSessionChooserWidget *widget) + { +- GtkTreeIter iter; +- +- /* Add some fake entries */ +- gtk_list_store_append (GTK_LIST_STORE (model), &iter); +- gtk_list_store_set (GTK_LIST_STORE (model), &iter, +- CHOOSER_LIST_NAME_COLUMN, _("Previous Session"), +- CHOOSER_LIST_ID_COLUMN, "__previous-session", +- -1); +- +- gtk_list_store_append (GTK_LIST_STORE (model), &iter); +- gtk_list_store_set (GTK_LIST_STORE (model), &iter, +- CHOOSER_LIST_NAME_COLUMN, _("System Default"), +- CHOOSER_LIST_ID_COLUMN, "__default-session", +- -1); +- +- gtk_list_store_append (GTK_LIST_STORE (model), &iter); +- gtk_list_store_set (GTK_LIST_STORE (model), &iter, +- CHOOSER_LIST_NAME_COLUMN, NULL, +- CHOOSER_LIST_ID_COLUMN, "__separator", +- -1); ++ gdm_chooser_widget_add_item (GDM_CHOOSER_WIDGET (widget), ++ GDM_SESSION_CHOOSER_SESSION_PREVIOUS, ++ NULL, _("Default"), ++ _("Login with the same session as " ++ "last time."), ++ FALSE, TRUE); ++ gdm_chooser_widget_add_item (GDM_CHOOSER_WIDGET (widget), ++ GDM_SESSION_CHOOSER_SESSION_DEFAULT, ++ NULL, _("Legacy"), ++ _("Login based on preset legacy configuration"), ++ FALSE, TRUE); + + g_hash_table_foreach (widget->priv->available_sessions, +- (GHFunc)add_session_to_model, ++ (GHFunc) add_session, + widget); + } + +-static gboolean +-separator_func (GtkTreeModel *model, +- GtkTreeIter *iter, +- gpointer data) +-{ +- int column = GPOINTER_TO_INT (data); +- char *text; +- +- gtk_tree_model_get (model, iter, column, &text, -1); +- +- if (text != NULL && strcmp (text, "__separator") == 0) { +- return TRUE; +- } +- +- g_free (text); +- +- return FALSE; +-} +- +-static int +-compare_session_names (char *name_a, +- char *name_b, +- char *id_a, +- char *id_b) +-{ +- +- if (id_a == NULL) { +- return 1; +- } else if (id_b == NULL) { +- return -1; +- } +- +- if (strcmp (id_a, "__previous-session") == 0) { +- return -1; +- } else if (strcmp (id_b, "__previous-session") == 0) { +- return 1; +- } else if (strcmp (id_a, "__default-session") == 0) { +- return -1; +- } else if (strcmp (id_b, "__default-session") == 0) { +- return 1; +- } else if (strcmp (id_a, "__separator") == 0) { +- return -1; +- } else if (strcmp (id_b, "__separator") == 0) { +- return 1; +- } +- +- if (name_a == NULL) { +- return 1; +- } else if (name_b == NULL) { +- return -1; +- } +- +- return g_utf8_collate (name_a, name_b); +-} +- +-static int +-compare_session (GtkTreeModel *model, +- GtkTreeIter *a, +- GtkTreeIter *b, +- gpointer user_data) +-{ +- char *name_a; +- char *name_b; +- char *id_a; +- char *id_b; +- int result; +- +- gtk_tree_model_get (model, a, CHOOSER_LIST_NAME_COLUMN, &name_a, -1); +- gtk_tree_model_get (model, b, CHOOSER_LIST_NAME_COLUMN, &name_b, -1); +- gtk_tree_model_get (model, a, CHOOSER_LIST_ID_COLUMN, &id_a, -1); +- gtk_tree_model_get (model, b, CHOOSER_LIST_ID_COLUMN, &id_b, -1); +- +- result = compare_session_names (name_a, name_b, id_a, id_b); +- +- g_free (name_a); +- g_free (name_b); +- g_free (id_a); +- g_free (id_b); +- +- return result; +-} +- + static void + gdm_session_chooser_widget_init (GdmSessionChooserWidget *widget) + { +- GtkWidget *scrolled; +- GtkTreeSelection *selection; +- GtkTreeViewColumn *column; +- GtkTreeModel *model; +- + widget->priv = GDM_SESSION_CHOOSER_WIDGET_GET_PRIVATE (widget); + ++ gdm_chooser_widget_set_separator_position (GDM_CHOOSER_WIDGET (widget), ++ GDM_CHOOSER_WIDGET_POSITION_TOP); + widget->priv->available_sessions = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify)chooser_session_free); + +- scrolled = gtk_scrolled_window_new (NULL, NULL); +- gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled), +- GTK_SHADOW_IN); +- gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled), +- GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC); +- gtk_box_pack_start (GTK_BOX (widget), scrolled, TRUE, TRUE, 0); +- +- widget->priv->treeview = gtk_tree_view_new (); +- gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (widget->priv->treeview), FALSE); +- g_signal_connect (widget->priv->treeview, +- "row-activated", +- G_CALLBACK (on_row_activated), +- widget); +- gtk_container_add (GTK_CONTAINER (scrolled), widget->priv->treeview); +- +- selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget->priv->treeview)); +- gtk_tree_selection_set_mode (selection, GTK_SELECTION_SINGLE); +- g_signal_connect (selection, "changed", +- G_CALLBACK (on_session_selected), +- widget); +- +- model = (GtkTreeModel *)gtk_list_store_new (3, +- G_TYPE_STRING, +- G_TYPE_STRING, +- G_TYPE_STRING); +- gtk_tree_view_set_model (GTK_TREE_VIEW (widget->priv->treeview), model); +- +- column = gtk_tree_view_column_new_with_attributes ("Session", +- gtk_cell_renderer_text_new (), +- "text", CHOOSER_LIST_NAME_COLUMN, +- NULL); +- gtk_tree_view_append_column (GTK_TREE_VIEW (widget->priv->treeview), column); +- +- column = gtk_tree_view_column_new_with_attributes ("Comment", +- gtk_cell_renderer_text_new (), +- "text", CHOOSER_LIST_COMMENT_COLUMN, +- NULL); +- gtk_tree_view_append_column (GTK_TREE_VIEW (widget->priv->treeview), column); +- +- gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (model), +- CHOOSER_LIST_NAME_COLUMN, +- compare_session, +- NULL, NULL); +- +- gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), +- CHOOSER_LIST_NAME_COLUMN, +- GTK_SORT_ASCENDING); +- +- gtk_tree_view_set_row_separator_func (GTK_TREE_VIEW (widget->priv->treeview), +- separator_func, +- GINT_TO_POINTER (CHOOSER_LIST_ID_COLUMN), +- NULL); +- + collect_sessions (widget); + +- populate_model (widget, model); ++ add_available_sessions (widget); + } + + static void +@@ -696,7 +426,9 @@ gdm_session_chooser_widget_new (void) + { + GObject *object; + +- object = g_object_new (GDM_TYPE_SESSION_CHOOSER_WIDGET, ++ object = g_object_new (GDM_TYPE_SESSION_CHOOSER_WIDGET, ++ "inactive-text", _("_Sessions:"), ++ "active-text", _("_Session:"), + NULL); + + return GTK_WIDGET (object); +diff --git a/gui/simple-greeter/gdm-session-chooser-widget.h b/gui/simple-greeter/gdm-session-chooser-widget.h +index ec32b23..63ea466 100644 +--- a/gui/simple-greeter/gdm-session-chooser-widget.h ++++ b/gui/simple-greeter/gdm-session-chooser-widget.h +@@ -22,7 +22,7 @@ + #define __GDM_SESSION_CHOOSER_WIDGET_H + + #include +-#include ++#include "gdm-chooser-widget.h" + + G_BEGIN_DECLS + +@@ -37,25 +37,26 @@ typedef struct GdmSessionChooserWidgetPrivate GdmSessionChooserWidgetPrivate; + + typedef struct + { +- GtkVBox parent; ++ GdmChooserWidget parent; + GdmSessionChooserWidgetPrivate *priv; + } GdmSessionChooserWidget; + + typedef struct + { +- GtkVBoxClass parent_class; +- +- /* signals */ +- void (* session_activated) (GdmSessionChooserWidget *widget); ++ GdmChooserWidgetClass parent_class; + } GdmSessionChooserWidgetClass; + ++#define GDM_SESSION_CHOOSER_SESSION_PREVIOUS "__previous-session" ++#define GDM_SESSION_CHOOSER_SESSION_DEFAULT "__default-session" ++ + GType gdm_session_chooser_widget_get_type (void); + GtkWidget * gdm_session_chooser_widget_new (void); + + char * gdm_session_chooser_widget_get_current_session_name (GdmSessionChooserWidget *widget); + void gdm_session_chooser_widget_set_current_session_name (GdmSessionChooserWidget *widget, + const char *session_name); +- ++void gdm_session_chooser_widget_set_show_only_chosen (GdmSessionChooserWidget *widget, ++ gboolean show_only); + G_END_DECLS + + #endif /* __GDM_SESSION_CHOOSER_WIDGET_H */ +-- +1.5.3.6 + diff --git a/5-dont-shrink-in-test-program.patch b/5-dont-shrink-in-test-program.patch new file mode 100644 index 0000000..9c79939 --- /dev/null +++ b/5-dont-shrink-in-test-program.patch @@ -0,0 +1,24 @@ +From ed5e63fbb8cf281f8e7bfd8062b3f453fcb3d279 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Thu, 13 Dec 2007 10:16:37 -0500 +Subject: [PATCH] Don't shrink to chosen item by by default for dialog + +--- + gui/simple-greeter/gdm-user-chooser-dialog.c | 1 - + 1 files changed, 0 insertions(+), 1 deletions(-) + +diff --git a/gui/simple-greeter/gdm-user-chooser-dialog.c b/gui/simple-greeter/gdm-user-chooser-dialog.c +index f3e83a2..4848177 100644 +--- a/gui/simple-greeter/gdm-user-chooser-dialog.c ++++ b/gui/simple-greeter/gdm-user-chooser-dialog.c +@@ -154,7 +154,6 @@ gdm_user_chooser_dialog_init (GdmUserChooserDialog *dialog) + dialog->priv = GDM_USER_CHOOSER_DIALOG_GET_PRIVATE (dialog); + + dialog->priv->chooser_widget = gdm_user_chooser_widget_new (); +- gdm_user_chooser_widget_set_show_only_chosen (GDM_USER_CHOOSER_WIDGET (dialog->priv->chooser_widget), TRUE); + gdm_user_chooser_widget_set_show_other_user (GDM_USER_CHOOSER_WIDGET (dialog->priv->chooser_widget), TRUE); + gdm_user_chooser_widget_set_show_guest_user (GDM_USER_CHOOSER_WIDGET (dialog->priv->chooser_widget), TRUE); + gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), dialog->priv->chooser_widget); +-- +1.5.3.6 + diff --git a/6-session-chooser-in-login-window.patch b/6-session-chooser-in-login-window.patch new file mode 100644 index 0000000..b07e104 --- /dev/null +++ b/6-session-chooser-in-login-window.patch @@ -0,0 +1,1568 @@ +From 755e5e94e6f06ff688497fe876e243836480a2c0 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Thu, 13 Dec 2007 10:59:21 -0500 +Subject: [PATCH] Add session chooser and greeter-login-window + This change adds the session chooser to the login window. + It changes the mechanism by the choosers are specified in + the glade file to use custom widgets. + +--- + gui/simple-greeter/Makefile.am | 2 + + gui/simple-greeter/gdm-greeter-login-window.c | 148 ++- + gui/simple-greeter/gdm-greeter-login-window.glade | 1279 +++++++++++++-------- + 3 files changed, 929 insertions(+), 500 deletions(-) + +diff --git a/gui/simple-greeter/Makefile.am b/gui/simple-greeter/Makefile.am +index 836c620..e64f9fb 100644 +--- a/gui/simple-greeter/Makefile.am ++++ b/gui/simple-greeter/Makefile.am +@@ -47,6 +47,8 @@ test_greeter_login_window_SOURCES = \ + gdm-greeter-login-window.c \ + gdm-chooser-widget.h \ + gdm-chooser-widget.c \ ++ gdm-session-chooser-widget.h \ ++ gdm-session-chooser-widget.c \ + gdm-user-chooser-widget.h \ + gdm-user-chooser-widget.c \ + gdm-user-chooser-dialog.h \ +diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c +index efc341e..ca14b38 100644 +--- a/gui/simple-greeter/gdm-greeter-login-window.c ++++ b/gui/simple-greeter/gdm-greeter-login-window.c +@@ -36,12 +36,16 @@ + #include + #include + #include ++ ++#include ++ + #include + + #include + + #include "gdm-greeter-login-window.h" + #include "gdm-user-chooser-widget.h" ++#include "gdm-session-chooser-widget.h" + + #if HAVE_PAM + #include +@@ -62,6 +66,7 @@ enum { + struct GdmGreeterLoginWindowPrivate + { + GladeXML *xml; ++ GtkWidget *session_chooser; + GtkWidget *user_chooser; + gboolean display_is_local; + char *timeformat; +@@ -177,7 +182,7 @@ switch_mode (GdmGreeterLoginWindow *login_window, + int number) + { + const char *default_name; +- GtkWidget *user_list; ++ GtkWidget *user_chooser; + GtkWidget *box; + + /* FIXME: do animation */ +@@ -191,6 +196,7 @@ switch_mode (GdmGreeterLoginWindow *login_window, + show_widget (login_window, "suspend-button", login_window->priv->display_is_local); + show_widget (login_window, "disconnect-button", ! login_window->priv->display_is_local); + show_widget (login_window, "auth-input-box", FALSE); ++ show_widget (login_window, "session-chooser", FALSE); + default_name = NULL; + break; + case MODE_AUTHENTICATION: +@@ -201,6 +207,7 @@ switch_mode (GdmGreeterLoginWindow *login_window, + show_widget (login_window, "suspend-button", FALSE); + show_widget (login_window, "disconnect-button", FALSE); + show_widget (login_window, "auth-input-box", TRUE); ++ show_widget (login_window, "session-chooser", TRUE); + default_name = "log-in-button"; + break; + default: +@@ -211,14 +218,21 @@ switch_mode (GdmGreeterLoginWindow *login_window, + gtk_button_box_set_layout (GTK_BUTTON_BOX (box), + (number == MODE_SELECTION) ? GTK_BUTTONBOX_SPREAD : GTK_BUTTONBOX_END ); + +- box = glade_xml_get_widget (login_window->priv->xml, "selection-box"); +- user_list = glade_xml_get_widget (login_window->priv->xml, "userlist-box"); +- gtk_box_set_child_packing (GTK_BOX (box), +- user_list, +- number == MODE_SELECTION, +- number == MODE_SELECTION, +- 10, +- GTK_PACK_START); ++ user_chooser = glade_xml_get_widget (login_window->priv->xml, "user-chooser"); ++ box = gtk_widget_get_parent (user_chooser); ++ if (GTK_IS_BOX (box)) { ++ guint padding; ++ GtkPackType pack_type; ++ ++ gtk_box_query_child_packing (GTK_BOX (box), user_chooser, ++ NULL, NULL, &padding, &pack_type); ++ gtk_box_set_child_packing (GTK_BOX (box), ++ user_chooser, ++ number == MODE_SELECTION, ++ number == MODE_SELECTION, ++ padding, pack_type); ++ } ++ + if (default_name != NULL) { + GtkWidget *widget; + +@@ -230,7 +244,10 @@ switch_mode (GdmGreeterLoginWindow *login_window, + static void + do_cancel (GdmGreeterLoginWindow *login_window) + { ++ + gdm_user_chooser_widget_set_chosen_user_name (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser), NULL); ++ gdm_session_chooser_widget_set_current_session_name (GDM_SESSION_CHOOSER_WIDGET (login_window->priv->session_chooser), ++ GDM_SESSION_CHOOSER_SESSION_PREVIOUS); + + switch_mode (login_window, MODE_SELECTION); + set_busy (login_window); +@@ -259,6 +276,8 @@ reset_dialog (GdmGreeterLoginWindow *login_window) + set_message (login_window, ""); + + gdm_user_chooser_widget_set_chosen_user_name (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser), NULL); ++ gdm_session_chooser_widget_set_current_session_name (GDM_SESSION_CHOOSER_WIDGET (login_window->priv->session_chooser), ++ GDM_SESSION_CHOOSER_SESSION_PREVIOUS); + + switch_mode (login_window, MODE_SELECTION); + +@@ -458,6 +477,29 @@ on_user_chosen (GdmUserChooserWidget *user_chooser, + } + + static void ++on_user_unchosen (GdmUserChooserWidget *user_chooser, ++ GdmGreeterLoginWindow *login_window) ++{ ++ do_cancel (login_window); ++} ++ ++static void ++on_session_activated (GdmSessionChooserWidget *session_chooser, ++ GdmGreeterLoginWindow *login_window) ++{ ++ char *session; ++ ++ session = gdm_session_chooser_widget_get_current_session_name (GDM_SESSION_CHOOSER_WIDGET (login_window->priv->session_chooser)); ++ if (session == NULL) { ++ return; ++ } ++ ++ g_signal_emit (login_window, signals[SESSION_SELECTED], 0, session); ++ ++ g_free (session); ++} ++ ++static void + update_clock (GtkLabel *label, + const char *format) + { +@@ -706,6 +748,37 @@ create_computer_info (GdmGreeterLoginWindow *login_window) + #define INVISIBLE_CHAR_BULLET 0x2022 + #define INVISIBLE_CHAR_NONE 0 + ++static GtkWidget * ++custom_widget_constructor (GladeXML *xml, ++ char *func_name, ++ char *name, ++ char *string1, ++ char *string2, ++ int int1, ++ int int2, ++ GdmGreeterLoginWindow *login_window) ++{ ++ GtkWidget *widget; ++ ++ g_assert (GLADE_IS_XML (xml)); ++ g_assert (name != NULL); ++ g_assert (GDM_IS_GREETER_LOGIN_WINDOW (login_window)); ++ ++ widget = NULL; ++ ++ if (strcmp (name, "user-chooser") == 0) { ++ widget = gdm_user_chooser_widget_new (); ++ } else if (strcmp (name, "session-chooser") == 0) { ++ widget = gdm_session_chooser_widget_new (); ++ } ++ ++ if (widget != NULL) { ++ gtk_widget_show (widget); ++ } ++ ++ return widget; ++} ++ + static void + load_theme (GdmGreeterLoginWindow *login_window) + { +@@ -713,6 +786,8 @@ load_theme (GdmGreeterLoginWindow *login_window) + GtkWidget *button; + GtkWidget *box; + ++ glade_set_custom_handler ((GladeXMLCustomWidgetHandler) custom_widget_constructor, ++ login_window); + login_window->priv->xml = glade_xml_new (GLADEDIR "/" GLADE_XML_FILE, + "window-box", + PACKAGE); +@@ -722,11 +797,45 @@ load_theme (GdmGreeterLoginWindow *login_window) + box = glade_xml_get_widget (login_window->priv->xml, "window-box"); + gtk_container_add (GTK_CONTAINER (login_window), box); + +- box = glade_xml_get_widget (login_window->priv->xml, "userlist-box"); +- if (box == NULL) { ++ login_window->priv->user_chooser = ++ glade_xml_get_widget (login_window->priv->xml, "user-chooser"); ++ ++ if (login_window->priv->user_chooser == NULL) { + g_critical ("Userlist box not found"); + } +- gtk_container_add (GTK_CONTAINER (box), login_window->priv->user_chooser); ++ ++ gdm_user_chooser_widget_set_show_only_chosen (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser), TRUE); ++ ++ /* FIXME: set from gconf */ ++ gdm_user_chooser_widget_set_show_other_user (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser), TRUE); ++ gdm_user_chooser_widget_set_show_guest_user (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser), TRUE); ++ ++ g_signal_connect (login_window->priv->user_chooser, ++ "activated", ++ G_CALLBACK (on_user_chosen), ++ login_window); ++ g_signal_connect (login_window->priv->user_chooser, ++ "deactivated", ++ G_CALLBACK (on_user_unchosen), ++ login_window); ++ ++ login_window->priv->session_chooser = ++ glade_xml_get_widget (login_window->priv->xml, "session-chooser"); ++ ++ if (login_window->priv->session_chooser == NULL) { ++ g_critical ("Session chooser not found in greeter theme"); ++ } ++ ++ gdm_session_chooser_widget_set_show_only_chosen (GDM_SESSION_CHOOSER_WIDGET (login_window->priv->session_chooser), TRUE); ++ ++ g_signal_connect (login_window->priv->session_chooser, ++ "activated", ++ G_CALLBACK (on_session_activated), ++ login_window); ++ ++ gdm_session_chooser_widget_set_current_session_name (GDM_SESSION_CHOOSER_WIDGET (login_window->priv->session_chooser), ++ GDM_SESSION_CHOOSER_SESSION_PREVIOUS); ++ + + button = glade_xml_get_widget (login_window->priv->xml, "log-in-button"); + gtk_widget_grab_default (button); +@@ -910,21 +1019,6 @@ gdm_greeter_login_window_init (GdmGreeterLoginWindow *login_window) + + login_window->priv->clock_show_seconds = TRUE; + +- login_window->priv->user_chooser = gdm_user_chooser_widget_new (); +- gdm_user_chooser_widget_set_show_only_chosen (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser), TRUE); +- +- /* FIXME: set from gconf */ +- gdm_user_chooser_widget_set_show_other_user (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser), TRUE); +- gdm_user_chooser_widget_set_show_guest_user (GDM_USER_CHOOSER_WIDGET (login_window->priv->user_chooser), TRUE); +- +- g_signal_connect (login_window->priv->user_chooser, +- "user-chosen", +- G_CALLBACK (on_user_chosen), +- login_window); +- +- gtk_widget_show_all (login_window->priv->user_chooser); +- +- gtk_window_set_keep_above (GTK_WINDOW (login_window), TRUE); + gtk_window_set_opacity (GTK_WINDOW (login_window), 0.85); + gtk_window_set_position (GTK_WINDOW (login_window), GTK_WIN_POS_CENTER_ALWAYS); + gtk_window_set_deletable (GTK_WINDOW (login_window), FALSE); +diff --git a/gui/simple-greeter/gdm-greeter-login-window.glade b/gui/simple-greeter/gdm-greeter-login-window.glade +index 2d1d61a..d30000e 100644 +--- a/gui/simple-greeter/gdm-greeter-login-window.glade ++++ b/gui/simple-greeter/gdm-greeter-login-window.glade +@@ -1,475 +1,808 @@ +- +- +- ++ ++ ++ + +- +- 400 +- True +- 12 +- Authentication Dialog +- GDK_WINDOW_TYPE_HINT_DIALOG +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- 10 +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- 64 +- computer +- +- +- +- +- False +- False +- +- +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- +- +- True +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- False +- False +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- Computer Name +- +- +- False +- +- +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- page 1 +- +- +- tab +- False +- False +- +- +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- Version +- +- +- 1 +- False +- +- +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- page 2 +- +- +- tab +- 1 +- False +- False +- +- +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- IP Address +- +- +- 2 +- False +- +- +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- page 3 +- +- +- tab +- 2 +- False +- False +- +- +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- Network status +- +- +- 3 +- False +- +- +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- page 4 +- +- +- tab +- 3 +- False +- False +- +- +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- Tue Oct 23 21:16:50 EDT 2007 +- +- +- 4 +- False +- +- +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- page 5 +- +- +- tab +- 4 +- False +- False +- +- +- +- +- +- +- False +- False +- 1 +- +- +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- 10 +- 10 +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- 10 +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- +- +- +- +- +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- 6 +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- Prompt: +- +- +- False +- False +- +- +- +- +- True +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- True +- +- +- 1 +- +- +- +- +- +- +- +- False +- False +- 1 +- +- +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- +- +- +- +- False +- False +- 2 +- +- +- +- +- +- +- 2 +- +- +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- 6 +- True +- GTK_BUTTONBOX_END +- +- +- True +- True +- True +- True +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- 0 +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- 16 +- window-close +- +- +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- Disconnect +- +- +- 1 +- +- +- +- +- +- +- +- +- True +- True +- True +- True +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- 0 +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- 16 +- media-playback-pause +- +- +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- 0 +- Suspend +- +- +- 1 +- +- +- +- +- +- +- 1 +- +- +- +- +- True +- True +- True +- True +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- 0 +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- 16 +- view-refresh +- +- +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- 0 +- Restart +- +- +- 1 +- +- +- +- +- +- +- 2 +- +- +- +- +- True +- True +- True +- True +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- 0 +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- 16 +- gnome-shutdown +- +- +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- Shut Down +- +- +- 1 +- +- +- +- +- +- +- 3 +- +- +- +- +- True +- True +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- gtk-cancel +- True +- 0 +- +- +- 4 +- +- +- +- +- True +- True +- True +- True +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- 0 +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- 16 +- go-home +- +- +- +- +- True +- GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK +- 0 +- Log In +- +- +- 1 +- +- +- +- +- +- +- 5 +- +- +- +- +- False +- False +- GTK_PACK_END +- 3 +- +- +- +- +- ++ ++ ++ 12 ++ 400 ++ True ++ Authentication Dialog ++ GTK_WINDOW_TOPLEVEL ++ GTK_WIN_POS_NONE ++ False ++ True ++ False ++ True ++ False ++ False ++ GDK_WINDOW_TYPE_HINT_DIALOG ++ GDK_GRAVITY_NORTH_WEST ++ True ++ False ++ ++ ++ ++ True ++ False ++ 10 ++ ++ ++ ++ True ++ 0.5 ++ 0.5 ++ 1 ++ 1 ++ 0 ++ 0 ++ 0 ++ 0 ++ ++ ++ ++ True ++ computer ++ 64 ++ 0.5 ++ 0.5 ++ 0 ++ 0 ++ ++ ++ ++ ++ 0 ++ False ++ False ++ ++ ++ ++ ++ ++ True ++ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK ++ True ++ False ++ ++ ++ ++ True ++ False ++ False ++ GTK_POS_TOP ++ False ++ False ++ ++ ++ ++ True ++ Computer Name ++ False ++ False ++ GTK_JUSTIFY_LEFT ++ False ++ False ++ 0.5 ++ 0.5 ++ 0 ++ 0 ++ PANGO_ELLIPSIZE_NONE ++ -1 ++ False ++ 0 ++ ++ ++ False ++ True ++ ++ ++ ++ ++ ++ True ++ page 1 ++ False ++ False ++ GTK_JUSTIFY_LEFT ++ False ++ False ++ 0.5 ++ 0.5 ++ 0 ++ 0 ++ PANGO_ELLIPSIZE_NONE ++ -1 ++ False ++ 0 ++ ++ ++ tab ++ ++ ++ ++ ++ ++ True ++ Version ++ False ++ False ++ GTK_JUSTIFY_LEFT ++ False ++ False ++ 0.5 ++ 0.5 ++ 0 ++ 0 ++ PANGO_ELLIPSIZE_NONE ++ -1 ++ False ++ 0 ++ ++ ++ False ++ True ++ ++ ++ ++ ++ ++ True ++ page 2 ++ False ++ False ++ GTK_JUSTIFY_LEFT ++ False ++ False ++ 0.5 ++ 0.5 ++ 0 ++ 0 ++ PANGO_ELLIPSIZE_NONE ++ -1 ++ False ++ 0 ++ ++ ++ tab ++ ++ ++ ++ ++ ++ True ++ IP Address ++ False ++ False ++ GTK_JUSTIFY_LEFT ++ False ++ False ++ 0.5 ++ 0.5 ++ 0 ++ 0 ++ PANGO_ELLIPSIZE_NONE ++ -1 ++ False ++ 0 ++ ++ ++ False ++ True ++ ++ ++ ++ ++ ++ True ++ page 3 ++ False ++ False ++ GTK_JUSTIFY_LEFT ++ False ++ False ++ 0.5 ++ 0.5 ++ 0 ++ 0 ++ PANGO_ELLIPSIZE_NONE ++ -1 ++ False ++ 0 ++ ++ ++ tab ++ ++ ++ ++ ++ ++ True ++ Network status ++ False ++ False ++ GTK_JUSTIFY_LEFT ++ False ++ False ++ 0.5 ++ 0.5 ++ 0 ++ 0 ++ PANGO_ELLIPSIZE_NONE ++ -1 ++ False ++ 0 ++ ++ ++ False ++ True ++ ++ ++ ++ ++ ++ True ++ page 4 ++ False ++ False ++ GTK_JUSTIFY_LEFT ++ False ++ False ++ 0.5 ++ 0.5 ++ 0 ++ 0 ++ PANGO_ELLIPSIZE_NONE ++ -1 ++ False ++ 0 ++ ++ ++ tab ++ ++ ++ ++ ++ ++ True ++ Tue Oct 23 21:16:50 EDT 2007 ++ False ++ False ++ GTK_JUSTIFY_LEFT ++ False ++ False ++ 0.5 ++ 0.5 ++ 0 ++ 0 ++ PANGO_ELLIPSIZE_NONE ++ -1 ++ False ++ 0 ++ ++ ++ False ++ True ++ ++ ++ ++ ++ ++ True ++ page 5 ++ False ++ False ++ GTK_JUSTIFY_LEFT ++ False ++ False ++ 0.5 ++ 0.5 ++ 0 ++ 0 ++ PANGO_ELLIPSIZE_NONE ++ -1 ++ False ++ 0 ++ ++ ++ tab ++ ++ ++ ++ ++ ++ ++ 0 ++ False ++ False ++ ++ ++ ++ ++ ++ True ++ 0.5 ++ 0.5 ++ 1 ++ 1 ++ 0 ++ 0 ++ 10 ++ 10 ++ ++ ++ ++ True ++ False ++ 10 ++ ++ ++ ++ True ++ 0 ++ 0 ++ Tue, 04 Dec 2007 23:50:30 GMT ++ ++ ++ 0 ++ True ++ True ++ ++ ++ ++ ++ ++ True ++ False ++ 6 ++ ++ ++ ++ True ++ Prompt: ++ False ++ False ++ GTK_JUSTIFY_LEFT ++ False ++ False ++ 0.5 ++ 0.5 ++ 0 ++ 0 ++ PANGO_ELLIPSIZE_NONE ++ -1 ++ False ++ 0 ++ ++ ++ 0 ++ False ++ False ++ ++ ++ ++ ++ ++ True ++ True ++ GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK ++ True ++ True ++ 0 ++ ++ True ++ ++ True ++ ++ ++ 0 ++ True ++ True ++ ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ False ++ False ++ ++ ++ ++ ++ ++ True ++ False ++ 0 ++ ++ ++ ++ True ++ ++ False ++ False ++ GTK_JUSTIFY_LEFT ++ False ++ False ++ 0.5 ++ 0.5 ++ 0 ++ 0 ++ PANGO_ELLIPSIZE_NONE ++ -1 ++ False ++ 0 ++ ++ ++ 0 ++ True ++ True ++ ++ ++ ++ ++ 0 ++ False ++ False ++ ++ ++ ++ ++ ++ 0 ++ 0 ++ Tue, 04 Dec 2007 23:26:50 GMT ++ ++ ++ 0 ++ True ++ True ++ ++ ++ ++ ++ ++ ++ 0 ++ True ++ True ++ ++ ++ ++ ++ ++ True ++ GTK_BUTTONBOX_END ++ 6 ++ ++ ++ ++ True ++ True ++ True ++ True ++ GTK_RELIEF_NORMAL ++ True ++ ++ ++ ++ True ++ False ++ 0 ++ ++ ++ ++ True ++ window-close ++ 16 ++ 0.5 ++ 0.5 ++ 0 ++ 0 ++ ++ ++ 0 ++ True ++ True ++ ++ ++ ++ ++ ++ True ++ Disconnect ++ False ++ False ++ GTK_JUSTIFY_LEFT ++ False ++ False ++ 0.5 ++ 0.5 ++ 0 ++ 0 ++ PANGO_ELLIPSIZE_NONE ++ -1 ++ False ++ 0 ++ ++ ++ 0 ++ True ++ True ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ True ++ True ++ True ++ True ++ GTK_RELIEF_NORMAL ++ True ++ ++ ++ ++ True ++ False ++ 0 ++ ++ ++ ++ True ++ media-playback-pause ++ 16 ++ 0.5 ++ 0.5 ++ 0 ++ 0 ++ ++ ++ 0 ++ True ++ True ++ ++ ++ ++ ++ ++ True ++ Suspend ++ False ++ False ++ GTK_JUSTIFY_LEFT ++ False ++ False ++ 0 ++ 0.5 ++ 0 ++ 0 ++ PANGO_ELLIPSIZE_NONE ++ -1 ++ False ++ 0 ++ ++ ++ 0 ++ True ++ True ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ True ++ True ++ True ++ True ++ GTK_RELIEF_NORMAL ++ True ++ ++ ++ ++ True ++ False ++ 0 ++ ++ ++ ++ True ++ view-refresh ++ 16 ++ 0.5 ++ 0.5 ++ 0 ++ 0 ++ ++ ++ 0 ++ True ++ True ++ ++ ++ ++ ++ ++ True ++ Restart ++ False ++ False ++ GTK_JUSTIFY_LEFT ++ False ++ False ++ 0 ++ 0.5 ++ 0 ++ 0 ++ PANGO_ELLIPSIZE_NONE ++ -1 ++ False ++ 0 ++ ++ ++ 0 ++ True ++ True ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ True ++ True ++ True ++ True ++ GTK_RELIEF_NORMAL ++ True ++ ++ ++ ++ True ++ False ++ 0 ++ ++ ++ ++ True ++ gnome-shutdown ++ 16 ++ 0.5 ++ 0.5 ++ 0 ++ 0 ++ ++ ++ 0 ++ True ++ True ++ ++ ++ ++ ++ ++ True ++ Shut Down ++ False ++ False ++ GTK_JUSTIFY_LEFT ++ False ++ False ++ 0.5 ++ 0.5 ++ 0 ++ 0 ++ PANGO_ELLIPSIZE_NONE ++ -1 ++ False ++ 0 ++ ++ ++ 0 ++ True ++ True ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ True ++ True ++ gtk-cancel ++ True ++ GTK_RELIEF_NORMAL ++ True ++ ++ ++ ++ ++ ++ True ++ True ++ True ++ True ++ GTK_RELIEF_NORMAL ++ True ++ ++ ++ ++ True ++ False ++ 0 ++ ++ ++ ++ True ++ go-home ++ 16 ++ 0.5 ++ 0.5 ++ 0 ++ 0 ++ ++ ++ 0 ++ True ++ True ++ ++ ++ ++ ++ ++ True ++ Log In ++ False ++ False ++ GTK_JUSTIFY_LEFT ++ False ++ False ++ 0 ++ 0.5 ++ 0 ++ 0 ++ PANGO_ELLIPSIZE_NONE ++ -1 ++ False ++ 0 ++ ++ ++ 0 ++ True ++ True ++ ++ ++ ++ ++ ++ ++ ++ ++ 0 ++ False ++ False ++ GTK_PACK_END ++ ++ ++ ++ ++ ++ + +-- +1.5.3.6 + diff --git a/7-login-window-animation.patch b/7-login-window-animation.patch new file mode 100644 index 0000000..035568c --- /dev/null +++ b/7-login-window-animation.patch @@ -0,0 +1,138 @@ +From 33c2ba849b1f752deb38cf8715571eadbc4b323b Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Thu, 13 Dec 2007 14:38:16 -0500 +Subject: [PATCH] add lame animation to greeter login window + +--- + gui/simple-greeter/gdm-greeter-login-window.c | 90 +++++++++++++++++++++++- + 1 files changed, 86 insertions(+), 4 deletions(-) + +diff --git a/gui/simple-greeter/gdm-greeter-login-window.c b/gui/simple-greeter/gdm-greeter-login-window.c +index ca14b38..ceb9e88 100644 +--- a/gui/simple-greeter/gdm-greeter-login-window.c ++++ b/gui/simple-greeter/gdm-greeter-login-window.c +@@ -72,6 +72,8 @@ struct GdmGreeterLoginWindowPrivate + char *timeformat; + guint update_clock_id; + gboolean clock_show_seconds; ++ ++ guint animation_timeout_id; + }; + + enum { +@@ -860,12 +862,60 @@ load_theme (GdmGreeterLoginWindow *login_window) + switch_mode (login_window, MODE_SELECTION); + } + ++static gboolean ++fit_window_to_children (GdmGreeterLoginWindow *window) ++{ ++ int x; ++ int y; ++ int width; ++ int height; ++ int height_step; ++ int width_step; ++ ++ /* FIXME: this animation logic is really dumb ++ */ ++ ++ if (!GTK_WIDGET_REALIZED (GTK_WIDGET (window))) { ++ return FALSE; ++ } ++ ++ gdk_window_get_geometry (GTK_WIDGET (window)->window, ++ &x, &y, &width, &height, NULL); ++ ++ if (height == GTK_WIDGET (window)->requisition.height) { ++ return FALSE; ++ } ++ ++ if (width < GTK_WIDGET (window)->requisition.width) { ++ width_step = MIN (1, GTK_WIDGET (window)->requisition.width - width); ++ } else if (width > GTK_WIDGET (window)->requisition.width) { ++ width_step = -1 * MIN (1, width - GTK_WIDGET (window)->requisition.width); ++ } else { ++ width_step = 0; ++ } ++ ++ if (height < GTK_WIDGET (window)->requisition.height) { ++ height_step = MIN ((int) 25, GTK_WIDGET (window)->requisition.height - height); ++ } else if (height > GTK_WIDGET (window)->requisition.height) { ++ height_step = -1 * MIN ((int) 25, height - GTK_WIDGET (window)->requisition.height); ++ } else { ++ height_step = 0; ++ } ++ ++ gdk_window_resize (GTK_WIDGET (window)->window, ++ width + width_step, ++ height + height_step); ++ ++ return TRUE; ++} ++ + static void + gdm_greeter_login_window_size_request (GtkWidget *widget, + GtkRequisition *requisition) + { +- int screen_w; +- int screen_h; ++ int screen_w; ++ int screen_h; ++ GtkRequisition child_requisition; + + if (GTK_WIDGET_CLASS (gdm_greeter_login_window_parent_class)->size_request) { + GTK_WIDGET_CLASS (gdm_greeter_login_window_parent_class)->size_request (widget, requisition); +@@ -874,8 +924,39 @@ gdm_greeter_login_window_size_request (GtkWidget *widget, + screen_w = gdk_screen_get_width (gtk_widget_get_screen (widget)); + screen_h = gdk_screen_get_height (gtk_widget_get_screen (widget)); + +- requisition->height = screen_h * 0.5; +- requisition->width = screen_w * 0.3; ++ gtk_widget_size_request (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 ++clear_animation_timeout_id (GdmGreeterLoginWindow *window) ++{ ++ window->priv->animation_timeout_id = 0; ++} ++ ++static void ++gdm_greeter_login_window_size_allocate (GtkWidget *widget, ++ GtkAllocation *allocation) ++{ ++ GdmGreeterLoginWindow *window; ++ ++ window = GDM_GREETER_LOGIN_WINDOW (widget); ++ ++ if (window->priv->animation_timeout_id == 0) { ++ window->priv->animation_timeout_id = ++ g_timeout_add_full (G_PRIORITY_DEFAULT_IDLE, 20, ++ (GSourceFunc) fit_window_to_children, ++ widget, ++ (GDestroyNotify) clear_animation_timeout_id); ++ } ++ ++ GTK_WIDGET_CLASS (gdm_greeter_login_window_parent_class)->size_allocate (widget, allocation); + } + + static GObject * +@@ -910,6 +991,7 @@ gdm_greeter_login_window_class_init (GdmGreeterLoginWindowClass *klass) + object_class->finalize = gdm_greeter_login_window_finalize; + + widget_class->size_request = gdm_greeter_login_window_size_request; ++ widget_class->size_allocate = gdm_greeter_login_window_size_allocate; + + signals [BEGIN_VERIFICATION] = + g_signal_new ("begin-verification", +-- +1.5.3.6 + diff --git a/gdm.spec b/gdm.spec index 13929b0..9d5d989 100644 --- a/gdm.spec +++ b/gdm.spec @@ -16,7 +16,7 @@ Summary: The GNOME Display Manager Name: gdm Version: 2.21.2 -Release: 0.2007.11.20.4%{?dist} +Release: 0.2007.11.20.5%{?dist} Epoch: 1 License: GPLv2+ Group: User Interface/X @@ -82,6 +82,13 @@ Requires: audit-libs >= %{libauditver} Patch0: gdm-2.21.2-use-metacity.patch Patch1: gdm-2.21.2-fix-background.patch +Patch2: 2-new-chooser-widget.patch +Patch3: 3-switch-user-chooser-over.patch +Patch4: 4-switch-session-chooser-over.patch +Patch5: 5-dont-shrink-in-test-program.patch +Patch6: 6-session-chooser-in-login-window.patch +Patch7: 7-login-window-animation.patch + %description Gdm (the GNOME Display Manager) is a highly configurable @@ -93,6 +100,12 @@ several different X sessions on your local machine at the same time. %setup -q %patch0 -p1 -b .use-metacity %patch1 -p1 -b .fix-background +%patch2 -p1 -b .new-chooser-widget +%patch3 -p1 -b .switch-user-chooser-over +%patch4 -p1 -b .switch-session-chooser-over +%patch5 -p1 -b .dont-shrink-in-test-program +%patch6 -p1 -b .session-chooser-in-login-window +%patch7 -p1 -b .login-window-animation %build cp -f %{SOURCE1} data/gdm @@ -280,6 +293,10 @@ fi %attr(1770, root, gdm) %dir %{_localstatedir}/lib/gdm %changelog +* Thu Dec 13 2007 Ray Strode - 1:2.21.2-0.2007.11.20.5 +- add session chooser to login screen +- add hoaky animations + * Fri Nov 30 2007 Matthias Clasen - 1:2.21.2-0.2007.11.20.4 - Use the new "substack" support in pam to make keyring unlocking work