diff options
Diffstat (limited to 'gui/simple-greeter/gdm-chooser-widget.c')
-rw-r--r-- | gui/simple-greeter/gdm-chooser-widget.c | 2849 |
1 files changed, 0 insertions, 2849 deletions
diff --git a/gui/simple-greeter/gdm-chooser-widget.c b/gui/simple-greeter/gdm-chooser-widget.c deleted file mode 100644 index cab506c5..00000000 --- a/gui/simple-greeter/gdm-chooser-widget.c +++ /dev/null @@ -1,2849 +0,0 @@ -/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- - * - * Copyright (C) 2007 Ray Strode <rstrode@redhat.com> - * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu> - * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - */ - -#include "config.h" - -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> -#include <string.h> -#include <errno.h> -#include <dirent.h> -#include <sys/stat.h> -#include <syslog.h> -#include <locale.h> - -#include <glib.h> -#include <glib/gi18n.h> -#include <glib/gstdio.h> -#include <gtk/gtk.h> - -#include "gdm-chooser-widget.h" -#include "gdm-scrollable-widget.h" -#include "gdm-cell-renderer-timer.h" -#include "gdm-timer.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 *scrollable_widget; - - GtkWidget *items_view; - GtkListStore *list_store; - - GtkTreeModelFilter *model_filter; - GtkTreeModelSort *model_sorter; - - GdkPixbuf *is_in_use_pixbuf; - - /* row for the list_store model */ - GtkTreeRowReference *active_row; - GtkTreeRowReference *separator_row; - - GHashTable *rows_with_timers; - - GtkTreeViewColumn *status_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_rows_with_status; - gint number_of_rows_with_images; - gint number_of_active_timers; - - guint update_idle_id; - guint update_separator_idle_id; - guint update_cursor_idle_id; - guint update_visibility_idle_id; - guint update_items_idle_id; - guint timer_animation_timeout_id; - - gboolean list_visible; - - guint32 should_hide_inactive_items : 1; - guint32 emit_activated_after_resize_animation : 1; - - GdmChooserWidgetPosition separator_position; - GdmChooserWidgetState state; - - double active_row_normalized_position; -}; - -enum { - PROP_0, - PROP_INACTIVE_TEXT, - PROP_ACTIVE_TEXT, - PROP_LIST_VISIBLE -}; - -enum { - ACTIVATED = 0, - DEACTIVATED, - LOADED, - 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); - -static void update_timer_from_time (GdmChooserWidget *widget, - GtkTreeRowReference *row, - double now); - -G_DEFINE_TYPE (GdmChooserWidget, gdm_chooser_widget, GTK_TYPE_ALIGNMENT) - -enum { - CHOOSER_IMAGE_COLUMN = 0, - CHOOSER_NAME_COLUMN, - CHOOSER_COMMENT_COLUMN, - CHOOSER_PRIORITY_COLUMN, - CHOOSER_ITEM_IS_IN_USE_COLUMN, - CHOOSER_ITEM_IS_SEPARATED_COLUMN, - CHOOSER_ITEM_IS_VISIBLE_COLUMN, - CHOOSER_TIMER_START_TIME_COLUMN, - CHOOSER_TIMER_DURATION_COLUMN, - CHOOSER_TIMER_VALUE_COLUMN, - CHOOSER_ID_COLUMN, - CHOOSER_LOAD_FUNC_COLUMN, - CHOOSER_LOAD_DATA_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; -} - -typedef struct { - GdmChooserWidget *widget; - GdmChooserUpdateForeachFunc func; - gpointer user_data; -} UpdateForeachData; - -static gboolean -foreach_item (GtkTreeModel *model, - GtkTreePath *path, - GtkTreeIter *iter, - UpdateForeachData *data) -{ - GdkPixbuf *image; - char *name; - char *comment; - gboolean in_use; - gboolean is_separate; - gboolean res; - char *id; - gulong priority; - - gtk_tree_model_get (model, - iter, - CHOOSER_ID_COLUMN, &id, - CHOOSER_IMAGE_COLUMN, &image, - CHOOSER_NAME_COLUMN, &name, - CHOOSER_COMMENT_COLUMN, &comment, - CHOOSER_PRIORITY_COLUMN, &priority, - CHOOSER_ITEM_IS_IN_USE_COLUMN, &in_use, - CHOOSER_ITEM_IS_SEPARATED_COLUMN, &is_separate, - -1); - res = data->func (data->widget, - (const char *)id, - &image, - &name, - &comment, - &priority, - &in_use, - &is_separate, - data->user_data); - if (res) { - gtk_list_store_set (GTK_LIST_STORE (model), - iter, - CHOOSER_ID_COLUMN, id, - CHOOSER_IMAGE_COLUMN, image, - CHOOSER_NAME_COLUMN, name, - CHOOSER_COMMENT_COLUMN, comment, - CHOOSER_PRIORITY_COLUMN, priority, - CHOOSER_ITEM_IS_IN_USE_COLUMN, in_use, - CHOOSER_ITEM_IS_SEPARATED_COLUMN, is_separate, - -1); - } - - g_free (name); - g_free (comment); - if (image != NULL) { - g_object_unref (image); - } - - return FALSE; -} - -void -gdm_chooser_widget_update_foreach_item (GdmChooserWidget *widget, - GdmChooserUpdateForeachFunc func, - gpointer user_data) -{ - UpdateForeachData fdata; - - fdata.widget = widget; - fdata.func = func; - fdata.user_data = user_data; - gtk_tree_model_foreach (GTK_TREE_MODEL (widget->priv->list_store), - (GtkTreeModelForeachFunc) foreach_item, - &fdata); -} - -static void -translate_list_path_to_view_path (GdmChooserWidget *widget, - GtkTreePath **path) -{ - GtkTreePath *filtered_path; - GtkTreePath *sorted_path; - - /* the child model is the source for the filter */ - 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 void -translate_view_path_to_list_path (GdmChooserWidget *widget, - GtkTreePath **path) -{ - GtkTreePath *filtered_path; - GtkTreePath *list_path; - - /* the child model is the source for the filter */ - filtered_path = gtk_tree_model_sort_convert_path_to_child_path (widget->priv->model_sorter, - *path); - - list_path = gtk_tree_model_filter_convert_path_to_child_path (widget->priv->model_filter, - filtered_path); - gtk_tree_path_free (filtered_path); - - gtk_tree_path_free (*path); - *path = list_path; -} - -static GtkTreePath * -get_list_path_to_active_row (GdmChooserWidget *widget) -{ - GtkTreePath *path; - - if (widget->priv->active_row == NULL) { - return NULL; - } - - path = gtk_tree_row_reference_get_path (widget->priv->active_row); - if (path == NULL) { - return NULL; - } - - return path; -} - -static GtkTreePath * -get_view_path_to_active_row (GdmChooserWidget *widget) -{ - GtkTreePath *path; - - path = get_list_path_to_active_row (widget); - if (path == NULL) { - return NULL; - } - - translate_list_path_to_view_path (widget, &path); - - return path; -} - -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 = get_list_path_to_active_row (widget); - if (path == NULL) { - return NULL; - } - - 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 -get_selected_list_path (GdmChooserWidget *widget, - GtkTreePath **pathp) -{ - GtkTreeSelection *selection; - GtkTreeModel *sort_model; - GtkTreeIter sorted_iter; - GtkTreePath *path; - - path = NULL; - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget->priv->items_view)); - if (gtk_tree_selection_get_selected (selection, &sort_model, &sorted_iter)) { - - g_assert (sort_model == GTK_TREE_MODEL (widget->priv->model_sorter)); - - path = gtk_tree_model_get_path (sort_model, &sorted_iter); - - translate_view_path_to_list_path (widget, &path); - } else { - g_debug ("GdmChooserWidget: no rows selected"); - } - - *pathp = path; -} - -char * -gdm_chooser_widget_get_selected_item (GdmChooserWidget *widget) -{ - GtkTreeIter iter; - GtkTreeModel *model; - GtkTreePath *path; - char *id; - - id = NULL; - - get_selected_list_path (widget, &path); - - if (path == NULL) { - return NULL; - } - - model = GTK_TREE_MODEL (widget->priv->list_store); - - if (gtk_tree_model_get_iter (model, &iter, path)) { - gtk_tree_model_get (model, - &iter, - CHOOSER_ID_COLUMN, - &id, - -1); - } - - gtk_tree_path_free (path); - - return id; -} - -void -gdm_chooser_widget_set_selected_item (GdmChooserWidget *widget, - const char *id) -{ - GtkTreeIter iter; - GtkTreeSelection *selection; - GtkTreeModel *model; - - g_return_if_fail (GDM_IS_CHOOSER_WIDGET (widget)); - - g_debug ("GdmChooserWidget: setting selected item '%s'", - id ? id : "(null)"); - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget->priv->items_view)); - - model = GTK_TREE_MODEL (widget->priv->list_store); - - if (find_item (widget, id, &iter)) { - GtkTreePath *path; - - path = gtk_tree_model_get_path (model, &iter); - translate_list_path_to_view_path (widget, &path); - - gtk_tree_selection_select_path (selection, path); - - 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_path_free (path); - } else { - gtk_tree_selection_unselect_all (selection); - } -} - -static void -activate_from_item_id (GdmChooserWidget *widget, - const char *item_id) -{ - GtkTreeModel *model; - GtkTreePath *path; - GtkTreeIter iter; - char *path_str; - - model = GTK_TREE_MODEL (widget->priv->list_store); - path = NULL; - - if (find_item (widget, item_id, &iter)) { - path = gtk_tree_model_get_path (model, &iter); - - path_str = gtk_tree_path_to_string (path); - g_debug ("GdmChooserWidget: got list path '%s'", path_str); - g_free (path_str); - - translate_list_path_to_view_path (widget, &path); - - path_str = gtk_tree_path_to_string (path); - g_debug ("GdmChooserWidget: translated to view path '%s'", path_str); - g_free (path_str); - } - - if (path == NULL) { - g_debug ("GdmChooserWidget: unable to activate - path for item '%s' not found", item_id); - 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), - 0, 0, 0, 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 -on_shrink_animation_step (GdmScrollableWidget *scrollable_widget, - double progress, - int *new_height, - GdmChooserWidget *widget) -{ - GtkTreePath *active_row_path; - const double final_alignment = 0.5; - double row_alignment; - - active_row_path = get_view_path_to_active_row (widget); - row_alignment = widget->priv->active_row_normalized_position + progress * (final_alignment - widget->priv->active_row_normalized_position); - - 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 gboolean -update_separator_visibility (GdmChooserWidget *widget) -{ - GtkTreePath *separator_path; - GtkTreeIter iter; - gboolean is_visible; - - g_debug ("GdmChooserWidget: updating separator visibility"); - - separator_path = gtk_tree_row_reference_get_path (widget->priv->separator_row); - - if (separator_path == NULL) { - goto out; - } - - gtk_tree_model_get_iter (GTK_TREE_MODEL (widget->priv->list_store), - &iter, separator_path); - - if (widget->priv->number_of_normal_rows > 0 && - widget->priv->number_of_separated_rows > 0 && - widget->priv->state != GDM_CHOOSER_WIDGET_STATE_SHRUNK) { - is_visible = TRUE; - } else { - is_visible = FALSE; - } - - gtk_list_store_set (widget->priv->list_store, - &iter, - CHOOSER_ITEM_IS_VISIBLE_COLUMN, is_visible, - -1); - - out: - widget->priv->update_separator_idle_id = 0; - return FALSE; -} - -static void -queue_update_separator_visibility (GdmChooserWidget *widget) -{ - if (widget->priv->update_separator_idle_id == 0) { - g_debug ("GdmChooserWidget: queuing update separator visibility"); - - widget->priv->update_separator_idle_id = - g_idle_add ((GSourceFunc) update_separator_visibility, widget); - } -} - -static gboolean -update_visible_items (GdmChooserWidget *widget) -{ - GtkTreePath *path; - GtkTreePath *end; - GtkTreeIter iter; - - if (! gtk_tree_view_get_visible_range (GTK_TREE_VIEW (widget->priv->items_view), &path, &end)) { - g_debug ("GdmChooserWidget: Unable to get visible range"); - goto out; - } - - for (; gtk_tree_path_compare (path, end) <= 0; gtk_tree_path_next (path)) { - char *id; - gpointer user_data; - GdmChooserWidgetItemLoadFunc func; - - if (! gtk_tree_model_get_iter (GTK_TREE_MODEL (widget->priv->model_sorter), &iter, path)) - break; - - id = NULL; - gtk_tree_model_get (GTK_TREE_MODEL (widget->priv->model_sorter), - &iter, - CHOOSER_ID_COLUMN, &id, - CHOOSER_LOAD_FUNC_COLUMN, &func, - CHOOSER_LOAD_DATA_COLUMN, &user_data, - -1); - if (id != NULL && func != NULL) { - GtkTreeIter child_iter; - GtkTreeIter list_iter; - - g_debug ("Updating for %s", id); - - gtk_tree_model_sort_convert_iter_to_child_iter (widget->priv->model_sorter, - &child_iter, - &iter); - - gtk_tree_model_filter_convert_iter_to_child_iter (widget->priv->model_filter, - &list_iter, - &child_iter); - /* remove the func so it doesn't need to load again */ - gtk_list_store_set (GTK_LIST_STORE (widget->priv->list_store), - &list_iter, - CHOOSER_LOAD_FUNC_COLUMN, NULL, - -1); - - func (widget, id, user_data); - } - - g_free (id); - } - - gtk_tree_path_free (path); - gtk_tree_path_free (end); - out: - widget->priv->update_items_idle_id = 0; - - return FALSE; -} - -static void -set_chooser_list_visible (GdmChooserWidget *widget, - gboolean is_visible) -{ - if (widget->priv->list_visible != is_visible) { - widget->priv->list_visible = is_visible; - g_object_notify (G_OBJECT (widget), "list-visible"); - } -} - -static gboolean -update_chooser_visibility (GdmChooserWidget *widget) -{ - update_visible_items (widget); - - if (gdm_chooser_widget_get_number_of_items (widget) > 0) { - gtk_widget_show (widget->priv->frame); - set_chooser_list_visible (widget, gtk_widget_get_visible (GTK_WIDGET (widget))); - } else { - gtk_widget_hide (widget->priv->frame); - set_chooser_list_visible (widget, FALSE); - } - - widget->priv->update_visibility_idle_id = 0; - - return FALSE; -} - -static inline gboolean -iters_equal (GtkTreeIter *a, - GtkTreeIter *b) -{ - if (a->stamp != b->stamp) - return FALSE; - - if (a->user_data != b->user_data) - return FALSE; - - /* user_data2 and user_data3 are not used in GtkListStore */ - - return TRUE; -} - -static void -set_inactive_items_visible (GdmChooserWidget *widget, - gboolean should_show) -{ - GtkTreeModel *model; - GtkTreeModel *view_model; - char *active_item_id; - GtkTreeIter active_item_iter; - GtkTreeIter iter; - - g_debug ("setting inactive items visible"); - - active_item_id = get_active_item_id (widget, &active_item_iter); - if (active_item_id == NULL) { - g_debug ("GdmChooserWidget: No active item set"); - } - - model = GTK_TREE_MODEL (widget->priv->list_store); - - if (!gtk_tree_model_get_iter_first (model, &iter)) { - goto out; - } - - /* unset tree view model to hide row add/remove signals from gail */ - view_model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget->priv->items_view)); - g_object_ref (view_model); - gtk_tree_view_set_model (GTK_TREE_VIEW (widget->priv->items_view), NULL); - - g_debug ("GdmChooserWidget: Setting inactive items visible: %s", should_show ? "true" : "false"); - - do { - if (active_item_id == NULL || !iters_equal (&active_item_iter, &iter)) { - /* inactive item */ - gtk_list_store_set (widget->priv->list_store, - &iter, - CHOOSER_ITEM_IS_VISIBLE_COLUMN, should_show, - -1); - } else { - /* always show the active item */ - gtk_list_store_set (widget->priv->list_store, - &iter, - CHOOSER_ITEM_IS_VISIBLE_COLUMN, TRUE, - -1); - } - } while (gtk_tree_model_iter_next (model, &iter)); - - gtk_tree_view_set_model (GTK_TREE_VIEW (widget->priv->items_view), view_model); - g_object_unref (view_model); - - queue_update_separator_visibility (widget); - - out: - g_free (active_item_id); -} - -static void -on_shrink_animation_complete (GdmScrollableWidget *scrollable_widget, - GdmChooserWidget *widget) -{ - g_assert (widget->priv->state == GDM_CHOOSER_WIDGET_STATE_SHRINKING); - - g_debug ("GdmChooserWidget: shrink complete"); - - widget->priv->active_row_normalized_position = 0.5; - set_inactive_items_visible (GDM_CHOOSER_WIDGET (widget), FALSE); - gtk_tree_view_set_enable_search (GTK_TREE_VIEW (widget->priv->items_view), FALSE); - widget->priv->state = GDM_CHOOSER_WIDGET_STATE_SHRUNK; - - queue_update_separator_visibility (widget); - - if (widget->priv->emit_activated_after_resize_animation) { - g_signal_emit (widget, signals[ACTIVATED], 0); - widget->priv->emit_activated_after_resize_animation = FALSE; - } -} - -static int -get_height_of_row_at_path (GdmChooserWidget *widget, - GtkTreePath *path) -{ - GdkRectangle area; - - gtk_tree_view_get_background_area (GTK_TREE_VIEW (widget->priv->items_view), - path, NULL, &area); - - return area.height; -} - -static double -get_normalized_position_of_row_at_path (GdmChooserWidget *widget, - GtkTreePath *path) -{ - GdkRectangle area_of_row_at_path; - GdkRectangle area_of_visible_rows; - GtkAllocation items_view_allocation; - - gtk_widget_get_allocation (widget->priv->items_view, &items_view_allocation); - - gtk_tree_view_get_background_area (GTK_TREE_VIEW (widget->priv->items_view), - path, NULL, &area_of_row_at_path); - - 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 CLAMP (((double) area_of_row_at_path.y) / items_view_allocation.height, 0.0, 1.0); -} - -static void -start_shrink_animation (GdmChooserWidget *widget) -{ - GtkTreePath *active_row_path; - int active_row_height; - int number_of_visible_rows; - - g_assert (widget->priv->active_row != NULL); - - number_of_visible_rows = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (widget->priv->model_sorter), NULL); - - if (number_of_visible_rows <= 1) { - on_shrink_animation_complete (GDM_SCROLLABLE_WIDGET (widget->priv->scrollable_widget), - widget); - return; - } - - active_row_path = get_view_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 char * -get_first_item (GdmChooserWidget *widget) -{ - GtkTreeModel *model; - GtkTreeIter iter; - char *id; - - model = GTK_TREE_MODEL (widget->priv->list_store); - - if (!gtk_tree_model_get_iter_first (model, &iter)) { - g_assert_not_reached (); - } - - gtk_tree_model_get (model, &iter, - CHOOSER_ID_COLUMN, &id, -1); - return id; -} - -static gboolean -activate_if_one_item (GdmChooserWidget *widget) -{ - char *id; - - g_debug ("GdmChooserWidget: attempting to activate single item"); - - if (gdm_chooser_widget_get_number_of_items (widget) != 1) { - g_debug ("GdmChooserWidget: unable to activate single item - has %d items", gdm_chooser_widget_get_number_of_items (widget)); - return FALSE; - } - - id = get_first_item (widget); - if (id != NULL) { - gdm_chooser_widget_set_active_item (widget, id); - g_free (id); - } - - return FALSE; -} - -static void -_grab_focus (GtkWidget *widget) -{ - GtkWidget *foc_widget; - - foc_widget = GDM_CHOOSER_WIDGET (widget)->priv->items_view; - g_debug ("GdmChooserWidget: grabbing focus"); - - if (gtk_widget_has_focus (foc_widget)) { - g_debug ("GdmChooserWidget: not grabbing focus - already has it"); - return; - } - - gtk_widget_child_focus (foc_widget, GTK_DIR_TAB_FORWARD); -} - -static void -queue_update_visible_items (GdmChooserWidget *widget) -{ - if (widget->priv->update_items_idle_id != 0) { - g_source_remove (widget->priv->update_items_idle_id); - } - - widget->priv->update_items_idle_id = - g_timeout_add (100, (GSourceFunc) update_visible_items, widget); -} - -static void -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; - gtk_tree_view_set_enable_search (GTK_TREE_VIEW (widget->priv->items_view), TRUE); - queue_update_visible_items (widget); - - _grab_focus (GTK_WIDGET (widget)); -} - -static int -get_number_of_on_screen_rows (GdmChooserWidget *widget) -{ - 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); - - number_of_rows = *end_index - *start_index + 1; - - gtk_tree_path_free (start_path); - gtk_tree_path_free (end_path); - - return number_of_rows; -} - -static void -on_grow_animation_step (GdmScrollableWidget *scrollable_widget, - double progress, - int *new_height, - GdmChooserWidget *widget) -{ - int number_of_visible_rows; - int number_of_on_screen_rows; - - number_of_visible_rows = gtk_tree_model_iter_n_children (GTK_TREE_MODEL (widget->priv->model_sorter), NULL); - number_of_on_screen_rows = get_number_of_on_screen_rows (widget); - - GtkRequisition scrollable_widget_req; - gtk_widget_get_requisition (gtk_bin_get_child (GTK_BIN (scrollable_widget)), &scrollable_widget_req); - *new_height = scrollable_widget_req.height; -} - -static void -start_grow_animation (GdmChooserWidget *widget) -{ - GtkRequisition scrollable_widget_req; - gtk_widget_get_requisition (gtk_bin_get_child (GTK_BIN (widget->priv->scrollable_widget)), - &scrollable_widget_req); - - set_inactive_items_visible (widget, TRUE); - - gdm_scrollable_widget_slide_to_height (GDM_SCROLLABLE_WIDGET (widget->priv->scrollable_widget), - scrollable_widget_req.height, - (GdmScrollableWidgetSlideStepFunc) - on_grow_animation_step, widget, - (GdmScrollableWidgetSlideDoneFunc) - on_grow_animation_complete, widget); -} - -static void -skip_resize_animation (GdmChooserWidget *widget) -{ - if (widget->priv->state == GDM_CHOOSER_WIDGET_STATE_SHRINKING) { - set_inactive_items_visible (GDM_CHOOSER_WIDGET (widget), FALSE); - gtk_tree_view_set_enable_search (GTK_TREE_VIEW (widget->priv->items_view), FALSE); - widget->priv->state = GDM_CHOOSER_WIDGET_STATE_SHRUNK; - } else if (widget->priv->state == GDM_CHOOSER_WIDGET_STATE_GROWING) { - set_inactive_items_visible (GDM_CHOOSER_WIDGET (widget), TRUE); - gtk_tree_view_set_enable_search (GTK_TREE_VIEW (widget->priv->items_view), TRUE); - widget->priv->state = GDM_CHOOSER_WIDGET_STATE_GROWN; - _grab_focus (GTK_WIDGET (widget)); - } -} - -static void -gdm_chooser_widget_grow (GdmChooserWidget *widget) -{ - if (widget->priv->state == GDM_CHOOSER_WIDGET_STATE_GROWN) { - g_debug ("GdmChooserWidget: Asking for grow but already grown"); - return; - } - - if (widget->priv->state == GDM_CHOOSER_WIDGET_STATE_SHRINKING) { - gdm_scrollable_widget_stop_sliding (GDM_SCROLLABLE_WIDGET (widget->priv->scrollable_widget)); - } - - 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; - - if (gtk_widget_get_visible (GTK_WIDGET (widget))) { - start_grow_animation (widget); - } else { - skip_resize_animation (widget); - } -} - -static gboolean -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_view_scroll_to_cell (GTK_TREE_VIEW (widget->priv->items_view), - path, - NULL, - TRUE, - 0.5, - 0.0); - - } - gtk_tree_path_free (path); - - widget->priv->update_cursor_idle_id = 0; - return FALSE; -} - -static gboolean -clear_selection (GdmChooserWidget *widget) -{ - GtkTreeSelection *selection; - GtkWidget *window; - - g_debug ("GdmChooserWidget: clearing selection"); - - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget->priv->items_view)); - gtk_tree_selection_unselect_all (selection); - - window = gtk_widget_get_ancestor (GTK_WIDGET (widget), GTK_TYPE_WINDOW); - - if (window != NULL) { - gtk_window_set_focus (GTK_WINDOW (window), NULL); - } - - return FALSE; -} - -static void -gdm_chooser_widget_shrink (GdmChooserWidget *widget) -{ - g_assert (widget->priv->should_hide_inactive_items == TRUE); - - if (widget->priv->state == GDM_CHOOSER_WIDGET_STATE_GROWING) { - gdm_scrollable_widget_stop_sliding (GDM_SCROLLABLE_WIDGET (widget->priv->scrollable_widget)); - } - - 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); - - clear_selection (widget); - - widget->priv->state = GDM_CHOOSER_WIDGET_STATE_SHRINKING; - - if (gtk_widget_get_visible (GTK_WIDGET (widget))) { - start_shrink_animation (widget); - } else { - skip_resize_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); - - if (widget->priv->should_hide_inactive_items) { - g_debug ("GdmChooserWidget: will emit activated after resize"); - widget->priv->emit_activated_after_resize_animation = TRUE; - gdm_chooser_widget_shrink (widget); - } else { - g_debug ("GdmChooserWidget: emitting activated"); - g_signal_emit (widget, signals[ACTIVATED], 0); - } -} - -static void -deactivate (GdmChooserWidget *widget) -{ - GtkTreePath *path; - - if (widget->priv->active_row == NULL) { - return; - } - - path = get_view_path_to_active_row (widget); - - gtk_tree_row_reference_free (widget->priv->active_row); - widget->priv->active_row = NULL; - - gtk_tree_view_set_cursor (GTK_TREE_VIEW (widget->priv->items_view), - path, NULL, FALSE); - gtk_tree_path_free (path); - - if (widget->priv->state != GDM_CHOOSER_WIDGET_STATE_GROWN) { - gdm_chooser_widget_grow (widget); - } else { - queue_update_visible_items (widget); - } - - g_signal_emit (widget, signals[DEACTIVATED], 0); -} - -void -gdm_chooser_widget_activate_selected_item (GdmChooserWidget *widget) -{ - GtkTreeRowReference *row; - gboolean is_already_active; - GtkTreePath *path; - GtkTreeModel *model; - - row = NULL; - model = GTK_TREE_MODEL (widget->priv->list_store); - is_already_active = FALSE; - - path = NULL; - - get_selected_list_path (widget, &path); - if (path == NULL) { - g_debug ("GdmChooserWidget: no row selected"); - return; - } - - 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 (path, active_path) == 0) { - is_already_active = TRUE; - } - gtk_tree_path_free (active_path); - } - g_assert (path != NULL); - row = gtk_tree_row_reference_new (model, path); - gtk_tree_path_free (path); - - if (!is_already_active) { - activate_from_row (widget, row); - } else { - g_debug ("GdmChooserWidget: row is already active"); - } - 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)); - - g_debug ("GdmChooserWidget: setting active item '%s'", - id ? id : "(null)"); - - 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; - case PROP_LIST_VISIBLE: - g_value_set_boolean (value, self->priv->list_visible); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -gdm_chooser_widget_dispose (GObject *object) -{ - GdmChooserWidget *widget; - - widget = GDM_CHOOSER_WIDGET (object); - - if (widget->priv->update_items_idle_id > 0) { - g_source_remove (widget->priv->update_items_idle_id); - widget->priv->update_items_idle_id = 0; - } - - if (widget->priv->update_separator_idle_id > 0) { - g_source_remove (widget->priv->update_separator_idle_id); - widget->priv->update_separator_idle_id = 0; - } - - if (widget->priv->update_visibility_idle_id > 0) { - g_source_remove (widget->priv->update_visibility_idle_id); - widget->priv->update_visibility_idle_id = 0; - } - - if (widget->priv->update_cursor_idle_id > 0) { - g_source_remove (widget->priv->update_cursor_idle_id); - widget->priv->update_cursor_idle_id = 0; - } - - 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 void -gdm_chooser_widget_hide (GtkWidget *widget) -{ - skip_resize_animation (GDM_CHOOSER_WIDGET (widget)); - GTK_WIDGET_CLASS (gdm_chooser_widget_parent_class)->hide (widget); -} - -static void -gdm_chooser_widget_show (GtkWidget *widget) -{ - skip_resize_animation (GDM_CHOOSER_WIDGET (widget)); - - GTK_WIDGET_CLASS (gdm_chooser_widget_parent_class)->show (widget); -} - -static void -gdm_chooser_widget_map (GtkWidget *widget) -{ - queue_update_visible_items (GDM_CHOOSER_WIDGET (widget)); - - GTK_WIDGET_CLASS (gdm_chooser_widget_parent_class)->map (widget); -} - -static void -gdm_chooser_widget_size_allocate (GtkWidget *widget, - GtkAllocation *allocation) -{ - GdmChooserWidget *chooser_widget; - - GTK_WIDGET_CLASS (gdm_chooser_widget_parent_class)->size_allocate (widget, allocation); - - chooser_widget = GDM_CHOOSER_WIDGET (widget); - -} - -static gboolean -gdm_chooser_widget_focus (GtkWidget *widget, - GtkDirectionType direction) -{ - /* Since we only have one focusable child (the tree view), - * no matter which direction we're going the rules are the - * same: - * - * 1) if it's aready got focus, return FALSE to surrender - * that focus. - * 2) if it doesn't already have focus, then grab it - */ - if (gtk_container_get_focus_child (GTK_CONTAINER (widget)) != NULL) { - g_debug ("GdmChooserWidget: not focusing - focus child not null"); - return FALSE; - } - - _grab_focus (widget); - - return TRUE; -} - -static gboolean -gdm_chooser_widget_focus_in_event (GtkWidget *widget, - GdkEventFocus *focus_event) -{ - /* We don't ever want the chooser widget itself to have focus. - * Focus should always go to the tree view. - */ - _grab_focus (widget); - - return FALSE; -} - -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->dispose = gdm_chooser_widget_dispose; - object_class->finalize = gdm_chooser_widget_finalize; - widget_class->size_allocate = gdm_chooser_widget_size_allocate; - widget_class->hide = gdm_chooser_widget_hide; - widget_class->show = gdm_chooser_widget_show; - widget_class->map = gdm_chooser_widget_map; - widget_class->focus = gdm_chooser_widget_focus; - widget_class->focus_in_event = gdm_chooser_widget_focus_in_event; - - signals [LOADED] = g_signal_new ("loaded", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GdmChooserWidgetClass, loaded), - NULL, - NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, - 0); - - 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_object_class_install_property (object_class, - PROP_LIST_VISIBLE, - g_param_spec_boolean ("list-visible", - _("List Visible"), - _("Whether the chooser list is visible"), - FALSE, - G_PARAM_READABLE)); - - g_type_class_add_private (klass, sizeof (GdmChooserWidgetPrivate)); -} - -static void -on_row_activated (GtkTreeView *tree_view, - GtkTreePath *tree_path, - GtkTreeViewColumn *tree_column, - GdmChooserWidget *widget) -{ - char *path_str; - - path_str = gtk_tree_path_to_string (tree_path); - g_debug ("GdmChooserWidget: row activated '%s'", path_str ? path_str : "(null)"); - g_free (path_str); - gdm_chooser_widget_activate_selected_item (widget); -} - -static gboolean -path_is_separator (GdmChooserWidget *widget, - GtkTreeModel *model, - GtkTreePath *path) -{ - GtkTreePath *separator_path; - GtkTreePath *translated_path; - gboolean is_separator; - - separator_path = gtk_tree_row_reference_get_path (widget->priv->separator_row); - - if (separator_path == NULL) { - return FALSE; - } - - if (model == GTK_TREE_MODEL (widget->priv->model_sorter)) { - GtkTreePath *filtered_path; - - filtered_path = gtk_tree_model_sort_convert_path_to_child_path (widget->priv->model_sorter, path); - - translated_path = gtk_tree_model_filter_convert_path_to_child_path (widget->priv->model_filter, filtered_path); - gtk_tree_path_free (filtered_path); - } else if (model == GTK_TREE_MODEL (widget->priv->model_filter)) { - translated_path = gtk_tree_model_filter_convert_path_to_child_path (widget->priv->model_filter, path); - } else { - g_assert (model == GTK_TREE_MODEL (widget->priv->list_store)); - translated_path = gtk_tree_path_copy (path); - } - - if (gtk_tree_path_compare (separator_path, translated_path) == 0) { - is_separator = TRUE; - } else { - is_separator = FALSE; - } - gtk_tree_path_free (translated_path); - - return is_separator; -} - -static int -gdm_multilingual_collate (const gchar *text_a, const gchar *text_b) -{ - PangoDirection direction_a; - PangoDirection direction_b; - const gchar *p_a; - const gchar *p_b; - gchar *org_locale = NULL; - gchar *sub_a; - gchar *sub_b; - gunichar ch_a; - gunichar ch_b; - GUnicodeScript script_a; - GUnicodeScript script_b; - gboolean composed_alpha_a; - gboolean composed_alpha_b; - gboolean all_alpha_a; - gboolean all_alpha_b; - int result; - - direction_a = pango_find_base_dir (text_a, -1); - direction_b = pango_find_base_dir (text_b, -1); - if ((direction_a == PANGO_DIRECTION_LTR || - direction_a == PANGO_DIRECTION_NEUTRAL) && - direction_b == PANGO_DIRECTION_RTL) - return -1; - if (direction_a == PANGO_DIRECTION_RTL && - (direction_b == PANGO_DIRECTION_LTR || - direction_b == PANGO_DIRECTION_NEUTRAL)) - return 1; - - if (!g_get_charset (NULL)) { - org_locale = g_strdup (setlocale (LC_ALL, NULL)); - if (!setlocale (LC_ALL, "en_US.UTF-8")) { - setlocale (LC_ALL, org_locale); - g_free (org_locale); - org_locale = NULL; - } - } - - result = 0; - all_alpha_a = all_alpha_b = TRUE; - for (p_a = text_a, p_b = text_b; - p_a && *p_a && p_b && *p_b; - p_a = g_utf8_next_char (p_a), p_b = g_utf8_next_char (p_b)) { - ch_a = g_utf8_get_char (p_a); - ch_b = g_utf8_get_char (p_b); - script_a = g_unichar_get_script (ch_a); - script_b = g_unichar_get_script (ch_b); - composed_alpha_a = (script_a == G_UNICODE_SCRIPT_LATIN || - script_a == G_UNICODE_SCRIPT_GREEK || - script_a == G_UNICODE_SCRIPT_CYRILLIC ); - composed_alpha_b = (script_b == G_UNICODE_SCRIPT_LATIN || - script_b == G_UNICODE_SCRIPT_GREEK || - script_b == G_UNICODE_SCRIPT_CYRILLIC ); - all_alpha_a &= composed_alpha_a; - all_alpha_b &= composed_alpha_b; - if (all_alpha_a && !composed_alpha_b && - ch_b >= 0x530) { - result = -1; - break; - } else if (!composed_alpha_a && all_alpha_b && - ch_a >= 0x530) { - result = 1; - break; - } else if (ch_a != ch_b) { - sub_a = g_strndup (text_a, g_utf8_next_char (p_a) - text_a); - sub_b = g_strndup (text_b, g_utf8_next_char (p_b) - text_b); - result = g_utf8_collate (sub_a, sub_b); - g_free (sub_a); - g_free (sub_b); - if (result != 0) { - break; - } - } - } - if (result != 0) { - if (org_locale) { - setlocale (LC_ALL, org_locale); - g_free (org_locale); - org_locale = NULL; - } - return result; - } - if (org_locale) { - setlocale (LC_ALL, org_locale); - g_free (org_locale); - org_locale = NULL; - } - return g_utf8_collate (text_a, text_b); -} - -static int -compare_item (GtkTreeModel *model, - GtkTreeIter *a, - GtkTreeIter *b, - gpointer data) -{ - GdmChooserWidget *widget; - char *name_a; - char *name_b; - gulong prio_a; - gulong prio_b; - gboolean is_separate_a; - gboolean is_separate_b; - int result; - int direction; - GtkTreeIter *separator_iter; - char *id; - PangoAttrList *attrs; - - 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_PRIORITY_COLUMN, &prio_a, - CHOOSER_ITEM_IS_SEPARATED_COLUMN, &is_separate_a, - -1); - } - - 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_PRIORITY_COLUMN, &prio_b, - 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) { - if (prio_a == prio_b) { - char *text_a; - char *text_b; - - text_a = NULL; - text_b = NULL; - pango_parse_markup (name_a, -1, 0, &attrs, &text_a, NULL, NULL); - if (text_a == NULL) { - g_debug ("GdmChooserWidget: unable to parse markup: '%s'", name_a); - } - pango_parse_markup (name_b, -1, 0, &attrs, &text_b, NULL, NULL); - if (text_b == NULL) { - g_debug ("GdmChooserWidget: unable to parse markup: '%s'", name_b); - } - if (text_a != NULL && text_b != NULL) { - result = gdm_multilingual_collate (text_a, text_b); - } else { - result = gdm_multilingual_collate (name_a, name_b); - } - g_free (text_a); - g_free (text_b); - } else if (prio_a > prio_b) { - result = -1; - } else { - result = 1; - } - } 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 ("<b>%s</b>\n" - "<i><span size=\"x-small\">%s</span></i>", - name ? name : "(null)", widget->priv->in_use_message); - } else { - markup = g_strdup_printf ("%s", name ? name : "(null)"); - } - 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) -{ - g_debug ("GdmChooserWidget: updating column visibility"); - - 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_rows_with_status > 0) { - gtk_tree_view_column_set_visible (widget->priv->status_column, - TRUE); - } else { - gtk_tree_view_column_set_visible (widget->priv->status_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.0, 0.0, 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; - - if (!widget->priv->should_hide_inactive_items) { - return FALSE; - } - - 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 gboolean -search_equal_func (GtkTreeModel *model, - int column, - const char *key, - GtkTreeIter *iter, - GdmChooserWidget *widget) -{ - char *id; - char *name; - char *key_folded; - gboolean ret; - - if (key == NULL) { - return FALSE; - } - - ret = TRUE; - id = NULL; - name = NULL; - - key_folded = g_utf8_casefold (key, -1); - - gtk_tree_model_get (model, - iter, - CHOOSER_ID_COLUMN, &id, - CHOOSER_NAME_COLUMN, &name, - -1); - if (name != NULL) { - char *name_folded; - - name_folded = g_utf8_casefold (name, -1); - ret = !g_str_has_prefix (name_folded, key_folded); - g_free (name_folded); - - if (!ret) { - goto out; - } - } - - if (id != NULL) { - char *id_folded; - - - id_folded = g_utf8_casefold (id, -1); - ret = !g_str_has_prefix (id_folded, key_folded); - g_free (id_folded); - - if (!ret) { - goto out; - } - } - out: - g_free (id); - g_free (name); - g_free (key_folded); - - return ret; -} - -static void -search_position_func (GtkTreeView *tree_view, - GtkWidget *search_dialog, - gpointer user_data) -{ - /* Move it outside the region viewable by - * the user. - * FIXME: This is pretty inelegant. - * - * It might be nicer to make a GdmOffscreenBin - * widget that we pack into the chooser widget below - * the frame but gets redirected offscreen. - * - * Then we would add a GtkEntry to the bin and set - * that entry as the search entry for the tree view - * instead of using a search position func. - */ - gtk_window_move (GTK_WINDOW (search_dialog), -24000, -24000); -} - -static void -on_selection_changed (GtkTreeSelection *selection, - GdmChooserWidget *widget) -{ - GtkTreePath *path; - - get_selected_list_path (widget, &path); - if (path != NULL) { - char *path_str; - path_str = gtk_tree_path_to_string (path); - g_debug ("GdmChooserWidget: selection change to list path '%s'", path_str); - g_free (path_str); - } else { - g_debug ("GdmChooserWidget: selection cleared"); - } -} - -static void -on_adjustment_value_changed (GtkAdjustment *adjustment, - GdmChooserWidget *widget) -{ - queue_update_visible_items (widget); -} - -static void -gdm_chooser_widget_init (GdmChooserWidget *widget) -{ - GtkTreeViewColumn *column; - GtkTreeSelection *selection; - GtkCellRenderer *renderer; - GtkAdjustment *adjustment; - - widget->priv = GDM_CHOOSER_WIDGET_GET_PRIVATE (widget); - - /* Even though, we're a container and also don't ever take - * focus for ourselve, we set CAN_FOCUS so that gtk_widget_grab_focus - * works on us. We then override grab_focus requests to - * be redirected our internal tree view - */ - gtk_widget_set_can_focus (GTK_WIDGET (widget), TRUE); - - gtk_alignment_set_padding (GTK_ALIGNMENT (widget), 0, 0, 0, 0); - - add_frame (widget); - - 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->scrollable_widget); - - 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); - - gtk_tree_view_set_search_equal_func (GTK_TREE_VIEW (widget->priv->items_view), - (GtkTreeViewSearchEqualFunc)search_equal_func, - widget, - NULL); - - gtk_tree_view_set_search_position_func (GTK_TREE_VIEW (widget->priv->items_view), - (GtkTreeViewSearchPositionFunc)search_position_func, - widget, - NULL); - - /* 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->scrollable_widget), - 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_signal_connect (selection, "changed", G_CALLBACK (on_selection_changed), widget); - - g_assert (NUMBER_OF_CHOOSER_COLUMNS == 13); - widget->priv->list_store = gtk_list_store_new (NUMBER_OF_CHOOSER_COLUMNS, - GDK_TYPE_PIXBUF, - G_TYPE_STRING, - G_TYPE_STRING, - G_TYPE_ULONG, - G_TYPE_BOOLEAN, - G_TYPE_BOOLEAN, - G_TYPE_BOOLEAN, - G_TYPE_DOUBLE, - G_TYPE_DOUBLE, - G_TYPE_DOUBLE, - G_TYPE_STRING, - G_TYPE_POINTER, - G_TYPE_POINTER); - - 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, - "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); - - /* STATUS 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->status_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); - - renderer = gdm_cell_renderer_timer_new (); - gtk_tree_view_column_pack_start (column, renderer, FALSE); - gtk_tree_view_column_add_attribute (column, renderer, "value", - CHOOSER_TIMER_VALUE_COLUMN); - - widget->priv->rows_with_timers = - g_hash_table_new_full (g_str_hash, - g_str_equal, - (GDestroyNotify) g_free, - (GDestroyNotify) - gtk_tree_row_reference_free); - - add_separator (widget); - queue_column_visibility_update (widget); - - adjustment = gtk_tree_view_get_vadjustment (GTK_TREE_VIEW (widget->priv->items_view)); - g_signal_connect (adjustment, "value-changed", G_CALLBACK (on_adjustment_value_changed), 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_hash_table_destroy (widget->priv->rows_with_timers); - widget->priv->rows_with_timers = 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_update_item (GdmChooserWidget *widget, - const char *id, - GdkPixbuf *new_image, - const char *new_name, - const char *new_comment, - gulong new_priority, - gboolean new_in_use, - gboolean new_is_separate) -{ - GtkTreeModel *model; - GtkTreeIter iter; - GdkPixbuf *image; - gboolean is_separate; - gboolean 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, &in_use, - CHOOSER_ITEM_IS_SEPARATED_COLUMN, &is_separate, - -1); - - if (image != new_image) { - if (image == NULL && new_image != NULL) { - widget->priv->number_of_rows_with_images++; - } else if (image != NULL && new_image == NULL) { - widget->priv->number_of_rows_with_images--; - } - queue_column_visibility_update (widget); - } - if (image != NULL) { - g_object_unref (image); - } - - if (in_use != new_in_use) { - if (new_in_use) { - widget->priv->number_of_rows_with_status++; - } else { - widget->priv->number_of_rows_with_status--; - } - queue_column_visibility_update (widget); - } - - if (is_separate != new_is_separate) { - if (new_is_separate) { - widget->priv->number_of_separated_rows++; - widget->priv->number_of_normal_rows--; - } else { - widget->priv->number_of_separated_rows--; - widget->priv->number_of_normal_rows++; - } - queue_update_separator_visibility (widget); - } - - gtk_list_store_set (widget->priv->list_store, - &iter, - CHOOSER_IMAGE_COLUMN, new_image, - CHOOSER_NAME_COLUMN, new_name, - CHOOSER_COMMENT_COLUMN, new_comment, - CHOOSER_PRIORITY_COLUMN, new_priority, - CHOOSER_ITEM_IS_IN_USE_COLUMN, new_in_use, - CHOOSER_ITEM_IS_SEPARATED_COLUMN, new_is_separate, - -1); -} - -static void -queue_update_chooser_visibility (GdmChooserWidget *widget) -{ - if (widget->priv->update_visibility_idle_id == 0) { - widget->priv->update_visibility_idle_id = - g_idle_add ((GSourceFunc) update_chooser_visibility, widget); - } -} - -static void -queue_move_cursor_to_top (GdmChooserWidget *widget) -{ - if (widget->priv->update_cursor_idle_id == 0) { - widget->priv->update_cursor_idle_id = - g_idle_add ((GSourceFunc) move_cursor_to_top, widget); - } -} - -void -gdm_chooser_widget_add_item (GdmChooserWidget *widget, - const char *id, - GdkPixbuf *image, - const char *name, - const char *comment, - gulong priority, - gboolean in_use, - gboolean keep_separate, - GdmChooserWidgetItemLoadFunc load_func, - gpointer load_data) -{ - 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++; - } - queue_update_separator_visibility (widget); - - if (in_use) { - widget->priv->number_of_rows_with_status++; - queue_column_visibility_update (widget); - } - - if (image != NULL) { - widget->priv->number_of_rows_with_images++; - queue_column_visibility_update (widget); - } - - 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_PRIORITY_COLUMN, priority, - 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, - CHOOSER_LOAD_FUNC_COLUMN, load_func, - CHOOSER_LOAD_DATA_COLUMN, load_data, - -1); - - queue_update_chooser_visibility (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_rows_with_status--; - queue_column_visibility_update (widget); - } - - if (is_separate) { - widget->priv->number_of_separated_rows--; - } else { - widget->priv->number_of_normal_rows--; - } - queue_update_separator_visibility (widget); - - gtk_list_store_remove (widget->priv->list_store, &iter); - - queue_update_chooser_visibility (widget); -} - -gboolean -gdm_chooser_widget_lookup_item (GdmChooserWidget *widget, - const char *id, - GdkPixbuf **image, - char **name, - char **comment, - gulong *priority, - gboolean *is_in_use, - gboolean *is_separate) -{ - 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); - active_item_id = NULL; - - if (!find_item (widget, id, &iter)) { - return FALSE; - } - } - g_free (active_item_id); - - if (image != NULL) { - gtk_tree_model_get (GTK_TREE_MODEL (widget->priv->list_store), &iter, - CHOOSER_IMAGE_COLUMN, image, -1); - } - - if (name != NULL) { - gtk_tree_model_get (GTK_TREE_MODEL (widget->priv->list_store), &iter, - CHOOSER_NAME_COLUMN, name, -1); - } - - if (priority != NULL) { - gtk_tree_model_get (GTK_TREE_MODEL (widget->priv->list_store), &iter, - CHOOSER_PRIORITY_COLUMN, priority, -1); - } - - if (is_in_use != NULL) { - gtk_tree_model_get (GTK_TREE_MODEL (widget->priv->list_store), &iter, - CHOOSER_ITEM_IS_IN_USE_COLUMN, is_in_use, -1); - } - - if (is_separate != NULL) { - gtk_tree_model_get (GTK_TREE_MODEL (widget->priv->list_store), &iter, - 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; - gboolean was_in_use; - - g_return_if_fail (GDM_IS_CHOOSER_WIDGET (widget)); - - if (!find_item (widget, id, &iter)) { - return; - } - - gtk_tree_model_get (GTK_TREE_MODEL (widget->priv->list_store), &iter, - CHOOSER_ITEM_IS_IN_USE_COLUMN, &was_in_use, - -1); - - if (was_in_use != is_in_use) { - - if (is_in_use) { - widget->priv->number_of_rows_with_status++; - } else { - widget->priv->number_of_rows_with_status--; - } - queue_column_visibility_update (widget); - - gtk_list_store_set (widget->priv->list_store, - &iter, - CHOOSER_ITEM_IS_IN_USE_COLUMN, is_in_use, - -1); - - } -} - -void -gdm_chooser_widget_set_item_priority (GdmChooserWidget *widget, - const char *id, - gulong priority) -{ - GtkTreeIter iter; - gulong was_priority; - - g_return_if_fail (GDM_IS_CHOOSER_WIDGET (widget)); - - if (!find_item (widget, id, &iter)) { - return; - } - - gtk_tree_model_get (GTK_TREE_MODEL (widget->priv->list_store), &iter, - CHOOSER_PRIORITY_COLUMN, &was_priority, - -1); - - if (was_priority != priority) { - - gtk_list_store_set (widget->priv->list_store, - &iter, - CHOOSER_PRIORITY_COLUMN, priority, - -1); - gtk_tree_model_filter_refilter (widget->priv->model_filter); - } -} - -static double -get_current_time (void) -{ - const double microseconds_per_second = 1000000.0; - double timestamp; - GTimeVal now; - - g_get_current_time (&now); - - timestamp = ((microseconds_per_second * now.tv_sec) + now.tv_usec) / - microseconds_per_second; - - return timestamp; -} - -static gboolean -on_timer_timeout (GdmChooserWidget *widget) -{ - GHashTableIter iter; - GSList *list; - GSList *tmp; - gpointer key; - gpointer value; - double now; - - list = NULL; - g_hash_table_iter_init (&iter, widget->priv->rows_with_timers); - while (g_hash_table_iter_next (&iter, &key, &value)) { - list = g_slist_prepend (list, value); - } - - now = get_current_time (); - for (tmp = list; tmp != NULL; tmp = tmp->next) { - GtkTreeRowReference *row; - - row = (GtkTreeRowReference *) tmp->data; - - update_timer_from_time (widget, row, now); - } - g_slist_free (list); - - return TRUE; -} - -static void -start_timer (GdmChooserWidget *widget, - GtkTreeRowReference *row, - double duration) -{ - GtkTreeModel *model; - GtkTreePath *path; - GtkTreeIter iter; - - model = GTK_TREE_MODEL (widget->priv->list_store); - - path = gtk_tree_row_reference_get_path (row); - gtk_tree_model_get_iter (model, &iter, path); - gtk_tree_path_free (path); - - gtk_list_store_set (widget->priv->list_store, &iter, - CHOOSER_TIMER_START_TIME_COLUMN, - get_current_time (), -1); - gtk_list_store_set (widget->priv->list_store, &iter, - CHOOSER_TIMER_DURATION_COLUMN, - duration, -1); - gtk_list_store_set (widget->priv->list_store, &iter, - CHOOSER_TIMER_VALUE_COLUMN, 0.0, -1); - - widget->priv->number_of_active_timers++; - if (widget->priv->timer_animation_timeout_id == 0) { - g_assert (g_hash_table_size (widget->priv->rows_with_timers) == 1); - - widget->priv->timer_animation_timeout_id = - g_timeout_add (1000 / 20, - (GSourceFunc) on_timer_timeout, - widget); - - } -} - -static void -stop_timer (GdmChooserWidget *widget, - GtkTreeRowReference *row) -{ - GtkTreeModel *model; - GtkTreePath *path; - GtkTreeIter iter; - - model = GTK_TREE_MODEL (widget->priv->list_store); - - path = gtk_tree_row_reference_get_path (row); - gtk_tree_model_get_iter (model, &iter, path); - gtk_tree_path_free (path); - - gtk_list_store_set (widget->priv->list_store, &iter, - CHOOSER_TIMER_START_TIME_COLUMN, - 0.0, -1); - gtk_list_store_set (widget->priv->list_store, &iter, - CHOOSER_TIMER_DURATION_COLUMN, - 0.0, -1); - gtk_list_store_set (widget->priv->list_store, &iter, - CHOOSER_TIMER_VALUE_COLUMN, 0.0, -1); - - widget->priv->number_of_active_timers--; - if (widget->priv->number_of_active_timers == 0) { - g_source_remove (widget->priv->timer_animation_timeout_id); - widget->priv->timer_animation_timeout_id = 0; - } -} - -static void -update_timer_from_time (GdmChooserWidget *widget, - GtkTreeRowReference *row, - double now) -{ - GtkTreeModel *model; - GtkTreePath *path; - GtkTreeIter iter; - double start_time; - double duration; - double elapsed_ratio; - - model = GTK_TREE_MODEL (widget->priv->list_store); - - path = gtk_tree_row_reference_get_path (row); - gtk_tree_model_get_iter (model, &iter, path); - gtk_tree_path_free (path); - - gtk_tree_model_get (model, &iter, - CHOOSER_TIMER_START_TIME_COLUMN, &start_time, - CHOOSER_TIMER_DURATION_COLUMN, &duration, -1); - - if (duration > G_MINDOUBLE) { - elapsed_ratio = (now - start_time) / duration; - } else { - elapsed_ratio = 0.0; - } - - gtk_list_store_set (widget->priv->list_store, &iter, - CHOOSER_TIMER_VALUE_COLUMN, - elapsed_ratio, -1); - - if (elapsed_ratio > .999) { - char *id; - - stop_timer (widget, row); - - gtk_tree_model_get (model, &iter, - CHOOSER_ID_COLUMN, &id, -1); - g_hash_table_remove (widget->priv->rows_with_timers, - id); - g_free (id); - - widget->priv->number_of_rows_with_status--; - queue_column_visibility_update (widget); - } -} - -void -gdm_chooser_widget_set_item_timer (GdmChooserWidget *widget, - const char *id, - gulong timeout) -{ - GtkTreeModel *model; - GtkTreeRowReference *row; - - g_return_if_fail (GDM_IS_CHOOSER_WIDGET (widget)); - - model = GTK_TREE_MODEL (widget->priv->list_store); - - row = g_hash_table_lookup (widget->priv->rows_with_timers, - id); - - g_assert (row == NULL || gtk_tree_row_reference_valid (row)); - - if (row != NULL) { - stop_timer (widget, row); - } - - if (timeout == 0) { - if (row == NULL) { - g_warning ("could not find item with ID '%s' to " - "remove timer", id); - return; - } - - g_hash_table_remove (widget->priv->rows_with_timers, - id); - gtk_tree_model_filter_refilter (widget->priv->model_filter); - return; - } - - if (row == NULL) { - GtkTreeIter iter; - GtkTreePath *path; - - if (!find_item (widget, id, &iter)) { - g_warning ("could not find item with ID '%s' to " - "add timer", id); - return; - } - - path = gtk_tree_model_get_path (model, &iter); - row = gtk_tree_row_reference_new (model, path); - - g_hash_table_insert (widget->priv->rows_with_timers, - g_strdup (id), row); - - widget->priv->number_of_rows_with_status++; - queue_column_visibility_update (widget); - } - - start_timer (widget, row, timeout / 1000.0); -} - -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); - } -} - -int -gdm_chooser_widget_get_number_of_items (GdmChooserWidget *widget) -{ - return widget->priv->number_of_normal_rows + - widget->priv->number_of_separated_rows; -} - -void -gdm_chooser_widget_activate_if_one_item (GdmChooserWidget *widget) -{ - activate_if_one_item (widget); -} - -void -gdm_chooser_widget_propagate_pending_key_events (GdmChooserWidget *widget) -{ - if (!gdm_scrollable_widget_has_queued_key_events (GDM_SCROLLABLE_WIDGET (widget->priv->scrollable_widget))) { - return; - } - - gdm_scrollable_widget_replay_queued_key_events (GDM_SCROLLABLE_WIDGET (widget->priv->scrollable_widget)); -} - -void -gdm_chooser_widget_loaded (GdmChooserWidget *widget) -{ - g_signal_emit (widget, signals[LOADED], 0); - update_chooser_visibility (widget); - queue_move_cursor_to_top (widget); -} |