thunar-standard-view.c 190 KB
Newer Older
1
/* vi:set et ai sw=2 sts=2 ts=2: */
2
/*-
3
 * Copyright (c) 2005-2006 Benedikt Meurer <benny@xfce.org>
4
 * Copyright (c) 2009-2011 Jannis Pohlmann <jannis@xfce.org>
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License as
8
 * published by the Free Software Foundation; either version 2 of
9
 * the License, or (at your option) any later version.
10
 *
11 12
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16 17
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the Free
18 19
 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
20 21 22 23 24 25
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

26 27 28 29 30 31 32
#ifdef HAVE_MEMORY_H
#include <memory.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif

33 34
#include <gdk/gdkkeysyms.h>

35 36 37
#include <thunar/thunar-application.h>
#include <thunar/thunar-create-dialog.h>
#include <thunar/thunar-dialogs.h>
38
#include <thunar/thunar-dnd.h>
39
#include <thunar/thunar-enum-types.h>
40
#include <thunar/thunar-gio-extensions.h>
41
#include <thunar/thunar-gobject-extensions.h>
42
#include <thunar/thunar-gtk-extensions.h>
43
#include <thunar/thunar-history.h>
44
#include <thunar/thunar-icon-renderer.h>
45
#include <thunar/thunar-marshal.h>
Andre Miranda's avatar
Andre Miranda committed
46
#include <thunar/thunar-menu-util.h>
47
#include <thunar/thunar-pango-extensions.h>
48
#include <thunar/thunar-private.h>
49
#include <thunar/thunar-properties-dialog.h>
50
#include <thunar/thunar-renamer-dialog.h>
51
#include <thunar/thunar-simple-job.h>
52
#include <thunar/thunar-standard-view.h>
53
#include <thunar/thunar-standard-view-ui.h>
54
#include <thunar/thunar-templates-action.h>
55
#include <thunar/thunar-thumbnailer.h>
56
#include <thunar/thunar-util.h>
57

58 59 60 61
#if defined(GDK_WINDOWING_X11)
#include <gdk/gdkx.h>
#endif

62 63


64
/* Property identifiers */
65 66 67 68 69
enum
{
  PROP_0,
  PROP_CURRENT_DIRECTORY,
  PROP_LOADING,
70 71
  PROP_DISPLAY_NAME,
  PROP_TOOLTIP_TEXT,
72
  PROP_SELECTED_FILES,
73
  PROP_SHOW_HIDDEN,
74
  PROP_STATUSBAR_TEXT,
75
  PROP_UI_MANAGER,
76
  PROP_ZOOM_LEVEL,
77
  N_PROPERTIES
78 79
};

80 81 82 83
/* Signal identifiers */
enum
{
  DELETE_SELECTED_FILES,
84
  START_OPEN_LOCATION,
85 86 87
  LAST_SIGNAL,
};

88 89 90
/* Identifiers for DnD target types */
enum
{
91 92 93
  TARGET_TEXT_URI_LIST,
  TARGET_XDND_DIRECT_SAVE0,
  TARGET_NETSCAPE_URL,
94 95
};

96 97


98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
static void                 thunar_standard_view_component_init             (ThunarComponentIface     *iface);
static void                 thunar_standard_view_navigator_init             (ThunarNavigatorIface     *iface);
static void                 thunar_standard_view_view_init                  (ThunarViewIface          *iface);
static GObject             *thunar_standard_view_constructor                (GType                     type,
                                                                             guint                     n_construct_properties,
                                                                             GObjectConstructParam    *construct_properties);
static void                 thunar_standard_view_dispose                    (GObject                  *object);
static void                 thunar_standard_view_finalize                   (GObject                  *object);
static void                 thunar_standard_view_get_property               (GObject                  *object,
                                                                             guint                     prop_id,
                                                                             GValue                   *value,
                                                                             GParamSpec               *pspec);
static void                 thunar_standard_view_set_property               (GObject                  *object,
                                                                             guint                     prop_id,
                                                                             const GValue             *value,
                                                                             GParamSpec               *pspec);
static void                 thunar_standard_view_realize                    (GtkWidget                *widget);
static void                 thunar_standard_view_unrealize                  (GtkWidget                *widget);
static void                 thunar_standard_view_grab_focus                 (GtkWidget                *widget);
117 118
static gboolean             thunar_standard_view_draw                       (GtkWidget                *widget,
                                                                             cairo_t                  *cr);
119 120 121 122 123 124 125 126 127 128
static GList               *thunar_standard_view_get_selected_files         (ThunarComponent          *component);
static void                 thunar_standard_view_set_selected_files         (ThunarComponent          *component,
                                                                             GList                    *selected_files);
static GtkUIManager        *thunar_standard_view_get_ui_manager             (ThunarComponent          *component);
static void                 thunar_standard_view_set_ui_manager             (ThunarComponent          *component,
                                                                             GtkUIManager             *ui_manager);
static ThunarFile          *thunar_standard_view_get_current_directory      (ThunarNavigator          *navigator);
static void                 thunar_standard_view_set_current_directory      (ThunarNavigator          *navigator,
                                                                             ThunarFile               *current_directory);
static gboolean             thunar_standard_view_get_loading                (ThunarView               *view);
129 130
static void                 thunar_standard_view_set_loading                (ThunarStandardView       *standard_view,
                                                                             gboolean                  loading);
131 132 133 134 135 136 137 138
static const gchar         *thunar_standard_view_get_statusbar_text         (ThunarView               *view);
static gboolean             thunar_standard_view_get_show_hidden            (ThunarView               *view);
static void                 thunar_standard_view_set_show_hidden            (ThunarView               *view,
                                                                             gboolean                  show_hidden);
static ThunarZoomLevel      thunar_standard_view_get_zoom_level             (ThunarView               *view);
static void                 thunar_standard_view_set_zoom_level             (ThunarView               *view,
                                                                             ThunarZoomLevel           zoom_level);
static void                 thunar_standard_view_reset_zoom_level           (ThunarView               *view);
139 140
static void                 thunar_standard_view_reload                     (ThunarView               *view,
                                                                             gboolean                  reload_info);
141 142 143 144 145
static gboolean             thunar_standard_view_get_visible_range          (ThunarView               *view,
                                                                             ThunarFile              **start_file,
                                                                             ThunarFile              **end_file);
static void                 thunar_standard_view_scroll_to_file             (ThunarView               *view,
                                                                             ThunarFile               *file,
146
                                                                             gboolean                  select_file,
147 148 149
                                                                             gboolean                  use_align,
                                                                             gfloat                    row_align,
                                                                             gfloat                    col_align);
150 151 152 153 154
static gboolean             thunar_standard_view_delete_selected_files      (ThunarStandardView       *standard_view);
static GdkDragAction        thunar_standard_view_get_dest_actions           (ThunarStandardView       *standard_view,
                                                                             GdkDragContext           *context,
                                                                             gint                      x,
                                                                             gint                      y,
155
                                                                             guint                     timestamp,
156 157 158 159 160
                                                                             ThunarFile              **file_return);
