gdm r6100 - in trunk: . gui/simple-greeter



Author: halfline
Date: Thu Apr  3 22:09:04 2008
New Revision: 6100
URL: http://svn.gnome.org/viewvc/gdm?rev=6100&view=rev

Log:
2008-04-03 Ray Strode <rstrode redhat com>

	* gui/simple-greeter/gdm-scrollable-widget.[ch]:
	* gui/simple-greeter/Makefile.am:
	* gui/simple-greeter/gdm-chooser-widget.c:
	(struct GdmChooserWidgetPrivate),
	(get_path_to_active_row), (on_shrink_animation_step),
	(on_shrink_animation_complete),
	(get_height_of_row_at_path),
	(get_normalized_position_of_row_at_path),
	(start_shrink_animation),
	(on_grow_animation_complete),
	(get_height_of_screen), (start_grow_animation),
	(start_grow_animation), (gdm_chooser_widget_grow),
	(gdm_chooser_widget_shrink),
	(gdm_chooser_widget_class_init), (gdm_chooser_widget_init),
	(gdm_chooser_widget_finalize):
	Do chooser widget animation in a different, smoother way
	using a special widget that's like GtkScrolledWindow, but
	can animation instead of removing items from the list one
	by one


Added:
   trunk/gui/simple-greeter/gdm-scrollable-widget.c
   trunk/gui/simple-greeter/gdm-scrollable-widget.h
Modified:
   trunk/ChangeLog
   trunk/gui/simple-greeter/Makefile.am
   trunk/gui/simple-greeter/gdm-chooser-widget.c

Modified: trunk/gui/simple-greeter/Makefile.am
==============================================================================
--- trunk/gui/simple-greeter/Makefile.am	(original)
+++ trunk/gui/simple-greeter/Makefile.am	Thu Apr  3 22:09:04 2008
@@ -72,6 +72,8 @@
 	gdm-timer.c			\
 	gdm-greeter-login-window.h	\
 	gdm-greeter-login-window.c	\
+	gdm-scrollable-widget.h		\
+	gdm-scrollable-widget.c		\
 	gdm-chooser-widget.h		\
 	gdm-chooser-widget.c		\
 	gdm-sessions.h			\
@@ -109,6 +111,8 @@
 	gdm-cell-renderer-timer.c	\
 	gdm-timer.h			\
 	gdm-timer.c			\
+	gdm-scrollable-widget.h		\
+	gdm-scrollable-widget.c		\
 	gdm-chooser-widget.h		\
 	gdm-chooser-widget.c		\
 	gdm-language-chooser-widget.h	\
@@ -151,6 +155,8 @@
 	gdm-cell-renderer-timer.c	\
 	gdm-timer.h			\
 	gdm-timer.c			\
+	gdm-scrollable-widget.h		\
+	gdm-scrollable-widget.c		\
 	gdm-chooser-widget.h		\
 	gdm-chooser-widget.c		\
 	gdm-languages.h			\
@@ -183,6 +189,8 @@
 	gdm-timer.c			\
 	gdm-cell-renderer-timer.h	\
 	gdm-cell-renderer-timer.c	\
+	gdm-scrollable-widget.h		\
+	gdm-scrollable-widget.c		\
 	gdm-chooser-widget.h		\
 	gdm-chooser-widget.c		\
 	gdm-user-chooser-widget.h	\
@@ -229,6 +237,8 @@
 	gdm-timer.c			\
 	gdm-cell-renderer-timer.h	\
 	gdm-cell-renderer-timer.c	\
+	gdm-scrollable-widget.h		\
+	gdm-scrollable-widget.c		\
 	gdm-chooser-widget.h		\
 	gdm-chooser-widget.c		\
 	gdm-greeter-client.h		\

Modified: trunk/gui/simple-greeter/gdm-chooser-widget.c
==============================================================================
--- trunk/gui/simple-greeter/gdm-chooser-widget.c	(original)
+++ trunk/gui/simple-greeter/gdm-chooser-widget.c	Thu Apr  3 22:09:04 2008
@@ -35,6 +35,7 @@
 #include <gtk/gtk.h>
 
 #include "gdm-chooser-widget.h"
+#include "gdm-scrollable-widget.h"
 #include "gdm-cell-renderer-timer.h"
 #include "gdm-timer.h"
 
@@ -55,7 +56,7 @@
 {
         GtkWidget                *frame;
         GtkWidget                *frame_alignment;
-        GtkWidget                *scrolled_window;
+        GtkWidget                *scrollable_widget;
 
         GtkWidget                *items_view;
         GtkListStore             *list_store;
@@ -67,8 +68,6 @@
 
         GtkTreeRowReference      *active_row;
         GtkTreeRowReference      *separator_row;
-        GtkTreeRowReference      *top_edge_row;    /* Only around for shrink */
-        GtkTreeRowReference      *bottom_edge_row; /* animations */
 
         GHashTable               *rows_with_timers;
 
@@ -85,9 +84,6 @@
         gint                     number_of_rows_with_images;
         gint                     number_of_active_timers;
 
-        GdmTimer                *grow_animation_timer;
-        GdmTimer                *shrink_animation_timer;
-
         guint                    update_idle_id;
         guint                    timer_animation_timeout_id;
 
@@ -97,6 +93,7 @@
         GdmChooserWidgetPosition separator_position;
         GdmChooserWidgetState    state;
 
+        double                   active_row_normalized_position;
 };
 
 enum {
@@ -375,258 +372,173 @@
         *path = sorted_path;
 }
 
-static gboolean
-shrink_edge_toward_active_row (GdmChooserWidget     *widget,
-                               GtkTreeRowReference **edge_row)
+static GtkTreePath *
+get_path_to_active_row (GdmChooserWidget *widget)
 {
-        GtkTreePath  *active_path;
-        GtkTreePath  *edge_path;
-        GtkTreeIter   edge_iter;
-        gboolean      edge_is_hidden;
-        int           relative_position;
-
-        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 {
-                        if (!gtk_tree_path_prev (edge_path)) {
-                                edge_is_hidden = TRUE;
-                                goto out;
-                        }
-                }
-                gtk_tree_row_reference_free (*edge_row);
+        GtkTreePath *path;
 
-                *edge_row = gtk_tree_row_reference_new (GTK_TREE_MODEL (widget->priv->model_sorter),
-                                                        edge_path);
+        if (widget->priv->active_row == NULL) {
+                return NULL;
+        }
 
-                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);
+        path= gtk_tree_row_reference_get_path (widget->priv->active_row);
 
