diff options
author | Benedikt Meurer <benny@xfce.org> | 2006-04-14 14:52:13 +0000 |
---|---|---|
committer | Benedikt Meurer <benny@xfce.org> | 2006-04-14 14:52:13 +0000 |
commit | 38ac84356f6627573fee9ff47e231f23ed7eee1f (patch) | |
tree | 7d9bf00d58dd7cfc8d84804acccbde350bfcdf6f /thunar/thunar-abstract-icon-view.c | |
parent | 374e5bf82f7ef5f6c19caa0fb9ff7ff36e55e23b (diff) | |
download | thunar-38ac84356f6627573fee9ff47e231f23ed7eee1f.tar.gz |
2006-04-14 Benedikt Meurer <benny@xfce.org>
* docs/README.thunarrc, thunar/thunar-preferences.c: Add new option
LastCompactViewZoomLevel.
* thunar/thunar-abstract-icon-view-ui.xml, thunar/Makefile.am,
thunar/thunar-abstract-icon-view.{c,h}, thunar/thunar-window.c
thunar/thunar-compact-view.{c,h}, thunar/thunar-window-ui.xml,
thunar/thunar-icon-view.{c,h}: Add a "Compact View", which uses
ExoIconView with EXO_ICON_VIEW_LAYOUT_COLS layout mode. Based on
patches from Matt McClinch <mattmcclinch@gmail.com>.
* THANKS: Add Matt McClinch.
* po/POTFILES.in: Add new files.
* po/Thunar.pot, po/*.po: Merge new strings.
* po/de.po: Update german translations.
(Old svn revision: 20881)
Diffstat (limited to 'thunar/thunar-abstract-icon-view.c')
-rw-r--r-- | thunar/thunar-abstract-icon-view.c | 755 |
1 files changed, 755 insertions, 0 deletions
diff --git a/thunar/thunar-abstract-icon-view.c b/thunar/thunar-abstract-icon-view.c new file mode 100644 index 00000000..da47d51a --- /dev/null +++ b/thunar/thunar-abstract-icon-view.c @@ -0,0 +1,755 @@ +/* $Id$ */ +/*- + * Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org> + * + * 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 + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <gdk/gdkkeysyms.h> + +#include <thunar/thunar-gobject-extensions.h> +#include <thunar/thunar-gtk-extensions.h> +#include <thunar/thunar-abstract-icon-view.h> +#include <thunar/thunar-abstract-icon-view-ui.h> + + + +#define THUNAR_ABSTRACT_ICON_VIEW_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), THUNAR_TYPE_ABSTRACT_ICON_VIEW, ThunarAbstractIconViewPrivate)) + + + +static void thunar_abstract_icon_view_class_init (ThunarAbstractIconViewClass *klass); +static void thunar_abstract_icon_view_init (ThunarAbstractIconView *abstract_icon_view); +static void thunar_abstract_icon_view_connect_ui_manager (ThunarStandardView *standard_view, + GtkUIManager *ui_manager); +static void thunar_abstract_icon_view_disconnect_ui_manager (ThunarStandardView *standard_view, + GtkUIManager *ui_manager); +static GList *thunar_abstract_icon_view_get_selected_items (ThunarStandardView *standard_view); +static void thunar_abstract_icon_view_select_all (ThunarStandardView *standard_view); +static void thunar_abstract_icon_view_unselect_all (ThunarStandardView *standard_view); +static void thunar_abstract_icon_view_select_path (ThunarStandardView *standard_view, + GtkTreePath *path); +static void thunar_abstract_icon_view_set_cursor (ThunarStandardView *standard_view, + GtkTreePath *path, + gboolean start_editing); +static void thunar_abstract_icon_view_scroll_to_path (ThunarStandardView *standard_view, + GtkTreePath *path, + gboolean use_align, + gfloat row_align, + gfloat col_align); +static GtkTreePath *thunar_abstract_icon_view_get_path_at_pos (ThunarStandardView *standard_view, + gint x, + gint y); +static gboolean thunar_abstract_icon_view_get_visible_range (ThunarStandardView *standard_view, + GtkTreePath **start_path, + GtkTreePath **end_path); +static void thunar_abstract_icon_view_highlight_path (ThunarStandardView *standard_view, + GtkTreePath *path); +static GtkAction *thunar_abstract_icon_view_gesture_action (ThunarAbstractIconView *abstract_icon_view); +static void thunar_abstract_icon_view_action_sort (GtkAction *action, + GtkAction *current, + ThunarStandardView *standard_view); +static void thunar_abstract_icon_view_notify_model (ExoIconView *view, + GParamSpec *pspec, + ThunarAbstractIconView *abstract_icon_view); +static gboolean thunar_abstract_icon_view_button_press_event (ExoIconView *view, + GdkEventButton *event, + ThunarAbstractIconView *abstract_icon_view); +static gboolean thunar_abstract_icon_view_button_release_event (ExoIconView *view, + GdkEventButton *event, + ThunarAbstractIconView *abstract_icon_view); +static gboolean thunar_abstract_icon_view_expose_event (ExoIconView *view, + GdkEventExpose *event, + ThunarAbstractIconView *abstract_icon_view); +static gboolean thunar_abstract_icon_view_key_press_event (ExoIconView *view, + GdkEventKey *event, + ThunarAbstractIconView *abstract_icon_view); +static gboolean thunar_abstract_icon_view_motion_notify_event (ExoIconView *view, + GdkEventMotion *event, + ThunarAbstractIconView *abstract_icon_view); +static void thunar_abstract_icon_view_item_activated (ExoIconView *view, + GtkTreePath *path, + ThunarAbstractIconView *abstract_icon_view); +static void thunar_abstract_icon_view_sort_column_changed (GtkTreeSortable *sortable, + ThunarAbstractIconView *abstract_icon_view); +static void thunar_abstract_icon_view_zoom_level_changed (ThunarAbstractIconView *abstract_icon_view); + + + +struct _ThunarAbstractIconViewPrivate +{ + /* the UI manager merge id for the abstract icon view */ + gint ui_merge_id; + + /* mouse gesture support */ + gint gesture_start_x; + gint gesture_start_y; + gint gesture_current_x; + gint gesture_current_y; + gint gesture_expose_id; + gint gesture_motion_id; + gint gesture_release_id; +}; + + + +static const GtkActionEntry action_entries[] = +{ + { "arrange-items-menu", NULL, N_ ("Arran_ge Items"), NULL, NULL, NULL, }, +}; + +static const GtkRadioActionEntry column_action_entries[] = +{ + { "sort-by-name", NULL, N_ ("Sort By _Name"), NULL, N_ ("Keep items sorted by their name"), THUNAR_COLUMN_NAME, }, + { "sort-by-size", NULL, N_ ("Sort By _Size"), NULL, N_ ("Keep items sorted by their size"), THUNAR_COLUMN_SIZE, }, + { "sort-by-type", NULL, N_ ("Sort By _Type"), NULL, N_ ("Keep items sorted by their type"), THUNAR_COLUMN_TYPE, }, + { "sort-by-mtime", NULL, N_ ("Sort By Modification _Date"), NULL, N_ ("Keep items sorted by their modification date"), THUNAR_COLUMN_DATE_MODIFIED, }, +}; + +static const GtkRadioActionEntry order_action_entries[] = +{ + { "sort-ascending", NULL, N_ ("_Ascending"), NULL, N_ ("Sort items in ascending order"), GTK_SORT_ASCENDING, }, + { "sort-descending", NULL, N_ ("_Descending"), NULL, N_ ("Sort items in descending order"), GTK_SORT_DESCENDING, }, +}; + + + +GType +thunar_abstract_icon_view_get_type (void) +{ + static GType type = G_TYPE_INVALID; + + if (G_UNLIKELY (type == G_TYPE_INVALID)) + { + static const GTypeInfo info = + { + sizeof (ThunarAbstractIconViewClass), + NULL, + NULL, + (GClassInitFunc) thunar_abstract_icon_view_class_init, + NULL, + NULL, + sizeof (ThunarAbstractIconView), + 0, + (GInstanceInitFunc) thunar_abstract_icon_view_init, + NULL, + }; + + type = g_type_register_static (THUNAR_TYPE_STANDARD_VIEW, I_("ThunarAbstractIconView"), &info, G_TYPE_FLAG_ABSTRACT); + } + + return type; +} + + + +static void +thunar_abstract_icon_view_class_init (ThunarAbstractIconViewClass *klass) +{ + ThunarStandardViewClass *thunarstandard_view_class; + + /* add private data to the instance type */ + g_type_class_add_private (klass, sizeof (ThunarAbstractIconViewPrivate)); + + thunarstandard_view_class = THUNAR_STANDARD_VIEW_CLASS (klass); + thunarstandard_view_class->connect_ui_manager = thunar_abstract_icon_view_connect_ui_manager; + thunarstandard_view_class->disconnect_ui_manager = thunar_abstract_icon_view_disconnect_ui_manager; + thunarstandard_view_class->get_selected_items = thunar_abstract_icon_view_get_selected_items; + thunarstandard_view_class->select_all = thunar_abstract_icon_view_select_all; + thunarstandard_view_class->unselect_all = thunar_abstract_icon_view_unselect_all; + thunarstandard_view_class->select_path = thunar_abstract_icon_view_select_path; + thunarstandard_view_class->set_cursor = thunar_abstract_icon_view_set_cursor; + thunarstandard_view_class->scroll_to_path = thunar_abstract_icon_view_scroll_to_path; + thunarstandard_view_class->get_path_at_pos = thunar_abstract_icon_view_get_path_at_pos; + thunarstandard_view_class->get_visible_range = thunar_abstract_icon_view_get_visible_range; + thunarstandard_view_class->highlight_path = thunar_abstract_icon_view_highlight_path; +} + + + +static void +thunar_abstract_icon_view_init (ThunarAbstractIconView *abstract_icon_view) +{ + GtkWidget *view; + + /* connect private instance data */ + abstract_icon_view->priv = THUNAR_ABSTRACT_ICON_VIEW_GET_PRIVATE (abstract_icon_view); + + /* stay informed about zoom-level changes, so we can force a re-layout on the abstract_icon view */ + g_signal_connect (G_OBJECT (abstract_icon_view), "notify::zoom-level", G_CALLBACK (thunar_abstract_icon_view_zoom_level_changed), NULL); + + /* create the real view */ + view = exo_icon_view_new (); + g_signal_connect (G_OBJECT (view), "notify::model", G_CALLBACK (thunar_abstract_icon_view_notify_model), abstract_icon_view); + g_signal_connect (G_OBJECT (view), "button-press-event", G_CALLBACK (thunar_abstract_icon_view_button_press_event), abstract_icon_view); + g_signal_connect (G_OBJECT (view), "key-press-event", G_CALLBACK (thunar_abstract_icon_view_key_press_event), abstract_icon_view); + g_signal_connect (G_OBJECT (view), "item-activated", G_CALLBACK (thunar_abstract_icon_view_item_activated), abstract_icon_view); + g_signal_connect_swapped (G_OBJECT (view), "selection-changed", G_CALLBACK (thunar_standard_view_selection_changed), abstract_icon_view); + gtk_container_add (GTK_CONTAINER (abstract_icon_view), view); + gtk_widget_show (view); + + /* initialize the abstract icon view properties */ + exo_icon_view_set_enable_search (EXO_ICON_VIEW (view), TRUE); + exo_icon_view_set_selection_mode (EXO_ICON_VIEW (view), GTK_SELECTION_MULTIPLE); + + /* add the abstract icon renderer */ + g_object_set (G_OBJECT (THUNAR_STANDARD_VIEW (abstract_icon_view)->icon_renderer), "follow-state", TRUE, NULL); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (view), THUNAR_STANDARD_VIEW (abstract_icon_view)->icon_renderer, FALSE); + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (view), THUNAR_STANDARD_VIEW (abstract_icon_view)->icon_renderer, + "file", THUNAR_COLUMN_FILE); + + /* add the name renderer */ + g_object_set (G_OBJECT (THUNAR_STANDARD_VIEW (abstract_icon_view)->name_renderer), "follow-state", TRUE, NULL); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (view), THUNAR_STANDARD_VIEW (abstract_icon_view)->name_renderer, TRUE); + gtk_cell_layout_add_attribute (GTK_CELL_LAYOUT (view), THUNAR_STANDARD_VIEW (abstract_icon_view)->name_renderer, + "text", THUNAR_COLUMN_NAME); + + /* setup the abstract icon view actions */ + gtk_action_group_add_actions (THUNAR_STANDARD_VIEW (abstract_icon_view)->action_group, + action_entries, G_N_ELEMENTS (action_entries), + GTK_WIDGET (abstract_icon_view)); + gtk_action_group_add_radio_actions (THUNAR_STANDARD_VIEW (abstract_icon_view)->action_group, column_action_entries, + G_N_ELEMENTS (column_action_entries), THUNAR_COLUMN_NAME, + G_CALLBACK (thunar_abstract_icon_view_action_sort), abstract_icon_view); + gtk_action_group_add_radio_actions (THUNAR_STANDARD_VIEW (abstract_icon_view)->action_group, order_action_entries, + G_N_ELEMENTS (order_action_entries), GTK_SORT_ASCENDING, + G_CALLBACK (thunar_abstract_icon_view_action_sort), abstract_icon_view); + + /* we need to listen to sort column changes to sync the menu items */ + g_signal_connect (G_OBJECT (THUNAR_STANDARD_VIEW (abstract_icon_view)->model), "sort-column-changed", + G_CALLBACK (thunar_abstract_icon_view_sort_column_changed), abstract_icon_view); + thunar_abstract_icon_view_sort_column_changed (GTK_TREE_SORTABLE (THUNAR_STANDARD_VIEW (abstract_icon_view)->model), abstract_icon_view); +} + + + +static void +thunar_abstract_icon_view_connect_ui_manager (ThunarStandardView *standard_view, + GtkUIManager *ui_manager) +{ + ThunarAbstractIconView *abstract_icon_view = THUNAR_ABSTRACT_ICON_VIEW (standard_view); + GError *error = NULL; + + abstract_icon_view->priv->ui_merge_id = gtk_ui_manager_add_ui_from_string (ui_manager, thunar_abstract_icon_view_ui, + thunar_abstract_icon_view_ui_length, &error); + if (G_UNLIKELY (abstract_icon_view->priv->ui_merge_id == 0)) + { + g_error ("Failed to merge ThunarAbstractIconView menus: %s", error->message); + g_error_free (error); + } +} + + + +static void +thunar_abstract_icon_view_disconnect_ui_manager (ThunarStandardView *standard_view, + GtkUIManager *ui_manager) +{ + gtk_ui_manager_remove_ui (ui_manager, THUNAR_ABSTRACT_ICON_VIEW (standard_view)->priv->ui_merge_id); +} + + + +static GList* +thunar_abstract_icon_view_get_selected_items (ThunarStandardView *standard_view) +{ + return exo_icon_view_get_selected_items (EXO_ICON_VIEW (GTK_BIN (standard_view)->child)); +} + + + +static void +thunar_abstract_icon_view_select_all (ThunarStandardView *standard_view) +{ + g_return_if_fail (THUNAR_IS_ABSTRACT_ICON_VIEW (standard_view)); + exo_icon_view_select_all (EXO_ICON_VIEW (GTK_BIN (standard_view)->child)); +} + + + +static void +thunar_abstract_icon_view_unselect_all (ThunarStandardView *standard_view) +{ + g_return_if_fail (THUNAR_IS_ABSTRACT_ICON_VIEW (standard_view)); + exo_icon_view_unselect_all (EXO_ICON_VIEW (GTK_BIN (standard_view)->child)); +} + + + +static void +thunar_abstract_icon_view_select_path (ThunarStandardView *standard_view, + GtkTreePath *path) +{ + g_return_if_fail (THUNAR_IS_ABSTRACT_ICON_VIEW (standard_view)); + exo_icon_view_select_path (EXO_ICON_VIEW (GTK_BIN (standard_view)->child), path); +} + + + +static void +thunar_abstract_icon_view_set_cursor (ThunarStandardView *standard_view, + GtkTreePath *path, + gboolean start_editing) +{ + GtkCellRendererMode mode; + + g_return_if_fail (THUNAR_IS_ABSTRACT_ICON_VIEW (standard_view)); + + /* make sure the name renderer is editable */ + mode = standard_view->name_renderer->mode; + standard_view->name_renderer->mode = GTK_CELL_RENDERER_MODE_EDITABLE; + + /* tell the abstract_icon view to start editing the given item */ + exo_icon_view_set_cursor (EXO_ICON_VIEW (GTK_BIN (standard_view)->child), path, standard_view->name_renderer, start_editing); + + /* reset the name renderer mode */ + standard_view->name_renderer->mode = mode; +} + + + +static void +thunar_abstract_icon_view_scroll_to_path (ThunarStandardView *standard_view, + GtkTreePath *path, + gboolean use_align, + gfloat row_align, + gfloat col_align) +{ + g_return_if_fail (THUNAR_IS_ABSTRACT_ICON_VIEW (standard_view)); + exo_icon_view_scroll_to_path (EXO_ICON_VIEW (GTK_BIN (standard_view)->child), path, use_align, row_align, col_align); +} + + + +static GtkTreePath* +thunar_abstract_icon_view_get_path_at_pos (ThunarStandardView *standard_view, + gint x, + gint y) +{ + g_return_val_if_fail (THUNAR_IS_ABSTRACT_ICON_VIEW (standard_view), NULL); + return exo_icon_view_get_path_at_pos (EXO_ICON_VIEW (GTK_BIN (standard_view)->child), x, y); +} + + + +static gboolean +thunar_abstract_icon_view_get_visible_range (ThunarStandardView *standard_view, + GtkTreePath **start_path, + GtkTreePath **end_path) +{ + g_return_val_if_fail (THUNAR_IS_ABSTRACT_ICON_VIEW (standard_view), FALSE); + return exo_icon_view_get_visible_range (EXO_ICON_VIEW (GTK_BIN (standard_view)->child), start_path, end_path); +} + + + +static void +thunar_abstract_icon_view_highlight_path (ThunarStandardView *standard_view, + GtkTreePath *path) +{ + g_return_if_fail (THUNAR_IS_ABSTRACT_ICON_VIEW (standard_view)); + exo_icon_view_set_drag_dest_item (EXO_ICON_VIEW (GTK_BIN (standard_view)->child), path, EXO_ICON_VIEW_DROP_INTO); +} + + + +static GtkAction* +thunar_abstract_icon_view_gesture_action (ThunarAbstractIconView *abstract_icon_view) +{ + if (abstract_icon_view->priv->gesture_start_y - abstract_icon_view->priv->gesture_current_y > 40 + && ABS (abstract_icon_view->priv->gesture_start_x - abstract_icon_view->priv->gesture_current_x) < 40) + { + return gtk_ui_manager_get_action (THUNAR_STANDARD_VIEW (abstract_icon_view)->ui_manager, "/main-menu/go-menu/open-parent"); + } + else if (abstract_icon_view->priv->gesture_start_x - abstract_icon_view->priv->gesture_current_x > 40 + && ABS (abstract_icon_view->priv->gesture_start_y - abstract_icon_view->priv->gesture_current_y) < 40) + { + return gtk_ui_manager_get_action (THUNAR_STANDARD_VIEW (abstract_icon_view)->ui_manager, "/main-menu/go-menu/back"); + } + else if (abstract_icon_view->priv->gesture_current_x - abstract_icon_view->priv->gesture_start_x > 40 + && ABS (abstract_icon_view->priv->gesture_start_y - abstract_icon_view->priv->gesture_current_y) < 40) + { + return gtk_ui_manager_get_action (THUNAR_STANDARD_VIEW (abstract_icon_view)->ui_manager, "/main-menu/go-menu/forward"); + } + else if (abstract_icon_view->priv->gesture_current_y - abstract_icon_view->priv->gesture_start_y > 40 + && ABS (abstract_icon_view->priv->gesture_start_x - abstract_icon_view->priv->gesture_current_x) < 40) + { + return gtk_ui_manager_get_action (THUNAR_STANDARD_VIEW (abstract_icon_view)->ui_manager, "/main-menu/view-menu/reload"); + } + + return NULL; +} + + + +static void +thunar_abstract_icon_view_action_sort (GtkAction *action, + GtkAction *current, + ThunarStandardView *standard_view) +{ + GtkSortType order; + gint column; + + /* query the new sort column id */ + action = gtk_action_group_get_action (standard_view->action_group, "sort-by-name"); + column = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (action)); + + /* query the new sort order */ + action = gtk_action_group_get_action (standard_view->action_group, "sort-ascending"); + order = gtk_radio_action_get_current_value (GTK_RADIO_ACTION (action)); + + /* apply the new settings */ + gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (standard_view->model), column, order); +} + + + +static void +thunar_abstract_icon_view_notify_model (ExoIconView *view, + GParamSpec *pspec, + ThunarAbstractIconView *abstract_icon_view) +{ + /* We need to set the search column here, as ExoIconView resets it + * whenever a new model is set. + */ + exo_icon_view_set_search_column (view, THUNAR_COLUMN_NAME); +} + + + +static gboolean +thunar_abstract_icon_view_button_press_event (ExoIconView *view, + GdkEventButton *event, + ThunarAbstractIconView *abstract_icon_view) +{ + GtkTreePath *path; + GtkTreeIter iter; + ThunarFile *file; + GtkAction *action; + + if (event->type == GDK_BUTTON_PRESS && event->button == 3) + { + /* open the context menu on right clicks */ + if (exo_icon_view_get_item_at_pos (view, event->x, event->y, &path, NULL)) + { + /* select the path on which the user clicked if not selected yet */ + if (!exo_icon_view_path_is_selected (view, path)) + { + /* we don't unselect all other items if Control is active */ + if ((event->state & GDK_CONTROL_MASK) == 0) + exo_icon_view_unselect_all (view); + exo_icon_view_select_path (view, path); + } + gtk_tree_path_free (path); + + /* queue the menu popup */ + thunar_standard_view_queue_popup (THUNAR_STANDARD_VIEW (abstract_icon_view), event); + } + else if ((event->state & gtk_accelerator_get_default_mod_mask ()) == 0) + { + /* user clicked on an empty area, so we unselect everything + * to make sure that the folder context menu is opened. + */ + exo_icon_view_unselect_all (view); + + /* open the context menu */ + thunar_standard_view_context_menu (THUNAR_STANDARD_VIEW (abstract_icon_view), event->button, event->time); + } + + return TRUE; + } + else if ((event->type == GDK_BUTTON_PRESS || event->type == GDK_2BUTTON_PRESS) && event->button == 2) + { + /* unselect all currently selected items */ + exo_icon_view_unselect_all (view); + + /* determine the path to the item that was middle-clicked */ + if (exo_icon_view_get_item_at_pos (view, event->x, event->y, &path, NULL)) + { + /* select only the path to the item on which the user clicked */ + exo_icon_view_select_path (view, path); + + /* if the event was a double-click or we are in single-click mode, then + * we'll open the file or folder (folder's are opened in new windows) + */ + if (G_LIKELY (event->type == GDK_2BUTTON_PRESS || exo_icon_view_get_single_click (view))) + { + /* determine the file for the path */ + gtk_tree_model_get_iter (GTK_TREE_MODEL (THUNAR_STANDARD_VIEW (abstract_icon_view)->model), &iter, path); + file = thunar_list_model_get_file (THUNAR_STANDARD_VIEW (abstract_icon_view)->model, &iter); + if (G_LIKELY (file != NULL)) + { + /* determine the action to perform depending on the type of the file */ + action = thunar_gtk_ui_manager_get_action_by_name (THUNAR_STANDARD_VIEW (abstract_icon_view)->ui_manager, + thunar_file_is_directory (file) ? "open-in-new-window" : "open"); + + /* emit the action */ + if (G_LIKELY (action != NULL)) + gtk_action_activate (action); + + /* release the file reference */ + g_object_unref (G_OBJECT (file)); + } + } + + /* cleanup */ + gtk_tree_path_free (path); + } + else if (event->type == GDK_BUTTON_PRESS) + { + abstract_icon_view->priv->gesture_start_x = abstract_icon_view->priv->gesture_current_x = event->x; + abstract_icon_view->priv->gesture_start_y = abstract_icon_view->priv->gesture_current_y = event->y; + abstract_icon_view->priv->gesture_expose_id = g_signal_connect_after (G_OBJECT (view), "expose-event", + G_CALLBACK (thunar_abstract_icon_view_expose_event), + G_OBJECT (abstract_icon_view)); + abstract_icon_view->priv->gesture_motion_id = g_signal_connect (G_OBJECT (view), "motion-notify-event", + G_CALLBACK (thunar_abstract_icon_view_motion_notify_event), + G_OBJECT (abstract_icon_view)); + abstract_icon_view->priv->gesture_release_id = g_signal_connect (G_OBJECT (view), "button-release-event", + G_CALLBACK (thunar_abstract_icon_view_button_release_event), + G_OBJECT (abstract_icon_view)); + } + + /* don't run the default handler here */ + return TRUE; + } + + return FALSE; +} + + + +static gboolean +thunar_abstract_icon_view_button_release_event (ExoIconView *view, + GdkEventButton *event, + ThunarAbstractIconView *abstract_icon_view) +{ + GtkAction *action; + + g_return_val_if_fail (EXO_IS_ICON_VIEW (view), FALSE); + g_return_val_if_fail (THUNAR_IS_ABSTRACT_ICON_VIEW (abstract_icon_view), FALSE); + g_return_val_if_fail (abstract_icon_view->priv->gesture_expose_id > 0, FALSE); + g_return_val_if_fail (abstract_icon_view->priv->gesture_motion_id > 0, FALSE); + g_return_val_if_fail (abstract_icon_view->priv->gesture_release_id > 0, FALSE); + + /* run the selected action (if any) */ + action = thunar_abstract_icon_view_gesture_action (abstract_icon_view); + if (G_LIKELY (action != NULL)) + gtk_action_activate (action); + + /* unregister the "expose-event" handler */ + g_signal_handler_disconnect (G_OBJECT (view), abstract_icon_view->priv->gesture_expose_id); + abstract_icon_view->priv->gesture_expose_id = 0; + + /* unregister the "motion-notify-event" handler */ + g_signal_handler_disconnect (G_OBJECT (view), abstract_icon_view->priv->gesture_motion_id); + abstract_icon_view->priv->gesture_motion_id = 0; + + /* unregister the "button-release-event" handler */ + g_signal_handler_disconnect (G_OBJECT (view), abstract_icon_view->priv->gesture_release_id); + abstract_icon_view->priv->gesture_release_id = 0; + + /* redraw the abstract_icon view */ + gtk_widget_queue_draw (GTK_WIDGET (view)); + + return FALSE; +} + + + +static gboolean +thunar_abstract_icon_view_expose_event (ExoIconView *view, + GdkEventExpose *event, + ThunarAbstractIconView *abstract_icon_view) +{ + GtkIconSet *stock_icon_set; + GtkAction *action = NULL; + GdkPixbuf *stock_icon = NULL; + gchar *stock_id; +#if GTK_CHECK_VERSION(2,7,1) + GdkColor bg; + cairo_t *cr; +#endif + + g_return_val_if_fail (EXO_IS_ICON_VIEW (view), FALSE); + g_return_val_if_fail (THUNAR_IS_ABSTRACT_ICON_VIEW (abstract_icon_view), FALSE); + g_return_val_if_fail (abstract_icon_view->priv->gesture_expose_id > 0, FALSE); + g_return_val_if_fail (abstract_icon_view->priv->gesture_motion_id > 0, FALSE); + g_return_val_if_fail (abstract_icon_view->priv->gesture_release_id > 0, FALSE); + + /* shade the abstract_icon view content while performing mouse gestures */ +#if GTK_CHECK_VERSION(2,7,1) + cr = gdk_cairo_create (event->window); + bg = GTK_WIDGET (view)->style->base[GTK_STATE_NORMAL]; + cairo_set_source_rgba (cr, bg.red / 65535.0, bg.green / 65535.0, bg.blue / 65535.0, 0.7); + cairo_rectangle (cr, event->area.x, event->area.y, event->area.width, event->area.height); + cairo_clip (cr); + cairo_paint (cr); + cairo_destroy (cr); +#endif + + /* determine the gesture action */ + action = thunar_abstract_icon_view_gesture_action (abstract_icon_view); + if (G_LIKELY (action != NULL)) + { + /* determine the stock abstract_icon for the action */ + g_object_get (G_OBJECT (action), "stock-id", &stock_id, NULL); + + /* lookup the abstract_icon set for the stock abstract_icon */ + stock_icon_set = gtk_style_lookup_icon_set (GTK_WIDGET (view)->style, stock_id); + if (G_LIKELY (stock_icon_set != NULL)) + { + stock_icon = gtk_icon_set_render_icon (stock_icon_set, GTK_WIDGET (view)->style, + gtk_widget_get_direction (GTK_WIDGET (view)), + gtk_action_is_sensitive (action) ? 0 : GTK_STATE_INSENSITIVE, + GTK_ICON_SIZE_DND, GTK_WIDGET (view), NULL); + } + + /* draw the rendered icon */ + if (G_LIKELY (stock_icon != NULL)) + { + /* render the stock abstract_icon into the abstract_icon view window */ + gdk_draw_pixbuf (event->window, NULL, stock_icon, 0, 0, + abstract_icon_view->priv->gesture_start_x - gdk_pixbuf_get_width (stock_icon) / 2, + abstract_icon_view->priv->gesture_start_y - gdk_pixbuf_get_height (stock_icon) / 2, + gdk_pixbuf_get_width (stock_icon), gdk_pixbuf_get_height (stock_icon), + GDK_RGB_DITHER_NONE, 0, 0); + + /* release the stock abstract_icon */ + g_object_unref (G_OBJECT (stock_icon)); + } + + /* release the stock id */ + g_free (stock_id); + } + + return FALSE; +} + + + +static gboolean +thunar_abstract_icon_view_key_press_event (ExoIconView *view, + GdkEventKey *event, + ThunarAbstractIconView *abstract_icon_view) +{ + /* popup context menu if "Menu" or "<Shift>F10" is pressed */ + if (event->keyval == GDK_Menu || ((event->state & GDK_SHIFT_MASK) != 0 && event->keyval == GDK_F10)) + { + thunar_standard_view_context_menu (THUNAR_STANDARD_VIEW (abstract_icon_view), 0, event->time); + return TRUE; + } + + return FALSE; +} + + + +static gboolean +thunar_abstract_icon_view_motion_notify_event (ExoIconView *view, + GdkEventMotion *event, + ThunarAbstractIconView *abstract_icon_view) +{ + GdkRectangle area; + + g_return_val_if_fail (EXO_IS_ICON_VIEW (view), FALSE); + g_return_val_if_fail (THUNAR_IS_ABSTRACT_ICON_VIEW (abstract_icon_view), FALSE); + g_return_val_if_fail (abstract_icon_view->priv->gesture_expose_id > 0, FALSE); + g_return_val_if_fail (abstract_icon_view->priv->gesture_motion_id > 0, FALSE); + g_return_val_if_fail (abstract_icon_view->priv->gesture_release_id > 0, FALSE); + + /* schedule a complete redraw on the first motion event */ + if (abstract_icon_view->priv->gesture_current_x == abstract_icon_view->priv->gesture_start_x + && abstract_icon_view->priv->gesture_current_y == abstract_icon_view->priv->gesture_start_y) + { + gtk_widget_queue_draw (GTK_WIDGET (view)); + } + else + { + /* otherwise, just redraw the action abstract_icon area */ + gtk_icon_size_lookup (GTK_ICON_SIZE_DND, &area.width, &area.height); + area.x = abstract_icon_view->priv->gesture_start_x - area.width / 2; + area.y = abstract_icon_view->priv->gesture_start_y - area.height / 2; + gdk_window_invalidate_rect (event->window, &area, TRUE); + } + + /* update the current gesture position */ + abstract_icon_view->priv->gesture_current_x = event->x; + abstract_icon_view->priv->gesture_current_y = event->y; + + /* don't execute the default motion notify handler */ + return TRUE; +} + + + +static void +thunar_abstract_icon_view_item_activated (ExoIconView *view, + GtkTreePath *path, + ThunarAbstractIconView *abstract_icon_view) +{ + GtkAction *action; + + g_return_if_fail (THUNAR_IS_ABSTRACT_ICON_VIEW (abstract_icon_view)); + + /* be sure to have only the double clicked item selected */ + exo_icon_view_unselect_all (view); + exo_icon_view_select_path (view, path); + + /* emit the "open" action */ + action = thunar_gtk_ui_manager_get_action_by_name (THUNAR_STANDARD_VIEW (abstract_icon_view)->ui_manager, "open"); + if (G_LIKELY (action != NULL)) + gtk_action_activate (action); +} + + + +static void +thunar_abstract_icon_view_sort_column_changed (GtkTreeSortable *sortable, + ThunarAbstractIconView *abstract_icon_view) +{ + GtkSortType order; + GtkAction *action; + gint column; + + if (gtk_tree_sortable_get_sort_column_id (sortable, &column, &order)) + { + /* apply the new sort column */ + action = gtk_action_group_get_action (THUNAR_STANDARD_VIEW (abstract_icon_view)->action_group, "sort-by-name"); + exo_gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), column); + + /* apply the new sort order */ + action = gtk_action_group_get_action (THUNAR_STANDARD_VIEW (abstract_icon_view)->action_group, "sort-ascending"); + exo_gtk_radio_action_set_current_value (GTK_RADIO_ACTION (action), order); + } +} + + + +static void +thunar_abstract_icon_view_zoom_level_changed (ThunarAbstractIconView *abstract_icon_view) +{ + g_return_if_fail (THUNAR_IS_ABSTRACT_ICON_VIEW (abstract_icon_view)); + + /* we use the same trick as with ThunarDetailsView here, simply because its simple :-) */ + gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (GTK_BIN (abstract_icon_view)->child), + THUNAR_STANDARD_VIEW (abstract_icon_view)->icon_renderer, + NULL, NULL, NULL); +} + |