static ThunarFile          *thunar_standard_view_get_drop_file              (ThunarStandardView       *standard_view,
                                                                             gint                      x,
                                                                             gint                      y,
                                                                             GtkTreePath             **path_return);
161
static void                 thunar_standard_view_merge_custom_actions       (ThunarStandardView       *standard_view);
162
static void                 thunar_standard_view_update_statusbar_text      (ThunarStandardView       *standard_view);
163 164 165 166
static void                 thunar_standard_view_current_directory_destroy  (ThunarFile               *current_directory,
                                                                             ThunarStandardView       *standard_view);
static void                 thunar_standard_view_current_directory_changed  (ThunarFile               *current_directory,
                                                                             ThunarStandardView       *standard_view);
167 168 169 170 171
static void                 thunar_standard_view_action_create_empty_file   (GtkAction                *action,
                                                                             ThunarStandardView       *standard_view);
static void                 thunar_standard_view_action_create_folder       (GtkAction                *action,
                                                                             ThunarStandardView       *standard_view);
static void                 thunar_standard_view_action_create_template     (GtkAction                *action,
172
                                                                             const ThunarFile         *file,
173 174 175 176 177
                                                                             ThunarStandardView       *standard_view);
static void                 thunar_standard_view_action_properties          (GtkAction                *action,
                                                                             ThunarStandardView       *standard_view);
static void                 thunar_standard_view_action_cut                 (GtkAction                *action,
                                                                             ThunarStandardView       *standard_view);
178 179
static void                 thunar_standard_view_action_copy                (GtkAction                *action,
                                                                             ThunarStandardView       *standard_view);
180 181
static void                 thunar_standard_view_action_paste               (GtkAction                *action,
                                                                             ThunarStandardView       *standard_view);
182 183 184
static void                 thunar_standard_view_action_move_to_trash       (GtkAction                *action,
                                                                             ThunarStandardView       *standard_view);
static void                 thunar_standard_view_action_delete             (GtkAction                *action,
185 186 187 188 189 190 191
                                                                             ThunarStandardView       *standard_view);
static void                 thunar_standard_view_action_paste_into_folder   (GtkAction                *action,
                                                                             ThunarStandardView       *standard_view);
static void                 thunar_standard_view_action_select_all_files    (GtkAction                *action,
                                                                             ThunarStandardView       *standard_view);
static void                 thunar_standard_view_action_select_by_pattern   (GtkAction                *action,
                                                                             ThunarStandardView       *standard_view);
192 193
static void                 thunar_standard_view_action_selection_invert    (GtkAction                *action,
                                                                             ThunarStandardView       *standard_view);
194 195 196 197 198 199
static void                 thunar_standard_view_action_duplicate           (GtkAction                *action,
                                                                             ThunarStandardView       *standard_view);
static void                 thunar_standard_view_action_make_link           (GtkAction                *action,
                                                                             ThunarStandardView       *standard_view);
static void                 thunar_standard_view_action_rename              (GtkAction                *action,
                                                                             ThunarStandardView       *standard_view);
200 201
static void                 thunar_standard_view_action_restore             (GtkAction                *action,
                                                                             ThunarStandardView       *standard_view);
202 203
static GClosure            *thunar_standard_view_new_files_closure          (ThunarStandardView       *standard_view,
                                                                             GtkWidget                *source_view);
204 205
static void                 thunar_standard_view_new_files                  (ThunarStandardView       *standard_view,
                                                                             GList                    *path_list);
206 207 208 209 210 211
static gboolean             thunar_standard_view_button_release_event       (GtkWidget                *view,
                                                                             GdkEventButton           *event,
                                                                             ThunarStandardView       *standard_view);
static gboolean             thunar_standard_view_motion_notify_event        (GtkWidget                *view,
                                                                             GdkEventMotion           *event,
                                                                             ThunarStandardView       *standard_view);
212 213 214
static gboolean             thunar_standard_view_key_press_event            (GtkWidget                *view,
                                                                             GdkEventKey              *event,
                                                                             ThunarStandardView       *standard_view);
215 216 217
static gboolean             thunar_standard_view_scroll_event               (GtkWidget                *view,
                                                                             GdkEventScroll           *event,
                                                                             ThunarStandardView       *standard_view);
218 219 220
static gboolean             thunar_standard_view_button_press_event         (GtkWidget                *view,
                                                                             GdkEventButton           *event,
                                                                             ThunarStandardView       *standard_view);
221 222 223 224
static gboolean             thunar_standard_view_drag_drop                  (GtkWidget                *view,
                                                                             GdkDragContext           *context,
                                                                             gint                      x,
                                                                             gint                      y,
225
                                                                             guint                     timestamp,
226 227 228 229 230 231 232
                                                                             ThunarStandardView       *standard_view);
static void                 thunar_standard_view_drag_data_received         (GtkWidget                *view,
                                                                             GdkDragContext           *context,
                                                                             gint                      x,
                                                                             gint                      y,
                                                                             GtkSelectionData         *selection_data,
                                                                             guint                     info,
233
                                                                             guint                     timestamp,
234 235 236
                                                                             ThunarStandardView       *standard_view);
static void                 thunar_standard_view_drag_leave                 (GtkWidget                *view,
                                                                             GdkDragContext           *context,
237
                                                                             guint                     timestamp,
238 239 240 241 242
                                                                             ThunarStandardView       *standard_view);
static gboolean             thunar_standard_view_drag_motion                (GtkWidget                *view,
                                                                             GdkDragContext           *context,
                                                                             gint                      x,
                                                                             gint                      y,
243
                                                                             guint                     timestamp,
244 245 246 247 248 249 250 251
                                                                             ThunarStandardView       *standard_view);
static void                 thunar_standard_view_drag_begin                 (GtkWidget                *view,
                                                                             GdkDragContext           *context,
                                                                             ThunarStandardView       *standard_view);
static void                 thunar_standard_view_drag_data_get              (GtkWidget                *view,
                                                                             GdkDragContext           *context,
                                                                             GtkSelectionData         *selection_data,
                                                                             guint                     info,
252
                                                                             guint                     timestamp,
253 254 255 256 257 258 259
                                                                             ThunarStandardView       *standard_view);
static void                 thunar_standard_view_drag_data_delete           (GtkWidget                *view,
                                                                             GdkDragContext           *context,
                                                                             ThunarStandardView       *standard_view);
static void                 thunar_standard_view_drag_end                   (GtkWidget                *view,
                                                                             GdkDragContext           *context,
                                                                             ThunarStandardView       *standard_view);
260 261 262
static void                 thunar_standard_view_row_deleted                (ThunarListModel          *model,
                                                                             GtkTreePath              *path,
                                                                             ThunarStandardView       *standard_view);
263 264 265
static void                 thunar_standard_view_select_after_row_deleted   (ThunarListModel          *model,
                                                                             GtkTreePath              *path,
                                                                             ThunarStandardView       *standard_view);
266
static gboolean             thunar_standard_view_restore_selection_idle     (ThunarStandardView       *standard_view);
267 268 269 270
static void                 thunar_standard_view_row_changed                (ThunarListModel          *model,
                                                                             GtkTreePath              *path,
                                                                             GtkTreeIter              *iter,
                                                                             ThunarStandardView       *standard_view);