-                edge_is_hidden = FALSE;
-        } else {
-                edge_is_hidden = TRUE;
+        if (path == NULL) {
+                return NULL;
         }
-out:
-        gtk_tree_path_free (active_path);
-        gtk_tree_path_free (edge_path);
 
-        return edge_is_hidden;
+        translate_base_path_to_sorted_path (widget, &path);
+
+        return path;
 }
 
-static gboolean
-run_shrink_animation (GdmChooserWidget *widget,
-                      int               number_of_iterations)
+static void
+on_shrink_animation_step (GdmScrollableWidget *scrollable_widget,
+                          double               progress,
+                          GdmChooserWidget    *widget)
 {
-        gboolean is_done;
-
-        is_done = FALSE;
-
-        if (widget->priv->top_edge_row != NULL) {
-                is_done = shrink_edge_toward_active_row (widget,
-                                                         &widget->priv->top_edge_row);
-        }
+        GtkTreePath   *active_row_path;
+        const double   final_alignment = 0.5;
+        double         row_alignment;
 
-        if (widget->priv->bottom_edge_row != NULL) {
-                is_done = is_done &&
-                        shrink_edge_toward_active_row (widget,
-                                                       &widget->priv->bottom_edge_row);
-        }
-
-        number_of_iterations--;
-
-        if (number_of_iterations != 0) {
-                is_done = run_shrink_animation (widget, number_of_iterations);
-        }
+        active_row_path = get_path_to_active_row (widget);
+        row_alignment = widget->priv->active_row_normalized_position + progress * (final_alignment - widget->priv->active_row_normalized_position);
 
-        return is_done;
+        gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (widget->priv->items_view),
+                                     active_row_path, NULL, TRUE, row_alignment, 0.0);
+        gtk_tree_path_free (active_row_path);
 }
 
-static int
-get_number_of_on_screen_rows (GdmChooserWidget *widget)
+static void
+set_inactive_items_visible (GdmChooserWidget *widget,
+                            gboolean          should_show)
 {
-        GtkTreePath *start_path;
-        GtkTreePath *end_path;
-        int         *start_index;
-        int         *end_index;
-        int          number_of_rows;
-
-        if (!gtk_tree_view_get_visible_range (GTK_TREE_VIEW (widget->priv->items_view),
-                                              &start_path, &end_path)) {
-                return 0;
-        }
-
-        start_index = gtk_tree_path_get_indices (start_path);
-        end_index = gtk_tree_path_get_indices (end_path);
+        GtkTreeModel *model;
+        char         *active_item_id;
+        GtkTreeIter   active_item_iter;
+        GtkTreeIter   iter;
 
-        number_of_rows = *end_index - *start_index;
+        model = GTK_TREE_MODEL (widget->priv->list_store);
 
-        gtk_tree_path_free (start_path);
-        gtk_tree_path_free (end_path);
+        if (!gtk_tree_model_get_iter_first (model, &iter)) {
+                return;
+        }
 
-        return number_of_rows;
-}
+        active_item_id = get_active_item_id (widget, &active_item_iter);
 
-static gboolean
-run_grow_animation (GdmChooserWidget *widget,
-                    int               number_of_iterations)
-{
-        gboolean     is_done;
-        GtkTreePath *path;
-        GtkTreeIter  iter;
-        gboolean     is_visible;
+        do {
+                gboolean is_active;
 
-        is_done = FALSE;
+                is_active = FALSE;
+                if (active_item_id != NULL) {
+                        char *id;
 
-        path = gtk_tree_path_new_first ();
+                        gtk_tree_model_get (model, &iter,
+                                            CHOOSER_ID_COLUMN, &id, -1);
 
-        do {
-                if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (widget->priv->list_store),
-                                              &iter, path)) {
-                        is_done = TRUE;
-                        break;
+                        if (strcmp (active_item_id, id) == 0) {
+                                is_active = TRUE;
+                                g_free (active_item_id);
+                                active_item_id = NULL;
+                        }
+                        g_free (id);
                 }
 
-                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);
+                if (!is_active) {
+                        gtk_list_store_set (widget->priv->list_store,
+                                            &iter,
+                                            CHOOSER_ITEM_IS_VISIBLE_COLUMN, should_show,
+                                            -1);
                 } else {
-                        gtk_list_store_set (GTK_LIST_STORE (widget->priv->list_store),
+                        gtk_list_store_set (widget->priv->list_store,
                                             &iter,
                                             CHOOSER_ITEM_IS_VISIBLE_COLUMN, TRUE,
                                             -1);
                 }
-        } while (is_visible);
-
-        gtk_tree_path_free (path);
-
-        number_of_iterations--;
-
-        if (number_of_iterations != 0) {
-                is_done = run_grow_animation (widget, number_of_iterations);
-        }
+        } while (gtk_tree_model_iter_next (model, &iter));
 
-        return is_done;
+        g_free (active_item_id);
 }
 
 static void
-on_shrink_animation_tick (GdmChooserWidget *widget,
-                          double            progress)
+on_shrink_animation_complete (GdmScrollableWidget *scrollable_widget,
+                              GdmChooserWidget    *widget)
 {
-        int number_of_iterations;
-        int number_of_visible_rows;
-        int number_of_rows;
-        int number_of_rows_to_be_gone;
-        int number_of_rows_gone;
-
-        if (widget->priv->state != GDM_CHOOSER_WIDGET_STATE_SHRINKING) {
-                return;
-        }
-
-        number_of_visible_rows = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (widget->priv->model_sorter), NULL);
-
-        if (number_of_visible_rows <= 1) {
-                gdm_timer_stop (widget->priv->shrink_animation_timer);
-                return;
-        }
-
-        number_of_rows = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (widget->priv->list_store), NULL);
-
-        number_of_rows_to_be_gone = progress * number_of_rows;
-        number_of_rows_gone = number_of_rows - number_of_visible_rows;
-
-        number_of_iterations = number_of_rows_to_be_gone - number_of_rows_gone;
+        g_assert (widget->priv->state == GDM_CHOOSER_WIDGET_STATE_SHRINKING);
 
-        if (number_of_iterations <= 0) {
-                return;
-        }
+        widget->priv->active_row_normalized_position = 0.5;
+        set_inactive_items_visible (GDM_CHOOSER_WIDGET (widget), FALSE);
+        widget->priv->state = GDM_CHOOSER_WIDGET_STATE_SHRUNK;
 
-        if (run_shrink_animation (widget, number_of_iterations)) {
-                gdm_timer_stop (widget->priv->shrink_animation_timer);
+        if (widget->priv->emit_activated_after_resize_animation) {
+                g_signal_emit (widget, signals[ACTIVATED], 0);
+                widget->priv->emit_activated_after_resize_animation = FALSE;
         }
 }
 
