Location | Tool | Test ID | Function | Issue |
---|---|---|---|---|
nautilus-places-sidebar.c:1232:0 | cppcheck | uninitvar | Uninitialized variable: action | |
nautilus-places-sidebar.c:1232:13 | clang-analyzer | The left operand of '!=' is a garbage value |
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
3 /*
4 * Nautilus
5 *
6 * This library 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 the
9 * License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this library; if not, write to the Free Software
18 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 *
20 * Authors : Mr Jamie McCracken (jamiemcc at blueyonder dot co dot uk)
21 * Cosimo Cecchi <cosimoc@gnome.org>
22 *
23 */
24
25 #include <config.h>
26
27 #include <gdk/gdkkeysyms.h>
28 #include <gtk/gtk.h>
29 #include <glib/gi18n.h>
30 #include <gio/gio.h>
31
32 #include <libnautilus-private/nautilus-dnd.h>
33 #include <libnautilus-private/nautilus-bookmark.h>
34 #include <libnautilus-private/nautilus-global-preferences.h>
35 #include <libnautilus-private/nautilus-file.h>
36 #include <libnautilus-private/nautilus-file-utilities.h>
37 #include <libnautilus-private/nautilus-file-operations.h>
38 #include <libnautilus-private/nautilus-trash-monitor.h>
39 #include <libnautilus-private/nautilus-icon-names.h>
40
41 #include <eel/eel-debug.h>
42 #include <eel/eel-gtk-extensions.h>
43 #include <eel/eel-glib-extensions.h>
44 #include <eel/eel-graphic-effects.h>
45 #include <eel/eel-string.h>
46 #include <eel/eel-stock-dialogs.h>
47
48 #include "nautilus-application.h"
49 #include "nautilus-bookmark-list.h"
50 #include "nautilus-places-sidebar.h"
51 #include "nautilus-properties-window.h"
52 #include "nautilus-window.h"
53 #include "nautilus-window-slot.h"
54
55 #define DEBUG_FLAG NAUTILUS_DEBUG_PLACES
56 #include <libnautilus-private/nautilus-debug.h>
57
58 #define EJECT_BUTTON_XPAD 6
59 #define ICON_CELL_XPAD 6
60
61 typedef struct {
62 GtkScrolledWindow parent;
63 GtkTreeView *tree_view;
64 GtkCellRenderer *eject_icon_cell_renderer;
65 char *uri;
66 GtkListStore *store;
67 NautilusWindow *window;
68 NautilusBookmarkList *bookmarks;
69 GVolumeMonitor *volume_monitor;
70
71 gboolean devices_header_added;
72 gboolean bookmarks_header_added;
73
74 /* DnD */
75 GList *drag_list;
76 gboolean drag_data_received;
77 int drag_data_info;
78 gboolean drop_occured;
79
80 GtkWidget *popup_menu;
81 GtkWidget *popup_menu_open_in_new_tab_item;
82 GtkWidget *popup_menu_add_shortcut_item;
83 GtkWidget *popup_menu_remove_item;
84 GtkWidget *popup_menu_rename_item;
85 GtkWidget *popup_menu_separator_item;
86 GtkWidget *popup_menu_mount_item;
87 GtkWidget *popup_menu_unmount_item;
88 GtkWidget *popup_menu_eject_item;
89 GtkWidget *popup_menu_rescan_item;
90 GtkWidget *popup_menu_empty_trash_item;
91 GtkWidget *popup_menu_start_item;
92 GtkWidget *popup_menu_stop_item;
93 GtkWidget *popup_menu_properties_separator_item;
94 GtkWidget *popup_menu_properties_item;
95
96 /* volume mounting - delayed open process */
97 gboolean mounting;
98 NautilusWindowSlot *go_to_after_mount_slot;
99 NautilusWindowOpenFlags go_to_after_mount_flags;
100
101 GDBusProxy *hostnamed_proxy;
102 char *hostname;
103
104 guint bookmarks_changed_id;
105 } NautilusPlacesSidebar;
106
107 typedef struct {
108 GtkScrolledWindowClass parent;
109 } NautilusPlacesSidebarClass;
110
111 typedef struct {
112 GObject parent;
113 } NautilusPlacesSidebarProvider;
114
115 typedef struct {
116 GObjectClass parent;
117 } NautilusPlacesSidebarProviderClass;
118
119 enum {
120 PLACES_SIDEBAR_COLUMN_ROW_TYPE,
121 PLACES_SIDEBAR_COLUMN_URI,
122 PLACES_SIDEBAR_COLUMN_DRIVE,
123 PLACES_SIDEBAR_COLUMN_VOLUME,
124 PLACES_SIDEBAR_COLUMN_MOUNT,
125 PLACES_SIDEBAR_COLUMN_NAME,
126 PLACES_SIDEBAR_COLUMN_GICON,
127 PLACES_SIDEBAR_COLUMN_INDEX,
128 PLACES_SIDEBAR_COLUMN_EJECT,
129 PLACES_SIDEBAR_COLUMN_NO_EJECT,
130 PLACES_SIDEBAR_COLUMN_BOOKMARK,
131 PLACES_SIDEBAR_COLUMN_TOOLTIP,
132 PLACES_SIDEBAR_COLUMN_EJECT_GICON,
133 PLACES_SIDEBAR_COLUMN_SECTION_TYPE,
134 PLACES_SIDEBAR_COLUMN_HEADING_TEXT,
135
136 PLACES_SIDEBAR_COLUMN_COUNT
137 };
138
139 typedef enum {
140 PLACES_BUILT_IN,
141 PLACES_XDG_DIR,
142 PLACES_MOUNTED_VOLUME,
143 PLACES_BOOKMARK,
144 PLACES_HEADING,
145 } PlaceType;
146
147 typedef enum {
148 SECTION_DEVICES,
149 SECTION_BOOKMARKS,
150 SECTION_COMPUTER,
151 SECTION_NETWORK,
152 } SectionType;
153
154 static void open_selected_bookmark (NautilusPlacesSidebar *sidebar,
155 GtkTreeModel *model,
156 GtkTreeIter *iter,
157 NautilusWindowOpenFlags flags);
158 static void nautilus_places_sidebar_style_set (GtkWidget *widget,
159 GtkStyle *previous_style);
160 static gboolean eject_or_unmount_bookmark (NautilusPlacesSidebar *sidebar,
161 GtkTreePath *path);
162 static gboolean eject_or_unmount_selection (NautilusPlacesSidebar *sidebar);
163 static void check_unmount_and_eject (GMount *mount,
164 GVolume *volume,
165 GDrive *drive,
166 gboolean *show_unmount,
167 gboolean *show_eject);
168
169 static void bookmarks_check_popup_sensitivity (NautilusPlacesSidebar *sidebar);
170
171 /* Identifiers for target types */
172 enum {
173 GTK_TREE_MODEL_ROW,
174 TEXT_URI_LIST
175 };
176
177 /* Target types for dragging from the shortcuts list */
178 static const GtkTargetEntry nautilus_shortcuts_source_targets[] = {
179 { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, GTK_TREE_MODEL_ROW }
180 };
181
182 /* Target types for dropping into the shortcuts list */
183 static const GtkTargetEntry nautilus_shortcuts_drop_targets [] = {
184 { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, GTK_TREE_MODEL_ROW },
185 { "text/uri-list", 0, TEXT_URI_LIST }
186 };
187
188 /* Drag and drop interface declarations */
189 typedef struct {
190 GtkListStore parent;
191
192 NautilusPlacesSidebar *sidebar;
193 } NautilusShortcutsModel;
194
195 typedef struct {
196 GtkListStoreClass parent_class;
197 } NautilusShortcutsModelClass;
198
199 GType _nautilus_shortcuts_model_get_type (void);
200 static void _nautilus_shortcuts_model_drag_source_init (GtkTreeDragSourceIface *iface);
201 G_DEFINE_TYPE_WITH_CODE (NautilusShortcutsModel, _nautilus_shortcuts_model, GTK_TYPE_LIST_STORE,
202 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
203 _nautilus_shortcuts_model_drag_source_init));
204 static GtkListStore *nautilus_shortcuts_model_new (NautilusPlacesSidebar *sidebar);
205
206 G_DEFINE_TYPE (NautilusPlacesSidebar, nautilus_places_sidebar, GTK_TYPE_SCROLLED_WINDOW);
207
208 static gboolean
209 is_built_in_bookmark (NautilusFile *file)
210 {
211 gboolean built_in;
212 gint idx;
213
214 if (nautilus_file_is_home (file)) {
215 return TRUE;
216 }
217
218 if (nautilus_file_is_desktop_directory (file) &&
219 !g_settings_get_boolean (gnome_background_preferences, NAUTILUS_PREFERENCES_SHOW_DESKTOP)) {
220 return FALSE;
221 }
222
223 built_in = FALSE;
224
225 for (idx = 0; idx < G_USER_N_DIRECTORIES; idx++) {
226 /* PUBLIC_SHARE and TEMPLATES are not in our built-in list */
227 if (nautilus_file_is_user_special_directory (file, idx)) {
228 if (idx != G_USER_DIRECTORY_PUBLIC_SHARE && idx != G_USER_DIRECTORY_TEMPLATES) {
229 built_in = TRUE;
230 }
231
232 break;
233 }
234 }
235
236 return built_in;
237 }
238
239 static GtkTreeIter
240 add_heading (NautilusPlacesSidebar *sidebar,
241 SectionType section_type,
242 const gchar *title)
243 {
244 GtkTreeIter iter;
245
246 gtk_list_store_append (sidebar->store, &iter);
247 gtk_list_store_set (sidebar->store, &iter,
248 PLACES_SIDEBAR_COLUMN_ROW_TYPE, PLACES_HEADING,
249 PLACES_SIDEBAR_COLUMN_SECTION_TYPE, section_type,
250 PLACES_SIDEBAR_COLUMN_HEADING_TEXT, title,
251 PLACES_SIDEBAR_COLUMN_EJECT, FALSE,
252 PLACES_SIDEBAR_COLUMN_NO_EJECT, TRUE,
253 -1);
254
255 return iter;
256 }
257
258 static void
259 check_heading_for_section (NautilusPlacesSidebar *sidebar,
260 SectionType section_type)
261 {
262 switch (section_type) {
263 case SECTION_DEVICES:
264 if (!sidebar->devices_header_added) {
265 add_heading (sidebar, SECTION_DEVICES,
266 _("Devices"));
267 sidebar->devices_header_added = TRUE;
268 }
269
270 break;
271 case SECTION_BOOKMARKS:
272 if (!sidebar->bookmarks_header_added) {
273 add_heading (sidebar, SECTION_BOOKMARKS,
274 _("Bookmarks"));
275 sidebar->bookmarks_header_added = TRUE;
276 }
277
278 break;
279 default:
280 break;
281 }
282 }
283
284 static void
285 add_place (NautilusPlacesSidebar *sidebar,
286 PlaceType place_type,
287 SectionType section_type,
288 const char *name,
289 GIcon *icon,
290 const char *uri,
291 GDrive *drive,
292 GVolume *volume,
293 GMount *mount,
294 const int index,
295 const char *tooltip)
296 {
297 GtkTreeIter iter;
298 GIcon *eject;
299 gboolean show_eject, show_unmount;
300 gboolean show_eject_button;
301
302 check_heading_for_section (sidebar, section_type);
303
304 check_unmount_and_eject (mount, volume, drive,
305 &show_unmount, &show_eject);
306
307 if (show_unmount || show_eject) {
308 g_assert (place_type != PLACES_BOOKMARK);
309 }
310
311 if (mount == NULL) {
312 show_eject_button = FALSE;
313 } else {
314 show_eject_button = (show_unmount || show_eject);
315 }
316
317 if (show_eject_button) {
318 eject = g_themed_icon_new_with_default_fallbacks ("media-eject-symbolic");
319 } else {
320 eject = NULL;
321 }
322
323 gtk_list_store_append (sidebar->store, &iter);
324 gtk_list_store_set (sidebar->store, &iter,
325 PLACES_SIDEBAR_COLUMN_GICON, icon,
326 PLACES_SIDEBAR_COLUMN_NAME, name,
327 PLACES_SIDEBAR_COLUMN_URI, uri,
328 PLACES_SIDEBAR_COLUMN_DRIVE, drive,
329 PLACES_SIDEBAR_COLUMN_VOLUME, volume,
330 PLACES_SIDEBAR_COLUMN_MOUNT, mount,
331 PLACES_SIDEBAR_COLUMN_ROW_TYPE, place_type,
332 PLACES_SIDEBAR_COLUMN_INDEX, index,
333 PLACES_SIDEBAR_COLUMN_EJECT, show_eject_button,
334 PLACES_SIDEBAR_COLUMN_NO_EJECT, !show_eject_button,
335 PLACES_SIDEBAR_COLUMN_BOOKMARK, place_type != PLACES_BOOKMARK,
336 PLACES_SIDEBAR_COLUMN_TOOLTIP, tooltip,
337 PLACES_SIDEBAR_COLUMN_EJECT_GICON, eject,
338 PLACES_SIDEBAR_COLUMN_SECTION_TYPE, section_type,
339 -1);
340
341 if (eject != NULL) {
342 g_object_unref (eject);
343 }
344 }
345
346 typedef struct {
347 const gchar *location;
348 const gchar *last_uri;
349 NautilusPlacesSidebar *sidebar;
350 GtkTreePath *path;
351 } RestoreLocationData;
352
353 static gboolean
354 restore_selection_foreach (GtkTreeModel *model,
355 GtkTreePath *path,
356 GtkTreeIter *iter,
357 gpointer user_data)
358 {
359 RestoreLocationData *data = user_data;
360 gchar *uri;
361
362 gtk_tree_model_get (model, iter,
363 PLACES_SIDEBAR_COLUMN_URI, &uri,
364 -1);
365
366 if (g_strcmp0 (uri, data->last_uri) == 0 ||
367 g_strcmp0 (uri, data->location) == 0) {
368 data->path = gtk_tree_path_copy (path);
369 }
370
371 g_free (uri);
372
373 return (data->path != NULL);
374 }
375
376 static void
377 sidebar_update_restore_selection (NautilusPlacesSidebar *sidebar,
378 const gchar *location,
379 const gchar *last_uri)
380 {
381 RestoreLocationData data;
382 GtkTreeSelection *selection;
383
384 data.location = location;
385 data.last_uri = last_uri;
386 data.sidebar = sidebar;
387 data.path = NULL;
388
389 gtk_tree_model_foreach (GTK_TREE_MODEL (sidebar->store),
390 restore_selection_foreach, &data);
391
392 if (data.path != NULL) {
393 selection = gtk_tree_view_get_selection (sidebar->tree_view);
394 gtk_tree_selection_select_path (selection, data.path);
395 gtk_tree_path_free (data.path);
396 }
397 }
398
399 static gboolean
400 recent_is_supported (void)
401 {
402 const char * const *supported;
403 int i;
404
405 supported = g_vfs_get_supported_uri_schemes (g_vfs_get_default ());
406 if (!supported) {
407 return FALSE;
408 }
409
410 for (i = 0; supported[i] != NULL; i++) {
411 if (strcmp ("recent", supported[i]) == 0) {
412 return TRUE;
413 }
414 }
415 return FALSE;
416 }
417
418 static void
419 add_special_dirs (NautilusPlacesSidebar *sidebar)
420 {
421 GList *dirs;
422 int index;
423
424 dirs = NULL;
425 for (index = 0; index < G_USER_N_DIRECTORIES; index++) {
426 const char *path;
427 GFile *root;
428 GIcon *icon;
429 char *name;
430 char *mount_uri;
431 char *tooltip;
432
433 if (index == G_USER_DIRECTORY_DESKTOP ||
434 index == G_USER_DIRECTORY_TEMPLATES ||
435 index == G_USER_DIRECTORY_PUBLIC_SHARE) {
436 continue;
437 }
438
439 path = g_get_user_special_dir (index);
440
441 /* xdg resets special dirs to the home directory in case
442 * it's not finiding what it expects. We don't want the home
443 * to be added multiple times in that weird configuration.
444 */
445 if (path == NULL
446 || g_strcmp0 (path, g_get_home_dir ()) == 0
447 || g_list_find_custom (dirs, path, (GCompareFunc) g_strcmp0) != NULL) {
448 continue;
449 }
450
451 root = g_file_new_for_path (path);
452 name = g_file_get_basename (root);
453 icon = nautilus_special_directory_get_symbolic_icon (index);
454 mount_uri = g_file_get_uri (root);
455 tooltip = g_file_get_parse_name (root);
456
457 add_place (sidebar, PLACES_XDG_DIR,
458 SECTION_COMPUTER,
459 name, icon, mount_uri,
460 NULL, NULL, NULL, 0,
461 tooltip);
462 g_free (name);
463 g_object_unref (root);
464 g_object_unref (icon);
465 g_free (mount_uri);
466 g_free (tooltip);
467
468 dirs = g_list_prepend (dirs, (char *)path);
469 }
470
471 g_list_free (dirs);
472 }
473
474 static void
475 update_places (NautilusPlacesSidebar *sidebar)
476 {
477 NautilusBookmark *bookmark;
478 GtkTreeSelection *selection;
479 GtkTreeIter last_iter;
480 GtkTreeModel *model;
481 GVolumeMonitor *volume_monitor;
482 GList *mounts, *l, *ll;
483 GMount *mount;
484 GList *drives;
485 GDrive *drive;
486 GList *volumes;
487 GVolume *volume;
488 int bookmark_count, index;
489 char *location, *mount_uri, *name, *last_uri, *identifier;
490 const gchar *bookmark_name;
491 GIcon *icon;
492 GFile *root;
493 NautilusWindowSlot *slot;
494 char *tooltip;
495 GList *network_mounts, *network_volumes;
496 NautilusFile *file;
497
498 DEBUG ("Updating places sidebar");
499
500 model = NULL;
501 last_uri = NULL;
502
503 selection = gtk_tree_view_get_selection (sidebar->tree_view);
504 if (gtk_tree_selection_get_selected (selection, &model, &last_iter)) {
505 gtk_tree_model_get (model,
506 &last_iter,
507 PLACES_SIDEBAR_COLUMN_URI, &last_uri, -1);
508 }
509 gtk_list_store_clear (sidebar->store);
510
511 sidebar->devices_header_added = FALSE;
512 sidebar->bookmarks_header_added = FALSE;
513
514 slot = nautilus_window_get_active_slot (sidebar->window);
515 location = nautilus_window_slot_get_current_uri (slot);
516
517 network_mounts = network_volumes = NULL;
518 volume_monitor = sidebar->volume_monitor;
519
520 /* add built in bookmarks */
521
522 add_heading (sidebar, SECTION_COMPUTER,
523 _("Places"));
524
525 if (recent_is_supported ()) {
526 mount_uri = "recent:///"; /* No need to strdup */
527 icon = g_themed_icon_new ("document-open-recent-symbolic");
528 add_place (sidebar, PLACES_BUILT_IN,
529 SECTION_COMPUTER,
530 _("Recent"), icon, mount_uri,
531 NULL, NULL, NULL, 0,
532 _("Recent files"));
533 g_object_unref (icon);
534 }
535
536 /* home folder */
537 mount_uri = nautilus_get_home_directory_uri ();
538 icon = g_themed_icon_new (NAUTILUS_ICON_HOME);
539 add_place (sidebar, PLACES_BUILT_IN,
540 SECTION_COMPUTER,
541 _("Home"), icon,
542 mount_uri, NULL, NULL, NULL, 0,
543 _("Open your personal folder"));
544 g_object_unref (icon);
545 g_free (mount_uri);
546
547 if (g_settings_get_boolean (gnome_background_preferences, NAUTILUS_PREFERENCES_SHOW_DESKTOP)) {
548 /* desktop */
549 mount_uri = nautilus_get_desktop_directory_uri ();
550 icon = g_themed_icon_new (NAUTILUS_ICON_FOLDER);
551 add_place (sidebar, PLACES_BUILT_IN,
552 SECTION_COMPUTER,
553 _("Desktop"), icon,
554 mount_uri, NULL, NULL, NULL, 0,
555 _("Open the contents of your desktop in a folder"));
556 g_object_unref (icon);
557 g_free (mount_uri);
558 }
559
560 /* XDG directories */
561 add_special_dirs (sidebar);
562
563 mount_uri = "trash:///"; /* No need to strdup */
564 icon = nautilus_trash_monitor_get_icon ();
565 add_place (sidebar, PLACES_BUILT_IN,
566 SECTION_COMPUTER,
567 _("Trash"), icon, mount_uri,
568 NULL, NULL, NULL, 0,
569 _("Open the trash"));
570 g_object_unref (icon);
571
572 /* go through all connected drives */
573 drives = g_volume_monitor_get_connected_drives (volume_monitor);
574
575 for (l = drives; l != NULL; l = l->next) {
576 drive = l->data;
577
578 volumes = g_drive_get_volumes (drive);
579 if (volumes != NULL) {
580 for (ll = volumes; ll != NULL; ll = ll->next) {
581 volume = ll->data;
582 identifier = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_CLASS);
583
584 if (g_strcmp0 (identifier, "network") == 0) {
585 g_free (identifier);
586 network_volumes = g_list_prepend (network_volumes, volume);
587 continue;
588 }
589 g_free (identifier);
590
591 mount = g_volume_get_mount (volume);
592 if (mount != NULL) {
593 /* Show mounted volume in the sidebar */
594 icon = g_mount_get_symbolic_icon (mount);
595 root = g_mount_get_default_location (mount);
596 mount_uri = g_file_get_uri (root);
597 name = g_mount_get_name (mount);
598 tooltip = g_file_get_parse_name (root);
599
600 add_place (sidebar, PLACES_MOUNTED_VOLUME,
601 SECTION_DEVICES,
602 name, icon, mount_uri,
603 drive, volume, mount, 0, tooltip);
604 g_object_unref (root);
605 g_object_unref (mount);
606 g_object_unref (icon);
607 g_free (tooltip);
608 g_free (name);
609 g_free (mount_uri);
610 } else {
611 /* Do show the unmounted volumes in the sidebar;
612 * this is so the user can mount it (in case automounting
613 * is off).
614 *
615 * Also, even if automounting is enabled, this gives a visual
616 * cue that the user should remember to yank out the media if
617 * he just unmounted it.
618 */
619 icon = g_volume_get_symbolic_icon (volume);
620 name = g_volume_get_name (volume);
621 tooltip = g_strdup_printf (_("Mount and open %s"), name);
622
623 add_place (sidebar, PLACES_MOUNTED_VOLUME,
624 SECTION_DEVICES,
625 name, icon, NULL,
626 drive, volume, NULL, 0, tooltip);
627 g_object_unref (icon);
628 g_free (name);
629 g_free (tooltip);
630 }
631 g_object_unref (volume);
632 }
633 g_list_free (volumes);
634 } else {
635 if (g_drive_is_media_removable (drive) && !g_drive_is_media_check_automatic (drive)) {
636 /* If the drive has no mountable volumes and we cannot detect media change.. we
637 * display the drive in the sidebar so the user can manually poll the drive by
638 * right clicking and selecting "Rescan..."
639 *
640 * This is mainly for drives like floppies where media detection doesn't
641 * work.. but it's also for human beings who like to turn off media detection
642 * in the OS to save battery juice.
643 */
644 icon = g_drive_get_symbolic_icon (drive);
645 name = g_drive_get_name (drive);
646 tooltip = g_strdup_printf (_("Mount and open %s"), name);
647
648 add_place (sidebar, PLACES_BUILT_IN,
649 SECTION_DEVICES,
650 name, icon, NULL,
651 drive, NULL, NULL, 0, tooltip);
652 g_object_unref (icon);
653 g_free (tooltip);
654 g_free (name);
655 }
656 }
657 g_object_unref (drive);
658 }
659 g_list_free (drives);
660
661 /* add all volumes that is not associated with a drive */
662 volumes = g_volume_monitor_get_volumes (volume_monitor);
663 for (l = volumes; l != NULL; l = l->next) {
664 volume = l->data;
665 drive = g_volume_get_drive (volume);
666 if (drive != NULL) {
667 g_object_unref (volume);
668 g_object_unref (drive);
669 continue;
670 }
671
672 identifier = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_CLASS);
673
674 if (g_strcmp0 (identifier, "network") == 0) {
675 g_free (identifier);
676 network_volumes = g_list_prepend (network_volumes, volume);
677 continue;
678 }
679 g_free (identifier);
680
681 mount = g_volume_get_mount (volume);
682 if (mount != NULL) {
683 icon = g_mount_get_symbolic_icon (mount);
684 root = g_mount_get_default_location (mount);
685 mount_uri = g_file_get_uri (root);
686 tooltip = g_file_get_parse_name (root);
687 g_object_unref (root);
688 name = g_mount_get_name (mount);
689 add_place (sidebar, PLACES_MOUNTED_VOLUME,
690 SECTION_DEVICES,
691 name, icon, mount_uri,
692 NULL, volume, mount, 0, tooltip);
693 g_object_unref (mount);
694 g_object_unref (icon);
695 g_free (name);
696 g_free (tooltip);
697 g_free (mount_uri);
698 } else {
699 /* see comment above in why we add an icon for an unmounted mountable volume */
700 icon = g_volume_get_symbolic_icon (volume);
701 name = g_volume_get_name (volume);
702 add_place (sidebar, PLACES_MOUNTED_VOLUME,
703 SECTION_DEVICES,
704 name, icon, NULL,
705 NULL, volume, NULL, 0, name);
706 g_object_unref (icon);
707 g_free (name);
708 }
709 g_object_unref (volume);
710 }
711 g_list_free (volumes);
712
713 /* file system root */
714
715 mount_uri = "file:///"; /* No need to strdup */
716 icon = g_themed_icon_new (NAUTILUS_ICON_FILESYSTEM);
717 add_place (sidebar, PLACES_BUILT_IN,
718 SECTION_DEVICES,
719 sidebar->hostname, icon,
720 mount_uri, NULL, NULL, NULL, 0,
721 _("Open the contents of the File System"));
722 g_object_unref (icon);
723
724 /* add mounts that has no volume (/etc/mtab mounts, ftp, sftp,...) */
725 mounts = g_volume_monitor_get_mounts (volume_monitor);
726
727 for (l = mounts; l != NULL; l = l->next) {
728 mount = l->data;
729 if (g_mount_is_shadowed (mount)) {
730 g_object_unref (mount);
731 continue;
732 }
733 volume = g_mount_get_volume (mount);
734 if (volume != NULL) {
735 g_object_unref (volume);
736 g_object_unref (mount);
737 continue;
738 }
739 root = g_mount_get_default_location (mount);
740
741 if (!g_file_is_native (root)) {
742 network_mounts = g_list_prepend (network_mounts, mount);
743 g_object_unref (root);
744 continue;
745 }
746
747 icon = g_mount_get_symbolic_icon (mount);
748 mount_uri = g_file_get_uri (root);
749 name = g_mount_get_name (mount);
750 tooltip = g_file_get_parse_name (root);
751 add_place (sidebar, PLACES_MOUNTED_VOLUME,
752 SECTION_COMPUTER,
753 name, icon, mount_uri,
754 NULL, NULL, mount, 0, tooltip);
755 g_object_unref (root);
756 g_object_unref (mount);
757 g_object_unref (icon);
758 g_free (name);
759 g_free (mount_uri);
760 g_free (tooltip);
761 }
762 g_list_free (mounts);
763
764 /* add bookmarks */
765 bookmark_count = nautilus_bookmark_list_length (sidebar->bookmarks);
766
767 for (index = 0; index < bookmark_count; ++index) {
768 bookmark = nautilus_bookmark_list_item_at (sidebar->bookmarks, index);
769
770 if (nautilus_bookmark_uri_known_not_to_exist (bookmark)) {
771 continue;
772 }
773
774 root = nautilus_bookmark_get_location (bookmark);
775 file = nautilus_file_get (root);
776
777 if (is_built_in_bookmark (file)) {
778 g_object_unref (root);
779 nautilus_file_unref (file);
780 continue;
781 }
782 nautilus_file_unref (file);
783
784 bookmark_name = nautilus_bookmark_get_name (bookmark);
785 icon = nautilus_bookmark_get_symbolic_icon (bookmark);
786 mount_uri = nautilus_bookmark_get_uri (bookmark);
787 tooltip = g_file_get_parse_name (root);
788
789 add_place (sidebar, PLACES_BOOKMARK,
790 SECTION_BOOKMARKS,
791 bookmark_name, icon, mount_uri,
792 NULL, NULL, NULL, index,
793 tooltip);
794 g_object_unref (root);
795 g_object_unref (icon);
796 g_free (mount_uri);
797 g_free (tooltip);
798 }
799
800 /* network */
801 add_heading (sidebar, SECTION_NETWORK,
802 _("Network"));
803
804 mount_uri = "network:///"; /* No need to strdup */
805 icon = g_themed_icon_new (NAUTILUS_ICON_NETWORK);
806 add_place (sidebar, PLACES_BUILT_IN,
807 SECTION_NETWORK,
808 _("Browse Network"), icon,
809 mount_uri, NULL, NULL, NULL, 0,
810 _("Browse the contents of the network"));
811 g_object_unref (icon);
812
813 network_volumes = g_list_reverse (network_volumes);
814 for (l = network_volumes; l != NULL; l = l->next) {
815 volume = l->data;
816 mount = g_volume_get_mount (volume);
817
818 if (mount != NULL) {
819 network_mounts = g_list_prepend (network_mounts, mount);
820 continue;
821 } else {
822 icon = g_volume_get_symbolic_icon (volume);
823 name = g_volume_get_name (volume);
824 tooltip = g_strdup_printf (_("Mount and open %s"), name);
825
826 add_place (sidebar, PLACES_MOUNTED_VOLUME,
827 SECTION_NETWORK,
828 name, icon, NULL,
829 NULL, volume, NULL, 0, tooltip);
830 g_object_unref (icon);
831 g_free (name);
832 g_free (tooltip);
833 }
834 }
835
836 g_list_free_full (network_volumes, g_object_unref);
837
838 network_mounts = g_list_reverse (network_mounts);
839 for (l = network_mounts; l != NULL; l = l->next) {
840 mount = l->data;
841 root = g_mount_get_default_location (mount);
842 icon = g_mount_get_symbolic_icon (mount);
843 mount_uri = g_file_get_uri (root);
844 name = g_mount_get_name (mount);
845 tooltip = g_file_get_parse_name (root);
846 add_place (sidebar, PLACES_MOUNTED_VOLUME,
847 SECTION_NETWORK,
848 name, icon, mount_uri,
849 NULL, NULL, mount, 0, tooltip);
850 g_object_unref (root);
851 g_object_unref (icon);
852 g_free (name);
853 g_free (mount_uri);
854 g_free (tooltip);
855 }
856
857 g_list_free_full (network_mounts, g_object_unref);
858
859 /* restore selection */
860 sidebar_update_restore_selection (sidebar, location, last_uri);
861
862 g_free (location);
863 g_free (last_uri);
864 }
865
866 static void
867 mount_added_callback (GVolumeMonitor *volume_monitor,
868 GMount *mount,
869 NautilusPlacesSidebar *sidebar)
870 {
871 update_places (sidebar);
872 }
873
874 static void
875 mount_removed_callback (GVolumeMonitor *volume_monitor,
876 GMount *mount,
877 NautilusPlacesSidebar *sidebar)
878 {
879 update_places (sidebar);
880 }
881
882 static void
883 mount_changed_callback (GVolumeMonitor *volume_monitor,
884 GMount *mount,
885 NautilusPlacesSidebar *sidebar)
886 {
887 update_places (sidebar);
888 }
889
890 static void
891 volume_added_callback (GVolumeMonitor *volume_monitor,
892 GVolume *volume,
893 NautilusPlacesSidebar *sidebar)
894 {
895 update_places (sidebar);
896 }
897
898 static void
899 volume_removed_callback (GVolumeMonitor *volume_monitor,
900 GVolume *volume,
901 NautilusPlacesSidebar *sidebar)
902 {
903 update_places (sidebar);
904 }
905
906 static void
907 volume_changed_callback (GVolumeMonitor *volume_monitor,
908 GVolume *volume,
909 NautilusPlacesSidebar *sidebar)
910 {
911 update_places (sidebar);
912 }
913
914 static void
915 drive_disconnected_callback (GVolumeMonitor *volume_monitor,
916 GDrive *drive,
917 NautilusPlacesSidebar *sidebar)
918 {
919 update_places (sidebar);
920 }
921
922 static void
923 drive_connected_callback (GVolumeMonitor *volume_monitor,
924 GDrive *drive,
925 NautilusPlacesSidebar *sidebar)
926 {
927 update_places (sidebar);
928 }
929
930 static void
931 drive_changed_callback (GVolumeMonitor *volume_monitor,
932 GDrive *drive,
933 NautilusPlacesSidebar *sidebar)
934 {
935 update_places (sidebar);
936 }
937
938 static gboolean
939 over_eject_button (NautilusPlacesSidebar *sidebar,
940 gint x,
941 gint y,
942 GtkTreePath **path)
943 {
944 GtkTreeViewColumn *column;
945 int width, x_offset, hseparator;
946 int eject_button_size;
947 gboolean show_eject;
948 GtkTreeIter iter;
949 GtkTreeModel *model;
950
951 *path = NULL;
952 model = gtk_tree_view_get_model (sidebar->tree_view);
953
954 if (gtk_tree_view_get_path_at_pos (sidebar->tree_view,
955 x, y,
956 path, &column, NULL, NULL)) {
957
958 gtk_tree_model_get_iter (model, &iter, *path);
959 gtk_tree_model_get (model, &iter,
960 PLACES_SIDEBAR_COLUMN_EJECT, &show_eject,
961 -1);
962
963 if (!show_eject) {
964 goto out;
965 }
966
967
968 gtk_widget_style_get (GTK_WIDGET (sidebar->tree_view),
969 "horizontal-separator", &hseparator,
970 NULL);
971
972 /* Reload cell attributes for this particular row */
973 gtk_tree_view_column_cell_set_cell_data (column,
974 model, &iter, FALSE, FALSE);
975
976 gtk_tree_view_column_cell_get_position (column,
977 sidebar->eject_icon_cell_renderer,
978 &x_offset, &width);
979
980 eject_button_size = nautilus_get_icon_size_for_stock_size (GTK_ICON_SIZE_MENU);
981
982 /* This is kinda weird, but we have to do it to workaround gtk+ expanding
983 * the eject cell renderer (even thought we told it not to) and we then
984 * had to set it right-aligned */
985 x_offset += width - hseparator - EJECT_BUTTON_XPAD - eject_button_size;
986
987 if (x - x_offset >= 0 &&
988 x - x_offset <= eject_button_size) {
989 return TRUE;
990 }
991 }
992
993 out:
994 if (*path != NULL) {
995 gtk_tree_path_free (*path);
996 *path = NULL;
997 }
998
999 return FALSE;
1000 }
1001
1002 static gboolean
1003 clicked_eject_button (NautilusPlacesSidebar *sidebar,
1004 GtkTreePath **path)
1005 {
1006 GdkEvent *event = gtk_get_current_event ();
1007 GdkEventButton *button_event = (GdkEventButton *) event;
1008
1009 if ((event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE) &&
1010 over_eject_button (sidebar, button_event->x, button_event->y, path)) {
1011 return TRUE;
1012 }
1013
1014 return FALSE;
1015 }
1016
1017 static void
1018 desktop_setting_changed_callback (gpointer user_data)
1019 {
1020 NautilusPlacesSidebar *sidebar;
1021
1022 sidebar = NAUTILUS_PLACES_SIDEBAR (user_data);
1023
1024 update_places (sidebar);
1025 }
1026
1027 static void
1028 update_current_uri (NautilusPlacesSidebar *sidebar)
1029 {
1030 GtkTreeSelection *selection;
1031 GtkTreeIter iter;
1032 gboolean valid;
1033 char *uri;
1034
1035 if (sidebar->uri == NULL) {
1036 return;
1037 }
1038
1039 /* set selection if any place matches location */
1040 selection = gtk_tree_view_get_selection (sidebar->tree_view);
1041 gtk_tree_selection_unselect_all (selection);
1042 valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (sidebar->store),
1043 &iter);
1044
1045 while (valid) {
1046 gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
1047 PLACES_SIDEBAR_COLUMN_URI, &uri,
1048 -1);
1049
1050 if (uri != NULL) {
1051 if (strcmp (uri, sidebar->uri) == 0) {
1052 g_free (uri);
1053 gtk_tree_selection_select_iter (selection, &iter);
1054 break;
1055 }
1056 g_free (uri);
1057 }
1058 valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (sidebar->store),
1059 &iter);
1060 }
1061 }
1062
1063 static void
1064 loading_uri_callback (NautilusWindow *window,
1065 char *location,
1066 NautilusPlacesSidebar *sidebar)
1067 {
1068 if (g_strcmp0 (sidebar->uri, location) != 0) {
1069 g_free (sidebar->uri);
1070 sidebar->uri = g_strdup (location);
1071
1072 update_current_uri (sidebar);
1073 }
1074 }
1075
1076 /* Computes the appropriate row and position for dropping */
1077 static gboolean
1078 compute_drop_position (GtkTreeView *tree_view,
1079 int x,
1080 int y,
1081 GtkTreePath **path,
1082 GtkTreeViewDropPosition *pos,
1083 NautilusPlacesSidebar *sidebar)
1084 {
1085 GtkTreeModel *model;
1086 GtkTreeIter iter;
1087 PlaceType place_type;
1088 SectionType section_type;
1089
1090 if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
1091 x, y,
1092 path, pos)) {
1093 return FALSE;
1094 }
1095
1096 model = gtk_tree_view_get_model (tree_view);
1097
1098 gtk_tree_model_get_iter (model, &iter, *path);
1099 gtk_tree_model_get (model, &iter,
1100 PLACES_SIDEBAR_COLUMN_ROW_TYPE, &place_type,
1101 PLACES_SIDEBAR_COLUMN_SECTION_TYPE, §ion_type,
1102 -1);
1103
1104 if (section_type != SECTION_BOOKMARKS &&
1105 place_type == PLACES_HEADING) {
1106 /* never drop on headings, but special case the bookmarks heading,
1107 * so we can drop bookmarks in between it and the first item when
1108 * reordering.
1109 */
1110 gtk_tree_path_free (*path);
1111 *path = NULL;
1112
1113 return FALSE;
1114 }
1115
1116 if (section_type != SECTION_BOOKMARKS &&
1117 sidebar->drag_data_received &&
1118 sidebar->drag_data_info == GTK_TREE_MODEL_ROW) {
1119 /* don't allow dropping bookmarks into non-bookmark areas */
1120 gtk_tree_path_free (*path);
1121 *path = NULL;
1122
1123 return FALSE;
1124 }
1125
1126 if (sidebar->drag_data_received &&
1127 sidebar->drag_data_info == GTK_TREE_MODEL_ROW) {
1128 /* bookmark rows can only be reordered */
1129 *pos = GTK_TREE_VIEW_DROP_AFTER;
1130 } else {
1131 *pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
1132 }
1133
1134 return TRUE;
1135 }
1136
1137 static gboolean
1138 get_drag_data (GtkTreeView *tree_view,
1139 GdkDragContext *context,
1140 unsigned int time)
1141 {
1142 GdkAtom target;
1143
1144 target = gtk_drag_dest_find_target (GTK_WIDGET (tree_view),
1145 context,
1146 NULL);
1147
1148 if (target == GDK_NONE) {
1149 return FALSE;
1150 }
1151
1152 gtk_drag_get_data (GTK_WIDGET (tree_view),
1153 context, target, time);
1154
1155 return TRUE;
1156 }
1157
1158 static void
1159 free_drag_data (NautilusPlacesSidebar *sidebar)
1160 {
1161 sidebar->drag_data_received = FALSE;
1162
1163 if (sidebar->drag_list) {
1164 nautilus_drag_destroy_selection_list (sidebar->drag_list);
1165 sidebar->drag_list = NULL;
1166 }
1167 }
1168
1169 static gboolean
1170 drag_motion_callback (GtkTreeView *tree_view,
1171 GdkDragContext *context,
1172 int x,
1173 int y,
1174 unsigned int time,
1175 NautilusPlacesSidebar *sidebar)
1176 {
1177 GtkTreePath *path;
1178 GtkTreeViewDropPosition pos;
1179 int action;
1180 GtkTreeIter iter;
1181 char *uri;
1182 gboolean res;
1183
1184 if (!sidebar->drag_data_received) {
1185 if (!get_drag_data (tree_view, context, time)) {
1186 return FALSE;
1187 }
1188 }
1189
1190 path = NULL;
1191 res = compute_drop_position (tree_view, x, y, &path, &pos, sidebar);
1192
1193 if (!res) {
1194 goto out;
1195 }
1196
1197 if (pos == GTK_TREE_VIEW_DROP_AFTER ) {
1198 if (sidebar->drag_data_received &&
1199 sidebar->drag_data_info == GTK_TREE_MODEL_ROW) {
1200 action = GDK_ACTION_MOVE;
1201 } else {
1202 action = 0;
1203 }
1204 } else {
1205 if (sidebar->drag_list == NULL) {
1206 action = 0;
1207 } else {
1208 gtk_tree_model_get_iter (GTK_TREE_MODEL (sidebar->store),
1209 &iter, path);
1210 gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store),
1211 &iter,
1212 PLACES_SIDEBAR_COLUMN_URI, &uri,
1213 -1);
1214 nautilus_drag_default_drop_action_for_icons (context, uri,
1215 sidebar->drag_list,
1216 &action);
1217 g_free (uri);
1218 }
1219 }
1220
1221 if (action != 0) {
1222 gtk_tree_view_set_drag_dest_row (tree_view, path, pos);
1223 }
1224
1225 if (path != NULL) {
1226 gtk_tree_path_free (path);
1227 }
1228
1229 out:
1230 g_signal_stop_emission_by_name (tree_view, "drag-motion");
1231
1232 if (action != 0) {
(emitted by cppcheck) (emitted by clang-analyzer)TODO: a detailed trace is available in the data model (not yet rendered in this report)
1233 gdk_drag_status (context, action, time);
1234 } else {
1235 gdk_drag_status (context, 0, time);
1236 }
1237
1238 return TRUE;
1239 }
1240
1241 static void
1242 drag_leave_callback (GtkTreeView *tree_view,
1243 GdkDragContext *context,
1244 unsigned int time,
1245 NautilusPlacesSidebar *sidebar)
1246 {
1247 free_drag_data (sidebar);
1248 gtk_tree_view_set_drag_dest_row (tree_view, NULL, 0);
1249 g_signal_stop_emission_by_name (tree_view, "drag-leave");
1250 }
1251
1252 static GList *
1253 uri_list_from_selection (GList *selection)
1254 {
1255 NautilusDragSelectionItem *item;
1256 GList *ret;
1257 GList *l;
1258
1259 ret = NULL;
1260 for (l = selection; l != NULL; l = l->next) {
1261 item = l->data;
1262 ret = g_list_prepend (ret, item->uri);
1263 }
1264
1265 return g_list_reverse (ret);
1266 }
1267
1268 static GList*
1269 build_selection_list (const char *data)
1270 {
1271 NautilusDragSelectionItem *item;
1272 GList *result;
1273 char **uris;
1274 char *uri;
1275 int i;
1276
1277 uris = g_uri_list_extract_uris (data);
1278
1279 result = NULL;
1280 for (i = 0; uris[i]; i++) {
1281 uri = uris[i];
1282 item = nautilus_drag_selection_item_new ();
1283 item->uri = g_strdup (uri);
1284 item->got_icon_position = FALSE;
1285 result = g_list_prepend (result, item);
1286 }
1287
1288 g_strfreev (uris);
1289
1290 return g_list_reverse (result);
1291 }
1292
1293 static gboolean
1294 get_selected_iter (NautilusPlacesSidebar *sidebar,
1295 GtkTreeIter *iter)
1296 {
1297 GtkTreeSelection *selection;
1298
1299 selection = gtk_tree_view_get_selection (sidebar->tree_view);
1300
1301 return gtk_tree_selection_get_selected (selection, NULL, iter);
1302 }
1303
1304 /* Reorders the selected bookmark to the specified position */
1305 static void
1306 reorder_bookmarks (NautilusPlacesSidebar *sidebar,
1307 int new_position)
1308 {
1309 GtkTreeIter iter;
1310 PlaceType type;
1311 int old_position;
1312
1313 /* Get the selected path */
1314 if (!get_selected_iter (sidebar, &iter)) {
1315 return;
1316 }
1317
1318 gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
1319 PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type,
1320 PLACES_SIDEBAR_COLUMN_INDEX, &old_position,
1321 -1);
1322
1323 if (type != PLACES_BOOKMARK ||
1324 old_position < 0 ||
1325 old_position >= nautilus_bookmark_list_length (sidebar->bookmarks)) {
1326 return;
1327 }
1328
1329 nautilus_bookmark_list_move_item (sidebar->bookmarks, old_position,
1330 new_position);
1331 }
1332
1333 static void
1334 drag_data_received_callback (GtkWidget *widget,
1335 GdkDragContext *context,
1336 int x,
1337 int y,
1338 GtkSelectionData *selection_data,
1339 unsigned int info,
1340 unsigned int time,
1341 NautilusPlacesSidebar *sidebar)
1342 {
1343 GtkTreeView *tree_view;
1344 GtkTreePath *tree_path;
1345 GtkTreeViewDropPosition tree_pos;
1346 GtkTreeIter iter;
1347 int position;
1348 GtkTreeModel *model;
1349 char *drop_uri;
1350 GList *selection_list, *uris;
1351 PlaceType place_type;
1352 SectionType section_type;
1353 gboolean success;
1354
1355 tree_view = GTK_TREE_VIEW (widget);
1356
1357 if (!sidebar->drag_data_received) {
1358 if (gtk_selection_data_get_target (selection_data) != GDK_NONE &&
1359 info == TEXT_URI_LIST) {
1360 sidebar->drag_list = build_selection_list ((const gchar *) gtk_selection_data_get_data (selection_data));
1361 } else {
1362 sidebar->drag_list = NULL;
1363 }
1364 sidebar->drag_data_received = TRUE;
1365 sidebar->drag_data_info = info;
1366 }
1367
1368 g_signal_stop_emission_by_name (widget, "drag-data-received");
1369
1370 if (!sidebar->drop_occured) {
1371 return;
1372 }
1373
1374 /* Compute position */
1375 success = compute_drop_position (tree_view, x, y, &tree_path, &tree_pos, sidebar);
1376 if (!success) {
1377 goto out;
1378 }
1379
1380 success = FALSE;
1381
1382 if (tree_pos == GTK_TREE_VIEW_DROP_AFTER) {
1383 model = gtk_tree_view_get_model (tree_view);
1384
1385 if (!gtk_tree_model_get_iter (model, &iter, tree_path)) {
1386 goto out;
1387 }
1388
1389 gtk_tree_model_get (model, &iter,
1390 PLACES_SIDEBAR_COLUMN_SECTION_TYPE, §ion_type,
1391 PLACES_SIDEBAR_COLUMN_ROW_TYPE, &place_type,
1392 PLACES_SIDEBAR_COLUMN_INDEX, &position,
1393 -1);
1394
1395 if (section_type != SECTION_BOOKMARKS) {
1396 goto out;
1397 }
1398
1399 if (tree_pos == GTK_TREE_VIEW_DROP_AFTER && place_type != PLACES_HEADING) {
1400 /* heading already has position 0 */
1401 position++;
1402 }
1403
1404 switch (info) {
1405 case GTK_TREE_MODEL_ROW:
1406 reorder_bookmarks (sidebar, position);
1407 success = TRUE;
1408 break;
1409 default:
1410 g_assert_not_reached ();
1411 break;
1412 }
1413 } else {
1414 GdkDragAction real_action;
1415
1416 /* file transfer requested */
1417 real_action = gdk_drag_context_get_selected_action (context);
1418
1419 if (real_action == GDK_ACTION_ASK) {
1420 real_action =
1421 nautilus_drag_drop_action_ask (GTK_WIDGET (tree_view),
1422 gdk_drag_context_get_actions (context));
1423 }
1424
1425 if (real_action > 0) {
1426 model = gtk_tree_view_get_model (tree_view);
1427
1428 gtk_tree_model_get_iter (model, &iter, tree_path);
1429 gtk_tree_model_get (model, &iter,
1430 PLACES_SIDEBAR_COLUMN_URI, &drop_uri,
1431 -1);
1432
1433 switch (info) {
1434 case TEXT_URI_LIST:
1435 selection_list = build_selection_list ((const gchar *) gtk_selection_data_get_data (selection_data));
1436 uris = uri_list_from_selection (selection_list);
1437 nautilus_file_operations_copy_move (uris, NULL, drop_uri,
1438 real_action, GTK_WIDGET (tree_view),
1439 NULL, NULL);
1440 nautilus_drag_destroy_selection_list (selection_list);
1441 g_list_free (uris);
1442 success = TRUE;
1443 break;
1444 case GTK_TREE_MODEL_ROW:
1445 success = FALSE;
1446 break;
1447 default:
1448 g_assert_not_reached ();
1449 break;
1450 }
1451
1452 g_free (drop_uri);
1453 }
1454 }
1455
1456 out:
1457 sidebar->drop_occured = FALSE;
1458 free_drag_data (sidebar);
1459 gtk_drag_finish (context, success, FALSE, time);
1460
1461 gtk_tree_path_free (tree_path);
1462 }
1463
1464 static gboolean
1465 drag_drop_callback (GtkTreeView *tree_view,
1466 GdkDragContext *context,
1467 int x,
1468 int y,
1469 unsigned int time,
1470 NautilusPlacesSidebar *sidebar)
1471 {
1472 gboolean retval = FALSE;
1473 sidebar->drop_occured = TRUE;
1474 retval = get_drag_data (tree_view, context, time);
1475 g_signal_stop_emission_by_name (tree_view, "drag-drop");
1476 return retval;
1477 }
1478
1479 /* Callback used when the file list's popup menu is detached */
1480 static void
1481 bookmarks_popup_menu_detach_cb (GtkWidget *attach_widget,
1482 GtkMenu *menu)
1483 {
1484 NautilusPlacesSidebar *sidebar;
1485
1486 sidebar = NAUTILUS_PLACES_SIDEBAR (attach_widget);
1487 g_assert (NAUTILUS_IS_PLACES_SIDEBAR (sidebar));
1488
1489 sidebar->popup_menu = NULL;
1490 sidebar->popup_menu_add_shortcut_item = NULL;
1491 sidebar->popup_menu_remove_item = NULL;
1492 sidebar->popup_menu_rename_item = NULL;
1493 sidebar->popup_menu_separator_item = NULL;
1494 sidebar->popup_menu_mount_item = NULL;
1495 sidebar->popup_menu_unmount_item = NULL;
1496 sidebar->popup_menu_eject_item = NULL;
1497 sidebar->popup_menu_rescan_item = NULL;
1498 sidebar->popup_menu_start_item = NULL;
1499 sidebar->popup_menu_stop_item = NULL;
1500 sidebar->popup_menu_empty_trash_item = NULL;
1501 sidebar->popup_menu_properties_separator_item = NULL;
1502 sidebar->popup_menu_properties_item = NULL;
1503 }
1504
1505 static void
1506 check_unmount_and_eject (GMount *mount,
1507 GVolume *volume,
1508 GDrive *drive,
1509 gboolean *show_unmount,
1510 gboolean *show_eject)
1511 {
1512 *show_unmount = FALSE;
1513 *show_eject = FALSE;
1514
1515 if (drive != NULL) {
1516 *show_eject = g_drive_can_eject (drive);
1517 }
1518
1519 if (volume != NULL) {
1520 *show_eject |= g_volume_can_eject (volume);
1521 }
1522 if (mount != NULL) {
1523 *show_eject |= g_mount_can_eject (mount);
1524 *show_unmount = g_mount_can_unmount (mount) && !*show_eject;
1525 }
1526 }
1527
1528 static void
1529 check_visibility (GMount *mount,
1530 GVolume *volume,
1531 GDrive *drive,
1532 gboolean *show_mount,
1533 gboolean *show_unmount,
1534 gboolean *show_eject,
1535 gboolean *show_rescan,
1536 gboolean *show_start,
1537 gboolean *show_stop)
1538 {
1539 *show_mount = FALSE;
1540 *show_rescan = FALSE;
1541 *show_start = FALSE;
1542 *show_stop = FALSE;
1543
1544 check_unmount_and_eject (mount, volume, drive, show_unmount, show_eject);
1545
1546 if (drive != NULL) {
1547 if (g_drive_is_media_removable (drive) &&
1548 !g_drive_is_media_check_automatic (drive) &&
1549 g_drive_can_poll_for_media (drive))
1550 *show_rescan = TRUE;
1551
1552 *show_start = g_drive_can_start (drive) || g_drive_can_start_degraded (drive);
1553 *show_stop = g_drive_can_stop (drive);
1554
1555 if (*show_stop)
1556 *show_unmount = FALSE;
1557 }
1558
1559 if (volume != NULL) {
1560 if (mount == NULL)
1561 *show_mount = g_volume_can_mount (volume);
1562 }
1563 }
1564
1565 static void
1566 bookmarks_check_popup_sensitivity (NautilusPlacesSidebar *sidebar)
1567 {
1568 GtkTreeIter iter;
1569 PlaceType type;
1570 GDrive *drive = NULL;
1571 GVolume *volume = NULL;
1572 GMount *mount = NULL;
1573 GFile *location;
1574 NautilusDirectory *directory;
1575 gboolean show_mount;
1576 gboolean show_unmount;
1577 gboolean show_eject;
1578 gboolean show_rescan;
1579 gboolean show_start;
1580 gboolean show_stop;
1581 gboolean show_empty_trash;
1582 gboolean show_properties;
1583 char *uri = NULL;
1584
1585 type = PLACES_BUILT_IN;
1586
1587 if (sidebar->popup_menu == NULL) {
1588 return;
1589 }
1590
1591 if (get_selected_iter (sidebar, &iter)) {
1592 gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
1593 PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type,
1594 PLACES_SIDEBAR_COLUMN_DRIVE, &drive,
1595 PLACES_SIDEBAR_COLUMN_VOLUME, &volume,
1596 PLACES_SIDEBAR_COLUMN_MOUNT, &mount,
1597 PLACES_SIDEBAR_COLUMN_URI, &uri,
1598 -1);
1599 }
1600
1601 gtk_widget_set_visible (sidebar->popup_menu_add_shortcut_item, (type == PLACES_MOUNTED_VOLUME));
1602
1603 gtk_widget_set_sensitive (sidebar->popup_menu_remove_item, (type == PLACES_BOOKMARK));
1604 gtk_widget_set_sensitive (sidebar->popup_menu_rename_item, (type == PLACES_BOOKMARK));
1605 gtk_widget_set_sensitive (sidebar->popup_menu_empty_trash_item, !nautilus_trash_monitor_is_empty ());
1606
1607 check_visibility (mount, volume, drive,
1608 &show_mount, &show_unmount, &show_eject, &show_rescan, &show_start, &show_stop);
1609
1610 /* We actually want both eject and unmount since eject will unmount all volumes.
1611 * TODO: hide unmount if the drive only has a single mountable volume
1612 */
1613
1614 show_empty_trash = (uri != NULL) &&
1615 (!strcmp (uri, "trash:///"));
1616
1617 /* Only show properties for local mounts */
1618 show_properties = (mount != NULL);
1619 if (mount != NULL) {
1620 location = g_mount_get_default_location (mount);
1621 directory = nautilus_directory_get (location);
1622
1623 show_properties = nautilus_directory_is_local (directory);
1624
1625 nautilus_directory_unref (directory);
1626 g_object_unref (location);
1627 }
1628
1629 gtk_widget_set_visible (sidebar->popup_menu_separator_item,
1630 show_mount || show_unmount || show_eject || show_empty_trash);
1631 gtk_widget_set_visible (sidebar->popup_menu_mount_item, show_mount);
1632 gtk_widget_set_visible (sidebar->popup_menu_unmount_item, show_unmount);
1633 gtk_widget_set_visible (sidebar->popup_menu_eject_item, show_eject);
1634 gtk_widget_set_visible (sidebar->popup_menu_rescan_item, show_rescan);
1635 gtk_widget_set_visible (sidebar->popup_menu_start_item, show_start);
1636 gtk_widget_set_visible (sidebar->popup_menu_stop_item, show_stop);
1637 gtk_widget_set_visible (sidebar->popup_menu_empty_trash_item, show_empty_trash);
1638 gtk_widget_set_visible (sidebar->popup_menu_properties_separator_item, show_properties);
1639 gtk_widget_set_visible (sidebar->popup_menu_properties_item, show_properties);
1640
1641 /* Adjust start/stop items to reflect the type of the drive */
1642 gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_start_item), _("_Start"));
1643 gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_stop_item), _("_Stop"));
1644 if ((show_start || show_stop) && drive != NULL) {
1645 switch (g_drive_get_start_stop_type (drive)) {
1646 case G_DRIVE_START_STOP_TYPE_SHUTDOWN:
1647 /* start() for type G_DRIVE_START_STOP_TYPE_SHUTDOWN is normally not used */
1648 gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_start_item), _("_Power On"));
1649 gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_stop_item), _("_Safely Remove Drive"));
1650 break;
1651 case G_DRIVE_START_STOP_TYPE_NETWORK:
1652 gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_start_item), _("_Connect Drive"));
1653 gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_stop_item), _("_Disconnect Drive"));
1654 break;
1655 case G_DRIVE_START_STOP_TYPE_MULTIDISK:
1656 gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_start_item), _("_Start Multi-disk Device"));
1657 gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_stop_item), _("_Stop Multi-disk Device"));
1658 break;
1659 case G_DRIVE_START_STOP_TYPE_PASSWORD:
1660 /* stop() for type G_DRIVE_START_STOP_TYPE_PASSWORD is normally not used */
1661 gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_start_item), _("_Unlock Drive"));
1662 gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_stop_item), _("_Lock Drive"));
1663 break;
1664
1665 default:
1666 case G_DRIVE_START_STOP_TYPE_UNKNOWN:
1667 /* uses defaults set above */
1668 break;
1669 }
1670 }
1671
1672
1673 g_free (uri);
1674 }
1675
1676 /* Callback used when the selection in the shortcuts tree changes */
1677 static void
1678 bookmarks_selection_changed_cb (GtkTreeSelection *selection,
1679 NautilusPlacesSidebar *sidebar)
1680 {
1681 bookmarks_check_popup_sensitivity (sidebar);
1682 }
1683
1684 static void
1685 volume_mounted_cb (GVolume *volume,
1686 gboolean success,
1687 GObject *user_data)
1688 {
1689 GMount *mount;
1690 NautilusPlacesSidebar *sidebar;
1691 GFile *location;
1692
1693 sidebar = NAUTILUS_PLACES_SIDEBAR (user_data);
1694
1695 sidebar->mounting = FALSE;
1696
1697 mount = g_volume_get_mount (volume);
1698 if (mount != NULL) {
1699 location = g_mount_get_default_location (mount);
1700
1701 if (sidebar->go_to_after_mount_slot != NULL) {
1702 if ((sidebar->go_to_after_mount_flags & NAUTILUS_WINDOW_OPEN_FLAG_NEW_WINDOW) == 0) {
1703 nautilus_window_slot_open_location (sidebar->go_to_after_mount_slot, location,
1704 sidebar->go_to_after_mount_flags);
1705 } else {
1706 NautilusWindow *new, *cur;
1707
1708 cur = NAUTILUS_WINDOW (sidebar->window);
1709 new = nautilus_application_create_window (NAUTILUS_APPLICATION (g_application_get_default ()),
1710 gtk_window_get_screen (GTK_WINDOW (cur)));
1711 nautilus_window_go_to (new, location);
1712 }
1713 }
1714
1715 g_object_unref (G_OBJECT (location));
1716 g_object_unref (G_OBJECT (mount));
1717 }
1718
1719 if (sidebar->go_to_after_mount_slot) {
1720 g_object_remove_weak_pointer (G_OBJECT (sidebar->go_to_after_mount_slot),
1721 (gpointer *) &sidebar->go_to_after_mount_slot);
1722 sidebar->go_to_after_mount_slot = NULL;
1723 }
1724 }
1725
1726 static void
1727 drive_start_from_bookmark_cb (GObject *source_object,
1728 GAsyncResult *res,
1729 gpointer user_data)
1730 {
1731 GError *error;
1732 char *primary;
1733 char *name;
1734
1735 error = NULL;
1736 if (!g_drive_poll_for_media_finish (G_DRIVE (source_object), res, &error)) {
1737 if (error->code != G_IO_ERROR_FAILED_HANDLED) {
1738 name = g_drive_get_name (G_DRIVE (source_object));
1739 primary = g_strdup_printf (_("Unable to start %s"), name);
1740 g_free (name);
1741 eel_show_error_dialog (primary,
1742 error->message,
1743 NULL);
1744 g_free (primary);
1745 }
1746 g_error_free (error);
1747 }
1748 }
1749
1750 static void
1751 open_selected_bookmark (NautilusPlacesSidebar *sidebar,
1752 GtkTreeModel *model,
1753 GtkTreeIter *iter,
1754 NautilusWindowOpenFlags flags)
1755 {
1756 NautilusWindowSlot *slot;
1757 GFile *location;
1758 char *uri;
1759
1760 if (!iter) {
1761 return;
1762 }
1763
1764 gtk_tree_model_get (model, iter, PLACES_SIDEBAR_COLUMN_URI, &uri, -1);
1765
1766 if (uri != NULL) {
1767 DEBUG ("Activating bookmark %s", uri);
1768
1769 location = g_file_new_for_uri (uri);
1770 /* Navigate to the clicked location */
1771 if ((flags & NAUTILUS_WINDOW_OPEN_FLAG_NEW_WINDOW) == 0) {
1772 slot = nautilus_window_get_active_slot (sidebar->window);
1773 nautilus_window_slot_open_location (slot, location, flags);
1774 } else {
1775 NautilusWindow *cur, *new;
1776
1777 cur = NAUTILUS_WINDOW (sidebar->window);
1778 new = nautilus_application_create_window (NAUTILUS_APPLICATION (g_application_get_default ()),
1779 gtk_window_get_screen (GTK_WINDOW (cur)));
1780 nautilus_window_go_to (new, location);
1781 }
1782 g_object_unref (location);
1783 g_free (uri);
1784
1785 } else {
1786 GDrive *drive;
1787 GVolume *volume;
1788 NautilusWindowSlot *slot;
1789
1790 gtk_tree_model_get (model, iter,
1791 PLACES_SIDEBAR_COLUMN_DRIVE, &drive,
1792 PLACES_SIDEBAR_COLUMN_VOLUME, &volume,
1793 -1);
1794
1795 if (volume != NULL && !sidebar->mounting) {
1796 sidebar->mounting = TRUE;
1797
1798 g_assert (sidebar->go_to_after_mount_slot == NULL);
1799
1800 slot = nautilus_window_get_active_slot (sidebar->window);
1801 sidebar->go_to_after_mount_slot = slot;
1802 g_object_add_weak_pointer (G_OBJECT (sidebar->go_to_after_mount_slot),
1803 (gpointer *) &sidebar->go_to_after_mount_slot);
1804
1805 sidebar->go_to_after_mount_flags = flags;
1806
1807 nautilus_file_operations_mount_volume_full (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (sidebar))),
1808 volume,
1809 volume_mounted_cb,
1810 G_OBJECT (sidebar));
1811 } else if (volume == NULL && drive != NULL &&
1812 (g_drive_can_start (drive) || g_drive_can_start_degraded (drive))) {
1813 GMountOperation *mount_op;
1814
1815 mount_op = gtk_mount_operation_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (sidebar))));
1816 g_drive_start (drive, G_DRIVE_START_NONE, mount_op, NULL, drive_start_from_bookmark_cb, NULL);
1817 g_object_unref (mount_op);
1818 }
1819
1820 if (drive != NULL)
1821 g_object_unref (drive);
1822 if (volume != NULL)
1823 g_object_unref (volume);
1824 }
1825 }
1826
1827 static void
1828 open_shortcut_from_menu (NautilusPlacesSidebar *sidebar,
1829 NautilusWindowOpenFlags flags)
1830 {
1831 GtkTreeModel *model;
1832 GtkTreeIter iter;
1833 GtkTreePath *path = NULL;
1834
1835 model = gtk_tree_view_get_model (sidebar->tree_view);
1836 gtk_tree_view_get_cursor (sidebar->tree_view, &path, NULL);
1837
1838 if (path != NULL && gtk_tree_model_get_iter (model, &iter, path)) {
1839 open_selected_bookmark (sidebar, model, &iter, flags);
1840 }
1841
1842 gtk_tree_path_free (path);
1843 }
1844
1845 static void
1846 open_shortcut_cb (GtkMenuItem *item,
1847 NautilusPlacesSidebar *sidebar)
1848 {
1849 open_shortcut_from_menu (sidebar, 0);
1850 }
1851
1852 static void
1853 open_shortcut_in_new_window_cb (GtkMenuItem *item,
1854 NautilusPlacesSidebar *sidebar)
1855 {
1856 open_shortcut_from_menu (sidebar, NAUTILUS_WINDOW_OPEN_FLAG_NEW_WINDOW);
1857 }
1858
1859 static void
1860 open_shortcut_in_new_tab_cb (GtkMenuItem *item,
1861 NautilusPlacesSidebar *sidebar)
1862 {
1863 open_shortcut_from_menu (sidebar, NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB);
1864 }
1865
1866 /* Add bookmark for the selected item */
1867 static void
1868 add_bookmark (NautilusPlacesSidebar *sidebar)
1869 {
1870 GtkTreeModel *model;
1871 GtkTreeIter iter;
1872 char *uri;
1873 char *name;
1874 GFile *location;
1875 NautilusBookmark *bookmark;
1876
1877 model = gtk_tree_view_get_model (sidebar->tree_view);
1878
1879 if (get_selected_iter (sidebar, &iter)) {
1880 gtk_tree_model_get (model, &iter,
1881 PLACES_SIDEBAR_COLUMN_URI, &uri,
1882 PLACES_SIDEBAR_COLUMN_NAME, &name,
1883 -1);
1884
1885 if (uri == NULL) {
1886 return;
1887 }
1888
1889 location = g_file_new_for_uri (uri);
1890 bookmark = nautilus_bookmark_new (location, name);
1891
1892 if (!nautilus_bookmark_list_contains (sidebar->bookmarks, bookmark)) {
1893 nautilus_bookmark_list_append (sidebar->bookmarks, bookmark);
1894 }
1895
1896 g_object_unref (location);
1897 g_object_unref (bookmark);
1898 g_free (uri);
1899 g_free (name);
1900 }
1901 }
1902
1903 static void
1904 add_shortcut_cb (GtkMenuItem *item,
1905 NautilusPlacesSidebar *sidebar)
1906 {
1907 add_bookmark (sidebar);
1908 }
1909
1910 /* Rename the selected bookmark */
1911 static void
1912 rename_selected_bookmark (NautilusPlacesSidebar *sidebar)
1913 {
1914 GtkTreeIter iter;
1915 GtkTreePath *path;
1916 GtkTreeViewColumn *column;
1917 GtkCellRenderer *cell;
1918 GList *renderers;
1919 PlaceType type;
1920
1921 if (get_selected_iter (sidebar, &iter)) {
1922 gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
1923 PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type,
1924 -1);
1925
1926 if (type != PLACES_BOOKMARK) {
1927 return;
1928 }
1929
1930 path = gtk_tree_model_get_path (GTK_TREE_MODEL (sidebar->store), &iter);
1931 column = gtk_tree_view_get_column (GTK_TREE_VIEW (sidebar->tree_view), 0);
1932 renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (column));
1933 cell = g_list_nth_data (renderers, 6);
1934 g_list_free (renderers);
1935 g_object_set (cell, "editable", TRUE, NULL);
1936 gtk_tree_view_set_cursor_on_cell (GTK_TREE_VIEW (sidebar->tree_view),
1937 path, column, cell, TRUE);
1938 gtk_tree_path_free (path);
1939 }
1940 }
1941
1942 static void
1943 rename_shortcut_cb (GtkMenuItem *item,
1944 NautilusPlacesSidebar *sidebar)
1945 {
1946 rename_selected_bookmark (sidebar);
1947 }
1948
1949 /* Removes the selected bookmarks */
1950 static void
1951 remove_selected_bookmarks (NautilusPlacesSidebar *sidebar)
1952 {
1953 GtkTreeIter iter;
1954 PlaceType type;
1955 int index;
1956
1957 if (!get_selected_iter (sidebar, &iter)) {
1958 return;
1959 }
1960
1961 gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
1962 PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type,
1963 -1);
1964
1965 if (type != PLACES_BOOKMARK) {
1966 return;
1967 }
1968
1969 gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
1970 PLACES_SIDEBAR_COLUMN_INDEX, &index,
1971 -1);
1972
1973 nautilus_bookmark_list_delete_item_at (sidebar->bookmarks, index);
1974 }
1975
1976 static void
1977 remove_shortcut_cb (GtkMenuItem *item,
1978 NautilusPlacesSidebar *sidebar)
1979 {
1980 remove_selected_bookmarks (sidebar);
1981 }
1982
1983 static void
1984 mount_shortcut_cb (GtkMenuItem *item,
1985 NautilusPlacesSidebar *sidebar)
1986 {
1987 GtkTreeIter iter;
1988 GVolume *volume;
1989
1990 if (!get_selected_iter (sidebar, &iter)) {
1991 return;
1992 }
1993
1994 gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
1995 PLACES_SIDEBAR_COLUMN_VOLUME, &volume,
1996 -1);
1997
1998 if (volume != NULL) {
1999 nautilus_file_operations_mount_volume (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (sidebar))), volume);
2000 g_object_unref (volume);
2001 }
2002 }
2003
2004 static void
2005 unmount_done (gpointer data)
2006 {
2007 NautilusWindow *window;
2008
2009 window = data;
2010 g_object_unref (window);
2011 }
2012
2013 static void
2014 show_unmount_progress_cb (GMountOperation *op,
2015 const gchar *message,
2016 gint64 time_left,
2017 gint64 bytes_left,
2018 gpointer user_data)
2019 {
2020 NautilusApplication *app = NAUTILUS_APPLICATION (g_application_get_default ());
2021
2022 if (bytes_left == 0) {
2023 nautilus_application_notify_unmount_done (app, message);
2024 } else {
2025 nautilus_application_notify_unmount_show (app, message);
2026 }
2027 }
2028
2029 static void
2030 show_unmount_progress_aborted_cb (GMountOperation *op,
2031 gpointer user_data)
2032 {
2033 NautilusApplication *app = NAUTILUS_APPLICATION (g_application_get_default ());
2034 nautilus_application_notify_unmount_done (app, NULL);
2035 }
2036
2037 static GMountOperation *
2038 get_unmount_operation (NautilusPlacesSidebar *sidebar)
2039 {
2040 GMountOperation *mount_op;
2041
2042 mount_op = gtk_mount_operation_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (sidebar))));
2043 g_signal_connect (mount_op, "show-unmount-progress",
2044 G_CALLBACK (show_unmount_progress_cb), sidebar);
2045 g_signal_connect (mount_op, "aborted",
2046 G_CALLBACK (show_unmount_progress_aborted_cb), sidebar);
2047
2048 return mount_op;
2049 }
2050
2051 static void
2052 do_unmount (GMount *mount,
2053 NautilusPlacesSidebar *sidebar)
2054 {
2055 GMountOperation *mount_op;
2056
2057 if (mount != NULL) {
2058 mount_op = get_unmount_operation (sidebar);
2059 nautilus_file_operations_unmount_mount_full (NULL, mount, mount_op, FALSE, TRUE,
2060 unmount_done,
2061 g_object_ref (sidebar->window));
2062 g_object_unref (mount_op);
2063 }
2064 }
2065
2066 static void
2067 do_unmount_selection (NautilusPlacesSidebar *sidebar)
2068 {
2069 GtkTreeIter iter;
2070 GMount *mount;
2071
2072 if (!get_selected_iter (sidebar, &iter)) {
2073 return;
2074 }
2075
2076 gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
2077 PLACES_SIDEBAR_COLUMN_MOUNT, &mount,
2078 -1);
2079
2080 if (mount != NULL) {
2081 do_unmount (mount, sidebar);
2082 g_object_unref (mount);
2083 }
2084 }
2085
2086 static void
2087 unmount_shortcut_cb (GtkMenuItem *item,
2088 NautilusPlacesSidebar *sidebar)
2089 {
2090 do_unmount_selection (sidebar);
2091 }
2092
2093 static void
2094 drive_eject_cb (GObject *source_object,
2095 GAsyncResult *res,
2096 gpointer user_data)
2097 {
2098 NautilusWindow *window;
2099 GError *error;
2100 char *primary;
2101 char *name;
2102
2103 window = user_data;
2104 g_object_unref (window);
2105
2106 error = NULL;
2107 if (!g_drive_eject_with_operation_finish (G_DRIVE (source_object), res, &error)) {
2108 if (error->code != G_IO_ERROR_FAILED_HANDLED) {
2109 name = g_drive_get_name (G_DRIVE (source_object));
2110 primary = g_strdup_printf (_("Unable to eject %s"), name);
2111 g_free (name);
2112 eel_show_error_dialog (primary,
2113 error->message,
2114 NULL);
2115 g_free (primary);
2116 }
2117 g_error_free (error);
2118 }
2119 }
2120
2121 static void
2122 volume_eject_cb (GObject *source_object,
2123 GAsyncResult *res,
2124 gpointer user_data)
2125 {
2126 NautilusWindow *window;
2127 GError *error;
2128 char *primary;
2129 char *name;
2130
2131 window = user_data;
2132 g_object_unref (window);
2133
2134 error = NULL;
2135 if (!g_volume_eject_with_operation_finish (G_VOLUME (source_object), res, &error)) {
2136 if (error->code != G_IO_ERROR_FAILED_HANDLED) {
2137 name = g_volume_get_name (G_VOLUME (source_object));
2138 primary = g_strdup_printf (_("Unable to eject %s"), name);
2139 g_free (name);
2140 eel_show_error_dialog (primary,
2141 error->message,
2142 NULL);
2143 g_free (primary);
2144 }
2145 g_error_free (error);
2146 }
2147 }
2148
2149 static void
2150 mount_eject_cb (GObject *source_object,
2151 GAsyncResult *res,
2152 gpointer user_data)
2153 {
2154 NautilusWindow *window;
2155 GError *error;
2156 char *primary;
2157 char *name;
2158
2159 window = user_data;
2160 g_object_unref (window);
2161
2162 error = NULL;
2163 if (!g_mount_eject_with_operation_finish (G_MOUNT (source_object), res, &error)) {
2164 if (error->code != G_IO_ERROR_FAILED_HANDLED) {
2165 name = g_mount_get_name (G_MOUNT (source_object));
2166 primary = g_strdup_printf (_("Unable to eject %s"), name);
2167 g_free (name);
2168 eel_show_error_dialog (primary,
2169 error->message,
2170 NULL);
2171 g_free (primary);
2172 }
2173 g_error_free (error);
2174 }
2175 }
2176
2177 static void
2178 do_eject (GMount *mount,
2179 GVolume *volume,
2180 GDrive *drive,
2181 NautilusPlacesSidebar *sidebar)
2182 {
2183 GMountOperation *mount_op = get_unmount_operation (sidebar);
2184
2185 if (mount != NULL) {
2186 g_mount_eject_with_operation (mount, 0, mount_op, NULL, mount_eject_cb,
2187 g_object_ref (sidebar->window));
2188 } else if (volume != NULL) {
2189 g_volume_eject_with_operation (volume, 0, mount_op, NULL, volume_eject_cb,
2190 g_object_ref (sidebar->window));
2191 } else if (drive != NULL) {
2192 g_drive_eject_with_operation (drive, 0, mount_op, NULL, drive_eject_cb,
2193 g_object_ref (sidebar->window));
2194 }
2195
2196 g_object_unref (mount_op);
2197 }
2198
2199 static void
2200 eject_shortcut_cb (GtkMenuItem *item,
2201 NautilusPlacesSidebar *sidebar)
2202 {
2203 GtkTreeIter iter;
2204 GMount *mount;
2205 GVolume *volume;
2206 GDrive *drive;
2207
2208 if (!get_selected_iter (sidebar, &iter)) {
2209 return;
2210 }
2211
2212 gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
2213 PLACES_SIDEBAR_COLUMN_MOUNT, &mount,
2214 PLACES_SIDEBAR_COLUMN_VOLUME, &volume,
2215 PLACES_SIDEBAR_COLUMN_DRIVE, &drive,
2216 -1);
2217
2218 do_eject (mount, volume, drive, sidebar);
2219 }
2220
2221 static gboolean
2222 eject_or_unmount_bookmark (NautilusPlacesSidebar *sidebar,
2223 GtkTreePath *path)
2224 {
2225 GtkTreeModel *model;
2226 GtkTreeIter iter;
2227 gboolean can_unmount, can_eject;
2228 GMount *mount;
2229 GVolume *volume;
2230 GDrive *drive;
2231 gboolean ret;
2232
2233 model = GTK_TREE_MODEL (sidebar->store);
2234
2235 if (!path) {
2236 return FALSE;
2237 }
2238 if (!gtk_tree_model_get_iter (model, &iter, path)) {
2239 return FALSE;
2240 }
2241
2242 gtk_tree_model_get (model, &iter,
2243 PLACES_SIDEBAR_COLUMN_MOUNT, &mount,
2244 PLACES_SIDEBAR_COLUMN_VOLUME, &volume,
2245 PLACES_SIDEBAR_COLUMN_DRIVE, &drive,
2246 -1);
2247
2248 ret = FALSE;
2249
2250 check_unmount_and_eject (mount, volume, drive, &can_unmount, &can_eject);
2251 /* if we can eject, it has priority over unmount */
2252 if (can_eject) {
2253 do_eject (mount, volume, drive, sidebar);
2254 ret = TRUE;
2255 } else if (can_unmount) {
2256 do_unmount (mount, sidebar);
2257 ret = TRUE;
2258 }
2259
2260 if (mount != NULL)
2261 g_object_unref (mount);
2262 if (volume != NULL)
2263 g_object_unref (volume);
2264 if (drive != NULL)
2265 g_object_unref (drive);
2266
2267 return ret;
2268 }
2269
2270 static gboolean
2271 eject_or_unmount_selection (NautilusPlacesSidebar *sidebar)
2272 {
2273 GtkTreeIter iter;
2274 GtkTreePath *path;
2275 gboolean ret;
2276
2277 if (!get_selected_iter (sidebar, &iter)) {
2278 return FALSE;
2279 }
2280
2281 path = gtk_tree_model_get_path (GTK_TREE_MODEL (sidebar->store), &iter);
2282 if (path == NULL) {
2283 return FALSE;
2284 }
2285
2286 ret = eject_or_unmount_bookmark (sidebar, path);
2287
2288 gtk_tree_path_free (path);
2289
2290 return ret;
2291 }
2292
2293 static void
2294 drive_poll_for_media_cb (GObject *source_object,
2295 GAsyncResult *res,
2296 gpointer user_data)
2297 {
2298 GError *error;
2299 char *primary;
2300 char *name;
2301
2302 error = NULL;
2303 if (!g_drive_poll_for_media_finish (G_DRIVE (source_object), res, &error)) {
2304 if (error->code != G_IO_ERROR_FAILED_HANDLED) {
2305 name = g_drive_get_name (G_DRIVE (source_object));
2306 primary = g_strdup_printf (_("Unable to poll %s for media changes"), name);
2307 g_free (name);
2308 eel_show_error_dialog (primary,
2309 error->message,
2310 NULL);
2311 g_free (primary);
2312 }
2313 g_error_free (error);
2314 }
2315 }
2316
2317 static void
2318 rescan_shortcut_cb (GtkMenuItem *item,
2319 NautilusPlacesSidebar *sidebar)
2320 {
2321 GtkTreeIter iter;
2322 GDrive *drive;
2323
2324 if (!get_selected_iter (sidebar, &iter)) {
2325 return;
2326 }
2327
2328 gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
2329 PLACES_SIDEBAR_COLUMN_DRIVE, &drive,
2330 -1);
2331
2332 if (drive != NULL) {
2333 g_drive_poll_for_media (drive, NULL, drive_poll_for_media_cb, NULL);
2334 }
2335 g_object_unref (drive);
2336 }
2337
2338 static void
2339 drive_start_cb (GObject *source_object,
2340 GAsyncResult *res,
2341 gpointer user_data)
2342 {
2343 GError *error;
2344 char *primary;
2345 char *name;
2346
2347 error = NULL;
2348 if (!g_drive_poll_for_media_finish (G_DRIVE (source_object), res, &error)) {
2349 if (error->code != G_IO_ERROR_FAILED_HANDLED) {
2350 name = g_drive_get_name (G_DRIVE (source_object));
2351 primary = g_strdup_printf (_("Unable to start %s"), name);
2352 g_free (name);
2353 eel_show_error_dialog (primary,
2354 error->message,
2355 NULL);
2356 g_free (primary);
2357 }
2358 g_error_free (error);
2359 }
2360 }
2361
2362 static void
2363 start_shortcut_cb (GtkMenuItem *item,
2364 NautilusPlacesSidebar *sidebar)
2365 {
2366 GtkTreeIter iter;
2367 GDrive *drive;
2368
2369 if (!get_selected_iter (sidebar, &iter)) {
2370 return;
2371 }
2372
2373 gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
2374 PLACES_SIDEBAR_COLUMN_DRIVE, &drive,
2375 -1);
2376
2377 if (drive != NULL) {
2378 GMountOperation *mount_op;
2379
2380 mount_op = gtk_mount_operation_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (sidebar))));
2381
2382 g_drive_start (drive, G_DRIVE_START_NONE, mount_op, NULL, drive_start_cb, NULL);
2383
2384 g_object_unref (mount_op);
2385 }
2386 g_object_unref (drive);
2387 }
2388
2389 static void
2390 drive_stop_cb (GObject *source_object,
2391 GAsyncResult *res,
2392 gpointer user_data)
2393 {
2394 NautilusWindow *window;
2395 GError *error;
2396 char *primary;
2397 char *name;
2398
2399 window = user_data;
2400 g_object_unref (window);
2401
2402 error = NULL;
2403 if (!g_drive_poll_for_media_finish (G_DRIVE (source_object), res, &error)) {
2404 if (error->code != G_IO_ERROR_FAILED_HANDLED) {
2405 name = g_drive_get_name (G_DRIVE (source_object));
2406 primary = g_strdup_printf (_("Unable to stop %s"), name);
2407 g_free (name);
2408 eel_show_error_dialog (primary,
2409 error->message,
2410 NULL);
2411 g_free (primary);
2412 }
2413 g_error_free (error);
2414 }
2415 }
2416
2417 static void
2418 stop_shortcut_cb (GtkMenuItem *item,
2419 NautilusPlacesSidebar *sidebar)
2420 {
2421 GtkTreeIter iter;
2422 GDrive *drive;
2423
2424 if (!get_selected_iter (sidebar, &iter)) {
2425 return;
2426 }
2427
2428 gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
2429 PLACES_SIDEBAR_COLUMN_DRIVE, &drive,
2430 -1);
2431
2432 if (drive != NULL) {
2433 GMountOperation *mount_op = get_unmount_operation (sidebar);
2434 g_drive_stop (drive, G_MOUNT_UNMOUNT_NONE, mount_op, NULL, drive_stop_cb,
2435 g_object_ref (sidebar->window));
2436 g_object_unref (mount_op);
2437 }
2438 g_object_unref (drive);
2439 }
2440
2441 static void
2442 empty_trash_cb (GtkMenuItem *item,
2443 NautilusPlacesSidebar *sidebar)
2444 {
2445 nautilus_file_operations_empty_trash (GTK_WIDGET (sidebar->window));
2446 }
2447
2448 static gboolean
2449 find_prev_or_next_row (NautilusPlacesSidebar *sidebar,
2450 GtkTreeIter *iter,
2451 gboolean go_up)
2452 {
2453 GtkTreeModel *model = GTK_TREE_MODEL (sidebar->store);
2454 gboolean res;
2455 int place_type;
2456
2457 if (go_up) {
2458 res = gtk_tree_model_iter_previous (model, iter);
2459 } else {
2460 res = gtk_tree_model_iter_next (model, iter);
2461 }
2462
2463 if (res) {
2464 gtk_tree_model_get (model, iter,
2465 PLACES_SIDEBAR_COLUMN_ROW_TYPE, &place_type,
2466 -1);
2467 if (place_type == PLACES_HEADING) {
2468 if (go_up) {
2469 res = gtk_tree_model_iter_previous (model, iter);
2470 } else {
2471 res = gtk_tree_model_iter_next (model, iter);
2472 }
2473 }
2474 }
2475
2476 return res;
2477 }
2478
2479 static gboolean
2480 find_prev_row (NautilusPlacesSidebar *sidebar, GtkTreeIter *iter)
2481 {
2482 return find_prev_or_next_row (sidebar, iter, TRUE);
2483 }
2484
2485 static gboolean
2486 find_next_row (NautilusPlacesSidebar *sidebar, GtkTreeIter *iter)
2487 {
2488 return find_prev_or_next_row (sidebar, iter, FALSE);
2489 }
2490
2491 static void
2492 properties_cb (GtkMenuItem *item,
2493 NautilusPlacesSidebar *sidebar)
2494 {
2495 GtkTreeModel *model;
2496 GtkTreePath *path = NULL;
2497 GtkTreeIter iter;
2498 GList *list;
2499 NautilusFile *file;
2500 char *uri;
2501
2502 model = gtk_tree_view_get_model (sidebar->tree_view);
2503 gtk_tree_view_get_cursor (sidebar->tree_view, &path, NULL);
2504
2505 if (path == NULL || !gtk_tree_model_get_iter (model, &iter, path)) {
2506 gtk_tree_path_free (path);
2507 return;
2508 }
2509
2510 gtk_tree_model_get (model, &iter, PLACES_SIDEBAR_COLUMN_URI, &uri, -1);
2511
2512 if (uri != NULL) {
2513
2514 file = nautilus_file_get_by_uri (uri);
2515 list = g_list_prepend (NULL, nautilus_file_ref (file));
2516
2517 nautilus_properties_window_present (list, GTK_WIDGET (sidebar), NULL);
2518
2519 nautilus_file_list_free (list);
2520 g_free (uri);
2521 }
2522
2523 gtk_tree_path_free (path);
2524 }
2525
2526 static gboolean
2527 nautilus_places_sidebar_focus (GtkWidget *widget,
2528 GtkDirectionType direction)
2529 {
2530 NautilusPlacesSidebar *sidebar = NAUTILUS_PLACES_SIDEBAR (widget);
2531 GtkTreePath *path;
2532 GtkTreeIter iter;
2533 gboolean res;
2534
2535 res = get_selected_iter (sidebar, &iter);
2536
2537 if (!res) {
2538 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (sidebar->store), &iter);
2539 res = find_next_row (sidebar, &iter);
2540 if (res) {
2541 path = gtk_tree_model_get_path (GTK_TREE_MODEL (sidebar->store), &iter);
2542 gtk_tree_view_set_cursor (sidebar->tree_view, path, NULL, FALSE);
2543 gtk_tree_path_free (path);
2544 }
2545 }
2546
2547 return GTK_WIDGET_CLASS (nautilus_places_sidebar_parent_class)->focus (widget, direction);
2548 }
2549
2550 /* Handler for GtkWidget::key-press-event on the shortcuts list */
2551 static gboolean
2552 bookmarks_key_press_event_cb (GtkWidget *widget,
2553 GdkEventKey *event,
2554 NautilusPlacesSidebar *sidebar)
2555 {
2556 guint modifiers;
2557 GtkTreeIter selected_iter;
2558 GtkTreePath *path;
2559
2560 if (!get_selected_iter (sidebar, &selected_iter)) {
2561 return FALSE;
2562 }
2563
2564 modifiers = gtk_accelerator_get_default_mod_mask ();
2565
2566 if ((event->keyval == GDK_KEY_Return ||
2567 event->keyval == GDK_KEY_KP_Enter ||
2568 event->keyval == GDK_KEY_ISO_Enter ||
2569 event->keyval == GDK_KEY_space)) {
2570 NautilusWindowOpenFlags flags = 0;
2571
2572 if ((event->state & modifiers) == GDK_SHIFT_MASK) {
2573 flags = NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB;
2574 } else if ((event->state & modifiers) == GDK_CONTROL_MASK) {
2575 flags = NAUTILUS_WINDOW_OPEN_FLAG_NEW_WINDOW;
2576 }
2577
2578 open_selected_bookmark (sidebar, GTK_TREE_MODEL (sidebar->store),
2579 &selected_iter, flags);
2580 return TRUE;
2581 }
2582
2583 if (event->keyval == GDK_KEY_Down &&
2584 (event->state & modifiers) == GDK_MOD1_MASK) {
2585 return eject_or_unmount_selection (sidebar);
2586 }
2587
2588 if (event->keyval == GDK_KEY_Up) {
2589 if (find_prev_row (sidebar, &selected_iter)) {
2590 path = gtk_tree_model_get_path (GTK_TREE_MODEL (sidebar->store), &selected_iter);
2591 gtk_tree_view_set_cursor (sidebar->tree_view, path, NULL, FALSE);
2592 gtk_tree_path_free (path);
2593 }
2594 return TRUE;
2595 }
2596
2597 if (event->keyval == GDK_KEY_Down) {
2598 if (find_next_row (sidebar, &selected_iter)) {
2599 path = gtk_tree_model_get_path (GTK_TREE_MODEL (sidebar->store), &selected_iter);
2600 gtk_tree_view_set_cursor (sidebar->tree_view, path, NULL, FALSE);
2601 gtk_tree_path_free (path);
2602 }
2603 return TRUE;
2604 }
2605
2606 if ((event->keyval == GDK_KEY_Delete
2607 || event->keyval == GDK_KEY_KP_Delete)
2608 && (event->state & modifiers) == 0) {
2609 remove_selected_bookmarks (sidebar);
2610 return TRUE;
2611 }
2612
2613 if ((event->keyval == GDK_KEY_F2)
2614 && (event->state & modifiers) == 0) {
2615 rename_selected_bookmark (sidebar);
2616 return TRUE;
2617 }
2618
2619 return FALSE;
2620 }
2621
2622 /* Constructs the popup menu for the file list if needed */
2623 static void
2624 bookmarks_build_popup_menu (NautilusPlacesSidebar *sidebar)
2625 {
2626 GtkWidget *item;
2627
2628 if (sidebar->popup_menu) {
2629 return;
2630 }
2631
2632 sidebar->popup_menu = gtk_menu_new ();
2633 gtk_menu_attach_to_widget (GTK_MENU (sidebar->popup_menu),
2634 GTK_WIDGET (sidebar),
2635 bookmarks_popup_menu_detach_cb);
2636
2637 item = gtk_image_menu_item_new_with_mnemonic (_("_Open"));
2638 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item),
2639 gtk_image_new_from_stock (GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU));
2640 g_signal_connect (item, "activate",
2641 G_CALLBACK (open_shortcut_cb), sidebar);
2642 gtk_widget_show (item);
2643 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item);
2644
2645 item = gtk_menu_item_new_with_mnemonic (_("Open in New _Tab"));
2646 sidebar->popup_menu_open_in_new_tab_item = item;
2647 g_signal_connect (item, "activate",
2648 G_CALLBACK (open_shortcut_in_new_tab_cb), sidebar);
2649 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item);
2650 gtk_widget_show (item);
2651
2652 item = gtk_menu_item_new_with_mnemonic (_("Open in New _Window"));
2653 g_signal_connect (item, "activate",
2654 G_CALLBACK (open_shortcut_in_new_window_cb), sidebar);
2655 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item);
2656 gtk_widget_show (item);
2657
2658 eel_gtk_menu_append_separator (GTK_MENU (sidebar->popup_menu));
2659
2660 item = gtk_menu_item_new_with_mnemonic (_("_Add Bookmark"));
2661 sidebar->popup_menu_add_shortcut_item = item;
2662 g_signal_connect (item, "activate",
2663 G_CALLBACK (add_shortcut_cb), sidebar);
2664 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item);
2665
2666 item = gtk_image_menu_item_new_with_label (_("Remove"));
2667 sidebar->popup_menu_remove_item = item;
2668 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item),
2669 gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU));
2670 g_signal_connect (item, "activate",
2671 G_CALLBACK (remove_shortcut_cb), sidebar);
2672 gtk_widget_show (item);
2673 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item);
2674
2675 item = gtk_menu_item_new_with_label (_("Rename..."));
2676 sidebar->popup_menu_rename_item = item;
2677 g_signal_connect (item, "activate",
2678 G_CALLBACK (rename_shortcut_cb), sidebar);
2679 gtk_widget_show (item);
2680 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item);
2681
2682 /* Mount/Unmount/Eject menu items */
2683
2684 sidebar->popup_menu_separator_item =
2685 GTK_WIDGET (eel_gtk_menu_append_separator (GTK_MENU (sidebar->popup_menu)));
2686
2687 item = gtk_menu_item_new_with_mnemonic (_("_Mount"));
2688 sidebar->popup_menu_mount_item = item;
2689 g_signal_connect (item, "activate",
2690 G_CALLBACK (mount_shortcut_cb), sidebar);
2691 gtk_widget_show (item);
2692 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item);
2693
2694 item = gtk_menu_item_new_with_mnemonic (_("_Unmount"));
2695 sidebar->popup_menu_unmount_item = item;
2696 g_signal_connect (item, "activate",
2697 G_CALLBACK (unmount_shortcut_cb), sidebar);
2698 gtk_widget_show (item);
2699 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item);
2700
2701 item = gtk_menu_item_new_with_mnemonic (_("_Eject"));
2702 sidebar->popup_menu_eject_item = item;
2703 g_signal_connect (item, "activate",
2704 G_CALLBACK (eject_shortcut_cb), sidebar);
2705 gtk_widget_show (item);
2706 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item);
2707
2708 item = gtk_menu_item_new_with_mnemonic (_("_Detect Media"));
2709 sidebar->popup_menu_rescan_item = item;
2710 g_signal_connect (item, "activate",
2711 G_CALLBACK (rescan_shortcut_cb), sidebar);
2712 gtk_widget_show (item);
2713 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item);
2714
2715 item = gtk_menu_item_new_with_mnemonic (_("_Start"));
2716 sidebar->popup_menu_start_item = item;
2717 g_signal_connect (item, "activate",
2718 G_CALLBACK (start_shortcut_cb), sidebar);
2719 gtk_widget_show (item);
2720 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item);
2721
2722 item = gtk_menu_item_new_with_mnemonic (_("_Stop"));
2723 sidebar->popup_menu_stop_item = item;
2724 g_signal_connect (item, "activate",
2725 G_CALLBACK (stop_shortcut_cb), sidebar);
2726 gtk_widget_show (item);
2727 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item);
2728
2729 /* Empty Trash menu item */
2730
2731 item = gtk_menu_item_new_with_mnemonic (_("Empty _Trash"));
2732 sidebar->popup_menu_empty_trash_item = item;
2733 g_signal_connect (item, "activate",
2734 G_CALLBACK (empty_trash_cb), sidebar);
2735 gtk_widget_show (item);
2736 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item);
2737
2738 /* Properties menu item */
2739
2740 sidebar->popup_menu_properties_separator_item =
2741 GTK_WIDGET (eel_gtk_menu_append_separator (GTK_MENU (sidebar->popup_menu)));
2742
2743 item = gtk_menu_item_new_with_mnemonic (_("_Properties"));
2744 sidebar->popup_menu_properties_item = item;
2745 g_signal_connect (item, "activate",
2746 G_CALLBACK (properties_cb), sidebar);
2747 gtk_widget_show (item);
2748 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item);
2749
2750 bookmarks_check_popup_sensitivity (sidebar);
2751 }
2752
2753 static void
2754 bookmarks_update_popup_menu (NautilusPlacesSidebar *sidebar)
2755 {
2756 bookmarks_build_popup_menu (sidebar);
2757 }
2758
2759 static void
2760 bookmarks_popup_menu (NautilusPlacesSidebar *sidebar,
2761 GdkEventButton *event)
2762 {
2763 bookmarks_update_popup_menu (sidebar);
2764 eel_pop_up_context_menu (GTK_MENU(sidebar->popup_menu),
2765 event);
2766 }
2767
2768 /* Callback used for the GtkWidget::popup-menu signal of the shortcuts list */
2769 static gboolean
2770 bookmarks_popup_menu_cb (GtkWidget *widget,
2771 NautilusPlacesSidebar *sidebar)
2772 {
2773 bookmarks_popup_menu (sidebar, NULL);
2774 return TRUE;
2775 }
2776
2777 static gboolean
2778 bookmarks_button_release_event_cb (GtkWidget *widget,
2779 GdkEventButton *event,
2780 NautilusPlacesSidebar *sidebar)
2781 {
2782 GtkTreePath *path;
2783 GtkTreeIter iter;
2784 GtkTreeModel *model;
2785 GtkTreeView *tree_view;
2786 gboolean ret = FALSE;
2787 gboolean res;
2788
2789 path = NULL;
2790
2791 if (event->type != GDK_BUTTON_RELEASE) {
2792 return TRUE;
2793 }
2794
2795 if (clicked_eject_button (sidebar, &path)) {
2796 eject_or_unmount_bookmark (sidebar, path);
2797 gtk_tree_path_free (path);
2798
2799 return FALSE;
2800 }
2801
2802 tree_view = GTK_TREE_VIEW (widget);
2803 model = gtk_tree_view_get_model (tree_view);
2804
2805 if (event->window != gtk_tree_view_get_bin_window (tree_view)) {
2806 return FALSE;
2807 }
2808
2809 res = gtk_tree_view_get_path_at_pos (tree_view, (int) event->x, (int) event->y,
2810 &path, NULL, NULL, NULL);
2811
2812 if (!res || path == NULL) {
2813 return FALSE;
2814 }
2815
2816 res = gtk_tree_model_get_iter (model, &iter, path);
2817 if (!res) {
2818 gtk_tree_path_free (path);
2819 return FALSE;
2820 }
2821
2822 if (event->button == 1) {
2823 open_selected_bookmark (sidebar, model, &iter, 0);
2824 } else if (event->button == 2) {
2825 NautilusWindowOpenFlags flags = 0;
2826
2827 flags = (event->state & GDK_CONTROL_MASK) ?
2828 NAUTILUS_WINDOW_OPEN_FLAG_NEW_WINDOW :
2829 NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB;
2830
2831 open_selected_bookmark (sidebar, model, &iter, flags);
2832 ret = TRUE;
2833 } else if (event->button == 3) {
2834 PlaceType row_type;
2835
2836 gtk_tree_model_get (model, &iter,
2837 PLACES_SIDEBAR_COLUMN_ROW_TYPE, &row_type,
2838 -1);
2839
2840 if (row_type != PLACES_HEADING) {
2841 bookmarks_popup_menu (sidebar, event);
2842 }
2843 }
2844
2845 gtk_tree_path_free (path);
2846
2847 return ret;
2848 }
2849
2850 static void
2851 bookmarks_edited (GtkCellRenderer *cell,
2852 gchar *path_string,
2853 gchar *new_text,
2854 NautilusPlacesSidebar *sidebar)
2855 {
2856 GtkTreePath *path;
2857 GtkTreeIter iter;
2858 NautilusBookmark *bookmark;
2859 int index;
2860
2861 g_object_set (cell, "editable", FALSE, NULL);
2862
2863 path = gtk_tree_path_new_from_string (path_string);
2864 gtk_tree_model_get_iter (GTK_TREE_MODEL (sidebar->store), &iter, path);
2865 gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
2866 PLACES_SIDEBAR_COLUMN_INDEX, &index,
2867 -1);
2868 gtk_tree_path_free (path);
2869 bookmark = nautilus_bookmark_list_item_at (sidebar->bookmarks, index);
2870
2871 if (bookmark != NULL) {
2872 nautilus_bookmark_set_custom_name (bookmark, new_text);
2873 }
2874 }
2875
2876 static void
2877 bookmarks_editing_canceled (GtkCellRenderer *cell,
2878 NautilusPlacesSidebar *sidebar)
2879 {
2880 g_object_set (cell, "editable", FALSE, NULL);
2881 }
2882
2883 static void
2884 trash_state_changed_cb (NautilusTrashMonitor *trash_monitor,
2885 gboolean state,
2886 gpointer data)
2887 {
2888 NautilusPlacesSidebar *sidebar;
2889
2890 sidebar = NAUTILUS_PLACES_SIDEBAR (data);
2891
2892 /* The trash icon changed, update the sidebar */
2893 update_places (sidebar);
2894
2895 bookmarks_check_popup_sensitivity (sidebar);
2896 }
2897
2898 static gboolean
2899 tree_selection_func (GtkTreeSelection *selection,
2900 GtkTreeModel *model,
2901 GtkTreePath *path,
2902 gboolean path_currently_selected,
2903 gpointer user_data)
2904 {
2905 GtkTreeIter iter;
2906 PlaceType row_type;
2907
2908 gtk_tree_model_get_iter (model, &iter, path);
2909 gtk_tree_model_get (model, &iter,
2910 PLACES_SIDEBAR_COLUMN_ROW_TYPE, &row_type,
2911 -1);
2912
2913 if (row_type == PLACES_HEADING) {
2914 return FALSE;
2915 }
2916
2917 return TRUE;
2918 }
2919
2920 static void
2921 icon_cell_renderer_func (GtkTreeViewColumn *column,
2922 GtkCellRenderer *cell,
2923 GtkTreeModel *model,
2924 GtkTreeIter *iter,
2925 gpointer user_data)
2926 {
2927 PlaceType type;
2928
2929 gtk_tree_model_get (model, iter,
2930 PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type,
2931 -1);
2932
2933 if (type == PLACES_HEADING) {
2934 g_object_set (cell,
2935 "visible", FALSE,
2936 NULL);
2937 } else {
2938 g_object_set (cell,
2939 "visible", TRUE,
2940 NULL);
2941 }
2942 }
2943
2944 static void
2945 padding_cell_renderer_func (GtkTreeViewColumn *column,
2946 GtkCellRenderer *cell,
2947 GtkTreeModel *model,
2948 GtkTreeIter *iter,
2949 gpointer user_data)
2950 {
2951 PlaceType type;
2952
2953 gtk_tree_model_get (model, iter,
2954 PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type,
2955 -1);
2956
2957 if (type == PLACES_HEADING) {
2958 g_object_set (cell,
2959 "visible", FALSE,
2960 "xpad", 0,
2961 "ypad", 0,
2962 NULL);
2963 } else {
2964 g_object_set (cell,
2965 "visible", TRUE,
2966 "xpad", 3,
2967 "ypad", 3,
2968 NULL);
2969 }
2970 }
2971
2972 static void
2973 heading_cell_renderer_func (GtkTreeViewColumn *column,
2974 GtkCellRenderer *cell,
2975 GtkTreeModel *model,
2976 GtkTreeIter *iter,
2977 gpointer user_data)
2978 {
2979 PlaceType type;
2980
2981 gtk_tree_model_get (model, iter,
2982 PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type,
2983 -1);
2984
2985 if (type == PLACES_HEADING) {
2986 g_object_set (cell,
2987 "visible", TRUE,
2988 NULL);
2989 } else {
2990 g_object_set (cell,
2991 "visible", FALSE,
2992 NULL);
2993 }
2994 }
2995
2996 static gint
2997 places_sidebar_sort_func (GtkTreeModel *model,
2998 GtkTreeIter *iter_a,
2999 GtkTreeIter *iter_b,
3000 gpointer user_data)
3001 {
3002 SectionType section_type_a, section_type_b;
3003 PlaceType place_type_a, place_type_b;
3004 gint retval = 0;
3005
3006 gtk_tree_model_get (model, iter_a,
3007 PLACES_SIDEBAR_COLUMN_SECTION_TYPE, §ion_type_a,
3008 PLACES_SIDEBAR_COLUMN_ROW_TYPE, &place_type_a,
3009 -1);
3010 gtk_tree_model_get (model, iter_b,
3011 PLACES_SIDEBAR_COLUMN_SECTION_TYPE, §ion_type_b,
3012 PLACES_SIDEBAR_COLUMN_ROW_TYPE, &place_type_b,
3013 -1);
3014
3015 /* fall back to the default order if we're not in the
3016 * XDG part of the computer section.
3017 */
3018 if ((section_type_a == section_type_b) &&
3019 (section_type_a == SECTION_COMPUTER) &&
3020 (place_type_a == place_type_b) &&
3021 (place_type_a == PLACES_XDG_DIR)) {
3022 gchar *name_a, *name_b;
3023
3024 gtk_tree_model_get (model, iter_a,
3025 PLACES_SIDEBAR_COLUMN_NAME, &name_a,
3026 -1);
3027 gtk_tree_model_get (model, iter_b,
3028 PLACES_SIDEBAR_COLUMN_NAME, &name_b,
3029 -1);
3030
3031 retval = g_utf8_collate (name_a, name_b);
3032
3033 g_free (name_a);
3034 g_free (name_b);
3035 }
3036
3037 return retval;
3038 }
3039
3040 static void
3041 update_hostname (NautilusPlacesSidebar *sidebar)
3042 {
3043 GVariant *variant;
3044 gsize len;
3045 const gchar *hostname;
3046
3047 if (sidebar->hostnamed_proxy == NULL)
3048 return;
3049
3050 variant = g_dbus_proxy_get_cached_property (sidebar->hostnamed_proxy,
3051 "PrettyHostname");
3052 if (variant == NULL) {
3053 return;
3054 }
3055
3056 hostname = g_variant_get_string (variant, &len);
3057 if (len > 0 &&
3058 g_strcmp0 (sidebar->hostname, hostname) != 0) {
3059 g_free (sidebar->hostname);
3060 sidebar->hostname = g_strdup (hostname);
3061 update_places (sidebar);
3062 }
3063
3064 g_variant_unref (variant);
3065 }
3066
3067 static void
3068 hostname_proxy_new_cb (GObject *source_object,
3069 GAsyncResult *res,
3070 gpointer user_data)
3071 {
3072 NautilusPlacesSidebar *sidebar = user_data;
3073 GError *error = NULL;
3074
3075 sidebar->hostnamed_proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
3076 if (error != NULL) {
3077 g_debug ("Failed to create D-Bus proxy: %s", error->message);
3078 g_error_free (error);
3079 return;
3080 }
3081
3082 g_signal_connect_swapped (sidebar->hostnamed_proxy,
3083 "g-properties-changed",
3084 G_CALLBACK (update_hostname),
3085 sidebar);
3086 update_hostname (sidebar);
3087 }
3088
3089 static void
3090 nautilus_places_sidebar_init (NautilusPlacesSidebar *sidebar)
3091 {
3092 GtkTreeView *tree_view;
3093 GtkTreeViewColumn *col;
3094 GtkCellRenderer *cell;
3095 GtkTreeSelection *selection;
3096
3097 sidebar->volume_monitor = g_volume_monitor_get ();
3098
3099 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sidebar),
3100 GTK_POLICY_NEVER,
3101 GTK_POLICY_AUTOMATIC);
3102 gtk_scrolled_window_set_hadjustment (GTK_SCROLLED_WINDOW (sidebar), NULL);
3103 gtk_scrolled_window_set_vadjustment (GTK_SCROLLED_WINDOW (sidebar), NULL);
3104 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sidebar), GTK_SHADOW_IN);
3105
3106 gtk_style_context_set_junction_sides (gtk_widget_get_style_context (GTK_WIDGET (sidebar)),
3107 GTK_JUNCTION_RIGHT | GTK_JUNCTION_LEFT);
3108
3109 /* tree view */
3110 tree_view = GTK_TREE_VIEW (gtk_tree_view_new ());
3111 gtk_tree_view_set_headers_visible (tree_view, FALSE);
3112
3113 col = GTK_TREE_VIEW_COLUMN (gtk_tree_view_column_new ());
3114
3115 /* initial padding */
3116 cell = gtk_cell_renderer_text_new ();
3117 gtk_tree_view_column_pack_start (col, cell, FALSE);
3118 g_object_set (cell,
3119 "xpad", 6,
3120 NULL);
3121
3122 /* headings */
3123 cell = gtk_cell_renderer_text_new ();
3124 gtk_tree_view_column_pack_start (col, cell, FALSE);
3125 gtk_tree_view_column_set_attributes (col, cell,
3126 "text", PLACES_SIDEBAR_COLUMN_HEADING_TEXT,
3127 NULL);
3128 g_object_set (cell,
3129 "weight", PANGO_WEIGHT_BOLD,
3130 "weight-set", TRUE,
3131 "ypad", 6,
3132 "xpad", 0,
3133 NULL);
3134 gtk_tree_view_column_set_cell_data_func (col, cell,
3135 heading_cell_renderer_func,
3136 sidebar, NULL);
3137
3138 /* icon padding */
3139 cell = gtk_cell_renderer_text_new ();
3140 gtk_tree_view_column_pack_start (col, cell, FALSE);
3141 gtk_tree_view_column_set_cell_data_func (col, cell,
3142 padding_cell_renderer_func,
3143 sidebar, NULL);
3144
3145 /* icon renderer */
3146 cell = gtk_cell_renderer_pixbuf_new ();
3147 g_object_set (cell, "follow-state", TRUE, NULL);
3148 gtk_tree_view_column_pack_start (col, cell, FALSE);
3149 gtk_tree_view_column_set_attributes (col, cell,
3150 "gicon", PLACES_SIDEBAR_COLUMN_GICON,
3151 NULL);
3152 gtk_tree_view_column_set_cell_data_func (col, cell,
3153 icon_cell_renderer_func,
3154 sidebar, NULL);
3155
3156 /* eject text renderer */
3157 cell = gtk_cell_renderer_text_new ();
3158 gtk_tree_view_column_pack_start (col, cell, TRUE);
3159 gtk_tree_view_column_set_attributes (col, cell,
3160 "text", PLACES_SIDEBAR_COLUMN_NAME,
3161 "visible", PLACES_SIDEBAR_COLUMN_EJECT,
3162 NULL);
3163 g_object_set (cell,
3164 "ellipsize", PANGO_ELLIPSIZE_END,
3165 "ellipsize-set", TRUE,
3166 NULL);
3167
3168 /* eject icon renderer */
3169 cell = gtk_cell_renderer_pixbuf_new ();
3170 sidebar->eject_icon_cell_renderer = cell;
3171 g_object_set (cell,
3172 "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE,
3173 "stock-size", GTK_ICON_SIZE_MENU,
3174 "xpad", EJECT_BUTTON_XPAD,
3175 /* align right, because for some reason gtk+ expands
3176 this even though we tell it not to. */
3177 "xalign", 1.0,
3178 "follow-state", TRUE,
3179 NULL);
3180 gtk_tree_view_column_pack_start (col, cell, FALSE);
3181 gtk_tree_view_column_set_attributes (col, cell,
3182 "visible", PLACES_SIDEBAR_COLUMN_EJECT,
3183 "gicon", PLACES_SIDEBAR_COLUMN_EJECT_GICON,
3184 NULL);
3185
3186 /* normal text renderer */
3187 cell = gtk_cell_renderer_text_new ();
3188 gtk_tree_view_column_pack_start (col, cell, TRUE);
3189 g_object_set (G_OBJECT (cell), "editable", FALSE, NULL);
3190 gtk_tree_view_column_set_attributes (col, cell,
3191 "text", PLACES_SIDEBAR_COLUMN_NAME,
3192 "visible", PLACES_SIDEBAR_COLUMN_NO_EJECT,
3193 "editable-set", PLACES_SIDEBAR_COLUMN_BOOKMARK,
3194 NULL);
3195 g_object_set (cell,
3196 "ellipsize", PANGO_ELLIPSIZE_END,
3197 "ellipsize-set", TRUE,
3198 NULL);
3199
3200 g_signal_connect (cell, "edited",
3201 G_CALLBACK (bookmarks_edited), sidebar);
3202 g_signal_connect (cell, "editing-canceled",
3203 G_CALLBACK (bookmarks_editing_canceled), sidebar);
3204
3205 /* this is required to align the eject buttons to the right */
3206 gtk_tree_view_column_set_max_width (GTK_TREE_VIEW_COLUMN (col), NAUTILUS_ICON_SIZE_SMALLER);
3207 gtk_tree_view_append_column (tree_view, col);
3208
3209 sidebar->store = nautilus_shortcuts_model_new (sidebar);
3210 gtk_tree_view_set_tooltip_column (tree_view, PLACES_SIDEBAR_COLUMN_TOOLTIP);
3211 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sidebar->store),
3212 PLACES_SIDEBAR_COLUMN_NAME,
3213 GTK_SORT_ASCENDING);
3214 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (sidebar->store),
3215 PLACES_SIDEBAR_COLUMN_NAME,
3216 places_sidebar_sort_func,
3217 sidebar, NULL);
3218
3219 gtk_tree_view_set_model (tree_view, GTK_TREE_MODEL (sidebar->store));
3220 gtk_container_add (GTK_CONTAINER (sidebar), GTK_WIDGET (tree_view));
3221 gtk_widget_show (GTK_WIDGET (tree_view));
3222 gtk_tree_view_set_enable_search (tree_view, FALSE);
3223
3224 gtk_widget_show (GTK_WIDGET (sidebar));
3225 sidebar->tree_view = tree_view;
3226
3227 gtk_tree_view_set_search_column (tree_view, PLACES_SIDEBAR_COLUMN_NAME);
3228 selection = gtk_tree_view_get_selection (tree_view);
3229 gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE);
3230
3231 gtk_tree_selection_set_select_function (selection,
3232 tree_selection_func,
3233 sidebar,
3234 NULL);
3235
3236 gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (tree_view),
3237 GDK_BUTTON1_MASK,
3238 nautilus_shortcuts_source_targets,
3239 G_N_ELEMENTS (nautilus_shortcuts_source_targets),
3240 GDK_ACTION_MOVE);
3241 gtk_drag_dest_set (GTK_WIDGET (tree_view),
3242 0,
3243 nautilus_shortcuts_drop_targets, G_N_ELEMENTS (nautilus_shortcuts_drop_targets),
3244 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK);
3245
3246 g_signal_connect (tree_view, "key-press-event",
3247 G_CALLBACK (bookmarks_key_press_event_cb), sidebar);
3248
3249 g_signal_connect (tree_view, "drag-motion",
3250 G_CALLBACK (drag_motion_callback), sidebar);
3251 g_signal_connect (tree_view, "drag-leave",
3252 G_CALLBACK (drag_leave_callback), sidebar);
3253 g_signal_connect (tree_view, "drag-data-received",
3254 G_CALLBACK (drag_data_received_callback), sidebar);
3255 g_signal_connect (tree_view, "drag-drop",
3256 G_CALLBACK (drag_drop_callback), sidebar);
3257
3258 g_signal_connect (selection, "changed",
3259 G_CALLBACK (bookmarks_selection_changed_cb), sidebar);
3260 g_signal_connect (tree_view, "popup-menu",
3261 G_CALLBACK (bookmarks_popup_menu_cb), sidebar);
3262 g_signal_connect (tree_view, "button-release-event",
3263 G_CALLBACK (bookmarks_button_release_event_cb), sidebar);
3264
3265 eel_gtk_tree_view_set_activate_on_single_click (sidebar->tree_view,
3266 TRUE);
3267
3268 g_signal_connect_swapped (gnome_background_preferences, "changed::" NAUTILUS_PREFERENCES_SHOW_DESKTOP,
3269 G_CALLBACK(desktop_setting_changed_callback),
3270 sidebar);
3271
3272 sidebar->hostname = g_strdup (_("Computer"));
3273 g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
3274 G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES,
3275 NULL,
3276 "org.freedesktop.hostname1",
3277 "/org/freedesktop/hostname1",
3278 "org.freedesktop.hostname1",
3279 NULL,
3280 hostname_proxy_new_cb,
3281 sidebar);
3282
3283 g_signal_connect_object (nautilus_trash_monitor_get (),
3284 "trash_state_changed",
3285 G_CALLBACK (trash_state_changed_cb),
3286 sidebar, 0);
3287 }
3288
3289 static void
3290 nautilus_places_sidebar_dispose (GObject *object)
3291 {
3292 NautilusPlacesSidebar *sidebar;
3293
3294 sidebar = NAUTILUS_PLACES_SIDEBAR (object);
3295
3296 sidebar->window = NULL;
3297 sidebar->tree_view = NULL;
3298
3299 g_free (sidebar->uri);
3300 sidebar->uri = NULL;
3301
3302 free_drag_data (sidebar);
3303
3304 if (sidebar->bookmarks_changed_id != 0) {
3305 g_signal_handler_disconnect (sidebar->bookmarks,
3306 sidebar->bookmarks_changed_id);
3307 sidebar->bookmarks_changed_id = 0;
3308 }
3309
3310 g_clear_object (&sidebar->store);
3311
3312 if (sidebar->go_to_after_mount_slot) {
3313 g_object_remove_weak_pointer (G_OBJECT (sidebar->go_to_after_mount_slot),
3314 (gpointer *) &sidebar->go_to_after_mount_slot);
3315 sidebar->go_to_after_mount_slot = NULL;
3316 }
3317
3318 g_signal_handlers_disconnect_by_func (nautilus_preferences,
3319 bookmarks_popup_menu_detach_cb,
3320 sidebar);
3321
3322 g_signal_handlers_disconnect_by_func (gnome_background_preferences,
3323 desktop_setting_changed_callback,
3324 sidebar);
3325
3326 if (sidebar->volume_monitor != NULL) {
3327 g_signal_handlers_disconnect_by_func (sidebar->volume_monitor,
3328 volume_added_callback, sidebar);
3329 g_signal_handlers_disconnect_by_func (sidebar->volume_monitor,
3330 volume_removed_callback, sidebar);
3331 g_signal_handlers_disconnect_by_func (sidebar->volume_monitor,
3332 volume_changed_callback, sidebar);
3333 g_signal_handlers_disconnect_by_func (sidebar->volume_monitor,
3334 mount_added_callback, sidebar);
3335 g_signal_handlers_disconnect_by_func (sidebar->volume_monitor,
3336 mount_removed_callback, sidebar);
3337 g_signal_handlers_disconnect_by_func (sidebar->volume_monitor,
3338 mount_changed_callback, sidebar);
3339 g_signal_handlers_disconnect_by_func (sidebar->volume_monitor,
3340 drive_disconnected_callback, sidebar);
3341 g_signal_handlers_disconnect_by_func (sidebar->volume_monitor,
3342 drive_connected_callback, sidebar);
3343 g_signal_handlers_disconnect_by_func (sidebar->volume_monitor,
3344 drive_changed_callback, sidebar);
3345
3346 g_clear_object (&sidebar->volume_monitor);
3347 }
3348
3349 g_clear_object (&sidebar->hostnamed_proxy);
3350 g_free (sidebar->hostname);
3351 sidebar->hostname = NULL;
3352
3353 G_OBJECT_CLASS (nautilus_places_sidebar_parent_class)->dispose (object);
3354 }
3355
3356 static void
3357 nautilus_places_sidebar_class_init (NautilusPlacesSidebarClass *class)
3358 {
3359 G_OBJECT_CLASS (class)->dispose = nautilus_places_sidebar_dispose;
3360
3361 GTK_WIDGET_CLASS (class)->style_set = nautilus_places_sidebar_style_set;
3362 GTK_WIDGET_CLASS (class)->focus = nautilus_places_sidebar_focus;
3363 }
3364
3365 static void
3366 nautilus_places_sidebar_set_parent_window (NautilusPlacesSidebar *sidebar,
3367 NautilusWindow *window)
3368 {
3369 NautilusWindowSlot *slot;
3370 NautilusApplication *app = NAUTILUS_APPLICATION (g_application_get_default ());
3371
3372 sidebar->window = window;
3373
3374 slot = nautilus_window_get_active_slot (window);
3375
3376 sidebar->bookmarks = nautilus_application_get_bookmarks (app);
3377 sidebar->bookmarks_changed_id =
3378 g_signal_connect_swapped (sidebar->bookmarks, "changed",
3379 G_CALLBACK (update_places),
3380 sidebar);
3381
3382 g_signal_connect_object (sidebar->volume_monitor, "volume_added",
3383 G_CALLBACK (volume_added_callback), sidebar, 0);
3384 g_signal_connect_object (sidebar->volume_monitor, "volume_removed",
3385 G_CALLBACK (volume_removed_callback), sidebar, 0);
3386 g_signal_connect_object (sidebar->volume_monitor, "volume_changed",
3387 G_CALLBACK (volume_changed_callback), sidebar, 0);
3388 g_signal_connect_object (sidebar->volume_monitor, "mount_added",
3389 G_CALLBACK (mount_added_callback), sidebar, 0);
3390 g_signal_connect_object (sidebar->volume_monitor, "mount_removed",
3391 G_CALLBACK (mount_removed_callback), sidebar, 0);
3392 g_signal_connect_object (sidebar->volume_monitor, "mount_changed",
3393 G_CALLBACK (mount_changed_callback), sidebar, 0);
3394 g_signal_connect_object (sidebar->volume_monitor, "drive_disconnected",
3395 G_CALLBACK (drive_disconnected_callback), sidebar, 0);
3396 g_signal_connect_object (sidebar->volume_monitor, "drive_connected",
3397 G_CALLBACK (drive_connected_callback), sidebar, 0);
3398 g_signal_connect_object (sidebar->volume_monitor, "drive_changed",
3399 G_CALLBACK (drive_changed_callback), sidebar, 0);
3400
3401 update_places (sidebar);
3402
3403 g_signal_connect_object (window, "loading-uri",
3404 G_CALLBACK (loading_uri_callback),
3405 sidebar, 0);
3406 sidebar->uri = nautilus_window_slot_get_current_uri (slot);
3407 update_current_uri (sidebar);
3408 }
3409
3410 static void
3411 nautilus_places_sidebar_style_set (GtkWidget *widget,
3412 GtkStyle *previous_style)
3413 {
3414 NautilusPlacesSidebar *sidebar;
3415
3416 sidebar = NAUTILUS_PLACES_SIDEBAR (widget);
3417
3418 update_places (sidebar);
3419 }
3420
3421 GtkWidget *
3422 nautilus_places_sidebar_new (NautilusWindow *window)
3423 {
3424 NautilusPlacesSidebar *sidebar;
3425
3426 sidebar = g_object_new (nautilus_places_sidebar_get_type (), NULL);
3427 nautilus_places_sidebar_set_parent_window (sidebar, window);
3428
3429 return GTK_WIDGET (sidebar);
3430 }
3431
3432
3433 /* Drag and drop interfaces */
3434
3435 /* GtkTreeDragSource::row_draggable implementation for the shortcuts filter model */
3436
3437 static gboolean
3438 nautilus_shortcuts_model_row_draggable (GtkTreeDragSource *drag_source,
3439 GtkTreePath *path)
3440 {
3441 GtkTreeModel *model;
3442 GtkTreeIter iter;
3443 PlaceType place_type;
3444 SectionType section_type;
3445
3446 model = GTK_TREE_MODEL (drag_source);
3447
3448 gtk_tree_model_get_iter (model, &iter, path);
3449 gtk_tree_model_get (model, &iter,
3450 PLACES_SIDEBAR_COLUMN_ROW_TYPE, &place_type,
3451 PLACES_SIDEBAR_COLUMN_SECTION_TYPE, §ion_type,
3452 -1);
3453
3454 if (place_type != PLACES_HEADING && section_type == SECTION_BOOKMARKS)
3455 return TRUE;
3456
3457 return FALSE;
3458 }
3459
3460 static void
3461 _nautilus_shortcuts_model_class_init (NautilusShortcutsModelClass *klass)
3462 {
3463
3464 }
3465
3466 static void
3467 _nautilus_shortcuts_model_init (NautilusShortcutsModel *model)
3468 {
3469 model->sidebar = NULL;
3470 }
3471
3472 static void
3473 _nautilus_shortcuts_model_drag_source_init (GtkTreeDragSourceIface *iface)
3474 {
3475 iface->row_draggable = nautilus_shortcuts_model_row_draggable;
3476 }
3477
3478 static GtkListStore *
3479 nautilus_shortcuts_model_new (NautilusPlacesSidebar *sidebar)
3480 {
3481 NautilusShortcutsModel *model;
3482 GType model_types[PLACES_SIDEBAR_COLUMN_COUNT] = {
3483 G_TYPE_INT,
3484 G_TYPE_STRING,
3485 G_TYPE_DRIVE,
3486 G_TYPE_VOLUME,
3487 G_TYPE_MOUNT,
3488 G_TYPE_STRING,
3489 G_TYPE_ICON,
3490 G_TYPE_INT,
3491 G_TYPE_BOOLEAN,
3492 G_TYPE_BOOLEAN,
3493 G_TYPE_BOOLEAN,
3494 G_TYPE_STRING,
3495 G_TYPE_ICON,
3496 G_TYPE_INT,
3497 G_TYPE_STRING
3498 };
3499
3500 model = g_object_new (_nautilus_shortcuts_model_get_type (), NULL);
3501 model->sidebar = sidebar;
3502
3503 gtk_list_store_set_column_types (GTK_LIST_STORE (model),
3504 PLACES_SIDEBAR_COLUMN_COUNT,
3505 model_types);
3506
3507 return GTK_LIST_STORE (model);
3508 }