271
static void                 thunar_standard_view_rows_reordered             (ThunarListModel          *model,
272
                                                                             GtkTreePath              *path,
273 274
                                                                             GtkTreeIter              *iter,
                                                                             gpointer                  new_order,
275
                                                                             ThunarStandardView       *standard_view);
276 277 278
static void                 thunar_standard_view_error                      (ThunarListModel          *model,
                                                                             const GError             *error,
                                                                             ThunarStandardView       *standard_view);
279 280
static void                 thunar_standard_view_sort_column_changed        (GtkTreeSortable          *tree_sortable,
                                                                             ThunarStandardView       *standard_view);
281
static void                 thunar_standard_view_loading_unbound            (gpointer                  user_data);
282 283
static gboolean             thunar_standard_view_drag_scroll_timer          (gpointer                  user_data);
static void                 thunar_standard_view_drag_scroll_timer_destroy  (gpointer                  user_data);
284 285
static gboolean             thunar_standard_view_drag_timer                 (gpointer                  user_data);
static void                 thunar_standard_view_drag_timer_destroy         (gpointer                  user_data);
286 287 288
static void                 thunar_standard_view_finished_thumbnailing      (ThunarThumbnailer        *thumbnailer,
                                                                             guint                     request,
                                                                             ThunarStandardView       *standard_view);
289
static void                 thunar_standard_view_thumbnailing_destroyed     (gpointer                  data);
290 291 292
static void                 thunar_standard_view_cancel_thumbnailing        (ThunarStandardView       *standard_view);
static void                 thunar_standard_view_schedule_thumbnail_timeout (ThunarStandardView       *standard_view);
static void                 thunar_standard_view_schedule_thumbnail_idle    (ThunarStandardView       *standard_view);
293 294
static gboolean             thunar_standard_view_request_thumbnails         (gpointer                  data);
static gboolean             thunar_standard_view_request_thumbnails_lazy    (gpointer                  data);
295
static void                 thunar_standard_view_thumbnail_mode_toggled     (ThunarStandardView       *standard_view,
296 297
                                                                             GParamSpec               *pspec,
                                                                             ThunarIconFactory        *icon_factory);
298 299 300 301
static void                 thunar_standard_view_scrolled                   (GtkAdjustment            *adjustment,
                                                                             ThunarStandardView       *standard_view);
static void                 thunar_standard_view_size_allocate              (ThunarStandardView       *standard_view,
                                                                             GtkAllocation            *allocation);
302 303 304



305 306
struct _ThunarStandardViewPrivate
{
307 308 309
  /* current directory of the view */
  ThunarFile             *current_directory;

310
  GtkAction              *action_create_folder;
311
  GtkAction              *action_create_document;
312 313
  GtkAction              *action_properties;
  GtkAction              *action_cut;
314
  GtkAction              *action_copy;
315
  GtkAction              *action_paste;
316
  GtkAction              *action_move_to_trash;
317
  GtkAction              *action_delete;
318
  GtkAction              *action_paste_into_folder;
319 320
  GtkAction              *action_duplicate;
  GtkAction              *action_make_link;
321
  GtkAction              *action_rename;
322
  GtkAction              *action_restore;
323

324 325 326
  /* history of the current view */
  ThunarHistory          *history;

327
  /* support for file manager extensions */
328
  ThunarxProviderFactory *provider_factory;
329

330 331 332
  /* zoom-level support */
  ThunarZoomLevel         zoom_level;

333 334 335
  /* scroll_to_file support */
  GHashTable             *scroll_to_files;

336 337 338 339
  /* statusbar */
  gchar                  *statusbar_text;
  guint                   statusbar_text_idle_id;

340 341 342
  /* custom menu actions support */
  GtkActionGroup         *custom_actions;
  gint                    custom_merge_id;
343 344

  /* right-click drag/popup support */
345
  GList                  *drag_g_file_list;
346
  guint                   drag_scroll_timer_id;
347
  guint                   drag_timer_id;
348
  GdkEvent               *drag_timer_event;
349 350
  gint                    drag_x;
  gint                    drag_y;
351 352

  /* drop site support */
353 354 355
  guint                   drop_data_ready : 1; /* whether the drop data was received already */
  guint                   drop_highlight : 1;
  guint                   drop_occurred : 1;   /* whether the data was dropped */
356
  GList                  *drop_file_list;      /* the list of URIs that are contained in the drop data */
357

358
  /* the "new-files" closure, which is used to select files whenever
359
   * new files are created by a ThunarJob associated with this view
360 361
   */
  GClosure               *new_files_closure;
362

363
  /* the "new-files" path list that was remembered in the closure callback
364 365 366
   * if the view is currently being loaded and as such the folder may
   * not have all "new-files" at hand. This list is used when the
   * folder tells that it's ready loading and the view will try again
367
   * to select exactly these files.
368 369 370
   */
  GList                  *new_files_path_list;

371 372 373 374 375 376
  /* scroll-to-file support */
  ThunarFile             *scroll_to_file;
  guint                   scroll_to_select : 1;
  guint                   scroll_to_use_align : 1;
  gfloat                  scroll_to_row_align;
  gfloat                  scroll_to_col_align;
377

378 379
  /* selected_files support */
  GList                  *selected_files;
380
  guint                   restore_selection_idle_id;
381

382 383 384 385 386 387
  /* support for generating thumbnails */
  ThunarThumbnailer      *thumbnailer;
  guint                   thumbnail_request;
  guint                   thumbnail_source_id;
  gboolean                thumbnailing_scheduled;

388 389 390
  /* file insert signal */
  gulong                  row_changed_id;

391
  /* Tree path for restoring the selection after selecting and
392 393
   * deleting an item */
  GtkTreePath            *selection_before_delete;
394 395 396 397
};