-static void
-on_grow_animation_tick (GdmChooserWidget *widget,
-                        double            progress)
+static int
+get_height_of_row_at_path (GdmChooserWidget *widget,
+                           GtkTreePath      *path)
 {
-        int number_of_iterations;
-        int number_of_visible_rows;
-        int number_of_rows;
-        int number_of_rows_wanted;
-
-        if (widget->priv->state != GDM_CHOOSER_WIDGET_STATE_GROWING) {
-                return;
-        }
-
-        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);
+        GdkRectangle area;
 
-        if (number_of_visible_rows == number_of_rows) {
-                gdm_timer_stop (widget->priv->shrink_animation_timer);
-                return;
-        }
+        gtk_tree_view_get_background_area (GTK_TREE_VIEW (widget->priv->items_view),
+                                           path, NULL, &area);
 
-        number_of_rows_wanted = progress * number_of_rows;
+        return area.height;
+}
 
-        number_of_iterations = number_of_rows_wanted - number_of_visible_rows;
+static double
+get_normalized_position_of_row_at_path (GdmChooserWidget *widget,
+                                        GtkTreePath      *path)
+{
+        GdkRectangle area_of_row_at_path;
+        GdkRectangle area_of_visible_rows;
 
-        if (number_of_iterations <= 0) {
-                return;
-        }
+        gtk_tree_view_get_background_area (GTK_TREE_VIEW (widget->priv->items_view),
+                                           path, NULL, &area_of_row_at_path);
 
-        if (run_grow_animation (widget, number_of_iterations)) {
-                gdm_timer_stop (widget->priv->shrink_animation_timer);
-        }
+        gtk_tree_view_convert_tree_to_widget_coords (GTK_TREE_VIEW (widget->priv->items_view),
+                                                     area_of_visible_rows.x,
+                                                     area_of_visible_rows.y,
+                                                     &area_of_visible_rows.x,
+                                                     &area_of_visible_rows.y);
+        return ((double) area_of_row_at_path.y) / widget->priv->items_view->allocation.height;
 }
 
 static void
-on_shrink_animation_stop (GdmChooserWidget *widget)
+start_shrink_animation (GdmChooserWidget *widget)
 {
+       GtkTreePath *active_row_path;
+       int          active_row_height;
+       int          number_of_visible_rows;
 
-        g_assert (widget->priv->state == GDM_CHOOSER_WIDGET_STATE_SHRINKING);
-        widget->priv->state = GDM_CHOOSER_WIDGET_STATE_SHRUNK;
-
-        if (widget->priv->top_edge_row != NULL) {
-                gtk_tree_row_reference_free (widget->priv->top_edge_row);
-                widget->priv->top_edge_row = NULL;
-        }
+       g_assert (widget->priv->active_row != NULL);
 
-        if (widget->priv->bottom_edge_row != NULL) {
-                gtk_tree_row_reference_free (widget->priv->bottom_edge_row);
-                widget->priv->bottom_edge_row = NULL;
-        }
+       number_of_visible_rows = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (widget->priv->model_sorter), NULL);
 
-        if (widget->priv->emit_activated_after_resize_animation) {
-                g_signal_emit (widget, signals[ACTIVATED], 0);
-                widget->priv->emit_activated_after_resize_animation = FALSE;
-        }
+       if (number_of_visible_rows <= 1) {
+               on_shrink_animation_complete (GDM_SCROLLABLE_WIDGET (widget->priv->scrollable_widget),
+                                             widget);
+               return;
+       }
 
-        gtk_widget_set_sensitive (GTK_WIDGET (widget), TRUE);
+       active_row_path = get_path_to_active_row (widget);
+       active_row_height = get_height_of_row_at_path (widget, active_row_path);
+       widget->priv->active_row_normalized_position = get_normalized_position_of_row_at_path (widget, active_row_path);
+       gtk_tree_path_free (active_row_path);
+
+       gdm_scrollable_widget_slide_to_height (GDM_SCROLLABLE_WIDGET (widget->priv->scrollable_widget),
+                                              active_row_height,
+                                              (GdmScrollableWidgetSlideStepFunc)
+                                              on_shrink_animation_step, widget,
+                                              (GdmScrollableWidgetSlideDoneFunc)
+                                              on_shrink_animation_complete, widget);
 }
 
 static void
-on_grow_animation_stop (GdmChooserWidget *widget)
+on_grow_animation_complete (GdmScrollableWidget *scrollable_widget,
+                            GdmChooserWidget *widget)
 {
         g_assert (widget->priv->state == GDM_CHOOSER_WIDGET_STATE_GROWING);
         widget->priv->state = GDM_CHOOSER_WIDGET_STATE_GROWN;
@@ -635,149 +547,44 @@
                 g_signal_emit (widget, signals[ACTIVATED], 0);
                 widget->priv->emit_activated_after_resize_animation = FALSE;
         }
-
-        gtk_widget_set_sensitive (GTK_WIDGET (widget), TRUE);
 }
 
-static void
-start_shrink_animation (GdmChooserWidget *widget)
+static int
+get_height_of_screen (GdmChooserWidget *widget)
 {
-       GtkTreePath *edge_path;
-       int          number_of_visible_rows;
-       int          number_of_rows;
-       int          number_of_on_screen_rows;
-       int          number_of_iterations;
-
-       if (widget->priv->shrink_animation_timer != NULL &&
-               gdm_timer_is_started (widget->priv->shrink_animation_timer)) {
-                gdm_timer_stop (widget->priv->shrink_animation_timer);
-       }
+        GdkScreen    *screen;
+        GdkRectangle  area;
+        int           monitor;
 
-       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);
+        screen = gtk_widget_get_screen (GTK_WIDGET (widget));
 
-       if (number_of_visible_rows <= 1) {
-               on_shrink_animation_stop (widget);
-               return;
-       }
+        monitor = gdk_screen_get_monitor_at_window (screen,
+                                                    GTK_WIDGET (widget)->window);
+        gdk_screen_get_monitor_geometry (screen, monitor, &area);
 
