2008-03-29 Cosimo Cecchi <cosimoc@gnome.org>
[nautilus.git] / src / nautilus-places-sidebar.c
blobcd326457d3c4207d2f72cb6a78bc923eb50c5257
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
3 /*
4 * Nautilus
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)
24 #include <config.h>
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>
60 #include <gio/gio.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))
70 typedef struct {
71 GtkScrolledWindow parent;
72 GtkTreeView *tree_view;
73 char *uri;
74 GtkListStore *store;
75 GtkTreeModel *filter_model;
76 NautilusWindowInfo *window;
77 NautilusBookmarkList *bookmarks;
78 GVolumeMonitor *volume_monitor;
80 /* DnD */
81 GList *drag_list;
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;
97 typedef struct {
98 GtkScrolledWindowClass parent;
99 } NautilusPlacesSidebarClass;
101 typedef struct {
102 GObject parent;
103 } NautilusPlacesSidebarProvider;
105 typedef struct {
106 GObjectClass parent;
107 } NautilusPlacesSidebarProviderClass;
109 enum {
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
122 typedef enum {
123 PLACES_BUILT_IN,
124 PLACES_MOUNTED_VOLUME,
125 PLACES_BOOKMARK,
126 PLACES_SEPARATOR
127 } PlaceType;
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,
133 GtkTreeModel *model,
134 GtkTreePath *path,
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 */
140 enum {
141 GTK_TREE_MODEL_ROW,
142 TEXT_URI_LIST
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 */
157 typedef struct {
158 GtkTreeModelFilter parent;
160 NautilusPlacesSidebar *sidebar;
161 } NautilusShortcutsModelFilter;
163 typedef struct {
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,
181 GtkTreePath *root);
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));
191 static GtkTreeIter
192 add_place (NautilusPlacesSidebar *sidebar,
193 PlaceType place_type,
194 const char *name,
195 GIcon *icon,
196 const char *uri,
197 GDrive *drive,
198 GVolume *volume,
199 GMount *mount,
200 const int index)
202 GdkPixbuf *pixbuf;
203 GtkTreeIter iter, child_iter;
204 NautilusIconInfo *icon_info;
205 int icon_size;
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,
222 -1);
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),
228 &child_iter,
229 &iter);
230 return child_iter;
233 static void
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;
241 GMount *mount;
242 GList *drives;
243 GDrive *drive;
244 GList *volumes;
245 GVolume *volume;
246 int bookmark_count, index;
247 char *location, *mount_uri, *name, *desktop_path;
248 GIcon *icon;
249 GFile *root;
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) {
260 char *display_name;
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,
266 display_name, icon,
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);
273 g_free (mount_uri);
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,
279 _("Desktop"), icon,
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);
285 g_free (mount_uri);
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,
301 _("Network"), icon,
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) {
313 drive = l->data;
315 volumes = g_drive_get_volumes (drive);
316 if (volumes != NULL) {
317 for (ll = volumes; ll != NULL; ll = ll->next) {
318 volume = ll->data;
319 mount = g_volume_get_mount (volume);
320 if (mount != NULL) {
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);
335 g_free (name);
336 g_free (mount_uri);
337 } else {
338 /* Do show the unmounted volumes in the sidebar;
339 * this is so the user can mount it (in case automounting
340 * is off).
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,
349 name, icon, NULL,
350 drive, volume, NULL, 0);
351 g_object_unref (icon);
352 g_free (name);
354 g_object_unref (volume);
356 g_list_free (volumes);
357 } else {
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,
370 name, icon, NULL,
371 drive, NULL, NULL, 0);
372 g_object_unref (icon);
373 g_free (name);
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) {
383 volume = l->data;
384 drive = g_volume_get_drive (volume);
385 if (drive != NULL) {
386 g_object_unref (volume);
387 g_object_unref (drive);
388 continue;
390 mount = g_volume_get_mount (volume);
391 if (mount != NULL) {
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);
405 g_free (name);
406 g_free (mount_uri);
407 } else {
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,
412 name, icon, NULL,
413 NULL, volume, NULL, 0);
414 g_object_unref (icon);
415 g_free (name);
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) {
424 mount = l->data;
425 volume = g_mount_get_volume (mount);
426 if (volume != NULL) {
427 g_object_unref (volume);
428 g_object_unref (mount);
429 continue;
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);
444 g_free (name);
445 g_free (mount_uri);
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);
459 /* add separator */
461 gtk_list_store_append (sidebar->store, &iter);
462 gtk_list_store_set (sidebar->store, &iter,
463 PLACES_SIDEBAR_COLUMN_ROW_TYPE, PLACES_SEPARATOR,
464 -1);
466 /* add bookmarks */
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)) {
473 continue;
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);
485 g_free (name);
486 g_object_unref (icon);
487 g_free (mount_uri);
489 g_free (location);
492 static gboolean
493 nautilus_shortcuts_row_separator_func (GtkTreeModel *model,
494 GtkTreeIter *iter,
495 gpointer data)
497 PlaceType type;
499 gtk_tree_model_get (model, iter, PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type, -1);
501 if (type == PLACES_SEPARATOR) {
502 return TRUE;
505 return FALSE;
508 static void
509 mount_added_callback (GVolumeMonitor *volume_monitor,
510 GMount *mount,
511 NautilusPlacesSidebar *sidebar)
513 update_places (sidebar);
516 static void
517 mount_removed_callback (GVolumeMonitor *volume_monitor,
518 GMount *mount,
519 NautilusPlacesSidebar *sidebar)
521 update_places (sidebar);
524 static void
525 mount_changed_callback (GVolumeMonitor *volume_monitor,
526 GMount *mount,
527 NautilusPlacesSidebar *sidebar)
529 update_places (sidebar);
532 static void
533 volume_added_callback (GVolumeMonitor *volume_monitor,
534 GVolume *volume,
535 NautilusPlacesSidebar *sidebar)
537 update_places (sidebar);
540 static void
541 volume_removed_callback (GVolumeMonitor *volume_monitor,
542 GVolume *volume,
543 NautilusPlacesSidebar *sidebar)
545 update_places (sidebar);
548 static void
549 volume_changed_callback (GVolumeMonitor *volume_monitor,
550 GVolume *volume,
551 NautilusPlacesSidebar *sidebar)
553 update_places (sidebar);
556 static void
557 drive_disconnected_callback (GVolumeMonitor *volume_monitor,
558 GDrive *drive,
559 NautilusPlacesSidebar *sidebar)
561 update_places (sidebar);
564 static void
565 drive_connected_callback (GVolumeMonitor *volume_monitor,
566 GDrive *drive,
567 NautilusPlacesSidebar *sidebar)
569 update_places (sidebar);
572 static void
573 drive_changed_callback (GVolumeMonitor *volume_monitor,
574 GDrive *drive,
575 NautilusPlacesSidebar *sidebar)
577 update_places (sidebar);
580 static void
581 row_activated_callback (GtkTreeView *tree_view,
582 GtkTreePath *path,
583 GtkTreeViewColumn *column,
584 gpointer user_data)
586 open_selected_bookmark (NAUTILUS_PLACES_SIDEBAR (user_data),
587 gtk_tree_view_get_model (tree_view),
588 path,
589 FALSE);
592 static void
593 update_click_policy (NautilusPlacesSidebar *sidebar)
595 int policy;
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);
603 static void
604 click_policy_changed_callback (gpointer user_data)
606 NautilusPlacesSidebar *sidebar;
608 sidebar = NAUTILUS_PLACES_SIDEBAR (user_data);
610 update_click_policy (sidebar);
613 static void
614 desktop_location_changed_callback (gpointer user_data)
616 NautilusPlacesSidebar *sidebar;
618 sidebar = NAUTILUS_PLACES_SIDEBAR (user_data);
620 update_places (sidebar);
623 static void
624 loading_uri_callback (NautilusWindowInfo *window,
625 char *location,
626 NautilusPlacesSidebar *sidebar)
628 GtkTreeSelection *selection;
629 GtkTreeIter iter;
630 gboolean valid;
631 char *uri;
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);
642 while (valid) {
643 gtk_tree_model_get (sidebar->filter_model, &iter,
644 PLACES_SIDEBAR_COLUMN_URI, &uri,
645 -1);
646 if (uri != NULL) {
647 if (strcmp (uri, location) == 0) {
648 g_free (uri);
649 gtk_tree_selection_select_iter (selection, &iter);
650 break;
652 g_free (uri);
654 valid = gtk_tree_model_iter_next (sidebar->filter_model, &iter);
660 static unsigned int
661 get_bookmark_index (GtkTreeView *tree_view)
663 GtkTreeModel *model;
664 GtkTreePath *p;
665 GtkTreeIter iter;
666 PlaceType place_type;
667 int bookmark_index;
669 model = gtk_tree_view_get_model (tree_view);
671 bookmark_index = -1;
673 /* find separator */
674 p = gtk_tree_path_new_first ();
675 while (p != NULL) {
676 gtk_tree_model_get_iter (model, &iter, p);
677 gtk_tree_model_get (model, &iter,
678 PLACES_SIDEBAR_COLUMN_ROW_TYPE, &place_type,
679 -1);
681 if (place_type == PLACES_SEPARATOR) {
682 bookmark_index = *gtk_tree_path_get_indices (p) + 1;
683 break;
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 */
696 static void
697 compute_drop_position (GtkTreeView *tree_view,
698 int x,
699 int y,
700 GtkTreePath **path,
701 GtkTreeViewDropPosition *pos,
702 NautilusPlacesSidebar *sidebar)
704 int bookmarks_index;
705 int num_bookmarks;
706 int row;
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,
715 path,
716 pos)) {
717 row = bookmarks_index + num_bookmarks - 1;
718 *path = gtk_tree_path_new_from_indices (row, -1);
719 *pos = GTK_TREE_VIEW_DROP_AFTER;
720 return;
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);
739 static void
740 get_drag_data (GtkTreeView *tree_view,
741 GdkDragContext *context,
742 unsigned int time)
744 GdkAtom target;
746 target = gtk_drag_dest_find_target (GTK_WIDGET (tree_view),
747 context,
748 NULL);
750 gtk_drag_get_data (GTK_WIDGET (tree_view),
751 context, target, time);
754 static void
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;
765 static gboolean
766 can_accept_file_as_bookmark (NautilusFile *file)
768 return nautilus_file_is_directory (file);
771 static gboolean
772 can_accept_items_as_bookmarks (const GList *items)
774 int max;
775 char *uri;
776 NautilusFile *file;
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);
786 return FALSE;
788 nautilus_file_unref (file);
791 return TRUE;
794 static void
795 drag_data_delete_callback (GtkWidget *widget,
796 GdkDragContext *context,
797 NautilusPlacesSidebar *sidebar)
799 g_signal_stop_emission_by_name (widget, "drag-data-delete");
802 static gboolean
803 drag_motion_callback (GtkTreeView *tree_view,
804 GdkDragContext *context,
805 int x,
806 int y,
807 unsigned int time,
808 NautilusPlacesSidebar *sidebar)
810 GtkTreePath *path;
811 GtkTreeViewDropPosition pos;
812 int action;
813 GtkTreeIter iter, child_iter;
814 char *uri;
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;
826 } else {
827 action = 0;
829 } else {
830 if (sidebar->drag_list == NULL) {
831 action = 0;
832 } else {
833 gtk_tree_model_get_iter (sidebar->filter_model,
834 &iter, path);
835 gtk_tree_model_filter_convert_iter_to_child_iter (
836 GTK_TREE_MODEL_FILTER (sidebar->filter_model),
837 &child_iter, &iter);
838 gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store),
839 &child_iter,
840 PLACES_SIDEBAR_COLUMN_URI, &uri,
841 -1);
842 nautilus_drag_default_drop_action_for_icons (context, uri,
843 sidebar->drag_list,
844 &action);
845 g_free (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");
853 if (action != 0) {
854 gdk_drag_status (context, action, time);
855 return TRUE;
856 } else {
857 return FALSE;
861 static void
862 drag_leave_callback (GtkTreeView *tree_view,
863 GdkDragContext *context,
864 unsigned int time,
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 */
873 static void
874 bookmarks_drop_uris (NautilusPlacesSidebar *sidebar,
875 GtkSelectionData *selection_data,
876 int position)
878 NautilusBookmark *bookmark;
879 NautilusFile *file;
880 char *uri, *name;
881 char **uris;
882 int i;
883 GFile *location;
884 GIcon *icon;
886 uris = gtk_selection_data_get_uris (selection_data);
887 if (!uris)
888 return;
890 for (i = 0; uris[i]; i++) {
891 uri = uris[i];
892 file = nautilus_file_get_by_uri (uri);
894 if (!can_accept_file_as_bookmark (file)) {
895 nautilus_file_unref (file);
896 continue;
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,
907 FALSE, icon);
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);
916 g_free (name);
917 g_free (uri);
920 g_strfreev (uris);
923 static GList *
924 uri_list_from_selection (GList *selection)
926 NautilusDragSelectionItem *item;
927 GList *ret;
928 GList *l;
930 ret = NULL;
931 for (l = selection; l != NULL; l = l->next) {
932 item = l->data;
933 ret = g_list_prepend (ret, item->uri);
936 return g_list_reverse (ret);
939 static GList*
940 build_selection_list (const char *data)
942 NautilusDragSelectionItem *item;
943 GList *result;
944 char **uris;
945 char *uri;
946 int i;
948 uris = g_uri_list_extract_uris (data);
950 result = NULL;
951 for (i = 0; uris[i]; i++) {
952 uri = uris[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);
959 g_strfreev (uris);
961 return g_list_reverse (result);
964 static gboolean
965 get_selected_iter (NautilusPlacesSidebar *sidebar,
966 GtkTreeIter *iter)
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)) {
973 return FALSE;
975 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (sidebar->filter_model),
976 iter,
977 &parent_iter);
978 return TRUE;
981 /* Reorders the selected bookmark to the specified position */
982 static void
983 reorder_bookmarks (NautilusPlacesSidebar *sidebar,
984 int new_position)
986 GtkTreeIter iter;
987 GtkTreePath *path;
988 NautilusBookmark *bookmark;
989 int old_position;
990 int bookmarks_index;
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) {
1004 return;
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) {
1011 return;
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) {
1016 old_position++;
1018 nautilus_bookmark_list_delete_item_at (sidebar->bookmarks, old_position);
1021 static void
1022 drag_data_received_callback (GtkWidget *widget,
1023 GdkDragContext *context,
1024 int x,
1025 int y,
1026 GtkSelectionData *selection_data,
1027 unsigned int info,
1028 unsigned int time,
1029 NautilusPlacesSidebar *sidebar)
1031 GtkTreeView *tree_view;
1032 GtkTreePath *tree_path;
1033 GtkTreeViewDropPosition tree_pos;
1034 GtkTreeIter iter;
1035 int position, bookmarks_index;
1036 GtkTreeModel *model;
1037 char *drop_uri;
1038 GList *selection_list, *uris;
1039 gboolean success;
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);
1047 } else {
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) {
1056 return;
1059 /* Compute position */
1060 compute_drop_position (tree_view, x, y, &tree_path, &tree_pos, sidebar);
1062 success = FALSE;
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) {
1071 position++;
1074 g_assert (position >= bookmarks_index);
1075 position -= bookmarks_index;
1077 switch (info) {
1078 case TEXT_URI_LIST:
1079 bookmarks_drop_uris (sidebar, selection_data, position);
1080 success = TRUE;
1081 break;
1082 case GTK_TREE_MODEL_ROW:
1083 reorder_bookmarks (sidebar, position);
1084 success = TRUE;
1085 break;
1086 default:
1087 g_assert_not_reached ();
1088 break;
1090 } else {
1091 /* file transfer requested */
1092 if (context->action == GDK_ACTION_ASK) {
1093 context->action =
1094 nautilus_drag_drop_action_ask (GTK_WIDGET (tree_view),
1095 context->actions);
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,
1104 -1);
1106 switch (info) {
1107 case TEXT_URI_LIST:
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),
1112 NULL, NULL);
1113 nautilus_drag_destroy_selection_list (selection_list);
1114 g_list_free (uris);
1115 success = TRUE;
1116 break;
1117 case GTK_TREE_MODEL_ROW:
1118 success = FALSE;
1119 break;
1120 default:
1121 g_assert_not_reached ();
1122 break;
1125 g_free (drop_uri);
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);
1136 static gboolean
1137 drag_drop_callback (GtkTreeView *tree_view,
1138 GdkDragContext *context,
1139 int x,
1140 int y,
1141 unsigned int time,
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");
1147 return TRUE;
1150 /* Callback used when the file list's popup menu is detached */
1151 static void
1152 bookmarks_popup_menu_detach_cb (GtkWidget *attach_widget,
1153 GtkMenu *menu)
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;
1172 static void
1173 check_visibility (GMount *mount,
1174 GVolume *volume,
1175 GDrive *drive,
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);
1199 if (mount == NULL)
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);
1208 #ifdef TODO_GIO
1209 if (something &&
1210 g_find_program_in_path ("gfloppy")) {
1211 *show_format = TRUE;
1213 #endif
1216 static void
1217 bookmarks_check_popup_sensitivity (NautilusPlacesSidebar *sidebar)
1219 GtkTreeIter iter;
1220 PlaceType type;
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;
1230 char *uri = NULL;
1232 type = PLACES_BUILT_IN;
1234 if (sidebar->popup_menu == NULL) {
1235 return;
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,
1245 -1);
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);
1271 g_free (uri);
1274 /* Callback used when the selection in the shortcuts tree changes */
1275 static void
1276 bookmarks_selection_changed_cb (GtkTreeSelection *selection,
1277 NautilusPlacesSidebar *sidebar)
1279 bookmarks_check_popup_sensitivity (sidebar);
1282 static void
1283 open_selected_bookmark (NautilusPlacesSidebar *sidebar,
1284 GtkTreeModel *model,
1285 GtkTreePath *path,
1286 gboolean open_in_new_window)
1288 GtkTreeIter iter;
1289 GFile *location;
1290 char *uri;
1292 if (!path) {
1293 return;
1296 if (!gtk_tree_model_get_iter (model, &iter, path)) {
1297 return;
1300 gtk_tree_model_get (model, &iter, PLACES_SIDEBAR_COLUMN_URI, &uri, -1);
1302 if (uri != NULL) {
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,
1311 0, NULL);
1312 } else {
1313 NautilusWindow *cur, *new;
1315 cur = NAUTILUS_WINDOW (sidebar->window);
1316 new = nautilus_application_create_navigation_window (cur->application,
1317 NULL,
1318 gtk_window_get_screen (GTK_WINDOW (cur)));
1319 nautilus_window_go_to (new, location);
1321 g_object_unref (location);
1322 g_free (uri);
1324 } else {
1325 GVolume *volume;
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);
1335 static void
1336 open_shortcut_from_menu (NautilusPlacesSidebar *sidebar,
1337 gboolean open_in_new_window)
1339 GtkTreeModel *model;
1340 GtkTreePath *path;
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);
1350 static void
1351 open_shortcut_cb (GtkMenuItem *item,
1352 NautilusPlacesSidebar *sidebar)
1354 open_shortcut_from_menu (sidebar, FALSE);
1357 static void
1358 open_shortcut_in_new_window_cb (GtkMenuItem *item,
1359 NautilusPlacesSidebar *sidebar)
1361 open_shortcut_from_menu (sidebar, TRUE);
1364 /* Rename the selected bookmark */
1365 static void
1366 rename_selected_bookmark (NautilusPlacesSidebar *sidebar)
1368 GtkTreeIter iter;
1369 GtkTreePath *path;
1370 GtkTreeViewColumn *column;
1371 GtkCellRenderer *cell;
1372 GList *renderers;
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);
1387 static void
1388 rename_shortcut_cb (GtkMenuItem *item,
1389 NautilusPlacesSidebar *sidebar)
1391 rename_selected_bookmark (sidebar);
1394 /* Removes the selected bookmarks */
1395 static void
1396 remove_selected_bookmarks (NautilusPlacesSidebar *sidebar)
1398 GtkTreeIter iter;
1399 PlaceType type;
1400 int index;
1402 if (!get_selected_iter (sidebar, &iter)) {
1403 return;
1406 gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
1407 PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type,
1408 -1);
1410 if (type != PLACES_BOOKMARK) {
1411 return;
1414 gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
1415 PLACES_SIDEBAR_COLUMN_INDEX, &index,
1416 -1);
1418 nautilus_bookmark_list_delete_item_at (sidebar->bookmarks, index);
1421 static void
1422 remove_shortcut_cb (GtkMenuItem *item,
1423 NautilusPlacesSidebar *sidebar)
1425 remove_selected_bookmarks (sidebar);
1428 static void
1429 mount_shortcut_cb (GtkMenuItem *item,
1430 NautilusPlacesSidebar *sidebar)
1432 GtkTreeIter iter;
1433 GVolume *volume;
1435 if (!get_selected_iter (sidebar, &iter)) {
1436 return;
1439 gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
1440 PLACES_SIDEBAR_COLUMN_VOLUME, &volume,
1441 -1);
1443 if (volume != NULL) {
1444 nautilus_inhibit_autorun_for_volume (volume);
1445 nautilus_file_operations_mount_volume (NULL, volume);
1446 g_object_unref (volume);
1450 static void
1451 unmount_shortcut_cb (GtkMenuItem *item,
1452 NautilusPlacesSidebar *sidebar)
1454 GtkTreeIter iter;
1455 GMount *mount;
1456 GVolume *volume;
1458 if (!get_selected_iter (sidebar, &iter)) {
1459 return;
1462 gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
1463 PLACES_SIDEBAR_COLUMN_VOLUME, &volume,
1464 PLACES_SIDEBAR_COLUMN_MOUNT, &mount,
1465 -1);
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);
1482 static void
1483 drive_eject_cb (GObject *source_object,
1484 GAsyncResult *res,
1485 gpointer user_data)
1487 GError *error;
1488 char *primary;
1489 char *name;
1490 error = NULL;
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);
1495 g_free (name);
1496 eel_show_error_dialog (primary,
1497 error->message,
1498 NULL);
1499 g_free (primary);
1501 g_error_free (error);
1505 static void
1506 volume_eject_cb (GObject *source_object,
1507 GAsyncResult *res,
1508 gpointer user_data)
1510 GError *error;
1511 char *primary;
1512 char *name;
1513 error = NULL;
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);
1518 g_free (name);
1519 eel_show_error_dialog (primary,
1520 error->message,
1521 NULL);
1522 g_free (primary);
1524 g_error_free (error);
1528 static void
1529 mount_eject_cb (GObject *source_object,
1530 GAsyncResult *res,
1531 gpointer user_data)
1533 GError *error;
1534 char *primary;
1535 char *name;
1536 error = NULL;
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);
1541 g_free (name);
1542 eel_show_error_dialog (primary,
1543 error->message,
1544 NULL);
1545 g_free (primary);
1547 g_error_free (error);
1551 static void
1552 eject_shortcut_cb (GtkMenuItem *item,
1553 NautilusPlacesSidebar *sidebar)
1555 GtkTreeIter iter;
1556 GMount *mount;
1557 GVolume *volume;
1558 GDrive *drive;
1560 if (!get_selected_iter (sidebar, &iter)) {
1561 return;
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,
1568 -1);
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);
1578 if (mount != NULL)
1579 g_object_unref (mount);
1580 if (volume != NULL)
1581 g_object_unref (volume);
1582 if (drive != NULL)
1583 g_object_unref (drive);
1586 static void
1587 drive_poll_for_media_cb (GObject *source_object,
1588 GAsyncResult *res,
1589 gpointer user_data)
1591 GError *error;
1592 char *primary;
1593 char *name;
1595 error = NULL;
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);
1600 g_free (name);
1601 eel_show_error_dialog (primary,
1602 error->message,
1603 NULL);
1604 g_free (primary);
1606 g_error_free (error);
1610 static void
1611 rescan_shortcut_cb (GtkMenuItem *item,
1612 NautilusPlacesSidebar *sidebar)
1614 GtkTreeIter iter;
1615 GDrive *drive;
1617 if (!get_selected_iter (sidebar, &iter)) {
1618 return;
1621 gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
1622 PLACES_SIDEBAR_COLUMN_DRIVE, &drive,
1623 -1);
1625 if (drive != NULL) {
1626 g_drive_poll_for_media (drive, NULL, drive_poll_for_media_cb, NULL);
1628 g_object_unref (drive);
1631 static void
1632 format_shortcut_cb (GtkMenuItem *item,
1633 NautilusPlacesSidebar *sidebar)
1635 g_spawn_command_line_async ("gfloppy", NULL);
1638 static void
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 */
1646 static gboolean
1647 bookmarks_key_press_event_cb (GtkWidget *widget,
1648 GdkEventKey *event,
1649 NautilusPlacesSidebar *sidebar)
1651 guint modifiers;
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);
1660 return TRUE;
1663 if ((event->keyval == GDK_F2)
1664 && (event->state & modifiers) == 0) {
1665 rename_selected_bookmark (sidebar);
1666 return TRUE;
1669 return FALSE;
1672 /* Constructs the popup menu for the file list if needed */
1673 static void
1674 bookmarks_build_popup_menu (NautilusPlacesSidebar *sidebar)
1676 GtkWidget *item;
1678 if (sidebar->popup_menu) {
1679 return;
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);
1769 static void
1770 bookmarks_update_popup_menu (NautilusPlacesSidebar *sidebar)
1772 bookmarks_build_popup_menu (sidebar);
1775 static void
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,
1783 event);
1786 /* Callback used for the GtkWidget::popup-menu signal of the shortcuts list */
1787 static gboolean
1788 bookmarks_popup_menu_cb (GtkWidget *widget,
1789 NautilusPlacesSidebar *sidebar)
1791 bookmarks_popup_menu (sidebar, NULL);
1792 return TRUE;
1795 /* Callback used when a button is pressed on the shortcuts list.
1796 * We trap button 3 to bring up a popup menu.
1798 static gboolean
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);
1806 return FALSE;
1810 static void
1811 bookmarks_edited (GtkCellRenderer *cell,
1812 gchar *path_string,
1813 gchar *new_text,
1814 NautilusPlacesSidebar *sidebar)
1816 GtkTreePath *path;
1817 GtkTreeIter iter;
1818 NautilusBookmark *bookmark;
1819 int index;
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,
1827 -1);
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);
1837 static void
1838 bookmarks_editing_canceled (GtkCellRenderer *cell,
1839 NautilusPlacesSidebar *sidebar)
1841 g_object_set (cell, "editable", FALSE, NULL);
1844 static void
1845 trash_state_changed_cb (NautilusTrashMonitor *trash_monitor,
1846 gboolean state,
1847 gpointer data)
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);
1859 static void
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),
1870 GTK_POLICY_NEVER,
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);
1875 /* tree view */
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,
1885 NULL);
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,
1891 NULL);
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,
1900 NULL,
1901 NULL);
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,
1907 G_TYPE_INT,
1908 G_TYPE_STRING,
1909 G_TYPE_DRIVE,
1910 G_TYPE_VOLUME,
1911 G_TYPE_MOUNT,
1912 G_TYPE_STRING,
1913 GDK_TYPE_PIXBUF,
1914 G_TYPE_INT
1916 sidebar->filter_model = nautilus_shortcuts_model_filter_new (sidebar,
1917 GTK_TREE_MODEL (sidebar->store),
1918 NULL);
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),
1936 GDK_BUTTON1_MASK,
1937 nautilus_shortcuts_source_targets,
1938 G_N_ELEMENTS (nautilus_shortcuts_source_targets),
1939 GDK_ACTION_MOVE);
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,
1967 sidebar);
1968 update_click_policy (sidebar);
1970 eel_preferences_add_callback_while_alive (NAUTILUS_PREFERENCES_DESKTOP_IS_HOME_DIR,
1971 desktop_location_changed_callback,
1972 sidebar,
1973 G_OBJECT (sidebar));
1975 g_signal_connect_object (nautilus_trash_monitor_get (),
1976 "trash_state_changed",
1977 G_CALLBACK (trash_state_changed_cb),
1978 sidebar, 0);
1981 static void
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,
2002 sidebar);
2004 G_OBJECT_CLASS (nautilus_places_sidebar_parent_class)->finalize (object);
2007 static void
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;
2015 static const char *
2016 nautilus_places_sidebar_get_sidebar_id (NautilusSidebar *sidebar)
2018 return NAUTILUS_PLACES_SIDEBAR_ID;
2021 static char *
2022 nautilus_places_sidebar_get_tab_label (NautilusSidebar *sidebar)
2024 return g_strdup (_("Places"));
2027 static char *
2028 nautilus_places_sidebar_get_tab_tooltip (NautilusSidebar *sidebar)
2030 return g_strdup (_("Show Places"));
2033 static GdkPixbuf *
2034 nautilus_places_sidebar_get_tab_icon (NautilusSidebar *sidebar)
2036 return NULL;
2039 static void
2040 nautilus_places_sidebar_is_visible_changed (NautilusSidebar *sidebar,
2041 gboolean is_visible)
2043 /* Do nothing */
2046 static void
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;
2056 static void
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),
2071 sidebar, 0);
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);
2095 static void
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);
2120 static void
2121 sidebar_provider_iface_init (NautilusSidebarProviderIface *iface)
2123 iface->create = nautilus_places_sidebar_create;
2126 static void
2127 nautilus_places_sidebar_provider_init (NautilusPlacesSidebarProvider *sidebar)
2131 static void
2132 nautilus_places_sidebar_provider_class_init (NautilusPlacesSidebarProviderClass *class)
2136 void
2137 nautilus_places_sidebar_register (void)
2139 nautilus_module_add_type (nautilus_places_sidebar_provider_get_type ());
2142 /* Drag and drop interfaces */
2144 static void
2145 _nautilus_shortcuts_model_filter_class_init (NautilusShortcutsModelFilterClass *class)
2149 static void
2150 _nautilus_shortcuts_model_filter_init (NautilusShortcutsModelFilter *model)
2152 model->sidebar = NULL;
2155 /* GtkTreeDragSource::row_draggable implementation for the shortcuts filter model */
2156 static gboolean
2157 nautilus_shortcuts_model_filter_row_draggable (GtkTreeDragSource *drag_source,
2158 GtkTreePath *path)
2160 NautilusShortcutsModelFilter *model;
2161 int pos;
2162 int bookmarks_pos;
2163 int num_bookmarks;
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 */
2175 static gboolean
2176 nautilus_shortcuts_model_filter_drag_data_get (GtkTreeDragSource *drag_source,
2177 GtkTreePath *path,
2178 GtkSelectionData *selection_data)
2180 NautilusShortcutsModelFilter *model;
2182 model = NAUTILUS_SHORTCUTS_MODEL_FILTER (drag_source);
2184 /* FIXME */
2186 return FALSE;
2189 /* Fill the GtkTreeDragSourceIface vtable */
2190 static void
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,
2200 GtkTreePath *root)
2202 NautilusShortcutsModelFilter *model;
2204 model = g_object_new (NAUTILUS_SHORTCUTS_MODEL_FILTER_TYPE,
2205 "child-model", child_model,
2206 "virtual-root", root,
2207 NULL);
2209 model->sidebar = sidebar;
2211 return GTK_TREE_MODEL (model);