398
static const GtkActionEntry action_entries[] =
399
{
400 401
  { "file-context-menu", NULL, N_ ("File Context Menu"), NULL, NULL, NULL, },
  { "folder-context-menu", NULL, N_ ("Folder Context Menu"), NULL, NULL, NULL, },
402
  { "create-folder", "folder-new", N_ ("Create _Folder..."), "<control><shift>N", N_ ("Create an empty folder within the current folder"), G_CALLBACK (thunar_standard_view_action_create_folder), },
Jonas Kümmerlin's avatar
Jonas Kümmerlin committed
403
  { "properties", "document-properties", N_ ("_Properties..."), "<alt>Return", N_ ("View the properties of the selected file"), G_CALLBACK (thunar_standard_view_action_properties), },
404 405 406
  { "cut", "edit-cut", N_ ("Cu_t"), "<control>X", NULL, G_CALLBACK (thunar_standard_view_action_cut), },
  { "copy", "edit-copy", N_ ("_Copy"), "<control>C", NULL, G_CALLBACK (thunar_standard_view_action_copy), },
  { "paste", "edit-paste", N_ ("_Paste"), "<control>V", N_ ("Move or copy files previously selected by a Cut or Copy command"), G_CALLBACK (thunar_standard_view_action_paste), },
Andre Miranda's avatar
Andre Miranda committed
407
  { "move-to-trash", "user-trash", N_ ("Mo_ve to Trash"), NULL, NULL, G_CALLBACK (thunar_standard_view_action_move_to_trash), },
Jonas Kümmerlin's avatar
Jonas Kümmerlin committed
408 409
  { "delete", "edit-delete", N_ ("_Delete"), NULL, NULL, G_CALLBACK (thunar_standard_view_action_delete), },
  { "paste-into-folder", "edit-paste", N_ ("Paste Into Folder"), NULL, N_ ("Move or copy files previously selected by a Cut or Copy command into the selected folder"), G_CALLBACK (thunar_standard_view_action_paste_into_folder), },
410
  { "select-all-files", NULL, N_ ("Select _all Files"), NULL, N_ ("Select all files in this window"), G_CALLBACK (thunar_standard_view_action_select_all_files), },
411
  { "select-by-pattern", NULL, N_ ("Select _by Pattern..."), "<control>S", N_ ("Select all files that match a certain pattern"), G_CALLBACK (thunar_standard_view_action_select_by_pattern), },
412
  { "invert-selection", NULL, N_ ("_Invert Selection"), NULL, N_ ("Select all and only the items that are not currently selected"), G_CALLBACK (thunar_standard_view_action_selection_invert), },
413 414
  { "duplicate", NULL, N_ ("Du_plicate"), NULL, NULL, G_CALLBACK (thunar_standard_view_action_duplicate), },
  { "make-link", NULL, N_ ("Ma_ke Link"), NULL, NULL, G_CALLBACK (thunar_standard_view_action_make_link), },
415 416
  { "rename", NULL, N_ ("_Rename..."), "F2", NULL, G_CALLBACK (thunar_standard_view_action_rename), },
  { "restore", NULL, N_ ("_Restore"), NULL, NULL, G_CALLBACK (thunar_standard_view_action_restore), },
417
};
418

419 420 421
/* Target types for dragging from the view */
static const GtkTargetEntry drag_targets[] =
{
422
  { "text/uri-list", 0, TARGET_TEXT_URI_LIST, },
423 424
};

425 426 427
/* Target types for dropping to the view */
static const GtkTargetEntry drop_targets[] =
{
428
  { "text/uri-list", 0, TARGET_TEXT_URI_LIST, },
429
  { "XdndDirectSave0", 0, TARGET_XDND_DIRECT_SAVE0, },
430
  { "_NETSCAPE_URL", 0, TARGET_NETSCAPE_URL, },
431 432 433 434
};



435 436
static guint       standard_view_signals[LAST_SIGNAL];
static GParamSpec *standard_view_props[N_PROPERTIES] = { NULL, };
437 438 439



440 441 442
G_DEFINE_ABSTRACT_TYPE_WITH_CODE (ThunarStandardView, thunar_standard_view, GTK_TYPE_SCROLLED_WINDOW,
    G_IMPLEMENT_INTERFACE (THUNAR_TYPE_NAVIGATOR, thunar_standard_view_navigator_init)
    G_IMPLEMENT_INTERFACE (THUNAR_TYPE_COMPONENT, thunar_standard_view_component_init)
443 444
    G_IMPLEMENT_INTERFACE (THUNAR_TYPE_VIEW, thunar_standard_view_view_init)
    G_ADD_PRIVATE (ThunarStandardView))
445 446 447 448 449 450



static void
thunar_standard_view_class_init (ThunarStandardViewClass *klass)
{
451
  GtkWidgetClass *gtkwidget_class;
452
  GtkBindingSet  *binding_set;
453
  GObjectClass   *gobject_class;
454
  gpointer        g_iface;
455 456 457 458 459 460 461 462

  gobject_class = G_OBJECT_CLASS (klass);
  gobject_class->constructor = thunar_standard_view_constructor;
  gobject_class->dispose = thunar_standard_view_dispose;
  gobject_class->finalize = thunar_standard_view_finalize;
  gobject_class->get_property = thunar_standard_view_get_property;
  gobject_class->set_property = thunar_standard_view_set_property;

463 464 465
  gtkwidget_class = GTK_WIDGET_CLASS (klass);
  gtkwidget_class->realize = thunar_standard_view_realize;
  gtkwidget_class->unrealize = thunar_standard_view_unrealize;
466
  gtkwidget_class->grab_focus = thunar_standard_view_grab_focus;
467
  gtkwidget_class->draw = thunar_standard_view_draw;
468

469
  klass->delete_selected_files = thunar_standard_view_delete_selected_files;
470 471 472
  klass->connect_ui_manager = (gpointer) exo_noop;
  klass->disconnect_ui_manager = (gpointer) exo_noop;

473 474 475 476 477
  /**
   * ThunarStandardView:loading:
   *
   * Whether the folder associated with this view is
   * currently being loaded from the underlying media.
478 479 480
   *
   * Override property to set the property as writable
   * for the binding.
481
   **/
482 483 484 485 486 487 488
  standard_view_props[PROP_LOADING] =
      g_param_spec_override ("loading",
                             g_param_spec_boolean ("loading",
                                                   "loading",
                                                   "loading",
                                                   FALSE,
                                                   EXO_PARAM_READWRITE));
489

490 491 492 493 494
  /**
   * ThunarStandardView:display-name:
   *
   * Display name of the current directory, for label text
   **/
495 496 497 498 499 500
  standard_view_props[PROP_DISPLAY_NAME] =
      g_param_spec_string ("display-name",
                           "display-name",
                           "display-name",
                           NULL,
                           EXO_PARAM_READABLE);
501 502 503 504 505 506

  /**
   * ThunarStandardView:parse-name:
   *
   * Full parsed name of the current directory, for label tooltip
   **/
507 508 509 510 511 512
  standard_view_props[PROP_TOOLTIP_TEXT] =
      g_param_spec_string ("tooltip-text",
                           "tooltip-text",
                           "tooltip-text",
                           NULL,
                           EXO_PARAM_READABLE);
513

514
  /* override ThunarComponent's properties */
515 516 517 518 519 520 521 522
  g_iface = g_type_default_interface_peek (THUNAR_TYPE_COMPONENT);
  standard_view_props[PROP_SELECTED_FILES] =
      g_param_spec_override ("selected-files",
                             g_object_interface_find_property (g_iface, "selected-files"));

  standard_view_props[PROP_UI_MANAGER] =
      g_param_spec_override ("ui-manager",
                             g_object_interface_find_property (g_iface, "ui-manager"));
523

524
  /* override ThunarNavigator's properties */
525 526 527 528
  g_iface = g_type_default_interface_peek (THUNAR_TYPE_NAVIGATOR);
  standard_view_props[PROP_CURRENT_DIRECTORY] =
      g_param_spec_override ("current-directory",
                             g_object_interface_find_property (g_iface, "current-directory"));
529 530

  /* override ThunarView's properties */
531 532 533 534 535 536 537 538 539 540 541 542 543 544 545
  g_iface = g_type_default_interface_peek (THUNAR_TYPE_VIEW);
  standard_view_props[PROP_STATUSBAR_TEXT] =
      g_param_spec_override ("statusbar-text",
                             g_object_interface_find_property (g_iface, "statusbar-text"));

  standard_view_props[PROP_SHOW_HIDDEN] =
      g_param_spec_override ("show-hidden",
                             g_object_interface_find_property (g_iface, "show-hidden"));

  standard_view_props[PROP_ZOOM_LEVEL] =
      g_param_spec_override ("zoom-level",
                             g_object_interface_find_property (g_iface, "zoom-level"));

  /* install all properties */
  g_object_class_install_properties (gobject_class, N_PROPERTIES, standard_view_props);
546

547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566
  /**
   * ThunarStandardView::start-opn-location:
   * @standard_view : a #ThunarStandardView.
   * @initial_text  : the inital location text.
   *
   * Emitted by @standard_view, whenever the user requests to
   * select a custom location (using either the "Open Location"
   * dialog or the location entry widget) by specifying an
   * @initial_text (i.e. if the user types "/" into the
   * view).
   **/
  standard_view_signals[START_OPEN_LOCATION] =
    g_signal_new (I_("start-open-location"),
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (ThunarStandardViewClass, start_open_location),
                  NULL, NULL,
                  g_cclosure_marshal_VOID__STRING,
                  G_TYPE_NONE, 1, G_TYPE_STRING);

567 568 569 570 571 572 573 574
  /**
   * ThunarStandardView::delete-selected-files:
   * @standard_view : a #ThunarStandardView.
   *
   * Emitted whenever the user presses the Delete key. This
   * is an internal signal used to bind the action to keys.
   **/
  standard_view_signals[DELETE_SELECTED_FILES] =
575
    g_signal_new (I_("delete-selected-files"),
576 577 578 579 580 581 582 583 584
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
                  G_STRUCT_OFFSET (ThunarStandardViewClass, delete_selected_files),
                  g_signal_accumulator_true_handled, NULL,
                  _thunar_marshal_BOOLEAN__VOID,
                  G_TYPE_BOOLEAN, 0);

  /* setup the key bindings for the standard views */
  binding_set = gtk_binding_set_by_class (klass);
585 586 587 588 589
  gtk_binding_entry_add_signal (binding_set, GDK_KEY_BackSpace, GDK_CONTROL_MASK, "delete-selected-files", 0);
  gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, 0, "delete-selected-files", 0);
  gtk_binding_entry_add_signal (binding_set, GDK_KEY_Delete, GDK_SHIFT_MASK, "delete-selected-files", 0);
  gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, 0, "delete-selected-files", 0);
  gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_Delete, GDK_SHIFT_MASK, "delete-selected-files", 0);