-       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);
-
-       gtk_widget_set_sensitive (GTK_WIDGET (widget), FALSE);
-
-       number_of_on_screen_rows = get_number_of_on_screen_rows (widget);
-       number_of_iterations = number_of_visible_rows - number_of_on_screen_rows;
-       number_of_iterations = MAX (0, number_of_iterations);
-
-       run_shrink_animation (widget, number_of_iterations);
-
-       if (widget->priv->shrink_animation_timer == NULL) {
-               widget->priv->shrink_animation_timer = gdm_timer_new ();
-
-               g_signal_connect_swapped (G_OBJECT (widget->priv->shrink_animation_timer),
-                                         "tick", G_CALLBACK (on_shrink_animation_tick),
-                                         widget);
-               g_signal_connect_swapped (G_OBJECT (widget->priv->shrink_animation_timer),
-                                         "stop", G_CALLBACK (on_shrink_animation_stop),
-                                         widget);
-       }
-
-       gdm_timer_start (widget->priv->shrink_animation_timer, 1.0);
+        return area.height;
 }
 
 static void
 start_grow_animation (GdmChooserWidget *widget)
 {
-       int          number_of_visible_rows;
-       int          number_of_rows;
-
-       if (widget->priv->grow_animation_timer != NULL &&
-               gdm_timer_is_started (widget->priv->grow_animation_timer)) {
-                gdm_timer_stop (widget->priv->grow_animation_timer);
-       }
+        int number_of_visible_rows;
+        int number_of_rows;
 
-       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);
+        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 (number_of_visible_rows >= number_of_rows) {
-               on_grow_animation_stop (widget);
+        if (number_of_visible_rows >= number_of_rows) {
+               on_grow_animation_complete (GDM_SCROLLABLE_WIDGET (widget->priv->scrollable_widget), widget);
                return;
-       }
-
-       gtk_widget_set_sensitive (GTK_WIDGET (widget), FALSE);
-
-       if (widget->priv->grow_animation_timer == NULL) {
-               widget->priv->grow_animation_timer = gdm_timer_new ();
-
-               g_signal_connect_swapped (G_OBJECT (widget->priv->grow_animation_timer),
-                                         "tick", G_CALLBACK (on_grow_animation_tick),
-                                         widget);
-               g_signal_connect_swapped (G_OBJECT (widget->priv->grow_animation_timer),
-                                         "stop", G_CALLBACK (on_grow_animation_stop),
-                                         widget);
-       }
-       gdm_timer_start (widget->priv->grow_animation_timer, 1.0);
-}
-
-static void
-set_inactive_items_visible (GdmChooserWidget *widget,
-                            gboolean          should_show)
-{
-        GtkTreeModel *model;
-        char         *active_item_id;
-        GtkTreeIter   active_item_iter;
-        GtkTreeIter   iter;
-
-        model = GTK_TREE_MODEL (widget->priv->list_store);
-
-        if (!gtk_tree_model_get_iter_first (model, &iter)) {
-                return;
         }
 
-        active_item_id = get_active_item_id (widget, &active_item_iter);
-
-        do {
-                gboolean is_active;
-
-                is_active = FALSE;
-                if (active_item_id != NULL) {
-                        char *id;
-
-                        gtk_tree_model_get (model, &iter,
-                                            CHOOSER_ID_COLUMN, &id, -1);
-
-                        if (strcmp (active_item_id, id) == 0) {
-                                is_active = TRUE;
-                                g_free (active_item_id);
-                                active_item_id = NULL;
-                        }
-                        g_free (id);
-                }
-
-                if (!is_active) {
-                        gtk_list_store_set (widget->priv->list_store,
-                                            &iter,
-                                            CHOOSER_ITEM_IS_VISIBLE_COLUMN, should_show,
-                                            -1);
-                } else {
-                        gtk_list_store_set (widget->priv->list_store,
-                                            &iter,
-                                            CHOOSER_ITEM_IS_VISIBLE_COLUMN, TRUE,
-                                            -1);
-                }
-        } while (gtk_tree_model_iter_next (model, &iter));
-
-        g_free (active_item_id);
+        set_inactive_items_visible (widget, TRUE);
+        gdm_scrollable_widget_slide_to_height (GDM_SCROLLABLE_WIDGET (widget->priv->scrollable_widget),
+                                               get_height_of_screen (widget),
+                                               NULL, NULL,
+                                               (GdmScrollableWidgetSlideDoneFunc)
+                                               on_grow_animation_complete, widget);
 }
 
 static void
@@ -795,10 +602,6 @@
 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);
 
@@ -852,12 +655,6 @@
         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;
@@ -1097,120 +894,6 @@
 }
 
 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_hide (GtkWidget *widget)
 {
         skip_resize_animation (GDM_CHOOSER_WIDGET (widget));
@@ -1236,10 +919,6 @@
         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
         widget_class->hide = gdm_chooser_widget_hide;
         widget_class->show = gdm_chooser_widget_show;
 
@@ -1707,15 +1386,10 @@
 
         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);
+        widget->priv->scrollable_widget = gdm_scrollable_widget_new ();
+        gtk_widget_show (widget->priv->scrollable_widget);
         gtk_container_add (GTK_CONTAINER (widget->priv->frame_alignment),
-                           widget->priv->scrolled_window);
+                           widget->priv->scrollable_widget);
 
         widget->priv->items_view = gtk_tree_view_new ();
         gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (widget->priv->items_view),
@@ -1738,7 +1412,7 @@
                                widget);
 
         gtk_widget_show (widget->priv->items_view);
-        gtk_container_add (GTK_CONTAINER (widget->priv->scrolled_window),
+        gtk_container_add (GTK_CONTAINER (widget->priv->scrollable_widget),
                            widget->priv->items_view);
 
         selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget->priv->items_view));
@@ -1859,16 +1533,6 @@
         g_hash_table_destroy (widget->priv->rows_with_timers);
         widget->priv->rows_with_timers = NULL;
 
-        if (widget->priv->shrink_animation_timer != NULL) {
-                g_object_unref (widget->priv->shrink_animation_timer);
-                widget->priv->shrink_animation_timer = NULL;
-        }
-
-        if (widget->priv->grow_animation_timer != NULL) {
-                g_object_unref (widget->priv->grow_animation_timer);
-                widget->priv->grow_animation_timer = NULL;
-        }
-
         G_OBJECT_CLASS (gdm_chooser_widget_parent_class)->finalize (object);
 }
 

