1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
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.
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.
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.
20 * Author : Mr Jamie McCracken (jamiemcc at blueyonder dot co dot uk)
26 #include <eel/eel-debug.h>
27 #include <eel/eel-gtk-extensions.h>
28 #include <eel/eel-glib-extensions.h>
29 #include <eel/eel-preferences.h>
30 #include <eel/eel-string.h>
31 #include <eel/eel-stock-dialogs.h>
32 #include <gdk/gdkkeysyms.h>
33 #include <gtk/gtkalignment.h>
34 #include <gtk/gtkbutton.h>
35 #include <gtk/gtkvbox.h>
36 #include <gtk/gtkcellrendererpixbuf.h>
37 #include <gtk/gtkcellrenderertext.h>
38 #include <gtk/gtkliststore.h>
39 #include <gtk/gtkmain.h>
40 #include <gtk/gtksizegroup.h>
41 #include <gtk/gtkstock.h>
42 #include <gtk/gtktreemodel.h>
43 #include <gtk/gtktreeselection.h>
44 #include <gtk/gtkimagemenuitem.h>
45 #include <libgnome/gnome-macros.h>
46 #include <glib/gi18n.h>
47 #include <libgnomeui/gnome-popup-menu.h>
48 #include <libnautilus-private/nautilus-debug-log.h>
49 #include <libnautilus-private/nautilus-dnd.h>
50 #include <libnautilus-private/nautilus-bookmark.h>
51 #include <libnautilus-private/nautilus-global-preferences.h>
52 #include <libnautilus-private/nautilus-sidebar-provider.h>
53 #include <libnautilus-private/nautilus-module.h>
54 #include <libnautilus-private/nautilus-file.h>
55 #include <libnautilus-private/nautilus-file-utilities.h>
56 #include <libnautilus-private/nautilus-file-operations.h>
57 #include <libnautilus-private/nautilus-trash-monitor.h>
58 #include <libnautilus-private/nautilus-icon-names.h>
59 #include <libnautilus-private/nautilus-autorun.h>
62 #include "nautilus-bookmark-list.h"
63 #include "nautilus-places-sidebar.h"
64 #include "nautilus-window.h"
66 #define NAUTILUS_PLACES_SIDEBAR_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), NAUTILUS_TYPE_PLACES_SIDEBAR, NautilusPlacesSidebarClass))
67 #define NAUTILUS_IS_PLACES_SIDEBAR(obj) (GTK_CHECK_TYPE ((obj), NAUTILUS_TYPE_PLACES_SIDEBAR))
68 #define NAUTILUS_IS_PLACES_SIDEBAR_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), NAUTILUS_TYPE_PLACES_SIDEBAR))
71 GtkScrolledWindow parent
;
72 GtkTreeView
*tree_view
;
75 GtkTreeModel
*filter_model
;
76 NautilusWindowInfo
*window
;
77 NautilusBookmarkList
*bookmarks
;
78 GVolumeMonitor
*volume_monitor
;
82 gboolean drag_data_received
;
83 gboolean drop_occured
;
85 GtkWidget
*popup_menu
;
86 GtkWidget
*popup_menu_remove_item
;
87 GtkWidget
*popup_menu_rename_item
;
88 GtkWidget
*popup_menu_separator_item
;
89 GtkWidget
*popup_menu_mount_item
;
90 GtkWidget
*popup_menu_unmount_item
;
91 GtkWidget
*popup_menu_eject_item
;
92 GtkWidget
*popup_menu_rescan_item
;
93 GtkWidget
*popup_menu_format_item
;
94 GtkWidget
*popup_menu_empty_trash_item
;
95 } NautilusPlacesSidebar
;
98 GtkScrolledWindowClass parent
;
99 } NautilusPlacesSidebarClass
;
103 } NautilusPlacesSidebarProvider
;
107 } NautilusPlacesSidebarProviderClass
;
110 PLACES_SIDEBAR_COLUMN_ROW_TYPE
,
111 PLACES_SIDEBAR_COLUMN_URI
,
112 PLACES_SIDEBAR_COLUMN_DRIVE
,
113 PLACES_SIDEBAR_COLUMN_VOLUME
,
114 PLACES_SIDEBAR_COLUMN_MOUNT
,
115 PLACES_SIDEBAR_COLUMN_NAME
,
116 PLACES_SIDEBAR_COLUMN_ICON
,
117 PLACES_SIDEBAR_COLUMN_INDEX
,
119 PLACES_SIDEBAR_COLUMN_COUNT
124 PLACES_MOUNTED_VOLUME
,
129 static void nautilus_places_sidebar_iface_init (NautilusSidebarIface
*iface
);
130 static void sidebar_provider_iface_init (NautilusSidebarProviderIface
*iface
);
131 static GType
nautilus_places_sidebar_provider_get_type (void);
132 static void open_selected_bookmark (NautilusPlacesSidebar
*sidebar
,
135 gboolean open_in_new_window
);
136 static void nautilus_places_sidebar_style_set (GtkWidget
*widget
,
137 GtkStyle
*previous_style
);
139 /* Identifiers for target types */
145 /* Target types for dragging from the shortcuts list */
146 static const GtkTargetEntry nautilus_shortcuts_source_targets
[] = {
147 { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET
, GTK_TREE_MODEL_ROW
}
150 /* Target types for dropping into the shortcuts list */
151 static const GtkTargetEntry nautilus_shortcuts_drop_targets
[] = {
152 { "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET
, GTK_TREE_MODEL_ROW
},
153 { "text/uri-list", 0, TEXT_URI_LIST
}
156 /* Drag and drop interface declarations */
158 GtkTreeModelFilter parent
;
160 NautilusPlacesSidebar
*sidebar
;
161 } NautilusShortcutsModelFilter
;
164 GtkTreeModelFilterClass parent_class
;
165 } NautilusShortcutsModelFilterClass
;
167 #define NAUTILUS_SHORTCUTS_MODEL_FILTER_TYPE (_nautilus_shortcuts_model_filter_get_type ())
168 #define NAUTILUS_SHORTCUTS_MODEL_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NAUTILUS_SHORTCUTS_MODEL_FILTER_TYPE, NautilusShortcutsModelFilter))
170 GType
_nautilus_shortcuts_model_filter_get_type (void);
171 static void nautilus_shortcuts_model_filter_drag_source_iface_init (GtkTreeDragSourceIface
*iface
);
173 G_DEFINE_TYPE_WITH_CODE (NautilusShortcutsModelFilter
,
174 _nautilus_shortcuts_model_filter
,
175 GTK_TYPE_TREE_MODEL_FILTER
,
176 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE
,
177 nautilus_shortcuts_model_filter_drag_source_iface_init
));
179 static GtkTreeModel
*nautilus_shortcuts_model_filter_new (NautilusPlacesSidebar
*sidebar
,
180 GtkTreeModel
*child_model
,
183 G_DEFINE_TYPE_WITH_CODE (NautilusPlacesSidebar
, nautilus_places_sidebar
, GTK_TYPE_SCROLLED_WINDOW
,
184 G_IMPLEMENT_INTERFACE (NAUTILUS_TYPE_SIDEBAR
,
185 nautilus_places_sidebar_iface_init
));
187 G_DEFINE_TYPE_WITH_CODE (NautilusPlacesSidebarProvider
, nautilus_places_sidebar_provider
, G_TYPE_OBJECT
,
188 G_IMPLEMENT_INTERFACE (NAUTILUS_TYPE_SIDEBAR_PROVIDER
,
189 sidebar_provider_iface_init
));
192 add_place (NautilusPlacesSidebar
*sidebar
,
193 PlaceType place_type
,
203 GtkTreeIter iter
, child_iter
;
204 NautilusIconInfo
*icon_info
;
207 icon_size
= nautilus_get_icon_size_for_stock_size (GTK_ICON_SIZE_MENU
);
208 icon_info
= nautilus_icon_info_lookup (icon
, icon_size
);
210 pixbuf
= nautilus_icon_info_get_pixbuf_at_size (icon_info
, icon_size
);
211 g_object_unref (icon_info
);
212 gtk_list_store_append (sidebar
->store
, &iter
);
213 gtk_list_store_set (sidebar
->store
, &iter
,
214 PLACES_SIDEBAR_COLUMN_ICON
, pixbuf
,
215 PLACES_SIDEBAR_COLUMN_NAME
, name
,
216 PLACES_SIDEBAR_COLUMN_URI
, uri
,
217 PLACES_SIDEBAR_COLUMN_DRIVE
, drive
,
218 PLACES_SIDEBAR_COLUMN_VOLUME
, volume
,
219 PLACES_SIDEBAR_COLUMN_MOUNT
, mount
,
220 PLACES_SIDEBAR_COLUMN_ROW_TYPE
, place_type
,
221 PLACES_SIDEBAR_COLUMN_INDEX
, index
,
223 if (pixbuf
!= NULL
) {
224 g_object_unref (pixbuf
);
226 gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (sidebar
->filter_model
));
227 gtk_tree_model_filter_convert_child_iter_to_iter (GTK_TREE_MODEL_FILTER (sidebar
->filter_model
),
234 update_places (NautilusPlacesSidebar
*sidebar
)
236 NautilusBookmark
*bookmark
;
237 GtkTreeSelection
*selection
;
238 GtkTreeIter iter
, last_iter
;
239 GVolumeMonitor
*volume_monitor
;
240 GList
*mounts
, *l
, *ll
;
246 int bookmark_count
, index
;
247 char *location
, *mount_uri
, *name
, *desktop_path
;
252 selection
= gtk_tree_view_get_selection (sidebar
->tree_view
);
253 gtk_list_store_clear (sidebar
->store
);
254 location
= nautilus_window_info_get_current_location (sidebar
->window
);
256 /* add built in bookmarks */
257 desktop_path
= nautilus_get_desktop_directory ();
259 if (strcmp (g_get_home_dir(), desktop_path
) != 0) {
262 mount_uri
= nautilus_get_home_directory_uri ();
263 display_name
= g_filename_display_basename (g_get_home_dir ());
264 icon
= g_themed_icon_new (NAUTILUS_ICON_HOME
);
265 last_iter
= add_place (sidebar
, PLACES_BUILT_IN
,
267 mount_uri
, NULL
, NULL
, NULL
, 0);
268 g_object_unref (icon
);
269 g_free (display_name
);
270 if (strcmp (location
, mount_uri
) == 0) {
271 gtk_tree_selection_select_iter (selection
, &last_iter
);
276 mount_uri
= g_filename_to_uri (desktop_path
, NULL
, NULL
);
277 icon
= g_themed_icon_new (NAUTILUS_ICON_DESKTOP
);
278 last_iter
= add_place (sidebar
, PLACES_BUILT_IN
,
280 mount_uri
, NULL
, NULL
, NULL
, 0);
281 g_object_unref (icon
);
282 if (strcmp (location
, mount_uri
) == 0) {
283 gtk_tree_selection_select_iter (selection
, &last_iter
);
286 g_free (desktop_path
);
288 mount_uri
= "file:///"; /* No need to strdup */
289 icon
= g_themed_icon_new (NAUTILUS_ICON_FILESYSTEM
);
290 last_iter
= add_place (sidebar
, PLACES_BUILT_IN
,
291 _("File System"), icon
,
292 mount_uri
, NULL
, NULL
, NULL
, 0);
293 g_object_unref (icon
);
294 if (strcmp (location
, mount_uri
) == 0) {
295 gtk_tree_selection_select_iter (selection
, &last_iter
);
298 mount_uri
= "network:///"; /* No need to strdup */
299 icon
= g_themed_icon_new (NAUTILUS_ICON_NETWORK
);
300 last_iter
= add_place (sidebar
, PLACES_BUILT_IN
,
302 mount_uri
, NULL
, NULL
, NULL
, 0);
303 g_object_unref (icon
);
304 if (strcmp (location
, mount_uri
) == 0) {
305 gtk_tree_selection_select_iter (selection
, &last_iter
);
308 volume_monitor
= sidebar
->volume_monitor
;
310 /* first go through all connected drives */
311 drives
= g_volume_monitor_get_connected_drives (volume_monitor
);
312 for (l
= drives
; l
!= NULL
; l
= l
->next
) {
315 volumes
= g_drive_get_volumes (drive
);
316 if (volumes
!= NULL
) {
317 for (ll
= volumes
; ll
!= NULL
; ll
= ll
->next
) {
319 mount
= g_volume_get_mount (volume
);
321 /* Show mounted volume in the sidebar */
322 icon
= g_mount_get_icon (mount
);
323 root
= g_mount_get_root (mount
);
324 mount_uri
= g_file_get_uri (root
);
325 g_object_unref (root
);
326 name
= g_mount_get_name (mount
);
327 last_iter
= add_place (sidebar
, PLACES_MOUNTED_VOLUME
,
328 name
, icon
, mount_uri
,
329 drive
, volume
, mount
, 0);
330 if (strcmp (location
, mount_uri
) == 0) {
331 gtk_tree_selection_select_iter (selection
, &last_iter
);
333 g_object_unref (mount
);
334 g_object_unref (icon
);
338 /* Do show the unmounted volumes in the sidebar;
339 * this is so the user can mount it (in case automounting
342 * Also, even if automounting is enabled, this gives a visual
343 * cue that the user should remember to yank out the media if
344 * he just unmounted it.
346 icon
= g_volume_get_icon (volume
);
347 name
= g_volume_get_name (volume
);
348 last_iter
= add_place (sidebar
, PLACES_MOUNTED_VOLUME
,
350 drive
, volume
, NULL
, 0);
351 g_object_unref (icon
);
354 g_object_unref (volume
);
356 g_list_free (volumes
);
358 if (g_drive_is_media_removable (drive
) && !g_drive_is_media_check_automatic (drive
)) {
359 /* If the drive has no mountable volumes and we cannot detect media change.. we
360 * display the drive in the sidebar so the user can manually poll the drive by
361 * right clicking and selecting "Rescan..."
363 * This is mainly for drives like floppies where media detection doesn't
364 * work.. but it's also for human beings who like to turn off media detection
365 * in the OS to save battery juice.
367 icon
= g_drive_get_icon (drive
);
368 name
= g_drive_get_name (drive
);
369 last_iter
= add_place (sidebar
, PLACES_BUILT_IN
,
371 drive
, NULL
, NULL
, 0);
372 g_object_unref (icon
);
376 g_object_unref (drive
);
378 g_list_free (drives
);
380 /* add all volumes that is not associated with a drive */
381 volumes
= g_volume_monitor_get_volumes (volume_monitor
);
382 for (l
= volumes
; l
!= NULL
; l
= l
->next
) {
384 drive
= g_volume_get_drive (volume
);
386 g_object_unref (volume
);
387 g_object_unref (drive
);
390 mount
= g_volume_get_mount (volume
);
392 icon
= g_mount_get_icon (mount
);
393 root
= g_mount_get_root (mount
);
394 mount_uri
= g_file_get_uri (root
);
395 g_object_unref (root
);
396 name
= g_mount_get_name (mount
);
397 last_iter
= add_place (sidebar
, PLACES_MOUNTED_VOLUME
,
398 name
, icon
, mount_uri
,
399 NULL
, volume
, mount
, 0);
400 if (strcmp (location
, mount_uri
) == 0) {
401 gtk_tree_selection_select_iter (selection
, &last_iter
);
403 g_object_unref (mount
);
404 g_object_unref (icon
);
408 /* see comment above in why we add an icon for an unmounted mountable volume */
409 icon
= g_volume_get_icon (volume
);
410 name
= g_volume_get_name (volume
);
411 last_iter
= add_place (sidebar
, PLACES_MOUNTED_VOLUME
,
413 NULL
, volume
, NULL
, 0);
414 g_object_unref (icon
);
417 g_object_unref (volume
);
419 g_list_free (volumes
);
421 /* add mounts that has no volume (/etc/mtab mounts, ftp, sftp,...) */
422 mounts
= g_volume_monitor_get_mounts (volume_monitor
);
423 for (l
= mounts
; l
!= NULL
; l
= l
->next
) {
425 volume
= g_mount_get_volume (mount
);
426 if (volume
!= NULL
) {
427 g_object_unref (volume
);
428 g_object_unref (mount
);
431 icon
= g_mount_get_icon (mount
);
432 root
= g_mount_get_root (mount
);
433 mount_uri
= g_file_get_uri (root
);
434 g_object_unref (root
);
435 name
= g_mount_get_name (mount
);
436 last_iter
= add_place (sidebar
, PLACES_MOUNTED_VOLUME
,
437 name
, icon
, mount_uri
,
438 NULL
, NULL
, mount
, 0);
439 if (strcmp (location
, mount_uri
) == 0) {
440 gtk_tree_selection_select_iter (selection
, &last_iter
);
442 g_object_unref (mount
);
443 g_object_unref (icon
);
447 g_list_free (mounts
);
449 mount_uri
= "trash:///"; /* No need to strdup */
450 icon
= nautilus_trash_monitor_get_icon ();
451 last_iter
= add_place (sidebar
, PLACES_BUILT_IN
,
452 _("Trash"), icon
, mount_uri
,
453 NULL
, NULL
, NULL
, 0);
454 if (strcmp (location
, mount_uri
) == 0) {
455 gtk_tree_selection_select_iter (selection
, &last_iter
);
457 g_object_unref (icon
);
461 gtk_list_store_append (sidebar
->store
, &iter
);
462 gtk_list_store_set (sidebar
->store
, &iter
,
463 PLACES_SIDEBAR_COLUMN_ROW_TYPE
, PLACES_SEPARATOR
,
468 bookmark_count
= nautilus_bookmark_list_length (sidebar
->bookmarks
);
469 for (index
= 0; index
< bookmark_count
; ++index
) {
470 bookmark
= nautilus_bookmark_list_item_at (sidebar
->bookmarks
, index
);
472 if (nautilus_bookmark_uri_known_not_to_exist (bookmark
)) {
476 name
= nautilus_bookmark_get_name (bookmark
);
477 icon
= nautilus_bookmark_get_icon (bookmark
);
478 mount_uri
= nautilus_bookmark_get_uri (bookmark
);
479 last_iter
= add_place (sidebar
, PLACES_BOOKMARK
,
480 name
, icon
, mount_uri
,
481 NULL
, NULL
, NULL
, index
);
482 if (strcmp (location
, mount_uri
) == 0) {
483 gtk_tree_selection_select_iter (selection
, &last_iter
);
486 g_object_unref (icon
);
493 nautilus_shortcuts_row_separator_func (GtkTreeModel
*model
,
499 gtk_tree_model_get (model
, iter
, PLACES_SIDEBAR_COLUMN_ROW_TYPE
, &type
, -1);
501 if (type
== PLACES_SEPARATOR
) {
509 mount_added_callback (GVolumeMonitor
*volume_monitor
,
511 NautilusPlacesSidebar
*sidebar
)
513 update_places (sidebar
);
517 mount_removed_callback (GVolumeMonitor
*volume_monitor
,
519 NautilusPlacesSidebar
*sidebar
)
521 update_places (sidebar
);
525 mount_changed_callback (GVolumeMonitor
*volume_monitor
,
527 NautilusPlacesSidebar
*sidebar
)
529 update_places (sidebar
);
533 volume_added_callback (GVolumeMonitor
*volume_monitor
,
535 NautilusPlacesSidebar
*sidebar
)
537 update_places (sidebar
);
541 volume_removed_callback (GVolumeMonitor
*volume_monitor
,
543 NautilusPlacesSidebar
*sidebar
)
545 update_places (sidebar
);
549 volume_changed_callback (GVolumeMonitor
*volume_monitor
,
551 NautilusPlacesSidebar
*sidebar
)
553 update_places (sidebar
);
557 drive_disconnected_callback (GVolumeMonitor
*volume_monitor
,
559 NautilusPlacesSidebar
*sidebar
)
561 update_places (sidebar
);
565 drive_connected_callback (GVolumeMonitor
*volume_monitor
,
567 NautilusPlacesSidebar
*sidebar
)
569 update_places (sidebar
);
573 drive_changed_callback (GVolumeMonitor
*volume_monitor
,
575 NautilusPlacesSidebar
*sidebar
)
577 update_places (sidebar
);
581 row_activated_callback (GtkTreeView
*tree_view
,
583 GtkTreeViewColumn
*column
,
586 open_selected_bookmark (NAUTILUS_PLACES_SIDEBAR (user_data
),
587 gtk_tree_view_get_model (tree_view
),
593 update_click_policy (NautilusPlacesSidebar
*sidebar
)
597 policy
= eel_preferences_get_enum (NAUTILUS_PREFERENCES_CLICK_POLICY
);
599 eel_gtk_tree_view_set_activate_on_single_click
600 (sidebar
->tree_view
, policy
== NAUTILUS_CLICK_POLICY_SINGLE
);
604 click_policy_changed_callback (gpointer user_data
)
606 NautilusPlacesSidebar
*sidebar
;
608 sidebar
= NAUTILUS_PLACES_SIDEBAR (user_data
);
610 update_click_policy (sidebar
);
614 desktop_location_changed_callback (gpointer user_data
)
616 NautilusPlacesSidebar
*sidebar
;
618 sidebar
= NAUTILUS_PLACES_SIDEBAR (user_data
);
620 update_places (sidebar
);
624 loading_uri_callback (NautilusWindowInfo
*window
,
626 NautilusPlacesSidebar
*sidebar
)
628 GtkTreeSelection
*selection
;
633 if (strcmp (sidebar
->uri
, location
) != 0) {
634 g_free (sidebar
->uri
);
635 sidebar
->uri
= g_strdup (location
);
637 /* set selection if any place matches location */
638 selection
= gtk_tree_view_get_selection (sidebar
->tree_view
);
639 gtk_tree_selection_unselect_all (selection
);
640 valid
= gtk_tree_model_get_iter_first (sidebar
->filter_model
, &iter
);
643 gtk_tree_model_get (sidebar
->filter_model
, &iter
,
644 PLACES_SIDEBAR_COLUMN_URI
, &uri
,
647 if (strcmp (uri
, location
) == 0) {
649 gtk_tree_selection_select_iter (selection
, &iter
);
654 valid
= gtk_tree_model_iter_next (sidebar
->filter_model
, &iter
);
661 get_bookmark_index (GtkTreeView
*tree_view
)
666 PlaceType place_type
;
669 model
= gtk_tree_view_get_model (tree_view
);
674 p
= gtk_tree_path_new_first ();
676 gtk_tree_model_get_iter (model
, &iter
, p
);
677 gtk_tree_model_get (model
, &iter
,
678 PLACES_SIDEBAR_COLUMN_ROW_TYPE
, &place_type
,
681 if (place_type
== PLACES_SEPARATOR
) {
682 bookmark_index
= *gtk_tree_path_get_indices (p
) + 1;
686 gtk_tree_path_next (p
);
688 gtk_tree_path_free (p
);
690 g_assert (bookmark_index
>= 0);
692 return bookmark_index
;
695 /* Computes the appropriate row and position for dropping */
697 compute_drop_position (GtkTreeView
*tree_view
,
701 GtkTreeViewDropPosition
*pos
,
702 NautilusPlacesSidebar
*sidebar
)
708 bookmarks_index
= get_bookmark_index (tree_view
);
710 num_bookmarks
= nautilus_bookmark_list_length (sidebar
->bookmarks
);
712 if (!gtk_tree_view_get_dest_row_at_pos (tree_view
,
717 row
= bookmarks_index
+ num_bookmarks
- 1;
718 *path
= gtk_tree_path_new_from_indices (row
, -1);
719 *pos
= GTK_TREE_VIEW_DROP_AFTER
;
723 row
= *gtk_tree_path_get_indices (*path
);
724 gtk_tree_path_free (*path
);
726 if (row
< bookmarks_index
) {
727 /* Hardcoded shortcuts can only be dragged into */
728 *pos
= GTK_TREE_VIEW_DROP_INTO_OR_BEFORE
;
730 else if (row
> bookmarks_index
+ num_bookmarks
- 1) {
731 row
= bookmarks_index
+ num_bookmarks
- 1;
732 *pos
= GTK_TREE_VIEW_DROP_AFTER
;
735 *path
= gtk_tree_path_new_from_indices (row
, -1);
740 get_drag_data (GtkTreeView
*tree_view
,
741 GdkDragContext
*context
,
746 target
= gtk_drag_dest_find_target (GTK_WIDGET (tree_view
),
750 gtk_drag_get_data (GTK_WIDGET (tree_view
),
751 context
, target
, time
);
755 free_drag_data (NautilusPlacesSidebar
*sidebar
)
757 sidebar
->drag_data_received
= FALSE
;
759 if (sidebar
->drag_list
) {
760 nautilus_drag_destroy_selection_list (sidebar
->drag_list
);
761 sidebar
->drag_list
= NULL
;
766 can_accept_file_as_bookmark (NautilusFile
*file
)
768 return nautilus_file_is_directory (file
);
772 can_accept_items_as_bookmarks (const GList
*items
)
778 /* Iterate through selection checking if item will get accepted as a bookmark.
779 * If more than 100 items selected, return an over-optimistic result.
781 for (max
= 100; items
!= NULL
&& max
>= 0; items
= items
->next
, max
--) {
782 uri
= ((NautilusDragSelectionItem
*)items
->data
)->uri
;
783 file
= nautilus_file_get_by_uri (uri
);
784 if (!can_accept_file_as_bookmark (file
)) {
785 nautilus_file_unref (file
);
788 nautilus_file_unref (file
);
795 drag_data_delete_callback (GtkWidget
*widget
,
796 GdkDragContext
*context
,
797 NautilusPlacesSidebar
*sidebar
)
799 g_signal_stop_emission_by_name (widget
, "drag-data-delete");
803 drag_motion_callback (GtkTreeView
*tree_view
,
804 GdkDragContext
*context
,
808 NautilusPlacesSidebar
*sidebar
)
811 GtkTreeViewDropPosition pos
;
813 GtkTreeIter iter
, child_iter
;
816 if (!sidebar
->drag_data_received
) {
817 get_drag_data (tree_view
, context
, time
);
820 compute_drop_position (tree_view
, x
, y
, &path
, &pos
, sidebar
);
822 if (pos
== GTK_TREE_VIEW_DROP_BEFORE
||
823 pos
== GTK_TREE_VIEW_DROP_AFTER
) {
824 if (can_accept_items_as_bookmarks (sidebar
->drag_list
)) {
825 action
= GDK_ACTION_COPY
;
830 if (sidebar
->drag_list
== NULL
) {
833 gtk_tree_model_get_iter (sidebar
->filter_model
,
835 gtk_tree_model_filter_convert_iter_to_child_iter (
836 GTK_TREE_MODEL_FILTER (sidebar
->filter_model
),
838 gtk_tree_model_get (GTK_TREE_MODEL (sidebar
->store
),
840 PLACES_SIDEBAR_COLUMN_URI
, &uri
,
842 nautilus_drag_default_drop_action_for_icons (context
, uri
,
849 gtk_tree_view_set_drag_dest_row (tree_view
, path
, pos
);
850 gtk_tree_path_free (path
);
851 g_signal_stop_emission_by_name (tree_view
, "drag-motion");
854 gdk_drag_status (context
, action
, time
);
862 drag_leave_callback (GtkTreeView
*tree_view
,
863 GdkDragContext
*context
,
865 NautilusPlacesSidebar
*sidebar
)
867 free_drag_data (sidebar
);
868 gtk_tree_view_set_drag_dest_row (tree_view
, NULL
, GTK_TREE_VIEW_DROP_BEFORE
);
869 g_signal_stop_emission_by_name (tree_view
, "drag-leave");
872 /* Parses a "text/uri-list" string and inserts its URIs as bookmarks */
874 bookmarks_drop_uris (NautilusPlacesSidebar
*sidebar
,
875 GtkSelectionData
*selection_data
,
878 NautilusBookmark
*bookmark
;
886 uris
= gtk_selection_data_get_uris (selection_data
);
890 for (i
= 0; uris
[i
]; i
++) {
892 file
= nautilus_file_get_by_uri (uri
);
894 if (!can_accept_file_as_bookmark (file
)) {
895 nautilus_file_unref (file
);
899 uri
= nautilus_file_get_drop_target_uri (file
);
900 location
= g_file_new_for_uri (uri
);
901 nautilus_file_unref (file
);
903 name
= nautilus_compute_title_for_location (location
);
905 icon
= g_themed_icon_new (NAUTILUS_ICON_FOLDER
);
906 bookmark
= nautilus_bookmark_new_with_icon (location
, name
,
908 g_object_unref (icon
);
910 if (!nautilus_bookmark_list_contains (sidebar
->bookmarks
, bookmark
)) {
911 nautilus_bookmark_list_insert_item (sidebar
->bookmarks
, bookmark
, position
++);
914 g_object_unref (location
);
915 g_object_unref (bookmark
);
924 uri_list_from_selection (GList
*selection
)
926 NautilusDragSelectionItem
*item
;
931 for (l
= selection
; l
!= NULL
; l
= l
->next
) {
933 ret
= g_list_prepend (ret
, item
->uri
);
936 return g_list_reverse (ret
);
940 build_selection_list (const char *data
)
942 NautilusDragSelectionItem
*item
;
948 uris
= g_uri_list_extract_uris (data
);
951 for (i
= 0; uris
[i
]; i
++) {
953 item
= nautilus_drag_selection_item_new ();
954 item
->uri
= g_strdup (uri
);
955 item
->got_icon_position
= FALSE
;
956 result
= g_list_prepend (result
, item
);
961 return g_list_reverse (result
);
965 get_selected_iter (NautilusPlacesSidebar
*sidebar
,
968 GtkTreeSelection
*selection
;
969 GtkTreeIter parent_iter
;
971 selection
= gtk_tree_view_get_selection (sidebar
->tree_view
);
972 if (!gtk_tree_selection_get_selected (selection
, NULL
, &parent_iter
)) {
975 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (sidebar
->filter_model
),
981 /* Reorders the selected bookmark to the specified position */
983 reorder_bookmarks (NautilusPlacesSidebar
*sidebar
,
988 NautilusBookmark
*bookmark
;
992 /* Get the selected path */
994 if (!get_selected_iter (sidebar
, &iter
))
995 g_assert_not_reached ();
997 path
= gtk_tree_model_get_path (GTK_TREE_MODEL (sidebar
->store
), &iter
);
998 old_position
= *gtk_tree_path_get_indices (path
);
999 gtk_tree_path_free (path
);
1001 bookmarks_index
= get_bookmark_index (sidebar
->tree_view
);
1002 old_position
-= bookmarks_index
;
1003 if (old_position
< 0) {
1006 g_assert (old_position
< nautilus_bookmark_list_length (sidebar
->bookmarks
));
1008 /* Remove the path from the old position and insert it in the new one */
1010 if (old_position
== new_position
) {
1013 bookmark
= nautilus_bookmark_list_item_at (sidebar
->bookmarks
, old_position
);
1014 nautilus_bookmark_list_insert_item (sidebar
->bookmarks
, bookmark
, new_position
);
1015 if (old_position
> new_position
) {
1018 nautilus_bookmark_list_delete_item_at (sidebar
->bookmarks
, old_position
);
1022 drag_data_received_callback (GtkWidget
*widget
,
1023 GdkDragContext
*context
,
1026 GtkSelectionData
*selection_data
,
1029 NautilusPlacesSidebar
*sidebar
)
1031 GtkTreeView
*tree_view
;
1032 GtkTreePath
*tree_path
;
1033 GtkTreeViewDropPosition tree_pos
;
1035 int position
, bookmarks_index
;
1036 GtkTreeModel
*model
;
1038 GList
*selection_list
, *uris
;
1041 tree_view
= GTK_TREE_VIEW (widget
);
1043 if (!sidebar
->drag_data_received
) {
1044 if (selection_data
->target
!= GDK_NONE
&&
1045 info
== TEXT_URI_LIST
) {
1046 sidebar
->drag_list
= build_selection_list (selection_data
->data
);
1048 sidebar
->drag_list
= NULL
;
1050 sidebar
->drag_data_received
= TRUE
;
1053 g_signal_stop_emission_by_name (widget
, "drag-data-received");
1055 if (!sidebar
->drop_occured
) {
1059 /* Compute position */
1060 compute_drop_position (tree_view
, x
, y
, &tree_path
, &tree_pos
, sidebar
);
1064 if (tree_pos
== GTK_TREE_VIEW_DROP_BEFORE
||
1065 tree_pos
== GTK_TREE_VIEW_DROP_AFTER
) {
1066 /* bookmark addition requested */
1067 bookmarks_index
= get_bookmark_index (tree_view
);
1068 position
= *gtk_tree_path_get_indices (tree_path
);
1070 if (tree_pos
== GTK_TREE_VIEW_DROP_AFTER
) {
1074 g_assert (position
>= bookmarks_index
);
1075 position
-= bookmarks_index
;
1079 bookmarks_drop_uris (sidebar
, selection_data
, position
);
1082 case GTK_TREE_MODEL_ROW
:
1083 reorder_bookmarks (sidebar
, position
);
1087 g_assert_not_reached ();
1091 /* file transfer requested */
1092 if (context
->action
== GDK_ACTION_ASK
) {
1094 nautilus_drag_drop_action_ask (GTK_WIDGET (tree_view
),
1098 if (context
->action
> 0) {
1099 model
= gtk_tree_view_get_model (tree_view
);
1101 gtk_tree_model_get_iter (model
, &iter
, tree_path
);
1102 gtk_tree_model_get (model
, &iter
,
1103 PLACES_SIDEBAR_COLUMN_URI
, &drop_uri
,
1108 selection_list
= build_selection_list (selection_data
->data
);
1109 uris
= uri_list_from_selection (selection_list
);
1110 nautilus_file_operations_copy_move (uris
, NULL
, drop_uri
,
1111 context
->action
, GTK_WIDGET (tree_view
),
1113 nautilus_drag_destroy_selection_list (selection_list
);
1117 case GTK_TREE_MODEL_ROW
:
1121 g_assert_not_reached ();
1129 sidebar
->drop_occured
= FALSE
;
1130 free_drag_data (sidebar
);
1131 gtk_drag_finish (context
, success
, FALSE
, time
);
1133 gtk_tree_path_free (tree_path
);
1137 drag_drop_callback (GtkTreeView
*tree_view
,
1138 GdkDragContext
*context
,
1142 NautilusPlacesSidebar
*sidebar
)
1144 sidebar
->drop_occured
= TRUE
;
1145 get_drag_data (tree_view
, context
, time
);
1146 g_signal_stop_emission_by_name (tree_view
, "drag-drop");
1150 /* Callback used when the file list's popup menu is detached */
1152 bookmarks_popup_menu_detach_cb (GtkWidget
*attach_widget
,
1155 NautilusPlacesSidebar
*sidebar
;
1157 sidebar
= NAUTILUS_PLACES_SIDEBAR (attach_widget
);
1158 g_assert (NAUTILUS_IS_PLACES_SIDEBAR (sidebar
));
1160 sidebar
->popup_menu
= NULL
;
1161 sidebar
->popup_menu_remove_item
= NULL
;
1162 sidebar
->popup_menu_rename_item
= NULL
;
1163 sidebar
->popup_menu_separator_item
= NULL
;
1164 sidebar
->popup_menu_mount_item
= NULL
;
1165 sidebar
->popup_menu_unmount_item
= NULL
;
1166 sidebar
->popup_menu_eject_item
= NULL
;
1167 sidebar
->popup_menu_rescan_item
= NULL
;
1168 sidebar
->popup_menu_format_item
= NULL
;
1169 sidebar
->popup_menu_empty_trash_item
= NULL
;
1173 check_visibility (GMount
*mount
,
1176 gboolean
*show_mount
,
1177 gboolean
*show_unmount
,
1178 gboolean
*show_eject
,
1179 gboolean
*show_rescan
,
1180 gboolean
*show_format
)
1182 *show_mount
= FALSE
;
1183 *show_unmount
= FALSE
;
1184 *show_eject
= FALSE
;
1185 *show_format
= FALSE
;
1186 *show_rescan
= FALSE
;
1188 if (drive
!= NULL
) {
1189 *show_eject
= g_drive_can_eject (drive
);
1191 if (g_drive_is_media_removable (drive
) &&
1192 !g_drive_is_media_check_automatic (drive
) &&
1193 g_drive_can_poll_for_media (drive
))
1194 *show_rescan
= TRUE
;
1197 if (volume
!= NULL
) {
1198 *show_eject
|= g_volume_can_eject (volume
);
1200 *show_mount
= g_volume_can_mount (volume
);
1203 if (mount
!= NULL
) {
1204 *show_unmount
= g_mount_can_unmount (mount
);
1205 *show_eject
|= g_mount_can_eject (mount
);
1210 g_find_program_in_path ("gfloppy")) {
1211 *show_format
= TRUE
;
1217 bookmarks_check_popup_sensitivity (NautilusPlacesSidebar
*sidebar
)
1221 GDrive
*drive
= NULL
;
1222 GVolume
*volume
= NULL
;
1223 GMount
*mount
= NULL
;
1224 gboolean show_mount
;
1225 gboolean show_unmount
;
1226 gboolean show_eject
;
1227 gboolean show_rescan
;
1228 gboolean show_format
;
1229 gboolean show_empty_trash
;
1232 type
= PLACES_BUILT_IN
;
1234 if (sidebar
->popup_menu
== NULL
) {
1238 if (get_selected_iter (sidebar
, &iter
)) {
1239 gtk_tree_model_get (GTK_TREE_MODEL (sidebar
->store
), &iter
,
1240 PLACES_SIDEBAR_COLUMN_ROW_TYPE
, &type
,
1241 PLACES_SIDEBAR_COLUMN_DRIVE
, &drive
,
1242 PLACES_SIDEBAR_COLUMN_VOLUME
, &volume
,
1243 PLACES_SIDEBAR_COLUMN_MOUNT
, &mount
,
1244 PLACES_SIDEBAR_COLUMN_URI
, &uri
,
1248 gtk_widget_set_sensitive (sidebar
->popup_menu_remove_item
, (type
== PLACES_BOOKMARK
));
1249 gtk_widget_set_sensitive (sidebar
->popup_menu_rename_item
, (type
== PLACES_BOOKMARK
));
1250 gtk_widget_set_sensitive (sidebar
->popup_menu_empty_trash_item
, !nautilus_trash_monitor_is_empty ());
1252 check_visibility (mount
, volume
, drive
,
1253 &show_mount
, &show_unmount
, &show_eject
, &show_rescan
, &show_format
);
1255 /* We actually want both eject and unmount since eject will unmount all volumes.
1256 * TODO: hide unmount if the drive only has a single mountable volume
1259 show_empty_trash
= (uri
!= NULL
) &&
1260 (!strcmp (uri
, "trash:///"));
1262 eel_gtk_widget_set_shown (sidebar
->popup_menu_separator_item
,
1263 show_mount
|| show_unmount
|| show_eject
|| show_format
|| show_empty_trash
);
1264 eel_gtk_widget_set_shown (sidebar
->popup_menu_mount_item
, show_mount
);
1265 eel_gtk_widget_set_shown (sidebar
->popup_menu_unmount_item
, show_unmount
);
1266 eel_gtk_widget_set_shown (sidebar
->popup_menu_eject_item
, show_eject
);
1267 eel_gtk_widget_set_shown (sidebar
->popup_menu_rescan_item
, show_rescan
);
1268 eel_gtk_widget_set_shown (sidebar
->popup_menu_format_item
, show_format
);
1269 eel_gtk_widget_set_shown (sidebar
->popup_menu_empty_trash_item
, show_empty_trash
);
1274 /* Callback used when the selection in the shortcuts tree changes */
1276 bookmarks_selection_changed_cb (GtkTreeSelection
*selection
,
1277 NautilusPlacesSidebar
*sidebar
)
1279 bookmarks_check_popup_sensitivity (sidebar
);
1283 open_selected_bookmark (NautilusPlacesSidebar
*sidebar
,
1284 GtkTreeModel
*model
,
1286 gboolean open_in_new_window
)
1296 if (!gtk_tree_model_get_iter (model
, &iter
, path
)) {
1300 gtk_tree_model_get (model
, &iter
, PLACES_SIDEBAR_COLUMN_URI
, &uri
, -1);
1303 nautilus_debug_log (FALSE
, NAUTILUS_DEBUG_LOG_DOMAIN_USER
,
1304 "activate from places sidebar window=%p: %s",
1305 sidebar
->window
, uri
);
1306 location
= g_file_new_for_uri (uri
);
1307 /* Navigate to the clicked location */
1308 if (!open_in_new_window
) {
1309 nautilus_window_info_open_location (sidebar
->window
, location
,
1310 NAUTILUS_WINDOW_OPEN_ACCORDING_TO_MODE
,
1313 NautilusWindow
*cur
, *new;
1315 cur
= NAUTILUS_WINDOW (sidebar
->window
);
1316 new = nautilus_application_create_navigation_window (cur
->application
,
1318 gtk_window_get_screen (GTK_WINDOW (cur
)));
1319 nautilus_window_go_to (new, location
);
1321 g_object_unref (location
);
1326 gtk_tree_model_get (model
, &iter
, PLACES_SIDEBAR_COLUMN_VOLUME
, &volume
, -1);
1327 if (volume
!= NULL
) {
1328 nautilus_inhibit_autorun_for_volume (volume
);
1329 nautilus_file_operations_mount_volume (NULL
, volume
);
1330 g_object_unref (volume
);
1336 open_shortcut_from_menu (NautilusPlacesSidebar
*sidebar
,
1337 gboolean open_in_new_window
)
1339 GtkTreeModel
*model
;
1342 model
= gtk_tree_view_get_model (sidebar
->tree_view
);
1343 gtk_tree_view_get_cursor (sidebar
->tree_view
, &path
, NULL
);
1345 open_selected_bookmark (sidebar
, model
, path
, open_in_new_window
);
1347 gtk_tree_path_free (path
);
1351 open_shortcut_cb (GtkMenuItem
*item
,
1352 NautilusPlacesSidebar
*sidebar
)
1354 open_shortcut_from_menu (sidebar
, FALSE
);
1358 open_shortcut_in_new_window_cb (GtkMenuItem
*item
,
1359 NautilusPlacesSidebar
*sidebar
)
1361 open_shortcut_from_menu (sidebar
, TRUE
);
1364 /* Rename the selected bookmark */
1366 rename_selected_bookmark (NautilusPlacesSidebar
*sidebar
)
1370 GtkTreeViewColumn
*column
;
1371 GtkCellRenderer
*cell
;
1374 if (get_selected_iter (sidebar
, &iter
)) {
1375 path
= gtk_tree_model_get_path (GTK_TREE_MODEL (sidebar
->store
), &iter
);
1376 column
= gtk_tree_view_get_column (GTK_TREE_VIEW (sidebar
->tree_view
), 0);
1377 renderers
= gtk_tree_view_column_get_cell_renderers (column
);
1378 cell
= g_list_nth_data (renderers
, 1);
1379 g_list_free (renderers
);
1380 g_object_set (cell
, "editable", TRUE
, NULL
);
1381 gtk_tree_view_set_cursor_on_cell (GTK_TREE_VIEW (sidebar
->tree_view
),
1382 path
, column
, cell
, TRUE
);
1383 gtk_tree_path_free (path
);
1388 rename_shortcut_cb (GtkMenuItem
*item
,
1389 NautilusPlacesSidebar
*sidebar
)
1391 rename_selected_bookmark (sidebar
);
1394 /* Removes the selected bookmarks */
1396 remove_selected_bookmarks (NautilusPlacesSidebar
*sidebar
)
1402 if (!get_selected_iter (sidebar
, &iter
)) {
1406 gtk_tree_model_get (GTK_TREE_MODEL (sidebar
->store
), &iter
,
1407 PLACES_SIDEBAR_COLUMN_ROW_TYPE
, &type
,
1410 if (type
!= PLACES_BOOKMARK
) {
1414 gtk_tree_model_get (GTK_TREE_MODEL (sidebar
->store
), &iter
,
1415 PLACES_SIDEBAR_COLUMN_INDEX
, &index
,
1418 nautilus_bookmark_list_delete_item_at (sidebar
->bookmarks
, index
);
1422 remove_shortcut_cb (GtkMenuItem
*item
,
1423 NautilusPlacesSidebar
*sidebar
)
1425 remove_selected_bookmarks (sidebar
);
1429 mount_shortcut_cb (GtkMenuItem
*item
,
1430 NautilusPlacesSidebar
*sidebar
)
1435 if (!get_selected_iter (sidebar
, &iter
)) {
1439 gtk_tree_model_get (GTK_TREE_MODEL (sidebar
->store
), &iter
,
1440 PLACES_SIDEBAR_COLUMN_VOLUME
, &volume
,
1443 if (volume
!= NULL
) {
1444 nautilus_inhibit_autorun_for_volume (volume
);
1445 nautilus_file_operations_mount_volume (NULL
, volume
);
1446 g_object_unref (volume
);
1451 unmount_shortcut_cb (GtkMenuItem
*item
,
1452 NautilusPlacesSidebar
*sidebar
)
1458 if (!get_selected_iter (sidebar
, &iter
)) {
1462 gtk_tree_model_get (GTK_TREE_MODEL (sidebar
->store
), &iter
,
1463 PLACES_SIDEBAR_COLUMN_VOLUME
, &volume
,
1464 PLACES_SIDEBAR_COLUMN_MOUNT
, &mount
,
1467 if (mount
!= NULL
) {
1468 GtkWidget
*toplevel
;
1470 toplevel
= gtk_widget_get_toplevel (GTK_WIDGET (sidebar
->tree_view
));
1471 nautilus_file_operations_unmount_mount (GTK_WINDOW (toplevel
),
1472 mount
, FALSE
, TRUE
);
1474 if (mount
!= NULL
) {
1475 g_object_unref (mount
);
1477 if (volume
!= NULL
) {
1478 g_object_unref (volume
);
1483 drive_eject_cb (GObject
*source_object
,
1491 if (!g_drive_eject_finish (G_DRIVE (source_object
), res
, &error
)) {
1492 if (error
->code
!= G_IO_ERROR_FAILED_HANDLED
) {
1493 name
= g_drive_get_name (G_DRIVE (source_object
));
1494 primary
= g_strdup_printf (_("Unable to eject %s"), name
);
1496 eel_show_error_dialog (primary
,
1501 g_error_free (error
);
1506 volume_eject_cb (GObject
*source_object
,
1514 if (!g_volume_eject_finish (G_VOLUME (source_object
), res
, &error
)) {
1515 if (error
->code
!= G_IO_ERROR_FAILED_HANDLED
) {
1516 name
= g_volume_get_name (G_VOLUME (source_object
));
1517 primary
= g_strdup_printf (_("Unable to eject %s"), name
);
1519 eel_show_error_dialog (primary
,
1524 g_error_free (error
);
1529 mount_eject_cb (GObject
*source_object
,
1537 if (!g_mount_eject_finish (G_MOUNT (source_object
), res
, &error
)) {
1538 if (error
->code
!= G_IO_ERROR_FAILED_HANDLED
) {
1539 name
= g_mount_get_name (G_MOUNT (source_object
));
1540 primary
= g_strdup_printf (_("Unable to eject %s"), name
);
1542 eel_show_error_dialog (primary
,
1547 g_error_free (error
);
1552 eject_shortcut_cb (GtkMenuItem
*item
,
1553 NautilusPlacesSidebar
*sidebar
)
1560 if (!get_selected_iter (sidebar
, &iter
)) {
1564 gtk_tree_model_get (GTK_TREE_MODEL (sidebar
->store
), &iter
,
1565 PLACES_SIDEBAR_COLUMN_MOUNT
, &mount
,
1566 PLACES_SIDEBAR_COLUMN_VOLUME
, &volume
,
1567 PLACES_SIDEBAR_COLUMN_DRIVE
, &drive
,
1570 if (mount
!= NULL
) {
1571 g_mount_eject (mount
, 0, NULL
, mount_eject_cb
, NULL
);
1572 } else if (volume
!= NULL
) {
1573 g_volume_eject (volume
, 0, NULL
, volume_eject_cb
, NULL
);
1574 } else if (drive
!= NULL
) {
1575 g_drive_eject (drive
, 0, NULL
, drive_eject_cb
, NULL
);
1579 g_object_unref (mount
);
1581 g_object_unref (volume
);
1583 g_object_unref (drive
);
1587 drive_poll_for_media_cb (GObject
*source_object
,
1596 if (!g_drive_poll_for_media_finish (G_DRIVE (source_object
), res
, &error
)) {
1597 if (error
->code
!= G_IO_ERROR_FAILED_HANDLED
) {
1598 name
= g_drive_get_name (G_DRIVE (source_object
));
1599 primary
= g_strdup_printf (_("Unable to poll %s for media changes"), name
);
1601 eel_show_error_dialog (primary
,
1606 g_error_free (error
);
1611 rescan_shortcut_cb (GtkMenuItem
*item
,
1612 NautilusPlacesSidebar
*sidebar
)
1617 if (!get_selected_iter (sidebar
, &iter
)) {
1621 gtk_tree_model_get (GTK_TREE_MODEL (sidebar
->store
), &iter
,
1622 PLACES_SIDEBAR_COLUMN_DRIVE
, &drive
,
1625 if (drive
!= NULL
) {
1626 g_drive_poll_for_media (drive
, NULL
, drive_poll_for_media_cb
, NULL
);
1628 g_object_unref (drive
);
1632 format_shortcut_cb (GtkMenuItem
*item
,
1633 NautilusPlacesSidebar
*sidebar
)
1635 g_spawn_command_line_async ("gfloppy", NULL
);
1639 empty_trash_cb (GtkMenuItem
*item
,
1640 NautilusPlacesSidebar
*sidebar
)
1642 nautilus_file_operations_empty_trash (GTK_WIDGET (sidebar
->window
));
1645 /* Handler for GtkWidget::key-press-event on the shortcuts list */
1647 bookmarks_key_press_event_cb (GtkWidget
*widget
,
1649 NautilusPlacesSidebar
*sidebar
)
1653 modifiers
= gtk_accelerator_get_default_mod_mask ();
1655 if ((event
->keyval
== GDK_BackSpace
1656 || event
->keyval
== GDK_Delete
1657 || event
->keyval
== GDK_KP_Delete
)
1658 && (event
->state
& modifiers
) == 0) {
1659 remove_selected_bookmarks (sidebar
);
1663 if ((event
->keyval
== GDK_F2
)
1664 && (event
->state
& modifiers
) == 0) {
1665 rename_selected_bookmark (sidebar
);
1672 /* Constructs the popup menu for the file list if needed */
1674 bookmarks_build_popup_menu (NautilusPlacesSidebar
*sidebar
)
1678 if (sidebar
->popup_menu
) {
1682 sidebar
->popup_menu
= gtk_menu_new ();
1683 gtk_menu_attach_to_widget (GTK_MENU (sidebar
->popup_menu
),
1684 GTK_WIDGET (sidebar
),
1685 bookmarks_popup_menu_detach_cb
);
1687 item
= gtk_image_menu_item_new_with_mnemonic (_("_Open"));
1688 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item
),
1689 gtk_image_new_from_stock (GTK_STOCK_OPEN
, GTK_ICON_SIZE_MENU
));
1690 g_signal_connect (item
, "activate",
1691 G_CALLBACK (open_shortcut_cb
), sidebar
);
1692 gtk_widget_show (item
);
1693 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar
->popup_menu
), item
);
1695 item
= gtk_menu_item_new_with_mnemonic (_("Open in New _Window"));
1696 g_signal_connect (item
, "activate",
1697 G_CALLBACK (open_shortcut_in_new_window_cb
), sidebar
);
1698 gtk_widget_show (item
);
1699 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar
->popup_menu
), item
);
1701 item
= gtk_image_menu_item_new_with_label (_("Remove"));
1702 sidebar
->popup_menu_remove_item
= item
;
1703 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item
),
1704 gtk_image_new_from_stock (GTK_STOCK_REMOVE
, GTK_ICON_SIZE_MENU
));
1705 g_signal_connect (item
, "activate",
1706 G_CALLBACK (remove_shortcut_cb
), sidebar
);
1707 gtk_widget_show (item
);
1708 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar
->popup_menu
), item
);
1710 item
= gtk_menu_item_new_with_label (_("Rename..."));
1711 sidebar
->popup_menu_rename_item
= item
;
1712 g_signal_connect (item
, "activate",
1713 G_CALLBACK (rename_shortcut_cb
), sidebar
);
1714 gtk_widget_show (item
);
1715 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar
->popup_menu
), item
);
1717 /* Mount/Unmount/Eject menu items */
1719 sidebar
->popup_menu_separator_item
=
1720 GTK_WIDGET (eel_gtk_menu_append_separator (GTK_MENU (sidebar
->popup_menu
)));
1722 item
= gtk_menu_item_new_with_mnemonic (_("_Mount"));
1723 sidebar
->popup_menu_mount_item
= item
;
1724 g_signal_connect (item
, "activate",
1725 G_CALLBACK (mount_shortcut_cb
), sidebar
);
1726 gtk_widget_show (item
);
1727 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar
->popup_menu
), item
);
1729 item
= gtk_menu_item_new_with_mnemonic (_("_Unmount"));
1730 sidebar
->popup_menu_unmount_item
= item
;
1731 g_signal_connect (item
, "activate",
1732 G_CALLBACK (unmount_shortcut_cb
), sidebar
);
1733 gtk_widget_show (item
);
1734 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar
->popup_menu
), item
);
1736 item
= gtk_menu_item_new_with_mnemonic (_("_Eject"));
1737 sidebar
->popup_menu_eject_item
= item
;
1738 g_signal_connect (item
, "activate",
1739 G_CALLBACK (eject_shortcut_cb
), sidebar
);
1740 gtk_widget_show (item
);
1741 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar
->popup_menu
), item
);
1743 item
= gtk_menu_item_new_with_mnemonic (_("_Rescan"));
1744 sidebar
->popup_menu_rescan_item
= item
;
1745 g_signal_connect (item
, "activate",
1746 G_CALLBACK (rescan_shortcut_cb
), sidebar
);
1747 gtk_widget_show (item
);
1748 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar
->popup_menu
), item
);
1750 item
= gtk_menu_item_new_with_mnemonic (_("_Format"));
1751 sidebar
->popup_menu_format_item
= item
;
1752 g_signal_connect (item
, "activate",
1753 G_CALLBACK (format_shortcut_cb
), sidebar
);
1754 gtk_widget_show (item
);
1755 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar
->popup_menu
), item
);
1757 /* Empty Trash menu item */
1759 item
= gtk_menu_item_new_with_mnemonic (_("Empty _Trash"));
1760 sidebar
->popup_menu_empty_trash_item
= item
;
1761 g_signal_connect (item
, "activate",
1762 G_CALLBACK (empty_trash_cb
), sidebar
);
1763 gtk_widget_show (item
);
1764 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar
->popup_menu
), item
);
1766 bookmarks_check_popup_sensitivity (sidebar
);
1770 bookmarks_update_popup_menu (NautilusPlacesSidebar
*sidebar
)
1772 bookmarks_build_popup_menu (sidebar
);
1776 bookmarks_popup_menu (NautilusPlacesSidebar
*sidebar
,
1777 GdkEventButton
*event
)
1779 bookmarks_update_popup_menu (sidebar
);
1780 eel_pop_up_context_menu (GTK_MENU(sidebar
->popup_menu
),
1781 EEL_DEFAULT_POPUP_MENU_DISPLACEMENT
,
1782 EEL_DEFAULT_POPUP_MENU_DISPLACEMENT
,
1786 /* Callback used for the GtkWidget::popup-menu signal of the shortcuts list */
1788 bookmarks_popup_menu_cb (GtkWidget
*widget
,
1789 NautilusPlacesSidebar
*sidebar
)
1791 bookmarks_popup_menu (sidebar
, NULL
);
1795 /* Callback used when a button is pressed on the shortcuts list.
1796 * We trap button 3 to bring up a popup menu.
1799 bookmarks_button_press_event_cb (GtkWidget
*widget
,
1800 GdkEventButton
*event
,
1801 NautilusPlacesSidebar
*sidebar
)
1803 if (event
->button
== 3) {
1804 bookmarks_popup_menu (sidebar
, event
);
1811 bookmarks_edited (GtkCellRenderer
*cell
,
1814 NautilusPlacesSidebar
*sidebar
)
1818 NautilusBookmark
*bookmark
;
1821 g_object_set (cell
, "editable", FALSE
, NULL
);
1823 path
= gtk_tree_path_new_from_string (path_string
);
1824 gtk_tree_model_get_iter (GTK_TREE_MODEL (sidebar
->store
), &iter
, path
);
1825 gtk_tree_model_get (GTK_TREE_MODEL (sidebar
->store
), &iter
,
1826 PLACES_SIDEBAR_COLUMN_INDEX
, &index
,
1828 gtk_tree_path_free (path
);
1829 bookmark
= nautilus_bookmark_list_item_at (sidebar
->bookmarks
, index
);
1831 if (bookmark
!= NULL
) {
1832 nautilus_bookmark_set_has_custom_name (bookmark
, TRUE
);
1833 nautilus_bookmark_set_name (bookmark
, new_text
);
1838 bookmarks_editing_canceled (GtkCellRenderer
*cell
,
1839 NautilusPlacesSidebar
*sidebar
)
1841 g_object_set (cell
, "editable", FALSE
, NULL
);
1845 trash_state_changed_cb (NautilusTrashMonitor
*trash_monitor
,
1849 NautilusPlacesSidebar
*sidebar
;
1851 sidebar
= NAUTILUS_PLACES_SIDEBAR (data
);
1853 /* The trash icon changed, update the sidebar */
1854 update_places (sidebar
);
1856 bookmarks_check_popup_sensitivity (sidebar
);
1860 nautilus_places_sidebar_init (NautilusPlacesSidebar
*sidebar
)
1862 GtkTreeView
*tree_view
;
1863 GtkTreeViewColumn
*col
;
1864 GtkCellRenderer
*cell
;
1865 GtkTreeSelection
*selection
;
1867 sidebar
->volume_monitor
= g_volume_monitor_get ();
1869 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sidebar
),
1871 GTK_POLICY_AUTOMATIC
);
1872 gtk_scrolled_window_set_hadjustment (GTK_SCROLLED_WINDOW (sidebar
), NULL
);
1873 gtk_scrolled_window_set_vadjustment (GTK_SCROLLED_WINDOW (sidebar
), NULL
);
1876 tree_view
= GTK_TREE_VIEW (gtk_tree_view_new ());
1877 gtk_tree_view_set_headers_visible (tree_view
, FALSE
);
1879 col
= GTK_TREE_VIEW_COLUMN (gtk_tree_view_column_new ());
1881 cell
= gtk_cell_renderer_pixbuf_new ();
1882 gtk_tree_view_column_pack_start (col
, cell
, FALSE
);
1883 gtk_tree_view_column_set_attributes (col
, cell
,
1884 "pixbuf", PLACES_SIDEBAR_COLUMN_ICON
,
1887 cell
= gtk_cell_renderer_text_new ();
1888 gtk_tree_view_column_pack_start (col
, cell
, TRUE
);
1889 gtk_tree_view_column_set_attributes (col
, cell
,
1890 "text", PLACES_SIDEBAR_COLUMN_NAME
,
1893 g_signal_connect (cell
, "edited",
1894 G_CALLBACK (bookmarks_edited
), sidebar
);
1895 g_signal_connect (cell
, "editing-canceled",
1896 G_CALLBACK (bookmarks_editing_canceled
), sidebar
);
1898 gtk_tree_view_set_row_separator_func (tree_view
,
1899 nautilus_shortcuts_row_separator_func
,
1903 gtk_tree_view_column_set_fixed_width (col
, NAUTILUS_ICON_SIZE_SMALLER
);
1904 gtk_tree_view_append_column (tree_view
, col
);
1906 sidebar
->store
= gtk_list_store_new (PLACES_SIDEBAR_COLUMN_COUNT
,
1916 sidebar
->filter_model
= nautilus_shortcuts_model_filter_new (sidebar
,
1917 GTK_TREE_MODEL (sidebar
->store
),
1920 gtk_tree_view_set_model (tree_view
, sidebar
->filter_model
);
1921 gtk_container_add (GTK_CONTAINER (sidebar
), GTK_WIDGET (tree_view
));
1922 gtk_widget_show (GTK_WIDGET (tree_view
));
1924 gtk_widget_show (GTK_WIDGET (sidebar
));
1925 sidebar
->tree_view
= tree_view
;
1927 selection
= gtk_tree_view_get_selection (tree_view
);
1928 gtk_tree_selection_set_mode (selection
, GTK_SELECTION_BROWSE
);
1930 g_signal_connect_object
1931 (tree_view
, "row_activated",
1932 G_CALLBACK (row_activated_callback
), sidebar
, 0);
1935 gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (tree_view
),
1937 nautilus_shortcuts_source_targets
,
1938 G_N_ELEMENTS (nautilus_shortcuts_source_targets
),
1940 gtk_drag_dest_set (GTK_WIDGET (tree_view
),
1942 nautilus_shortcuts_drop_targets
, G_N_ELEMENTS (nautilus_shortcuts_drop_targets
),
1943 GDK_ACTION_MOVE
| GDK_ACTION_COPY
| GDK_ACTION_LINK
);
1945 g_signal_connect (tree_view
, "key-press-event",
1946 G_CALLBACK (bookmarks_key_press_event_cb
), sidebar
);
1948 g_signal_connect (tree_view
, "drag-data-delete",
1949 G_CALLBACK (drag_data_delete_callback
), sidebar
);
1950 g_signal_connect (tree_view
, "drag-motion",
1951 G_CALLBACK (drag_motion_callback
), sidebar
);
1952 g_signal_connect (tree_view
, "drag-leave",
1953 G_CALLBACK (drag_leave_callback
), sidebar
);
1954 g_signal_connect (tree_view
, "drag-data-received",
1955 G_CALLBACK (drag_data_received_callback
), sidebar
);
1956 g_signal_connect (tree_view
, "drag-drop",
1957 G_CALLBACK (drag_drop_callback
), sidebar
);
1958 g_signal_connect (selection
, "changed",
1959 G_CALLBACK (bookmarks_selection_changed_cb
), sidebar
);
1960 g_signal_connect (tree_view
, "popup-menu",
1961 G_CALLBACK (bookmarks_popup_menu_cb
), sidebar
);
1962 g_signal_connect (tree_view
, "button-press-event",
1963 G_CALLBACK (bookmarks_button_press_event_cb
), sidebar
);
1965 eel_preferences_add_callback (NAUTILUS_PREFERENCES_CLICK_POLICY
,
1966 click_policy_changed_callback
,
1968 update_click_policy (sidebar
);
1970 eel_preferences_add_callback_while_alive (NAUTILUS_PREFERENCES_DESKTOP_IS_HOME_DIR
,
1971 desktop_location_changed_callback
,
1973 G_OBJECT (sidebar
));
1975 g_signal_connect_object (nautilus_trash_monitor_get (),
1976 "trash_state_changed",
1977 G_CALLBACK (trash_state_changed_cb
),
1982 nautilus_places_sidebar_finalize (GObject
*object
)
1984 NautilusPlacesSidebar
*sidebar
;
1986 sidebar
= NAUTILUS_PLACES_SIDEBAR (object
);
1988 g_free (sidebar
->uri
);
1989 sidebar
->uri
= NULL
;
1991 free_drag_data (sidebar
);
1993 if (sidebar
->store
!= NULL
) {
1994 g_object_unref (sidebar
->store
);
1995 sidebar
->store
= NULL
;
1998 g_object_unref (sidebar
->volume_monitor
);
2000 eel_preferences_remove_callback (NAUTILUS_PREFERENCES_CLICK_POLICY
,
2001 click_policy_changed_callback
,
2004 G_OBJECT_CLASS (nautilus_places_sidebar_parent_class
)->finalize (object
);
2008 nautilus_places_sidebar_class_init (NautilusPlacesSidebarClass
*class)
2010 G_OBJECT_CLASS (class)->finalize
= nautilus_places_sidebar_finalize
;
2012 GTK_WIDGET_CLASS (class)->style_set
= nautilus_places_sidebar_style_set
;
2016 nautilus_places_sidebar_get_sidebar_id (NautilusSidebar
*sidebar
)
2018 return NAUTILUS_PLACES_SIDEBAR_ID
;
2022 nautilus_places_sidebar_get_tab_label (NautilusSidebar
*sidebar
)
2024 return g_strdup (_("Places"));
2028 nautilus_places_sidebar_get_tab_tooltip (NautilusSidebar
*sidebar
)
2030 return g_strdup (_("Show Places"));
2034 nautilus_places_sidebar_get_tab_icon (NautilusSidebar
*sidebar
)
2040 nautilus_places_sidebar_is_visible_changed (NautilusSidebar
*sidebar
,
2041 gboolean is_visible
)
2047 nautilus_places_sidebar_iface_init (NautilusSidebarIface
*iface
)
2049 iface
->get_sidebar_id
= nautilus_places_sidebar_get_sidebar_id
;
2050 iface
->get_tab_label
= nautilus_places_sidebar_get_tab_label
;
2051 iface
->get_tab_tooltip
= nautilus_places_sidebar_get_tab_tooltip
;
2052 iface
->get_tab_icon
= nautilus_places_sidebar_get_tab_icon
;
2053 iface
->is_visible_changed
= nautilus_places_sidebar_is_visible_changed
;
2057 nautilus_places_sidebar_set_parent_window (NautilusPlacesSidebar
*sidebar
,
2058 NautilusWindowInfo
*window
)
2060 sidebar
->window
= window
;
2062 sidebar
->bookmarks
= nautilus_window_info_get_bookmark_list (window
);
2063 sidebar
->uri
= nautilus_window_info_get_current_location (window
);
2065 g_signal_connect_object (sidebar
->bookmarks
, "contents_changed",
2066 G_CALLBACK (update_places
),
2067 sidebar
, G_CONNECT_SWAPPED
);
2069 g_signal_connect_object (window
, "loading_uri",
2070 G_CALLBACK (loading_uri_callback
),
2073 g_signal_connect_object (sidebar
->volume_monitor
, "volume_added",
2074 G_CALLBACK (volume_added_callback
), sidebar
, 0);
2075 g_signal_connect_object (sidebar
->volume_monitor
, "volume_removed",
2076 G_CALLBACK (volume_removed_callback
), sidebar
, 0);
2077 g_signal_connect_object (sidebar
->volume_monitor
, "volume_changed",
2078 G_CALLBACK (volume_changed_callback
), sidebar
, 0);
2079 g_signal_connect_object (sidebar
->volume_monitor
, "mount_added",
2080 G_CALLBACK (mount_added_callback
), sidebar
, 0);
2081 g_signal_connect_object (sidebar
->volume_monitor
, "mount_removed",
2082 G_CALLBACK (mount_removed_callback
), sidebar
, 0);
2083 g_signal_connect_object (sidebar
->volume_monitor
, "mount_changed",
2084 G_CALLBACK (mount_changed_callback
), sidebar
, 0);
2085 g_signal_connect_object (sidebar
->volume_monitor
, "drive_disconnected",
2086 G_CALLBACK (drive_disconnected_callback
), sidebar
, 0);
2087 g_signal_connect_object (sidebar
->volume_monitor
, "drive_connected",
2088 G_CALLBACK (drive_connected_callback
), sidebar
, 0);
2089 g_signal_connect_object (sidebar
->volume_monitor
, "drive_changed",
2090 G_CALLBACK (drive_changed_callback
), sidebar
, 0);
2092 update_places (sidebar
);
2096 nautilus_places_sidebar_style_set (GtkWidget
*widget
,
2097 GtkStyle
*previous_style
)
2099 NautilusPlacesSidebar
*sidebar
;
2101 sidebar
= NAUTILUS_PLACES_SIDEBAR (widget
);
2103 update_places (sidebar
);
2106 static NautilusSidebar
*
2107 nautilus_places_sidebar_create (NautilusSidebarProvider
*provider
,
2108 NautilusWindowInfo
*window
)
2110 NautilusPlacesSidebar
*sidebar
;
2112 sidebar
= g_object_new (nautilus_places_sidebar_get_type (), NULL
);
2113 nautilus_places_sidebar_set_parent_window (sidebar
, window
);
2114 g_object_ref (sidebar
);
2115 gtk_object_sink (GTK_OBJECT (sidebar
));
2117 return NAUTILUS_SIDEBAR (sidebar
);
2121 sidebar_provider_iface_init (NautilusSidebarProviderIface
*iface
)
2123 iface
->create
= nautilus_places_sidebar_create
;
2127 nautilus_places_sidebar_provider_init (NautilusPlacesSidebarProvider
*sidebar
)
2132 nautilus_places_sidebar_provider_class_init (NautilusPlacesSidebarProviderClass
*class)
2137 nautilus_places_sidebar_register (void)
2139 nautilus_module_add_type (nautilus_places_sidebar_provider_get_type ());
2142 /* Drag and drop interfaces */
2145 _nautilus_shortcuts_model_filter_class_init (NautilusShortcutsModelFilterClass
*class)
2150 _nautilus_shortcuts_model_filter_init (NautilusShortcutsModelFilter
*model
)
2152 model
->sidebar
= NULL
;
2155 /* GtkTreeDragSource::row_draggable implementation for the shortcuts filter model */
2157 nautilus_shortcuts_model_filter_row_draggable (GtkTreeDragSource
*drag_source
,
2160 NautilusShortcutsModelFilter
*model
;
2165 model
= NAUTILUS_SHORTCUTS_MODEL_FILTER (drag_source
);
2167 pos
= *gtk_tree_path_get_indices (path
);
2168 bookmarks_pos
= get_bookmark_index (model
->sidebar
->tree_view
);
2169 num_bookmarks
= nautilus_bookmark_list_length (model
->sidebar
->bookmarks
);
2171 return (pos
>= bookmarks_pos
&& pos
< bookmarks_pos
+ num_bookmarks
);
2174 /* GtkTreeDragSource::drag_data_get implementation for the shortcuts filter model */
2176 nautilus_shortcuts_model_filter_drag_data_get (GtkTreeDragSource
*drag_source
,
2178 GtkSelectionData
*selection_data
)
2180 NautilusShortcutsModelFilter
*model
;
2182 model
= NAUTILUS_SHORTCUTS_MODEL_FILTER (drag_source
);
2189 /* Fill the GtkTreeDragSourceIface vtable */
2191 nautilus_shortcuts_model_filter_drag_source_iface_init (GtkTreeDragSourceIface
*iface
)
2193 iface
->row_draggable
= nautilus_shortcuts_model_filter_row_draggable
;
2194 iface
->drag_data_get
= nautilus_shortcuts_model_filter_drag_data_get
;
2197 static GtkTreeModel
*
2198 nautilus_shortcuts_model_filter_new (NautilusPlacesSidebar
*sidebar
,
2199 GtkTreeModel
*child_model
,
2202 NautilusShortcutsModelFilter
*model
;
2204 model
= g_object_new (NAUTILUS_SHORTCUTS_MODEL_FILTER_TYPE
,
2205 "child-model", child_model
,
2206 "virtual-root", root
,
2209 model
->sidebar
= sidebar
;
2211 return GTK_TREE_MODEL (model
);