590 591 592 593
}



594 595 596 597 598 599 600 601 602 603 604
static void
thunar_standard_view_component_init (ThunarComponentIface *iface)
{
  iface->get_selected_files = thunar_standard_view_get_selected_files;
  iface->set_selected_files = thunar_standard_view_set_selected_files;
  iface->get_ui_manager = thunar_standard_view_get_ui_manager;
  iface->set_ui_manager = thunar_standard_view_set_ui_manager;
}



605 606 607 608 609 610 611 612 613 614 615 616 617 618
static void
thunar_standard_view_navigator_init (ThunarNavigatorIface *iface)
{
  iface->get_current_directory = thunar_standard_view_get_current_directory;
  iface->set_current_directory = thunar_standard_view_set_current_directory;
}



static void
thunar_standard_view_view_init (ThunarViewIface *iface)
{
  iface->get_loading = thunar_standard_view_get_loading;
  iface->get_statusbar_text = thunar_standard_view_get_statusbar_text;
619 620
  iface->get_show_hidden = thunar_standard_view_get_show_hidden;
  iface->set_show_hidden = thunar_standard_view_set_show_hidden;
621 622 623
  iface->get_zoom_level = thunar_standard_view_get_zoom_level;
  iface->set_zoom_level = thunar_standard_view_set_zoom_level;
  iface->reset_zoom_level = thunar_standard_view_reset_zoom_level;
624
  iface->reload = thunar_standard_view_reload;
625 626
  iface->get_visible_range = thunar_standard_view_get_visible_range;
  iface->scroll_to_file = thunar_standard_view_scroll_to_file;
627 628 629 630 631 632 633
}



static void
thunar_standard_view_init (ThunarStandardView *standard_view)
{
634
  standard_view->priv = thunar_standard_view_get_instance_private (standard_view);
635

636 637
  /* allocate the scroll_to_files mapping (directory GFile -> first visible child GFile) */
  standard_view->priv->scroll_to_files = g_hash_table_new_full (g_file_hash, (GEqualFunc) g_file_equal, g_object_unref, g_object_unref);
638

639 640 641
  /* grab a reference on the preferences */
  standard_view->preferences = thunar_preferences_get ();

642 643
  /* grab a reference on the provider factory */
  standard_view->priv->provider_factory = thunarx_provider_factory_get_default ();
644

645
  /* create a thumbnailer */
646
  standard_view->priv->thumbnailer = thunar_thumbnailer_get ();
647
  g_signal_connect (G_OBJECT (standard_view->priv->thumbnailer), "request-finished", G_CALLBACK (thunar_standard_view_finished_thumbnailing), standard_view);
648 649
  standard_view->priv->thumbnailing_scheduled = FALSE;

650
  /* initialize the scrolled window */
651 652 653 654 655
  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (standard_view),
                                  GTK_POLICY_AUTOMATIC,
                                  GTK_POLICY_AUTOMATIC);
  gtk_scrolled_window_set_hadjustment (GTK_SCROLLED_WINDOW (standard_view), NULL);
  gtk_scrolled_window_set_vadjustment (GTK_SCROLLED_WINDOW (standard_view), NULL);
656
  gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (standard_view), GTK_SHADOW_IN);
657

658
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
659
  /* setup the action group for this view */
660
  standard_view->action_group = gtk_action_group_new ("ThunarStandardView");
661
  gtk_action_group_set_translation_domain (standard_view->action_group, GETTEXT_PACKAGE);
662 663 664
  gtk_action_group_add_actions (standard_view->action_group, action_entries,
                                G_N_ELEMENTS (action_entries),
                                GTK_WIDGET (standard_view));
665

666
  /* lookup all actions to speed up access later */
667
  standard_view->priv->action_create_folder = gtk_action_group_get_action (standard_view->action_group, "create-folder");
668 669
  standard_view->priv->action_properties = gtk_action_group_get_action (standard_view->action_group, "properties");
  standard_view->priv->action_cut = gtk_action_group_get_action (standard_view->action_group, "cut");
670
  standard_view->priv->action_copy = gtk_action_group_get_action (standard_view->action_group, "copy");
671
  standard_view->priv->action_paste = gtk_action_group_get_action (standard_view->action_group, "paste");
672
  standard_view->priv->action_move_to_trash = gtk_action_group_get_action (standard_view->action_group, "move-to-trash");
673
  standard_view->priv->action_delete = gtk_action_group_get_action (standard_view->action_group, "delete");
674
  standard_view->priv->action_paste_into_folder = gtk_action_group_get_action (standard_view->action_group, "paste-into-folder");