Added: trunk/gui/simple-greeter/gdm-scrollable-widget.c
==============================================================================
--- (empty file)
+++ trunk/gui/simple-greeter/gdm-scrollable-widget.c	Thu Apr  3 22:09:04 2008
@@ -0,0 +1,659 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+ * USA.
+ *
+ * Written by: Ray Strode <rstrode redhat com>
+ *
+ * Parts taken from gtkscrolledwindow.c in the GTK+ toolkit.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+
+#include "gdm-scrollable-widget.h"
+#include "gdm-timer.h"
+
+#define GDM_SCROLLABLE_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_SCROLLABLE_WIDGET, GdmScrollableWidgetPrivate))
+
+enum
+{
+        SCROLL_CHILD,
+        MOVE_FOCUS_OUT,
+        NUMBER_OF_SIGNALS
+};
+
+typedef struct GdmScrollableWidgetAnimation GdmScrollableWidgetAnimation;
+
+struct GdmScrollableWidgetPrivate
+{
+        GtkWidget *scrollbar;
+
+        GdmScrollableWidgetAnimation *animation;
+        GtkWidget                    *invisible_event_sink;
+};
+
+struct GdmScrollableWidgetAnimation
+{
+        GtkWidget *widget;
+        GdmTimer  *timer;
+        int        start_height;
+        int        desired_height;
+        GdmScrollableWidgetSlideStepFunc step_func;
+        gpointer   step_func_user_data;
+        GdmScrollableWidgetSlideDoneFunc done_func;
+        gpointer   done_func_user_data;
+};
+
+static void     gdm_scrollable_widget_class_init  (GdmScrollableWidgetClass *klass);
+static void     gdm_scrollable_widget_init        (GdmScrollableWidget      *clock_widget);
+static void     gdm_scrollable_widget_finalize    (GObject             *object);
+
+static guint signals[NUMBER_OF_SIGNALS] = { 0 };
+
+G_DEFINE_TYPE (GdmScrollableWidget, gdm_scrollable_widget, GTK_TYPE_BIN)
+
+static GdmScrollableWidgetAnimation *
+gdm_scrollable_widget_animation_new (GtkWidget *widget,
+                                     int        start_height,
+                                     int        desired_height,
+                                     GdmScrollableWidgetSlideStepFunc step_func,
+                                     gpointer   step_func_user_data,
+                                     GdmScrollableWidgetSlideDoneFunc done_func,
+                                     gpointer   done_func_user_data)
+{
+        GdmScrollableWidgetAnimation *animation;
+
+        animation = g_slice_new (GdmScrollableWidgetAnimation);
+
+        animation->widget = widget;
+        animation->timer = gdm_timer_new ();
+        animation->start_height = start_height;
+        animation->desired_height = desired_height;
+        animation->step_func = step_func;
+        animation->step_func_user_data = step_func_user_data;
+        animation->done_func = done_func;
+        animation->done_func_user_data = done_func_user_data;
+
+        return animation;
+}
+
+static void
+gdm_scrollable_widget_animation_free (GdmScrollableWidgetAnimation *animation)
+{
+        g_object_unref (animation->timer);
+        g_slice_free (GdmScrollableWidgetAnimation, animation);
+}
+
+void
+on_animation_tick (GdmScrollableWidgetAnimation *animation,
+                   double                        progress)
+{
+        int progress_in_pixels;
+        int width;
+        int height;
+
+        progress_in_pixels = progress * (animation->start_height - animation->desired_height);
+
+        height = animation->start_height - progress_in_pixels;
+
+        gtk_widget_get_size_request (animation->widget, &width, NULL);
+        gtk_widget_set_size_request (animation->widget, width, height);
+
+        if (animation->step_func != NULL) {
+                animation->step_func (GDM_SCROLLABLE_WIDGET (animation->widget),
+                                      progress,
+                                      animation->step_func_user_data);
+        }
+}
+
+static gboolean
+gdm_scrollable_redirect_input_to_event_sink (GdmScrollableWidget *scrollable_widget)
+{
+        GdkGrabStatus status;
+
+        status = gdk_pointer_grab (scrollable_widget->priv->invisible_event_sink->window,
+                          FALSE, 0, NULL, NULL, GDK_CURRENT_TIME);
+        if (status != GDK_GRAB_SUCCESS) {
+                return FALSE;
+        }
+
+        status = gdk_keyboard_grab (scrollable_widget->priv->invisible_event_sink->window,
+                           FALSE, GDK_CURRENT_TIME);
+        if (status != GDK_GRAB_SUCCESS) {
+                gdk_pointer_ungrab (GDK_CURRENT_TIME);
+                return FALSE;
+        }
+
+        return TRUE;
+}
+
+static void
+gdm_scrollable_unredirect_input (GdmScrollableWidget *scrollable_widget)
+{
+        gdk_keyboard_ungrab (GDK_CURRENT_TIME);
+        gdk_pointer_ungrab (GDK_CURRENT_TIME);
+}
+
+void
+on_animation_stop (GdmScrollableWidgetAnimation *animation)
+{
+        GdmScrollableWidget *widget;
+        int                  width;
+
+        widget = GDM_SCROLLABLE_WIDGET (animation->widget);
+
+        if (animation->done_func != NULL) {
+                animation->done_func (widget, animation->done_func_user_data);
+        }
+
+        gdm_scrollable_widget_animation_free (widget->priv->animation);
+        widget->priv->animation = NULL;
+
+        gtk_widget_get_size_request (GTK_WIDGET (widget), &width, NULL);
+        gtk_widget_set_size_request (GTK_WIDGET (widget), width, -1);
+        gtk_widget_queue_resize (GTK_WIDGET (widget));
+
+        gdm_scrollable_unredirect_input (widget);
+}
+
+static void
+gdm_scrollable_widget_animation_start (GdmScrollableWidgetAnimation *animation)
+{
+        g_signal_connect_swapped (G_OBJECT (animation->timer), "tick",
+                                  G_CALLBACK (on_animation_tick),
+                                  animation);
+        g_signal_connect_swapped (G_OBJECT (animation->timer), "stop",
+                                  G_CALLBACK (on_animation_stop),
+                                  animation);
+        gdm_timer_start (animation->timer, .50);
+}
+
+static gboolean
+gdm_scrollable_widget_needs_scrollbar (GdmScrollableWidget *widget)
+{
+        GtkAdjustment *adjustment;
+
+        if (widget->priv->scrollbar == NULL) {
+                return FALSE;
+        }
+
+        if (widget->priv->animation != NULL) {
+                return FALSE;
+        }
+
+        adjustment = gtk_range_get_adjustment (GTK_RANGE (widget->priv->scrollbar));
+
+        return adjustment->upper - adjustment->lower > adjustment->page_size;
+}
+
+static void
+gdm_scrollable_widget_size_request (GtkWidget      *widget,
+                                    GtkRequisition *requisition)
+{
+        GdmScrollableWidget *scrollable_widget;
+        GtkRequisition       child_requisition;
+
+        scrollable_widget = GDM_SCROLLABLE_WIDGET (widget);
+
+        requisition->width = 2 * GTK_CONTAINER (widget)->border_width;
+        requisition->height = 2 * GTK_CONTAINER (widget)->border_width;
+
+        requisition->width += 2 * widget->style->xthickness;
+        requisition->height += 2 * widget->style->ythickness;
+
+        if (GTK_BIN (widget)->child && GTK_WIDGET_VISIBLE (GTK_BIN (widget)->child)) {
+                gtk_widget_size_request (GTK_BIN (widget)->child,
+                                         &child_requisition);
+                requisition->height += child_requisition.height;
+        }
+
+        if (gdm_scrollable_widget_needs_scrollbar (scrollable_widget)) {
+                GtkRequisition scrollbar_requisition;
+
+                gtk_widget_show (scrollable_widget->priv->scrollbar);
+
+                gtk_widget_size_request (scrollable_widget->priv->scrollbar,
+                                         &scrollbar_requisition);
+
+                requisition->height = MAX (requisition->height,
+                                           scrollbar_requisition.height);
+                requisition->width += scrollbar_requisition.width;
+        } else {
+                gtk_widget_hide (scrollable_widget->priv->scrollbar);
+        }
+}
+
+static void
+gdm_scrollable_widget_size_allocate (GtkWidget     *widget,
+                                     GtkAllocation *allocation)
+{
+        GdmScrollableWidget *scrollable_widget;
+        GtkAllocation        scrollbar_allocation;
+        GtkAllocation        child_allocation;
+        gboolean             has_child;
+        gboolean             needs_scrollbar;
+        gboolean             is_flipped;
+
+        scrollable_widget = GDM_SCROLLABLE_WIDGET (widget);
+
+        widget->allocation = *allocation;
+
+        has_child = GTK_BIN (widget)->child && GTK_WIDGET_VISIBLE (GTK_BIN (widget)->child);
+        needs_scrollbar = gdm_scrollable_widget_needs_scrollbar (scrollable_widget);
+        is_flipped = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
+
+        if (needs_scrollbar) {
+                GtkRequisition scrollbar_requisition;
+
+                gtk_widget_get_child_requisition (scrollable_widget->priv->scrollbar,
+                                                  &scrollbar_requisition);
+
+                scrollbar_allocation.width = scrollbar_requisition.width;
+
+                if (!is_flipped) {
+                        scrollbar_allocation.x = allocation->x + allocation->width;
+                        scrollbar_allocation.x -= GTK_CONTAINER (widget)->border_width;
+                        scrollbar_allocation.x -= scrollbar_allocation.width;
+                } else {
+                        scrollbar_allocation.x = allocation->x;
+                        scrollbar_allocation.x += GTK_CONTAINER (widget)->border_width;
+                }
+
+                scrollbar_allocation.height = allocation->height;
+                scrollbar_allocation.height -= 2 * GTK_CONTAINER (widget)->border_width;
+
+                scrollbar_allocation.y = allocation->y;
+                scrollbar_allocation.y += GTK_CONTAINER (widget)->border_width;
+
+                gtk_widget_size_allocate (scrollable_widget->priv->scrollbar,
+                                          &scrollbar_allocation);
+        }
+
+        if (has_child) {
+                GtkRequisition child_requisition;
+
+                gtk_widget_get_child_requisition (GTK_BIN (widget)->child,
+                                                  &child_requisition);
+
+                child_allocation.width = allocation->width;
+                child_allocation.width -= 2 * GTK_CONTAINER (widget)->border_width;
+                child_allocation.width -= 2 * widget->style->xthickness;
+
+                if (needs_scrollbar) {
+                        child_allocation.width -= scrollbar_allocation.width;
+                }
+
+                if (!is_flipped) {
+                        child_allocation.x = allocation->x;
+                        child_allocation.x += GTK_CONTAINER (widget)->border_width;
+                        child_allocation.x += widget->style->xthickness;
+                } else {
+                        child_allocation.x = allocation->x + allocation->width;
+                        child_allocation.x -= GTK_CONTAINER (widget)->border_width;
+                        child_allocation.x -= child_allocation.width;
+                        child_allocation.x -= widget->style->xthickness;
+                }
+
+                child_allocation.height = allocation->height;
+                child_allocation.height -= 2 * GTK_CONTAINER (widget)->border_width;
+                child_allocation.height -= 2 * widget->style->ythickness;
+
+                child_allocation.y = allocation->y;
+                child_allocation.y += GTK_CONTAINER (widget)->border_width;
+                child_allocation.y += widget->style->ythickness;
+
+                gtk_widget_size_allocate (GTK_BIN (widget)->child,
+                                          &child_allocation);
+        }
+}
+
+static void
+gdm_scrollable_widget_add (GtkContainer *container,
+                           GtkWidget    *child)
+{
+        GtkAdjustment *adjustment;
+
+        GTK_CONTAINER_CLASS (gdm_scrollable_widget_parent_class)->add (container, child);
+
+        adjustment = gtk_range_get_adjustment (GTK_RANGE (GDM_SCROLLABLE_WIDGET (container)->priv->scrollbar));
+
+        g_signal_connect_swapped (adjustment, "changed",
+                                  G_CALLBACK (gtk_widget_queue_resize),
+                                  container);
+
+        gtk_widget_set_scroll_adjustments (child, NULL, adjustment);
+}
+
+static void
+gdm_scrollable_widget_remove (GtkContainer *container,
+                              GtkWidget    *child)
+{
+        gtk_widget_set_scroll_adjustments (child, NULL, NULL);
+
+        GTK_CONTAINER_CLASS (gdm_scrollable_widget_parent_class)->remove (container, child);
+}
+
+static void
+gdm_scrollable_widget_forall (GtkContainer *container,
+                              gboolean      include_internals,
+                              GtkCallback   callback,
+                              gpointer      callback_data)
+{
+
+        GdmScrollableWidget *scrollable_widget;
+
+        scrollable_widget = GDM_SCROLLABLE_WIDGET (container);
+
+        GTK_CONTAINER_CLASS (gdm_scrollable_widget_parent_class)->forall (container,
+                                                                          include_internals,
+                                                                          callback,
+                                                                          callback_data);
+
+        if (!include_internals) {
+                return;
+        }
+
+        if (scrollable_widget->priv->scrollbar != NULL) {
+                callback (scrollable_widget->priv->scrollbar, callback_data);
+        }
+}
+
+static void
+gdm_scrollable_widget_destroy (GtkObject *object)
+{
+        GdmScrollableWidget *scrollable_widget;
+
+        scrollable_widget = GDM_SCROLLABLE_WIDGET (object);
+
+        gtk_widget_unparent (scrollable_widget->priv->scrollbar);
+        gtk_widget_destroy (scrollable_widget->priv->scrollbar);
+
+        GTK_OBJECT_CLASS (gdm_scrollable_widget_parent_class)->destroy (object);
+}
+
+static void
+gdm_scrollable_widget_finalize (GObject *object)
+{
+        GdmScrollableWidget *scrollable_widget;
+
+        scrollable_widget = GDM_SCROLLABLE_WIDGET (object);
+
+        G_OBJECT_CLASS (gdm_scrollable_widget_parent_class)->finalize (object);
+}
+
+static gboolean
+gdm_scrollable_widget_expose_event (GtkWidget      *widget,
+                                    GdkEventExpose *event)
+{
+        GdmScrollableWidget *scrollable_widget;
+        int                  x;
+        int                  y;
+        int                  width;
+        int                  height;
+        gboolean             is_flipped;
+
+        scrollable_widget = GDM_SCROLLABLE_WIDGET (widget);
+
+        if (!GTK_WIDGET_DRAWABLE (widget)) {
+                return FALSE;
+        }
+
+        is_flipped = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
+
+        x = widget->allocation.x;
+        x += 2 * GTK_CONTAINER (widget)->border_width;
+
+        width = widget->allocation.width;
+        width -= 2 * GTK_CONTAINER (widget)->border_width;
+
+        if (gdm_scrollable_widget_needs_scrollbar (scrollable_widget)) {
+                width -= scrollable_widget->priv->scrollbar->allocation.width;
+
+                if (is_flipped) {
+                        x += scrollable_widget->priv->scrollbar->allocation.width;
+                }
+        }
+
+        y = widget->allocation.y;
+        y += 2 * GTK_CONTAINER (widget)->border_width;
+
+        height = widget->allocation.height;
+        height -= 2 * GTK_CONTAINER (widget)->border_width;
+
+        gtk_paint_shadow (widget->style, widget->window,
+                          GTK_WIDGET_STATE (widget), GTK_SHADOW_IN,
+                          &event->area, widget, "scrolled_window",
+                          x, y, width, height);
+
+        return GTK_WIDGET_CLASS (gdm_scrollable_widget_parent_class)->expose_event (widget, event);
+}
+
+static gboolean
+gdm_scrollable_widget_scroll_event (GtkWidget      *widget,
+                                    GdkEventScroll *event)
+{
+        if (event->direction != GDK_SCROLL_UP && event->direction != GDK_SCROLL_DOWN) {
+                return FALSE;
+        }
+
+        if (!GTK_WIDGET_VISIBLE (GTK_WIDGET (widget))) {
+                return FALSE;
+        }
+
+        return gtk_widget_event (GDM_SCROLLABLE_WIDGET (widget)->priv->scrollbar,
+                                 (GdkEvent *) event);
+}
+
+static void
+add_scroll_binding (GtkBindingSet  *binding_set,
+                    guint           keyval,
+                    GdkModifierType mask,
+                    GtkScrollType   scroll)
+{
+        guint keypad_keyval = keyval - GDK_Left + GDK_KP_Left;
+
+        gtk_binding_entry_add_signal (binding_set, keyval, mask,
+                                      "scroll-child", 1,
+                                      GTK_TYPE_SCROLL_TYPE, scroll);
+        gtk_binding_entry_add_signal (binding_set, keypad_keyval, mask,
+                                      "scroll-child", 1,
+                                      GTK_TYPE_SCROLL_TYPE, scroll);
+}
+
+static void
+add_tab_bindings (GtkBindingSet    *binding_set,
+                  GdkModifierType   modifiers,
+                  GtkDirectionType  direction)
+{
+        gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers,
+                                      "move-focus-out", 1,
+                                      GTK_TYPE_DIRECTION_TYPE, direction);
+        gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
+                                      "move-focus-out", 1,
+                                      GTK_TYPE_DIRECTION_TYPE, direction);
+}
+
+static void
+gdm_scrollable_widget_class_install_bindings (GdmScrollableWidgetClass *klass)
+{
+        GtkBindingSet *binding_set;
+
+        binding_set = gtk_binding_set_by_class (klass);
+
+        add_scroll_binding (binding_set, GDK_Up, GDK_CONTROL_MASK, GTK_SCROLL_STEP_BACKWARD);
+        add_scroll_binding (binding_set, GDK_Down, GDK_CONTROL_MASK, GTK_SCROLL_STEP_FORWARD);
+
+        add_scroll_binding (binding_set, GDK_Page_Up, 0, GTK_SCROLL_PAGE_BACKWARD);
+        add_scroll_binding (binding_set, GDK_Page_Down, 0, GTK_SCROLL_PAGE_FORWARD);
+
+        add_scroll_binding (binding_set, GDK_Home, 0, GTK_SCROLL_START);
+        add_scroll_binding (binding_set, GDK_End, 0, GTK_SCROLL_END);
+
+        add_tab_bindings (binding_set, GDK_CONTROL_MASK, GTK_DIR_TAB_FORWARD);
+        add_tab_bindings (binding_set, GDK_CONTROL_MASK | GDK_SHIFT_MASK, GTK_DIR_TAB_BACKWARD);
+}
+
+static void
+gdm_scrollable_widget_class_init (GdmScrollableWidgetClass *klass)
+{
+        GObjectClass             *object_class;
+        GtkObjectClass           *gtk_object_class;
+        GtkWidgetClass           *widget_class;
+        GtkContainerClass        *container_class;
+        GdmScrollableWidgetClass *scrollable_widget_class;
+
+        object_class = G_OBJECT_CLASS (klass);
+        gtk_object_class = GTK_OBJECT_CLASS (klass);
+        widget_class = GTK_WIDGET_CLASS (klass);
+        container_class = GTK_CONTAINER_CLASS (klass);
+        scrollable_widget_class = GDM_SCROLLABLE_WIDGET_CLASS (klass);
+
+        object_class->finalize = gdm_scrollable_widget_finalize;
+
+        gtk_object_class->destroy = gdm_scrollable_widget_destroy;
+
+        widget_class->size_request = gdm_scrollable_widget_size_request;
+        widget_class->size_allocate = gdm_scrollable_widget_size_allocate;
+        widget_class->expose_event = gdm_scrollable_widget_expose_event;
+        widget_class->scroll_event = gdm_scrollable_widget_scroll_event;
+
+        container_class->add = gdm_scrollable_widget_add;
+        container_class->remove = gdm_scrollable_widget_remove;
+        container_class->forall = gdm_scrollable_widget_forall;
+
+        signals[SCROLL_CHILD] =
+          g_signal_new ("scroll-child",
+                        G_TYPE_FROM_CLASS (object_class),
+                        G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                        G_STRUCT_OFFSET (GtkScrolledWindowClass, scroll_child),
+                        NULL, NULL,
+                        g_cclosure_marshal_VOID__ENUM,
+                        G_TYPE_BOOLEAN, 1,
+                        GTK_TYPE_SCROLL_TYPE);
+        signals[MOVE_FOCUS_OUT] =
+          g_signal_new ("move-focus-out",
+                        G_TYPE_FROM_CLASS (object_class),
+                        G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+                        G_STRUCT_OFFSET (GtkScrolledWindowClass, move_focus_out),
+                        NULL, NULL,
+                        g_cclosure_marshal_VOID__ENUM,
+                        G_TYPE_NONE, 1,
+                        GTK_TYPE_DIRECTION_TYPE);
+        gdm_scrollable_widget_class_install_bindings (klass);
+
+        g_type_class_add_private (klass, sizeof (GdmScrollableWidgetPrivate));
+}
+
+static void
+gdm_scrollable_widget_add_scrollbar (GdmScrollableWidget *widget)
+{
+        gtk_widget_push_composite_child ();
+        widget->priv->scrollbar = gtk_vscrollbar_new (NULL);
+        gtk_widget_set_composite_name (widget->priv->scrollbar, "scrollbar");
+        gtk_widget_pop_composite_child ();
+        gtk_widget_set_parent (widget->priv->scrollbar, GTK_WIDGET (widget));
+        g_object_ref (widget->priv->scrollbar);
+}
+
+static void
+gdm_scrollable_widget_add_invisible_event_sink (GdmScrollableWidget *widget)
+{
+        widget->priv->invisible_event_sink =
+            gtk_invisible_new_for_screen (gtk_widget_get_screen (GTK_WIDGET (widget)));
+        gtk_widget_show (widget->priv->invisible_event_sink);
+}
+
+static void
+gdm_scrollable_widget_init (GdmScrollableWidget *widget)
+{
+        widget->priv = GDM_SCROLLABLE_WIDGET_GET_PRIVATE (widget);
+
+        gdm_scrollable_widget_add_scrollbar (widget);
+        gdm_scrollable_widget_add_invisible_event_sink (widget);
+}
+
+GtkWidget *
+gdm_scrollable_widget_new (void)
+{
+        GObject *object;
+
+        object = g_object_new (GDM_TYPE_SCROLLABLE_WIDGET, NULL);
+
+        return GTK_WIDGET (object);
+}
+
+static gboolean
+gdm_scrollable_widget_animations_are_disabled (GdmScrollableWidget *scrollable_widget)
+{
+        GtkSettings *settings;
+        gboolean     animations_are_enabled;
+
+        settings = gtk_settings_get_for_screen (gtk_widget_get_screen (GTK_WIDGET (scrollable_widget)));
+        g_object_get (settings, "gtk-enable-animations", &animations_are_enabled, NULL);
+
+        return animations_are_enabled == FALSE;
+}
+
+void
+gdm_scrollable_widget_slide_to_height (GdmScrollableWidget *scrollable_widget,
+                                       int                  height,
+                                       GdmScrollableWidgetSlideStepFunc step_func,
+                                       gpointer             step_user_data,
+                                       GdmScrollableWidgetSlideDoneFunc done_func,
+                                       gpointer             done_user_data)
+{
+        GtkWidget *widget;
+        gboolean   input_redirected;
+
+        g_return_if_fail (GDM_IS_SCROLLABLE_WIDGET (scrollable_widget));
+        widget = GTK_WIDGET (scrollable_widget);
+
+        g_return_if_fail (scrollable_widget->priv->animation == NULL);
+
+        input_redirected = gdm_scrollable_redirect_input_to_event_sink (scrollable_widget);
+
+        if (!input_redirected || gdm_scrollable_widget_animations_are_disabled (scrollable_widget)) {
+                if (step_func != NULL) {
+                        step_func (scrollable_widget, 0.0, step_user_data);
+                }
+
+                if (done_func != NULL) {
+                        done_func (scrollable_widget, done_user_data);
+                }
+
+                return;
+        }
+
+        scrollable_widget->priv->animation =
+            gdm_scrollable_widget_animation_new (widget,
+                                                 widget->allocation.height,
+                                                 height, step_func, step_user_data,
+                                                 done_func, done_user_data);
+
+        gdm_scrollable_widget_animation_start (scrollable_widget->priv->animation);
+}