675 676
  standard_view->priv->action_duplicate = gtk_action_group_get_action (standard_view->action_group, "duplicate");
  standard_view->priv->action_make_link = gtk_action_group_get_action (standard_view->action_group, "make-link");
677
  standard_view->priv->action_rename = gtk_action_group_get_action (standard_view->action_group, "rename");
678
  standard_view->priv->action_restore = gtk_action_group_get_action (standard_view->action_group, "restore");
679
G_GNUC_END_IGNORE_DEPRECATIONS
680

681
  /* add the "Create Document" sub menu action */
682 683 684 685 686
  standard_view->priv->action_create_document = thunar_templates_action_new ("create-document", _("Create _Document"));
  g_signal_connect (G_OBJECT (standard_view->priv->action_create_document), "create-empty-file",
                    G_CALLBACK (thunar_standard_view_action_create_empty_file), standard_view);
  g_signal_connect (G_OBJECT (standard_view->priv->action_create_document), "create-template",
                    G_CALLBACK (thunar_standard_view_action_create_template), standard_view);
687
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
688
  gtk_action_group_add_action (standard_view->action_group, standard_view->priv->action_create_document);
689
G_GNUC_END_IGNORE_DEPRECATIONS
690
  g_object_unref (G_OBJECT (standard_view->priv->action_create_document));
691

692 693 694 695
  /* setup the history support */
  standard_view->priv->history = g_object_new (THUNAR_TYPE_HISTORY, "action-group", standard_view->action_group, NULL);
  g_signal_connect_swapped (G_OBJECT (standard_view->priv->history), "change-directory", G_CALLBACK (thunar_navigator_change_directory), standard_view);

696
  /* setup the list model */
697
  standard_view->model = thunar_list_model_new ();
698
  g_signal_connect (G_OBJECT (standard_view->model), "row-deleted", G_CALLBACK (thunar_standard_view_row_deleted), standard_view);
699
  g_signal_connect_after (G_OBJECT (standard_view->model), "row-deleted", G_CALLBACK (thunar_standard_view_select_after_row_deleted), standard_view);
700 701
  standard_view->priv->row_changed_id = g_signal_connect (G_OBJECT (standard_view->model), "row-changed", G_CALLBACK (thunar_standard_view_row_changed), standard_view);
  g_signal_connect (G_OBJECT (standard_view->model), "rows-reordered", G_CALLBACK (thunar_standard_view_rows_reordered), standard_view);
702
  g_signal_connect (G_OBJECT (standard_view->model), "error", G_CALLBACK (thunar_standard_view_error), standard_view);
703
  exo_binding_new (G_OBJECT (standard_view->preferences), "misc-case-sensitive", G_OBJECT (standard_view->model), "case-sensitive");
704
  exo_binding_new (G_OBJECT (standard_view->preferences), "misc-date-style", G_OBJECT (standard_view->model), "date-style");
705
  exo_binding_new (G_OBJECT (standard_view->preferences), "misc-date-custom-style", G_OBJECT (standard_view->model), "date-custom-style");
706
  exo_binding_new (G_OBJECT (standard_view->preferences), "misc-folders-first", G_OBJECT (standard_view->model), "folders-first");
707
  exo_binding_new (G_OBJECT (standard_view->preferences), "misc-file-size-binary", G_OBJECT (standard_view->model), "file-size-binary");
708

709 710
  /* setup the icon renderer */
  standard_view->icon_renderer = thunar_icon_renderer_new ();
711
  g_object_ref_sink (G_OBJECT (standard_view->icon_renderer));
712
  exo_binding_new (G_OBJECT (standard_view), "zoom-level", G_OBJECT (standard_view->icon_renderer), "size");
713
  exo_binding_new (G_OBJECT (standard_view->icon_renderer), "size", G_OBJECT (standard_view->priv->thumbnailer), "thumbnail-size");
714

715
  /* setup the name renderer */
716
  standard_view->name_renderer = g_object_new (GTK_TYPE_CELL_RENDERER_TEXT,
717
#if PANGO_VERSION_CHECK (1, 44, 0)
718
                                               "attributes", thunar_pango_attr_disable_hyphens (),
719
#endif
720 721
                                               "alignment", PANGO_ALIGN_CENTER,
                                               "xalign", 0.5,
722
                                               NULL);
723
  g_object_ref_sink (G_OBJECT (standard_view->name_renderer));
724 725 726

  /* TODO: prelit underline
  exo_binding_new (G_OBJECT (standard_view->preferences), "misc-single-click", G_OBJECT (standard_view->name_renderer), "follow-prelit");*/
727

728 729 730
  /* be sure to update the selection whenever the folder changes */
  g_signal_connect_swapped (G_OBJECT (standard_view->model), "notify::folder", G_CALLBACK (thunar_standard_view_selection_changed), standard_view);

731 732 733
  /* be sure to update the statusbar text whenever the number of
   * files in our model changes.
   */
734
  g_signal_connect_swapped (G_OBJECT (standard_view->model), "notify::num-files", G_CALLBACK (thunar_standard_view_update_statusbar_text), standard_view);
735

736 737 738
  /* be sure to update the statusbar text whenever the file-size-binary property changes */
  g_signal_connect_swapped (G_OBJECT (standard_view->model), "notify::file-size-binary", G_CALLBACK (thunar_standard_view_update_statusbar_text), standard_view);

739
  /* connect to size allocation signals for generating thumbnail requests */
740
  g_signal_connect_after (G_OBJECT (standard_view), "size-allocate",
741
                          G_CALLBACK (thunar_standard_view_size_allocate), NULL);
Andre Miranda's avatar
Andre Miranda committed
742

743 744
  /* add widget to css class */
  gtk_style_context_add_class (gtk_widget_get_style_context (GTK_WIDGET (standard_view)), "standard-view");
745 746 747 748 749 750 751 752 753
}



static GObject*
thunar_standard_view_constructor (GType                  type,
                                  guint                  n_construct_properties,
                                  GObjectConstructParam *construct_properties)
{
754
  ThunarStandardView *standard_view;
755
  ThunarZoomLevel     zoom_level;
756
  GtkAdjustment      *adjustment;
757 758 759 760
  ThunarColumn        sort_column;
  GtkSortType         sort_order;
  GtkWidget          *view;
  GObject            *object;
761 762 763 764 765 766

  /* let the GObject constructor create the instance */
  object = G_OBJECT_CLASS (thunar_standard_view_parent_class)->constructor (type,
                                                                            n_construct_properties,
                                                                            construct_properties);

767 768 769 770 771 772 773 774
  /* cast to standard_view for convenience */
  standard_view = THUNAR_STANDARD_VIEW (object);

  /* setup the default zoom-level, determined from the "last-<view>-zoom-level" preference */
  g_object_get (G_OBJECT (standard_view->preferences), THUNAR_STANDARD_VIEW_GET_CLASS (standard_view)->zoom_level_property_name, &zoom_level, NULL);
  thunar_view_set_zoom_level (THUNAR_VIEW (standard_view), zoom_level);

  /* save the "zoom-level" as "last-<view>-zoom-level" whenever the user changes the zoom level */
775
  g_object_bind_property (object, "zoom-level", G_OBJECT (standard_view->preferences), THUNAR_STANDARD_VIEW_GET_CLASS (standard_view)->zoom_level_property_name, G_BINDING_DEFAULT);
776

777
  /* determine the real view widget (treeview or iconview) */
Jonas Kümmerlin's avatar
Jonas Kümmerlin committed
778
  view = gtk_bin_get_child (GTK_BIN (object));
779

780 781 782
  /* apply our list model to the real view (the child of the scrolled window),
   * we therefore assume that all real views have the "model" property.
   */
783
  g_object_set (G_OBJECT (view), "model", standard_view->model, NULL);
784

785
  /* apply the single-click settings to the view */
786
  exo_binding_new (G_OBJECT (standard_view->preferences), "misc-single-click", G_OBJECT (view), "single-click");
787
  exo_binding_new (G_OBJECT (standard_view->preferences), "misc-single-click-timeout", G_OBJECT (view), "single-click-timeout");
788

789 790 791 792 793 794 795
  /* apply the default sort column and sort order */
  g_object_get (G_OBJECT (standard_view->preferences), "last-sort-column", &sort_column, "last-sort-order", &sort_order, NULL);
  gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (standard_view->model), sort_column, sort_order);

  /* stay informed about changes to the sort column/order */
  g_signal_connect (G_OBJECT (standard_view->model), "sort-column-changed", G_CALLBACK (thunar_standard_view_sort_column_changed), standard_view);

796
  /* setup support to navigate using a horizontal mouse wheel and the back and forward buttons */
797
  g_signal_connect (G_OBJECT (view), "scroll-event", G_CALLBACK (thunar_standard_view_scroll_event), object);
798
  g_signal_connect (G_OBJECT (view), "button-press-event", G_CALLBACK (thunar_standard_view_button_press_event), object);
799

800 801 802
  /* need to catch certain keys for the internal view widget */
  g_signal_connect (G_OBJECT (view), "key-press-event", G_CALLBACK (thunar_standard_view_key_press_event), object);

803 804 805 806 807 808
  /* setup the real view as drop site */
  gtk_drag_dest_set (view, 0, drop_targets, G_N_ELEMENTS (drop_targets), GDK_ACTION_ASK | GDK_ACTION_COPY | GDK_ACTION_LINK | GDK_ACTION_MOVE);
  g_signal_connect (G_OBJECT (view), "drag-drop", G_CALLBACK (thunar_standard_view_drag_drop), object);
  g_signal_connect (G_OBJECT (view), "drag-data-received", G_CALLBACK (thunar_standard_view_drag_data_received), object);
  g_signal_connect (G_OBJECT (view), "drag-leave", G_CALLBACK (thunar_standard_view_drag_leave), object);
  g_signal_connect (G_OBJECT (view), "drag-motion", G_CALLBACK (thunar_standard_view_drag_motion), object);
809 810

  /* setup the real view as drag source */
811
  gtk_drag_source_set (view, GDK_BUTTON1_MASK, drag_targets, G_N_ELEMENTS (drag_targets), GDK_ACTION_COPY | GDK_ACTION_MOVE | GDK_ACTION_LINK);
812 813
  g_signal_connect (G_OBJECT (view), "drag-begin", G_CALLBACK (thunar_standard_view_drag_begin), object);
  g_signal_connect (G_OBJECT (view), "drag-data-get", G_CALLBACK (thunar_standard_view_drag_data_get), object);
814
  g_signal_connect (G_OBJECT (view), "drag-data-delete", G_CALLBACK (thunar_standard_view_drag_data_delete), object);
815
  g_signal_connect (G_OBJECT (view), "drag-end", G_CALLBACK (thunar_standard_view_drag_end), object);
816

817 818 819 820 821 822 823 824
  /* connect to scroll events for generating thumbnail requests */
  adjustment = gtk_scrolled_window_get_hadjustment (GTK_SCROLLED_WINDOW (standard_view));
  g_signal_connect (adjustment, "value-changed",
                    G_CALLBACK (thunar_standard_view_scrolled), object);
  adjustment = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (standard_view));
  g_signal_connect (adjustment, "value-changed",
                    G_CALLBACK (thunar_standard_view_scrolled), object);

825 826 827 828 829 830 831 832 833 834 835
  /* done, we have a working object */
  return object;
}



static void
thunar_standard_view_dispose (GObject *object)
{
  ThunarStandardView *standard_view = THUNAR_STANDARD_VIEW (object);

836 837 838
  /* cancel pending thumbnail sources and requests */
  thunar_standard_view_cancel_thumbnailing (standard_view);

839 840 841
  /* unregister the "loading" binding */
  if (G_UNLIKELY (standard_view->loading_binding != NULL))
    exo_binding_unbind (standard_view->loading_binding);
842

843
  /* be sure to cancel any pending drag autoscroll timer */
844
  if (G_UNLIKELY (standard_view->priv->drag_scroll_timer_id != 0))
845 846
    g_source_remove (standard_view->priv->drag_scroll_timer_id);

847 848 849 850
  /* be sure to cancel any pending drag timer */
  if (G_UNLIKELY (standard_view->priv->drag_timer_id != 0))
    g_source_remove (standard_view->priv->drag_timer_id);

851 852 853 854 855 856 857
  /* be sure to free any pending drag timer event */
  if (G_UNLIKELY (standard_view->priv->drag_timer_event != NULL))
    {
      gdk_event_free (standard_view->priv->drag_timer_event);
      standard_view->priv->drag_timer_event = NULL;
    }

858
  /* reset the UI manager property */
859
  thunar_component_set_ui_manager (THUNAR_COMPONENT (standard_view), NULL);
860

861 862 863 864 865 866 867 868 869
  /* disconnect from file */
  if (standard_view->priv->current_directory != NULL)
    {
      g_signal_handlers_disconnect_matched (standard_view->priv->current_directory,
                                            G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, standard_view);
      g_object_unref (standard_view->priv->current_directory);
      standard_view->priv->current_directory = NULL;
    }

870
  (*G_OBJECT_CLASS (thunar_standard_view_parent_class)->dispose) (object);
871 872 873 874 875 876 877 878 879
}