Added: trunk/gui/simple-greeter/gdm-scrollable-widget.h
==============================================================================
--- (empty file)
+++ trunk/gui/simple-greeter/gdm-scrollable-widget.h	Thu Apr  3 22:09:04 2008
@@ -0,0 +1,70 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ *  Written by: Ray Strode <rstrode redhat com>
+ */
+
+#ifndef __GDM_SCROLLABLE_WIDGET_H
+#define __GDM_SCROLLABLE_WIDGET_H
+
+#include <glib-object.h>
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define GDM_TYPE_SCROLLABLE_WIDGET         (gdm_scrollable_widget_get_type ())
+#define GDM_SCROLLABLE_WIDGET(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_SCROLLABLE_WIDGET, GdmScrollableWidget))
+#define GDM_SCROLLABLE_WIDGET_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_SCROLLABLE_WIDGET, GdmScrollableWidgetClass))
+#define GDM_IS_SCROLLABLE_WIDGET(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_SCROLLABLE_WIDGET))
+#define GDM_IS_SCROLLABLE_WIDGET_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_SCROLLABLE_WIDGET))
+#define GDM_SCROLLABLE_WIDGET_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_SCROLLABLE_WIDGET, GdmScrollableWidgetClass))
+
+typedef struct GdmScrollableWidgetClass GdmScrollableWidgetClass;
+typedef struct GdmScrollableWidget GdmScrollableWidget;
+typedef struct GdmScrollableWidgetPrivate GdmScrollableWidgetPrivate;
+typedef void (* GdmScrollableWidgetSlideStepFunc) (GdmScrollableWidget *scrollable_widget,
+                                                   double               progress,
+                                                   gpointer            *user_data);
+typedef void (* GdmScrollableWidgetSlideDoneFunc) (GdmScrollableWidget *scrollable_widget,
+                                                   gpointer            *user_data);
+
+struct GdmScrollableWidget
+{
+        GtkBin                      parent;
+        GdmScrollableWidgetPrivate *priv;
+};
+
+struct GdmScrollableWidgetClass
+{
+        GtkBinClass parent_class;
+
+        void (* scroll_child) (GdmScrollableWidget *widget, GtkScrollType type);
+        void (* move_focus_out) (GdmScrollableWidget *widget, GtkDirectionType type);
+
+};
+
+GType                  gdm_scrollable_widget_get_type               (void);
+GtkWidget *            gdm_scrollable_widget_new                    (void);
+void                   gdm_scrollable_widget_slide_to_height        (GdmScrollableWidget *widget,
+                                                                     int                  height,
+                                                                     GdmScrollableWidgetSlideStepFunc step_func,
+                                                                     gpointer             step_user_data,
+                                                                     GdmScrollableWidgetSlideDoneFunc done_func,
+                                                                     gpointer             data);
+#endif /* __GDM_SCROLLABLE_WIDGET_H */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]