static void
thunar_standard_view_finalize (GObject *object)
{
  ThunarStandardView *standard_view = THUNAR_STANDARD_VIEW (object);

880
  /* some safety checks */
881 882 883 884
  _thunar_assert (standard_view->loading_binding == NULL);
  _thunar_assert (standard_view->icon_factory == NULL);
  _thunar_assert (standard_view->ui_manager == NULL);
  _thunar_assert (standard_view->clipboard == NULL);
885

886
  /* release the thumbnailer */
887
  g_signal_handlers_disconnect_by_func (standard_view->priv->thumbnailer, thunar_standard_view_finished_thumbnailing, standard_view);
888 889
  g_object_unref (standard_view->priv->thumbnailer);

890 891 892 893
  /* release the scroll_to_file reference (if any) */
  if (G_UNLIKELY (standard_view->priv->scroll_to_file != NULL))
    g_object_unref (G_OBJECT (standard_view->priv->scroll_to_file));

894
  /* release the selected_files list (if any) */
895
  thunar_g_file_list_free (standard_view->priv->selected_files);
896

897 898
  /* release our reference on the provider factory */
  g_object_unref (G_OBJECT (standard_view->priv->provider_factory));
899

900
  /* release the drag path list (just in case the drag-end wasn't fired before) */
901
  thunar_g_file_list_free (standard_view->priv->drag_g_file_list);
902

903
  /* release the drop path list (just in case the drag-leave wasn't fired before) */
904
  thunar_g_file_list_free (standard_view->priv->drop_file_list);
905

906 907 908
  /* release the history */
  g_object_unref (standard_view->priv->history);

909 910 911
  /* release the reference on the name renderer */
  g_object_unref (G_OBJECT (standard_view->name_renderer));

912 913 914
  /* release the reference on the icon renderer */
  g_object_unref (G_OBJECT (standard_view->icon_renderer));

915 916 917
  /* release the reference on the action group */
  g_object_unref (G_OBJECT (standard_view->action_group));

918 919 920 921 922 923 924 925
  /* drop any existing "new-files" closure */
  if (G_UNLIKELY (standard_view->priv->new_files_closure != NULL))
    {
      g_closure_invalidate (standard_view->priv->new_files_closure);
      g_closure_unref (standard_view->priv->new_files_closure);
      standard_view->priv->new_files_closure = NULL;
    }

926
  /* drop any remaining "new-files" paths */
927
  thunar_g_file_list_free (standard_view->priv->new_files_path_list);
928

929 930 931
  /* release our reference on the preferences */
  g_object_unref (G_OBJECT (standard_view->preferences));

932
  /* disconnect from the list model */
933
  g_signal_handlers_disconnect_matched (G_OBJECT (standard_view->model), G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, standard_view);
934
  g_object_unref (G_OBJECT (standard_view->model));
935

936 937 938 939
  /* remove selection restore timeout */
  if (standard_view->priv->restore_selection_idle_id != 0)
    g_source_remove (standard_view->priv->restore_selection_idle_id);

940
  /* free the statusbar text (if any) */
941 942 943
  if (standard_view->priv->statusbar_text_idle_id != 0)
    g_source_remove (standard_view->priv->statusbar_text_idle_id);
  g_free (standard_view->priv->statusbar_text);
944

945 946 947
  /* release the scroll_to_files hash table */
  g_hash_table_destroy (standard_view->priv->scroll_to_files);

948
  (*G_OBJECT_CLASS (thunar_standard_view_parent_class)->finalize) (object);
949 950 951 952 953 954 955 956 957 958
}



static void
thunar_standard_view_get_property (GObject    *object,
                                   guint       prop_id,
                                   GValue     *value,
                                   GParamSpec *pspec)
{
959 960
  ThunarFile *current_directory;

961 962 963 964 965 966 967 968 969 970
  switch (prop_id)
    {
    case PROP_CURRENT_DIRECTORY:
      g_value_set_object (value, thunar_navigator_get_current_directory (THUNAR_NAVIGATOR (object)));
      break;

    case PROP_LOADING:
      g_value_set_boolean (value, thunar_view_get_loading (THUNAR_VIEW (object)));
      break;

971 972 973 974 975 976 977 978 979 980 981 982
    case PROP_DISPLAY_NAME:
      current_directory = thunar_navigator_get_current_directory (THUNAR_NAVIGATOR (object));
      if (current_directory != NULL)
        g_value_set_static_string (value, thunar_file_get_display_name (current_directory));
      break;

    case PROP_TOOLTIP_TEXT:
      current_directory = thunar_navigator_get_current_directory (THUNAR_NAVIGATOR (object));
      if (current_directory != NULL)
        g_value_take_string (value, g_file_get_parse_name (thunar_file_get_file (current_directory)));
      break;

983 984
    case PROP_SELECTED_FILES:
      g_value_set_boxed (value, thunar_component_get_selected_files (THUNAR_COMPONENT (object)));
985 986
      break;

987 988 989 990
    case PROP_SHOW_HIDDEN:
      g_value_set_boolean (value, thunar_view_get_show_hidden (THUNAR_VIEW (object)));
      break;

991 992 993 994
    case PROP_STATUSBAR_TEXT:
      g_value_set_static_string (value, thunar_view_get_statusbar_text (THUNAR_VIEW (object)));
      break;

995
    case PROP_UI_MANAGER:
996
      g_value_set_object (value, thunar_component_get_ui_manager (THUNAR_COMPONENT (object)));
997 998
      break;

999 1000 1001 1002
    case PROP_ZOOM_LEVEL:
      g_value_set_enum (value, thunar_view_get_zoom_level (THUNAR_VIEW (object)));
      break;

1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}



static void
thunar_standard_view_set_property (GObject      *object,
                                   guint         prop_id,
                                   const GValue *value,
                                   GParamSpec   *pspec)
{
1017 1018
  ThunarStandardView *standard_view = THUNAR_STANDARD_VIEW (object);

1019 1020 1021
  switch (prop_id)
    {
    case PROP_CURRENT_DIRECTORY:
1022 1023 1024
      thunar_navigator_set_current_directory (THUNAR_NAVIGATOR (object), g_value_get_object (value));
      break;

1025
    case PROP_LOADING:
1026 1027
      thunar_standard_view_set_loading (standard_view, g_value_get_boolean (value));
      break;
1028

1029 1030 1031
    case PROP_SELECTED_FILES:
      thunar_component_set_selected_files (THUNAR_COMPONENT (object), g_value_get_boxed (value));
      break;
1032

1033 1034 1035 1036
    case PROP_SHOW_HIDDEN:
      thunar_view_set_show_hidden (THUNAR_VIEW (object), g_value_get_boolean (value));
      break;

1037
    case PROP_UI_MANAGER:
1038
      thunar_component_set_ui_manager (THUNAR_COMPONENT (object), g_value_get_object (value));
1039 1040
      break;

1041 1042 1043 1044
    case PROP_ZOOM_LEVEL:
      thunar_view_set_zoom_level (THUNAR_VIEW (object), g_value_get_enum (value));
      break;

1045 1046 1047 1048 1049 1050 1051 1052
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}



1053 1054 1055 1056
static void
thunar_standard_view_realize (GtkWidget *widget)
{
  ThunarStandardView *standard_view = THUNAR_STANDARD_VIEW (widget);
1057
  GtkIconTheme       *icon_theme;
1058 1059 1060 1061 1062 1063 1064 1065
  GdkDisplay         *display;

  /* let the GtkWidget do its work */
  GTK_WIDGET_CLASS (thunar_standard_view_parent_class)->realize (widget);

  /* query the clipboard manager for the display */
  display = gtk_widget_get_display (widget);
  standard_view->clipboard = thunar_clipboard_manager_get_for_display (display);
1066 1067 1068 1069

  /* we need update the selection state based on the clipboard content */
  g_signal_connect_swapped (G_OBJECT (standard_view->clipboard), "changed",
                            G_CALLBACK (thunar_standard_view_selection_changed), standard_view);
1070 1071 1072 1073

  /* determine the icon factory for the screen on which we are realized */
  icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (widget));
  standard_view->