nautilus-3.6.3/src/nautilus-places-sidebar.c

Location Tool Test ID Function Issue
nautilus-places-sidebar.c:1232:0 cppcheck uninitvar Uninitialized variable: action
nautilus-places-sidebar.c:1232:13 clang-analyzer The left operand of '!=' is a garbage value
   1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
   2 
   3 /*
   4  *  Nautilus
   5  *
   6  *  This library is free software; you can redistribute it and/or
   7  *  modify it under the terms of the GNU General Public License as
   8  *  published by the Free Software Foundation; either version 2 of the
   9  *  License, or (at your option) any later version.
  10  *
  11  *  This library is distributed in the hope that it will be useful,
  12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14  *  General Public License for more details.
  15  *
  16  *  You should have received a copy of the GNU General Public License
  17  *  along with this library; if not, write to the Free Software
  18  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19  *
  20  *  Authors : Mr Jamie McCracken (jamiemcc at blueyonder dot co dot uk)
  21  *            Cosimo Cecchi <cosimoc@gnome.org>
  22  *
  23  */
  24  
  25 #include <config.h>
  26 
  27 #include <gdk/gdkkeysyms.h>
  28 #include <gtk/gtk.h>
  29 #include <glib/gi18n.h>
  30 #include <gio/gio.h>
  31 
  32 #include <libnautilus-private/nautilus-dnd.h>
  33 #include <libnautilus-private/nautilus-bookmark.h>
  34 #include <libnautilus-private/nautilus-global-preferences.h>
  35 #include <libnautilus-private/nautilus-file.h>
  36 #include <libnautilus-private/nautilus-file-utilities.h>
  37 #include <libnautilus-private/nautilus-file-operations.h>
  38 #include <libnautilus-private/nautilus-trash-monitor.h>
  39 #include <libnautilus-private/nautilus-icon-names.h>
  40 
  41 #include <eel/eel-debug.h>
  42 #include <eel/eel-gtk-extensions.h>
  43 #include <eel/eel-glib-extensions.h>
  44 #include <eel/eel-graphic-effects.h>
  45 #include <eel/eel-string.h>
  46 #include <eel/eel-stock-dialogs.h>
  47 
  48 #include "nautilus-application.h"
  49 #include "nautilus-bookmark-list.h"
  50 #include "nautilus-places-sidebar.h"
  51 #include "nautilus-properties-window.h"
  52 #include "nautilus-window.h"
  53 #include "nautilus-window-slot.h"
  54 
  55 #define DEBUG_FLAG NAUTILUS_DEBUG_PLACES
  56 #include <libnautilus-private/nautilus-debug.h>
  57 
  58 #define EJECT_BUTTON_XPAD 6
  59 #define ICON_CELL_XPAD 6
  60 
  61 typedef struct {
  62 	GtkScrolledWindow  parent;
  63 	GtkTreeView        *tree_view;
  64 	GtkCellRenderer    *eject_icon_cell_renderer;
  65 	char 	           *uri;
  66 	GtkListStore       *store;
  67 	NautilusWindow *window;
  68 	NautilusBookmarkList *bookmarks;
  69 	GVolumeMonitor *volume_monitor;
  70 
  71 	gboolean devices_header_added;
  72 	gboolean bookmarks_header_added;
  73 
  74 	/* DnD */
  75 	GList     *drag_list;
  76 	gboolean  drag_data_received;
  77 	int       drag_data_info;
  78 	gboolean  drop_occured;
  79 
  80 	GtkWidget *popup_menu;
  81 	GtkWidget *popup_menu_open_in_new_tab_item;
  82 	GtkWidget *popup_menu_add_shortcut_item;
  83 	GtkWidget *popup_menu_remove_item;
  84 	GtkWidget *popup_menu_rename_item;
  85 	GtkWidget *popup_menu_separator_item;
  86 	GtkWidget *popup_menu_mount_item;
  87 	GtkWidget *popup_menu_unmount_item;
  88 	GtkWidget *popup_menu_eject_item;
  89 	GtkWidget *popup_menu_rescan_item;
  90 	GtkWidget *popup_menu_empty_trash_item;
  91 	GtkWidget *popup_menu_start_item;
  92 	GtkWidget *popup_menu_stop_item;
  93 	GtkWidget *popup_menu_properties_separator_item;
  94 	GtkWidget *popup_menu_properties_item;
  95 
  96 	/* volume mounting - delayed open process */
  97 	gboolean mounting;
  98 	NautilusWindowSlot *go_to_after_mount_slot;
  99 	NautilusWindowOpenFlags go_to_after_mount_flags;
 100 
 101 	GDBusProxy *hostnamed_proxy;
 102 	char *hostname;
 103 
 104 	guint bookmarks_changed_id;
 105 } NautilusPlacesSidebar;
 106 
 107 typedef struct {
 108 	GtkScrolledWindowClass parent;
 109 } NautilusPlacesSidebarClass;
 110 
 111 typedef struct {
 112         GObject parent;
 113 } NautilusPlacesSidebarProvider;
 114 
 115 typedef struct {
 116         GObjectClass parent;
 117 } NautilusPlacesSidebarProviderClass;
 118 
 119 enum {
 120 	PLACES_SIDEBAR_COLUMN_ROW_TYPE,
 121 	PLACES_SIDEBAR_COLUMN_URI,
 122 	PLACES_SIDEBAR_COLUMN_DRIVE,
 123 	PLACES_SIDEBAR_COLUMN_VOLUME,
 124 	PLACES_SIDEBAR_COLUMN_MOUNT,
 125 	PLACES_SIDEBAR_COLUMN_NAME,
 126 	PLACES_SIDEBAR_COLUMN_GICON,
 127 	PLACES_SIDEBAR_COLUMN_INDEX,
 128 	PLACES_SIDEBAR_COLUMN_EJECT,
 129 	PLACES_SIDEBAR_COLUMN_NO_EJECT,
 130 	PLACES_SIDEBAR_COLUMN_BOOKMARK,
 131 	PLACES_SIDEBAR_COLUMN_TOOLTIP,
 132 	PLACES_SIDEBAR_COLUMN_EJECT_GICON,
 133 	PLACES_SIDEBAR_COLUMN_SECTION_TYPE,
 134 	PLACES_SIDEBAR_COLUMN_HEADING_TEXT,
 135 
 136 	PLACES_SIDEBAR_COLUMN_COUNT
 137 };
 138 
 139 typedef enum {
 140 	PLACES_BUILT_IN,
 141 	PLACES_XDG_DIR,
 142 	PLACES_MOUNTED_VOLUME,
 143 	PLACES_BOOKMARK,
 144 	PLACES_HEADING,
 145 } PlaceType;
 146 
 147 typedef enum {
 148 	SECTION_DEVICES,
 149 	SECTION_BOOKMARKS,
 150 	SECTION_COMPUTER,
 151 	SECTION_NETWORK,
 152 } SectionType;
 153 
 154 static void  open_selected_bookmark                    (NautilusPlacesSidebar        *sidebar,
 155 							GtkTreeModel                 *model,
 156 							GtkTreeIter                  *iter,
 157 							NautilusWindowOpenFlags flags);
 158 static void  nautilus_places_sidebar_style_set         (GtkWidget                    *widget,
 159 							GtkStyle                     *previous_style);
 160 static gboolean eject_or_unmount_bookmark              (NautilusPlacesSidebar *sidebar,
 161 							GtkTreePath *path);
 162 static gboolean eject_or_unmount_selection             (NautilusPlacesSidebar *sidebar);
 163 static void  check_unmount_and_eject                   (GMount *mount,
 164 							GVolume *volume,
 165 							GDrive *drive,
 166 							gboolean *show_unmount,
 167 							gboolean *show_eject);
 168 
 169 static void bookmarks_check_popup_sensitivity          (NautilusPlacesSidebar *sidebar);
 170 
 171 /* Identifiers for target types */
 172 enum {
 173 	GTK_TREE_MODEL_ROW,
 174 	TEXT_URI_LIST
 175 };
 176 
 177 /* Target types for dragging from the shortcuts list */
 178 static const GtkTargetEntry nautilus_shortcuts_source_targets[] = {
 179 	{ "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, GTK_TREE_MODEL_ROW }
 180 };
 181 
 182 /* Target types for dropping into the shortcuts list */
 183 static const GtkTargetEntry nautilus_shortcuts_drop_targets [] = {
 184 	{ "GTK_TREE_MODEL_ROW", GTK_TARGET_SAME_WIDGET, GTK_TREE_MODEL_ROW },
 185 	{ "text/uri-list", 0, TEXT_URI_LIST }
 186 };
 187 
 188 /* Drag and drop interface declarations */
 189 typedef struct {
 190 	GtkListStore parent;
 191 
 192 	NautilusPlacesSidebar *sidebar;
 193 } NautilusShortcutsModel;
 194 
 195 typedef struct {
 196 	GtkListStoreClass parent_class;
 197 } NautilusShortcutsModelClass;
 198 
 199 GType _nautilus_shortcuts_model_get_type (void);
 200 static void _nautilus_shortcuts_model_drag_source_init (GtkTreeDragSourceIface *iface);
 201 G_DEFINE_TYPE_WITH_CODE (NautilusShortcutsModel, _nautilus_shortcuts_model, GTK_TYPE_LIST_STORE,
 202 			 G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_DRAG_SOURCE,
 203 						_nautilus_shortcuts_model_drag_source_init));
 204 static GtkListStore *nautilus_shortcuts_model_new (NautilusPlacesSidebar *sidebar);
 205 
 206 G_DEFINE_TYPE (NautilusPlacesSidebar, nautilus_places_sidebar, GTK_TYPE_SCROLLED_WINDOW);
 207 
 208 static gboolean
 209 is_built_in_bookmark (NautilusFile *file)
 210 {
 211 	gboolean built_in;
 212 	gint idx;
 213 
 214 	if (nautilus_file_is_home (file)) {
 215 		return TRUE;
 216 	}
 217 
 218 	if (nautilus_file_is_desktop_directory (file) &&
 219 	    !g_settings_get_boolean (gnome_background_preferences, NAUTILUS_PREFERENCES_SHOW_DESKTOP)) {
 220 		return FALSE;
 221 	}
 222 
 223 	built_in = FALSE;
 224 
 225 	for (idx = 0; idx < G_USER_N_DIRECTORIES; idx++) {
 226 		/* PUBLIC_SHARE and TEMPLATES are not in our built-in list */
 227 		if (nautilus_file_is_user_special_directory (file, idx)) {
 228 			if (idx != G_USER_DIRECTORY_PUBLIC_SHARE &&  idx != G_USER_DIRECTORY_TEMPLATES) {
 229 				built_in = TRUE;
 230 			}
 231 
 232 			break;
 233 		}
 234 	}
 235 
 236 	return built_in;
 237 }
 238 
 239 static GtkTreeIter
 240 add_heading (NautilusPlacesSidebar *sidebar,
 241 	     SectionType section_type,
 242 	     const gchar *title)
 243 {
 244 	GtkTreeIter iter;
 245 
 246 	gtk_list_store_append (sidebar->store, &iter);
 247 	gtk_list_store_set (sidebar->store, &iter,
 248 			    PLACES_SIDEBAR_COLUMN_ROW_TYPE, PLACES_HEADING,
 249 			    PLACES_SIDEBAR_COLUMN_SECTION_TYPE, section_type,	
 250 			    PLACES_SIDEBAR_COLUMN_HEADING_TEXT, title,
 251 			    PLACES_SIDEBAR_COLUMN_EJECT, FALSE,
 252 			    PLACES_SIDEBAR_COLUMN_NO_EJECT, TRUE,
 253 			    -1);
 254 
 255 	return iter;
 256 }
 257 
 258 static void
 259 check_heading_for_section (NautilusPlacesSidebar *sidebar,
 260 			   SectionType section_type)
 261 {
 262 	switch (section_type) {
 263 	case SECTION_DEVICES:
 264 		if (!sidebar->devices_header_added) {
 265 			add_heading (sidebar, SECTION_DEVICES,
 266 				     _("Devices"));
 267 			sidebar->devices_header_added = TRUE;
 268 		}
 269 
 270 		break;
 271 	case SECTION_BOOKMARKS:
 272 		if (!sidebar->bookmarks_header_added) {
 273 			add_heading (sidebar, SECTION_BOOKMARKS,
 274 				     _("Bookmarks"));
 275 			sidebar->bookmarks_header_added = TRUE;
 276 		}
 277 
 278 		break;
 279 	default:
 280 		break;
 281 	}
 282 }
 283 
 284 static void
 285 add_place (NautilusPlacesSidebar *sidebar,
 286 	   PlaceType place_type,
 287 	   SectionType section_type,
 288 	   const char *name,
 289 	   GIcon *icon,
 290 	   const char *uri,
 291 	   GDrive *drive,
 292 	   GVolume *volume,
 293 	   GMount *mount,
 294 	   const int index,
 295 	   const char *tooltip)
 296 {
 297 	GtkTreeIter           iter;
 298 	GIcon *eject;
 299 	gboolean show_eject, show_unmount;
 300 	gboolean show_eject_button;
 301 
 302 	check_heading_for_section (sidebar, section_type);
 303 
 304 	check_unmount_and_eject (mount, volume, drive,
 305 				 &show_unmount, &show_eject);
 306 
 307 	if (show_unmount || show_eject) {
 308 		g_assert (place_type != PLACES_BOOKMARK);
 309 	}
 310 
 311 	if (mount == NULL) {
 312 		show_eject_button = FALSE;
 313 	} else {
 314 		show_eject_button = (show_unmount || show_eject);
 315 	}
 316 
 317 	if (show_eject_button) {
 318 		eject = g_themed_icon_new_with_default_fallbacks ("media-eject-symbolic");
 319 	} else {
 320 		eject = NULL;
 321 	}
 322 
 323 	gtk_list_store_append (sidebar->store, &iter);
 324 	gtk_list_store_set (sidebar->store, &iter,
 325 			    PLACES_SIDEBAR_COLUMN_GICON, icon,
 326 			    PLACES_SIDEBAR_COLUMN_NAME, name,
 327 			    PLACES_SIDEBAR_COLUMN_URI, uri,
 328 			    PLACES_SIDEBAR_COLUMN_DRIVE, drive,
 329 			    PLACES_SIDEBAR_COLUMN_VOLUME, volume,
 330 			    PLACES_SIDEBAR_COLUMN_MOUNT, mount,
 331 			    PLACES_SIDEBAR_COLUMN_ROW_TYPE, place_type,
 332 			    PLACES_SIDEBAR_COLUMN_INDEX, index,
 333 			    PLACES_SIDEBAR_COLUMN_EJECT, show_eject_button,
 334 			    PLACES_SIDEBAR_COLUMN_NO_EJECT, !show_eject_button,
 335 			    PLACES_SIDEBAR_COLUMN_BOOKMARK, place_type != PLACES_BOOKMARK,
 336 			    PLACES_SIDEBAR_COLUMN_TOOLTIP, tooltip,
 337 			    PLACES_SIDEBAR_COLUMN_EJECT_GICON, eject,
 338 			    PLACES_SIDEBAR_COLUMN_SECTION_TYPE, section_type,
 339 			    -1);
 340 
 341 	if (eject != NULL) {
 342 		g_object_unref (eject);
 343 	}
 344 }
 345 
 346 typedef struct {
 347 	const gchar *location;
 348 	const gchar *last_uri;
 349 	NautilusPlacesSidebar *sidebar;
 350 	GtkTreePath *path;
 351 } RestoreLocationData;
 352 
 353 static gboolean
 354 restore_selection_foreach (GtkTreeModel *model,
 355 			   GtkTreePath *path,
 356 			   GtkTreeIter *iter,
 357 			   gpointer user_data)
 358 {
 359 	RestoreLocationData *data = user_data;
 360 	gchar *uri;
 361 
 362 	gtk_tree_model_get (model, iter,
 363 			    PLACES_SIDEBAR_COLUMN_URI, &uri,
 364 			    -1);
 365 
 366 	if (g_strcmp0 (uri, data->last_uri) == 0 ||
 367 	    g_strcmp0 (uri, data->location) == 0) {
 368 		data->path = gtk_tree_path_copy (path);
 369 	}
 370 
 371 	g_free (uri);
 372 
 373 	return (data->path != NULL);
 374 }
 375 
 376 static void
 377 sidebar_update_restore_selection (NautilusPlacesSidebar *sidebar,
 378 				  const gchar *location,
 379 				  const gchar *last_uri)
 380 {
 381 	RestoreLocationData data;
 382 	GtkTreeSelection *selection;
 383 
 384 	data.location = location;
 385 	data.last_uri = last_uri;
 386 	data.sidebar = sidebar;
 387 	data.path = NULL;
 388 
 389 	gtk_tree_model_foreach (GTK_TREE_MODEL (sidebar->store),
 390 				restore_selection_foreach, &data);
 391 
 392 	if (data.path != NULL) {
 393 		selection = gtk_tree_view_get_selection (sidebar->tree_view);
 394 		gtk_tree_selection_select_path (selection, data.path);
 395 		gtk_tree_path_free (data.path);
 396 	}
 397 }
 398 
 399 static gboolean
 400 recent_is_supported (void)
 401 {
 402 	const char * const *supported;
 403 	int i;
 404 
 405 	supported = g_vfs_get_supported_uri_schemes (g_vfs_get_default ());
 406 	if (!supported) {
 407 		return FALSE;
 408 	}
 409 
 410 	for (i = 0; supported[i] != NULL; i++) {
 411 		if (strcmp ("recent", supported[i]) == 0) {
 412 			return TRUE;
 413 		}
 414 	}
 415 	return FALSE;
 416 }
 417 
 418 static void
 419 add_special_dirs (NautilusPlacesSidebar *sidebar)
 420 {
 421 	GList *dirs;
 422 	int index;
 423 
 424 	dirs = NULL;
 425 	for (index = 0; index < G_USER_N_DIRECTORIES; index++) {
 426 		const char *path;
 427 		GFile *root;
 428 		GIcon *icon;
 429 		char *name;
 430 		char *mount_uri;
 431 		char *tooltip;
 432 
 433 		if (index == G_USER_DIRECTORY_DESKTOP ||
 434 		    index == G_USER_DIRECTORY_TEMPLATES ||
 435 		    index == G_USER_DIRECTORY_PUBLIC_SHARE) {
 436 			continue;
 437 		}
 438 
 439 		path = g_get_user_special_dir (index);
 440 
 441 		/* xdg resets special dirs to the home directory in case
 442 		 * it's not finiding what it expects. We don't want the home
 443 		 * to be added multiple times in that weird configuration.
 444 		 */
 445 		if (path == NULL
 446 		    || g_strcmp0 (path, g_get_home_dir ()) == 0
 447 		    || g_list_find_custom (dirs, path, (GCompareFunc) g_strcmp0) != NULL) {
 448 			continue;
 449 		}
 450 
 451 		root = g_file_new_for_path (path);
 452 		name = g_file_get_basename (root);
 453 		icon = nautilus_special_directory_get_symbolic_icon (index);
 454 		mount_uri = g_file_get_uri (root);
 455 		tooltip = g_file_get_parse_name (root);
 456 
 457 		add_place (sidebar, PLACES_XDG_DIR,
 458 			   SECTION_COMPUTER,
 459 			   name, icon, mount_uri,
 460 			   NULL, NULL, NULL, 0,
 461 			   tooltip);
 462 		g_free (name);
 463 		g_object_unref (root);
 464 		g_object_unref (icon);
 465 		g_free (mount_uri);
 466 		g_free (tooltip);
 467 
 468 		dirs = g_list_prepend (dirs, (char *)path);
 469 	}
 470 
 471 	g_list_free (dirs);
 472 }
 473 
 474 static void
 475 update_places (NautilusPlacesSidebar *sidebar)
 476 {
 477 	NautilusBookmark *bookmark;
 478 	GtkTreeSelection *selection;
 479 	GtkTreeIter last_iter;
 480 	GtkTreeModel *model;
 481 	GVolumeMonitor *volume_monitor;
 482 	GList *mounts, *l, *ll;
 483 	GMount *mount;
 484 	GList *drives;
 485 	GDrive *drive;
 486 	GList *volumes;
 487 	GVolume *volume;
 488 	int bookmark_count, index;
 489 	char *location, *mount_uri, *name, *last_uri, *identifier;
 490 	const gchar *bookmark_name;
 491 	GIcon *icon;
 492 	GFile *root;
 493 	NautilusWindowSlot *slot;
 494 	char *tooltip;
 495 	GList *network_mounts, *network_volumes;
 496 	NautilusFile *file;
 497 
 498 	DEBUG ("Updating places sidebar");
 499 
 500 	model = NULL;
 501 	last_uri = NULL;
 502 
 503 	selection = gtk_tree_view_get_selection (sidebar->tree_view);
 504 	if (gtk_tree_selection_get_selected (selection, &model, &last_iter)) {
 505 		gtk_tree_model_get (model,
 506 				    &last_iter,
 507 				    PLACES_SIDEBAR_COLUMN_URI, &last_uri, -1);
 508 	}
 509 	gtk_list_store_clear (sidebar->store);
 510 
 511 	sidebar->devices_header_added = FALSE;
 512 	sidebar->bookmarks_header_added = FALSE;
 513 
 514 	slot = nautilus_window_get_active_slot (sidebar->window);
 515 	location = nautilus_window_slot_get_current_uri (slot);
 516 
 517 	network_mounts = network_volumes = NULL;
 518 	volume_monitor = sidebar->volume_monitor;
 519 
 520 	/* add built in bookmarks */
 521 
 522 	add_heading (sidebar, SECTION_COMPUTER,
 523 		     _("Places"));
 524 
 525 	if (recent_is_supported ()) {
 526 		mount_uri = "recent:///"; /* No need to strdup */
 527 		icon = g_themed_icon_new ("document-open-recent-symbolic");
 528 		add_place (sidebar, PLACES_BUILT_IN,
 529 			   SECTION_COMPUTER,
 530 			   _("Recent"), icon, mount_uri,
 531 			   NULL, NULL, NULL, 0,
 532 			   _("Recent files"));
 533 		g_object_unref (icon);
 534 	}
 535 
 536 	/* home folder */
 537 	mount_uri = nautilus_get_home_directory_uri ();
 538 	icon = g_themed_icon_new (NAUTILUS_ICON_HOME);
 539 	add_place (sidebar, PLACES_BUILT_IN,
 540 		   SECTION_COMPUTER,
 541 		   _("Home"), icon,
 542 		   mount_uri, NULL, NULL, NULL, 0,
 543 		   _("Open your personal folder"));
 544 	g_object_unref (icon);
 545 	g_free (mount_uri);
 546 
 547 	if (g_settings_get_boolean (gnome_background_preferences, NAUTILUS_PREFERENCES_SHOW_DESKTOP)) {
 548 		/* desktop */
 549 		mount_uri = nautilus_get_desktop_directory_uri ();
 550 		icon = g_themed_icon_new (NAUTILUS_ICON_FOLDER);
 551 		add_place (sidebar, PLACES_BUILT_IN,
 552 			   SECTION_COMPUTER,
 553 			   _("Desktop"), icon,
 554 			   mount_uri, NULL, NULL, NULL, 0,
 555 			   _("Open the contents of your desktop in a folder"));
 556 		g_object_unref (icon);
 557 		g_free (mount_uri);
 558 	}
 559 
 560 	/* XDG directories */
 561 	add_special_dirs (sidebar);
 562 
 563 	mount_uri = "trash:///"; /* No need to strdup */
 564 	icon = nautilus_trash_monitor_get_icon ();
 565 	add_place (sidebar, PLACES_BUILT_IN,
 566 		   SECTION_COMPUTER,
 567 		   _("Trash"), icon, mount_uri,
 568 		   NULL, NULL, NULL, 0,
 569 		   _("Open the trash"));
 570 	g_object_unref (icon);
 571 
 572 	/* go through all connected drives */
 573 	drives = g_volume_monitor_get_connected_drives (volume_monitor);
 574 
 575 	for (l = drives; l != NULL; l = l->next) {
 576 		drive = l->data;
 577 
 578 		volumes = g_drive_get_volumes (drive);
 579 		if (volumes != NULL) {
 580 			for (ll = volumes; ll != NULL; ll = ll->next) {
 581 				volume = ll->data;
 582 				identifier = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_CLASS);
 583 
 584 				if (g_strcmp0 (identifier, "network") == 0) {
 585 					g_free (identifier);
 586 					network_volumes = g_list_prepend (network_volumes, volume);
 587 					continue;
 588 				}
 589 				g_free (identifier);
 590 
 591 				mount = g_volume_get_mount (volume);
 592 				if (mount != NULL) {
 593 					/* Show mounted volume in the sidebar */
 594 					icon = g_mount_get_symbolic_icon (mount);
 595 					root = g_mount_get_default_location (mount);
 596 					mount_uri = g_file_get_uri (root);
 597 					name = g_mount_get_name (mount);
 598 					tooltip = g_file_get_parse_name (root);
 599 
 600 					add_place (sidebar, PLACES_MOUNTED_VOLUME,
 601 						   SECTION_DEVICES,
 602 						   name, icon, mount_uri,
 603 						   drive, volume, mount, 0, tooltip);
 604 					g_object_unref (root);
 605 					g_object_unref (mount);
 606 					g_object_unref (icon);
 607 					g_free (tooltip);
 608 					g_free (name);
 609 					g_free (mount_uri);
 610 				} else {
 611 					/* Do show the unmounted volumes in the sidebar;
 612 					 * this is so the user can mount it (in case automounting
 613 					 * is off).
 614 					 *
 615 					 * Also, even if automounting is enabled, this gives a visual
 616 					 * cue that the user should remember to yank out the media if
 617 					 * he just unmounted it.
 618 					 */
 619 					icon = g_volume_get_symbolic_icon (volume);
 620 					name = g_volume_get_name (volume);
 621 					tooltip = g_strdup_printf (_("Mount and open %s"), name);
 622 
 623 					add_place (sidebar, PLACES_MOUNTED_VOLUME,
 624 						   SECTION_DEVICES,
 625 						   name, icon, NULL,
 626 						   drive, volume, NULL, 0, tooltip);
 627 					g_object_unref (icon);
 628 					g_free (name);
 629 					g_free (tooltip);
 630 				}
 631 				g_object_unref (volume);
 632 			}
 633 			g_list_free (volumes);
 634 		} else {
 635 			if (g_drive_is_media_removable (drive) && !g_drive_is_media_check_automatic (drive)) {
 636 				/* If the drive has no mountable volumes and we cannot detect media change.. we
 637 				 * display the drive in the sidebar so the user can manually poll the drive by
 638 				 * right clicking and selecting "Rescan..."
 639 				 *
 640 				 * This is mainly for drives like floppies where media detection doesn't
 641 				 * work.. but it's also for human beings who like to turn off media detection
 642 				 * in the OS to save battery juice.
 643 				 */
 644 				icon = g_drive_get_symbolic_icon (drive);
 645 				name = g_drive_get_name (drive);
 646 				tooltip = g_strdup_printf (_("Mount and open %s"), name);
 647 
 648 				add_place (sidebar, PLACES_BUILT_IN,
 649 					   SECTION_DEVICES,
 650 					   name, icon, NULL,
 651 					   drive, NULL, NULL, 0, tooltip);
 652 				g_object_unref (icon);
 653 				g_free (tooltip);
 654 				g_free (name);
 655 			}
 656 		}
 657 		g_object_unref (drive);
 658 	}
 659 	g_list_free (drives);
 660 
 661 	/* add all volumes that is not associated with a drive */
 662 	volumes = g_volume_monitor_get_volumes (volume_monitor);
 663 	for (l = volumes; l != NULL; l = l->next) {
 664 		volume = l->data;
 665 		drive = g_volume_get_drive (volume);
 666 		if (drive != NULL) {
 667 		    	g_object_unref (volume);
 668 			g_object_unref (drive);
 669 			continue;
 670 		}
 671 
 672 		identifier = g_volume_get_identifier (volume, G_VOLUME_IDENTIFIER_KIND_CLASS);
 673 
 674 		if (g_strcmp0 (identifier, "network") == 0) {
 675 			g_free (identifier);
 676 			network_volumes = g_list_prepend (network_volumes, volume);
 677 			continue;
 678 		}
 679 		g_free (identifier);
 680 
 681 		mount = g_volume_get_mount (volume);
 682 		if (mount != NULL) {
 683 			icon = g_mount_get_symbolic_icon (mount);
 684 			root = g_mount_get_default_location (mount);
 685 			mount_uri = g_file_get_uri (root);
 686 			tooltip = g_file_get_parse_name (root);
 687 			g_object_unref (root);
 688 			name = g_mount_get_name (mount);
 689 			add_place (sidebar, PLACES_MOUNTED_VOLUME,
 690 				   SECTION_DEVICES,
 691 				   name, icon, mount_uri,
 692 				   NULL, volume, mount, 0, tooltip);
 693 			g_object_unref (mount);
 694 			g_object_unref (icon);
 695 			g_free (name);
 696 			g_free (tooltip);
 697 			g_free (mount_uri);
 698 		} else {
 699 			/* see comment above in why we add an icon for an unmounted mountable volume */
 700 			icon = g_volume_get_symbolic_icon (volume);
 701 			name = g_volume_get_name (volume);
 702 			add_place (sidebar, PLACES_MOUNTED_VOLUME,
 703 				   SECTION_DEVICES,
 704 				   name, icon, NULL,
 705 				   NULL, volume, NULL, 0, name);
 706 			g_object_unref (icon);
 707 			g_free (name);
 708 		}
 709 		g_object_unref (volume);
 710 	}
 711 	g_list_free (volumes);
 712 
 713 	/* file system root */
 714 
 715  	mount_uri = "file:///"; /* No need to strdup */
 716 	icon = g_themed_icon_new (NAUTILUS_ICON_FILESYSTEM);
 717 	add_place (sidebar, PLACES_BUILT_IN,
 718 		   SECTION_DEVICES,
 719 		   sidebar->hostname, icon,
 720 		   mount_uri, NULL, NULL, NULL, 0,
 721 		   _("Open the contents of the File System"));
 722 	g_object_unref (icon);
 723 
 724 	/* add mounts that has no volume (/etc/mtab mounts, ftp, sftp,...) */
 725 	mounts = g_volume_monitor_get_mounts (volume_monitor);
 726 
 727 	for (l = mounts; l != NULL; l = l->next) {
 728 		mount = l->data;
 729 		if (g_mount_is_shadowed (mount)) {
 730 			g_object_unref (mount);
 731 			continue;
 732 		}
 733 		volume = g_mount_get_volume (mount);
 734 		if (volume != NULL) {
 735 		    	g_object_unref (volume);
 736 			g_object_unref (mount);
 737 			continue;
 738 		}
 739 		root = g_mount_get_default_location (mount);
 740 
 741 		if (!g_file_is_native (root)) {
 742 			network_mounts = g_list_prepend (network_mounts, mount);
 743 			g_object_unref (root);
 744 			continue;
 745 		}
 746 
 747 		icon = g_mount_get_symbolic_icon (mount);
 748 		mount_uri = g_file_get_uri (root);
 749 		name = g_mount_get_name (mount);
 750 		tooltip = g_file_get_parse_name (root);
 751 		add_place (sidebar, PLACES_MOUNTED_VOLUME,
 752 			   SECTION_COMPUTER,
 753 			   name, icon, mount_uri,
 754 			   NULL, NULL, mount, 0, tooltip);
 755 		g_object_unref (root);
 756 		g_object_unref (mount);
 757 		g_object_unref (icon);
 758 		g_free (name);
 759 		g_free (mount_uri);
 760 		g_free (tooltip);
 761 	}
 762 	g_list_free (mounts);
 763 
 764 	/* add bookmarks */
 765 	bookmark_count = nautilus_bookmark_list_length (sidebar->bookmarks);
 766 
 767 	for (index = 0; index < bookmark_count; ++index) {
 768 		bookmark = nautilus_bookmark_list_item_at (sidebar->bookmarks, index);
 769 
 770 		if (nautilus_bookmark_uri_known_not_to_exist (bookmark)) {
 771 			continue;
 772 		}
 773 
 774 		root = nautilus_bookmark_get_location (bookmark);
 775 		file = nautilus_file_get (root);
 776 
 777 		if (is_built_in_bookmark (file)) {
 778 			g_object_unref (root);
 779 			nautilus_file_unref (file);
 780 			continue;
 781 		}
 782 		nautilus_file_unref (file);
 783 
 784 		bookmark_name = nautilus_bookmark_get_name (bookmark);
 785 		icon = nautilus_bookmark_get_symbolic_icon (bookmark);
 786 		mount_uri = nautilus_bookmark_get_uri (bookmark);
 787 		tooltip = g_file_get_parse_name (root);
 788 
 789 		add_place (sidebar, PLACES_BOOKMARK,
 790 			   SECTION_BOOKMARKS,
 791 			   bookmark_name, icon, mount_uri,
 792 			   NULL, NULL, NULL, index,
 793 			   tooltip);
 794 		g_object_unref (root);
 795 		g_object_unref (icon);
 796 		g_free (mount_uri);
 797 		g_free (tooltip);
 798 	}
 799 
 800 	/* network */
 801 	add_heading (sidebar, SECTION_NETWORK,
 802 		     _("Network"));
 803 
 804  	mount_uri = "network:///"; /* No need to strdup */
 805 	icon = g_themed_icon_new (NAUTILUS_ICON_NETWORK);
 806 	add_place (sidebar, PLACES_BUILT_IN,
 807 		   SECTION_NETWORK,
 808 		   _("Browse Network"), icon,
 809 		   mount_uri, NULL, NULL, NULL, 0,
 810 		   _("Browse the contents of the network"));
 811 	g_object_unref (icon);
 812 
 813 	network_volumes = g_list_reverse (network_volumes);
 814 	for (l = network_volumes; l != NULL; l = l->next) {
 815 		volume = l->data;
 816 		mount = g_volume_get_mount (volume);
 817 
 818 		if (mount != NULL) {
 819 			network_mounts = g_list_prepend (network_mounts, mount);
 820 			continue;
 821 		} else {
 822 			icon = g_volume_get_symbolic_icon (volume);
 823 			name = g_volume_get_name (volume);
 824 			tooltip = g_strdup_printf (_("Mount and open %s"), name);
 825 
 826 			add_place (sidebar, PLACES_MOUNTED_VOLUME,
 827 				   SECTION_NETWORK,
 828 				   name, icon, NULL,
 829 				   NULL, volume, NULL, 0, tooltip);
 830 			g_object_unref (icon);
 831 			g_free (name);
 832 			g_free (tooltip);
 833 		}
 834 	}
 835 
 836 	g_list_free_full (network_volumes, g_object_unref);
 837 
 838 	network_mounts = g_list_reverse (network_mounts);
 839 	for (l = network_mounts; l != NULL; l = l->next) {
 840 		mount = l->data;
 841 		root = g_mount_get_default_location (mount);
 842 		icon = g_mount_get_symbolic_icon (mount);
 843 		mount_uri = g_file_get_uri (root);
 844 		name = g_mount_get_name (mount);
 845 		tooltip = g_file_get_parse_name (root);
 846 		add_place (sidebar, PLACES_MOUNTED_VOLUME,
 847 			   SECTION_NETWORK,
 848 			   name, icon, mount_uri,
 849 			   NULL, NULL, mount, 0, tooltip);
 850 		g_object_unref (root);
 851 		g_object_unref (icon);
 852 		g_free (name);
 853 		g_free (mount_uri);
 854 		g_free (tooltip);
 855 	}
 856 
 857 	g_list_free_full (network_mounts, g_object_unref);
 858 
 859 	/* restore selection */
 860 	sidebar_update_restore_selection (sidebar, location, last_uri);
 861 
 862 	g_free (location);
 863 	g_free (last_uri);
 864 }
 865 
 866 static void
 867 mount_added_callback (GVolumeMonitor *volume_monitor,
 868 		      GMount *mount,
 869 		      NautilusPlacesSidebar *sidebar)
 870 {
 871 	update_places (sidebar);
 872 }
 873 
 874 static void
 875 mount_removed_callback (GVolumeMonitor *volume_monitor,
 876 			GMount *mount,
 877 			NautilusPlacesSidebar *sidebar)
 878 {
 879 	update_places (sidebar);
 880 }
 881 
 882 static void
 883 mount_changed_callback (GVolumeMonitor *volume_monitor,
 884 			GMount *mount,
 885 			NautilusPlacesSidebar *sidebar)
 886 {
 887 	update_places (sidebar);
 888 }
 889 
 890 static void
 891 volume_added_callback (GVolumeMonitor *volume_monitor,
 892 		       GVolume *volume,
 893 		       NautilusPlacesSidebar *sidebar)
 894 {
 895 	update_places (sidebar);
 896 }
 897 
 898 static void
 899 volume_removed_callback (GVolumeMonitor *volume_monitor,
 900 			 GVolume *volume,
 901 			 NautilusPlacesSidebar *sidebar)
 902 {
 903 	update_places (sidebar);
 904 }
 905 
 906 static void
 907 volume_changed_callback (GVolumeMonitor *volume_monitor,
 908 			 GVolume *volume,
 909 			 NautilusPlacesSidebar *sidebar)
 910 {
 911 	update_places (sidebar);
 912 }
 913 
 914 static void
 915 drive_disconnected_callback (GVolumeMonitor *volume_monitor,
 916 			     GDrive         *drive,
 917 			     NautilusPlacesSidebar *sidebar)
 918 {
 919 	update_places (sidebar);
 920 }
 921 
 922 static void
 923 drive_connected_callback (GVolumeMonitor *volume_monitor,
 924 			  GDrive         *drive,
 925 			  NautilusPlacesSidebar *sidebar)
 926 {
 927 	update_places (sidebar);
 928 }
 929 
 930 static void
 931 drive_changed_callback (GVolumeMonitor *volume_monitor,
 932 			GDrive         *drive,
 933 			NautilusPlacesSidebar *sidebar)
 934 {
 935 	update_places (sidebar);
 936 }
 937 
 938 static gboolean
 939 over_eject_button (NautilusPlacesSidebar *sidebar,
 940 		   gint x,
 941 		   gint y,
 942 		   GtkTreePath **path)
 943 {
 944 	GtkTreeViewColumn *column;
 945 	int width, x_offset, hseparator;
 946 	int eject_button_size;
 947 	gboolean show_eject;
 948 	GtkTreeIter iter;
 949 	GtkTreeModel *model;
 950 
 951 	*path = NULL;
 952 	model = gtk_tree_view_get_model (sidebar->tree_view);
 953 
 954 	if (gtk_tree_view_get_path_at_pos (sidebar->tree_view,
 955 					   x, y,
 956 					   path, &column, NULL, NULL)) {
 957 
 958 		gtk_tree_model_get_iter (model, &iter, *path);
 959 		gtk_tree_model_get (model, &iter,
 960 				    PLACES_SIDEBAR_COLUMN_EJECT, &show_eject,
 961 				    -1);
 962 
 963 		if (!show_eject) {
 964 			goto out;
 965 		}
 966 
 967 
 968 		gtk_widget_style_get (GTK_WIDGET (sidebar->tree_view),
 969 				      "horizontal-separator", &hseparator,
 970 				      NULL);
 971 
 972 		/* Reload cell attributes for this particular row */
 973 		gtk_tree_view_column_cell_set_cell_data (column,
 974 							 model, &iter, FALSE, FALSE);
 975 
 976 		gtk_tree_view_column_cell_get_position (column,
 977 							sidebar->eject_icon_cell_renderer,
 978 							&x_offset, &width);
 979 
 980 		eject_button_size = nautilus_get_icon_size_for_stock_size (GTK_ICON_SIZE_MENU);
 981 
 982 		/* This is kinda weird, but we have to do it to workaround gtk+ expanding
 983 		 * the eject cell renderer (even thought we told it not to) and we then
 984 		 * had to set it right-aligned */
 985 		x_offset += width - hseparator - EJECT_BUTTON_XPAD - eject_button_size;
 986 
 987 		if (x - x_offset >= 0 &&
 988 		    x - x_offset <= eject_button_size) {
 989 			return TRUE;
 990 		}
 991 	}
 992 
 993  out:
 994 	if (*path != NULL) {
 995 		gtk_tree_path_free (*path);
 996 		*path = NULL;
 997 	}
 998 
 999 	return FALSE;
1000 }
1001 
1002 static gboolean
1003 clicked_eject_button (NautilusPlacesSidebar *sidebar,
1004 		      GtkTreePath **path)
1005 {
1006 	GdkEvent *event = gtk_get_current_event ();
1007 	GdkEventButton *button_event = (GdkEventButton *) event;
1008 
1009 	if ((event->type == GDK_BUTTON_PRESS || event->type == GDK_BUTTON_RELEASE) &&
1010 	     over_eject_button (sidebar, button_event->x, button_event->y, path)) {
1011 		return TRUE;
1012 	}
1013 
1014 	return FALSE;
1015 }
1016 
1017 static void
1018 desktop_setting_changed_callback (gpointer user_data)
1019 {
1020 	NautilusPlacesSidebar *sidebar;
1021 
1022 	sidebar = NAUTILUS_PLACES_SIDEBAR (user_data);
1023 
1024 	update_places (sidebar);
1025 }
1026 
1027 static void
1028 update_current_uri (NautilusPlacesSidebar *sidebar)
1029 {
1030 	GtkTreeSelection *selection;
1031 	GtkTreeIter 	 iter;
1032 	gboolean 	 valid;
1033 	char  		 *uri;
1034 
1035 	if (sidebar->uri == NULL) {
1036 		return;
1037 	}
1038 
1039 	/* set selection if any place matches location */
1040 	selection = gtk_tree_view_get_selection (sidebar->tree_view);
1041 	gtk_tree_selection_unselect_all (selection);
1042 	valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (sidebar->store),
1043 					       &iter);
1044 
1045 	while (valid) {
1046 		gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter,
1047 				    PLACES_SIDEBAR_COLUMN_URI, &uri,
1048 				    -1);
1049 
1050 		if (uri != NULL) {
1051 			if (strcmp (uri, sidebar->uri) == 0) {
1052 				g_free (uri);
1053 				gtk_tree_selection_select_iter (selection, &iter);
1054 				break;
1055 			}
1056 			g_free (uri);
1057 		}
1058 		valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (sidebar->store),
1059 						  &iter);
1060 	}
1061 }
1062 
1063 static void
1064 loading_uri_callback (NautilusWindow *window,
1065 		      char *location,
1066 		      NautilusPlacesSidebar *sidebar)
1067 {
1068         if (g_strcmp0 (sidebar->uri, location) != 0) {
1069 		g_free (sidebar->uri);
1070                 sidebar->uri = g_strdup (location);
1071 
1072 		update_current_uri (sidebar);
1073 	}
1074 }
1075 
1076 /* Computes the appropriate row and position for dropping */
1077 static gboolean
1078 compute_drop_position (GtkTreeView             *tree_view,
1079 		       int                      x,
1080 		       int                      y,
1081 		       GtkTreePath            **path,
1082 		       GtkTreeViewDropPosition *pos,
1083 		       NautilusPlacesSidebar   *sidebar)
1084 {
1085 	GtkTreeModel *model;
1086 	GtkTreeIter iter;
1087 	PlaceType place_type;
1088 	SectionType section_type;
1089 
1090 	if (!gtk_tree_view_get_dest_row_at_pos (tree_view,
1091 						x, y,
1092 						path, pos)) {
1093 		return FALSE;
1094 	}
1095 
1096 	model = gtk_tree_view_get_model (tree_view);
1097 
1098 	gtk_tree_model_get_iter (model, &iter, *path);
1099 	gtk_tree_model_get (model, &iter,
1100 			    PLACES_SIDEBAR_COLUMN_ROW_TYPE, &place_type,
1101 			    PLACES_SIDEBAR_COLUMN_SECTION_TYPE, &section_type,
1102 			    -1);
1103 
1104 	if (section_type != SECTION_BOOKMARKS &&
1105 	    place_type == PLACES_HEADING) {
1106 		/* never drop on headings, but special case the bookmarks heading,
1107 		 * so we can drop bookmarks in between it and the first item when
1108 		 * reordering.
1109 		 */
1110 		gtk_tree_path_free (*path);
1111 		*path = NULL;
1112 		
1113 		return FALSE;
1114 	}
1115 
1116 	if (section_type != SECTION_BOOKMARKS &&
1117 	    sidebar->drag_data_received &&
1118 	    sidebar->drag_data_info == GTK_TREE_MODEL_ROW) {
1119 		/* don't allow dropping bookmarks into non-bookmark areas */
1120 		gtk_tree_path_free (*path);
1121 		*path = NULL;
1122 
1123 		return FALSE;
1124 	}
1125 
1126 	if (sidebar->drag_data_received &&
1127 	    sidebar->drag_data_info == GTK_TREE_MODEL_ROW) {
1128 		/* bookmark rows can only be reordered */
1129 		*pos = GTK_TREE_VIEW_DROP_AFTER;
1130 	} else {
1131 		*pos = GTK_TREE_VIEW_DROP_INTO_OR_BEFORE;
1132 	}
1133 
1134 	return TRUE;
1135 }
1136 
1137 static gboolean
1138 get_drag_data (GtkTreeView *tree_view,
1139 	       GdkDragContext *context, 
1140 	       unsigned int time)
1141 {
1142 	GdkAtom target;
1143 
1144 	target = gtk_drag_dest_find_target (GTK_WIDGET (tree_view), 
1145 					    context, 
1146 					    NULL);
1147 
1148 	if (target == GDK_NONE) {
1149 		return FALSE;
1150 	}
1151 
1152 	gtk_drag_get_data (GTK_WIDGET (tree_view),
1153 			   context, target, time);
1154 
1155 	return TRUE;
1156 }
1157 
1158 static void
1159 free_drag_data (NautilusPlacesSidebar *sidebar)
1160 {
1161 	sidebar->drag_data_received = FALSE;
1162 
1163 	if (sidebar->drag_list) {
1164 		nautilus_drag_destroy_selection_list (sidebar->drag_list);
1165 		sidebar->drag_list = NULL;
1166 	}
1167 }
1168 
1169 static gboolean
1170 drag_motion_callback (GtkTreeView *tree_view,
1171 		      GdkDragContext *context,
1172 		      int x,
1173 		      int y,
1174 		      unsigned int time,
1175 		      NautilusPlacesSidebar *sidebar)
1176 {
1177 	GtkTreePath *path;
1178 	GtkTreeViewDropPosition pos;
1179 	int action;
1180 	GtkTreeIter iter;
1181 	char *uri;
1182 	gboolean res;
1183 
1184 	if (!sidebar->drag_data_received) {
1185 		if (!get_drag_data (tree_view, context, time)) {
1186 			return FALSE;
1187 		}
1188 	}
1189 
1190 	path = NULL;
1191 	res = compute_drop_position (tree_view, x, y, &path, &pos, sidebar);
1192 
1193 	if (!res) {
1194 		goto out;
1195 	}
1196 
1197 	if (pos == GTK_TREE_VIEW_DROP_AFTER ) {
1198 		if (sidebar->drag_data_received &&
1199 		    sidebar->drag_data_info == GTK_TREE_MODEL_ROW) {
1200 			action = GDK_ACTION_MOVE;
1201 		} else {
1202 			action = 0;
1203 		}
1204 	} else {
1205 		if (sidebar->drag_list == NULL) {
1206 			action = 0;
1207 		} else {
1208 			gtk_tree_model_get_iter (GTK_TREE_MODEL (sidebar->store),
1209 						 &iter, path);
1210 			gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store),
1211 					    &iter,
1212 					    PLACES_SIDEBAR_COLUMN_URI, &uri,
1213 					    -1);
1214 			nautilus_drag_default_drop_action_for_icons (context, uri,
1215 								     sidebar->drag_list,
1216 								     &action);
1217 			g_free (uri);
1218 		}
1219 	}
1220 
1221 	if (action != 0) {
1222 		gtk_tree_view_set_drag_dest_row (tree_view, path, pos);
1223 	}
1224 
1225 	if (path != NULL) {
1226 		gtk_tree_path_free (path);
1227 	}
1228 
1229  out:
1230 	g_signal_stop_emission_by_name (tree_view, "drag-motion");
1231 
1232 	if (action != 0) {
Uninitialized variable: action
(emitted by cppcheck)
The left operand of '!=' is a garbage value
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

1233 gdk_drag_status (context, action, time); 1234 } else { 1235 gdk_drag_status (context, 0, time); 1236 } 1237 1238 return TRUE; 1239 } 1240 1241 static void 1242 drag_leave_callback (GtkTreeView *tree_view, 1243 GdkDragContext *context, 1244 unsigned int time, 1245 NautilusPlacesSidebar *sidebar) 1246 { 1247 free_drag_data (sidebar); 1248 gtk_tree_view_set_drag_dest_row (tree_view, NULL, 0); 1249 g_signal_stop_emission_by_name (tree_view, "drag-leave"); 1250 } 1251 1252 static GList * 1253 uri_list_from_selection (GList *selection) 1254 { 1255 NautilusDragSelectionItem *item; 1256 GList *ret; 1257 GList *l; 1258 1259 ret = NULL; 1260 for (l = selection; l != NULL; l = l->next) { 1261 item = l->data; 1262 ret = g_list_prepend (ret, item->uri); 1263 } 1264 1265 return g_list_reverse (ret); 1266 } 1267 1268 static GList* 1269 build_selection_list (const char *data) 1270 { 1271 NautilusDragSelectionItem *item; 1272 GList *result; 1273 char **uris; 1274 char *uri; 1275 int i; 1276 1277 uris = g_uri_list_extract_uris (data); 1278 1279 result = NULL; 1280 for (i = 0; uris[i]; i++) { 1281 uri = uris[i]; 1282 item = nautilus_drag_selection_item_new (); 1283 item->uri = g_strdup (uri); 1284 item->got_icon_position = FALSE; 1285 result = g_list_prepend (result, item); 1286 } 1287 1288 g_strfreev (uris); 1289 1290 return g_list_reverse (result); 1291 } 1292 1293 static gboolean 1294 get_selected_iter (NautilusPlacesSidebar *sidebar, 1295 GtkTreeIter *iter) 1296 { 1297 GtkTreeSelection *selection; 1298 1299 selection = gtk_tree_view_get_selection (sidebar->tree_view); 1300 1301 return gtk_tree_selection_get_selected (selection, NULL, iter); 1302 } 1303 1304 /* Reorders the selected bookmark to the specified position */ 1305 static void 1306 reorder_bookmarks (NautilusPlacesSidebar *sidebar, 1307 int new_position) 1308 { 1309 GtkTreeIter iter; 1310 PlaceType type; 1311 int old_position; 1312 1313 /* Get the selected path */ 1314 if (!get_selected_iter (sidebar, &iter)) { 1315 return; 1316 } 1317 1318 gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter, 1319 PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type, 1320 PLACES_SIDEBAR_COLUMN_INDEX, &old_position, 1321 -1); 1322 1323 if (type != PLACES_BOOKMARK || 1324 old_position < 0 || 1325 old_position >= nautilus_bookmark_list_length (sidebar->bookmarks)) { 1326 return; 1327 } 1328 1329 nautilus_bookmark_list_move_item (sidebar->bookmarks, old_position, 1330 new_position); 1331 } 1332 1333 static void 1334 drag_data_received_callback (GtkWidget *widget, 1335 GdkDragContext *context, 1336 int x, 1337 int y, 1338 GtkSelectionData *selection_data, 1339 unsigned int info, 1340 unsigned int time, 1341 NautilusPlacesSidebar *sidebar) 1342 { 1343 GtkTreeView *tree_view; 1344 GtkTreePath *tree_path; 1345 GtkTreeViewDropPosition tree_pos; 1346 GtkTreeIter iter; 1347 int position; 1348 GtkTreeModel *model; 1349 char *drop_uri; 1350 GList *selection_list, *uris; 1351 PlaceType place_type; 1352 SectionType section_type; 1353 gboolean success; 1354 1355 tree_view = GTK_TREE_VIEW (widget); 1356 1357 if (!sidebar->drag_data_received) { 1358 if (gtk_selection_data_get_target (selection_data) != GDK_NONE && 1359 info == TEXT_URI_LIST) { 1360 sidebar->drag_list = build_selection_list ((const gchar *) gtk_selection_data_get_data (selection_data)); 1361 } else { 1362 sidebar->drag_list = NULL; 1363 } 1364 sidebar->drag_data_received = TRUE; 1365 sidebar->drag_data_info = info; 1366 } 1367 1368 g_signal_stop_emission_by_name (widget, "drag-data-received"); 1369 1370 if (!sidebar->drop_occured) { 1371 return; 1372 } 1373 1374 /* Compute position */ 1375 success = compute_drop_position (tree_view, x, y, &tree_path, &tree_pos, sidebar); 1376 if (!success) { 1377 goto out; 1378 } 1379 1380 success = FALSE; 1381 1382 if (tree_pos == GTK_TREE_VIEW_DROP_AFTER) { 1383 model = gtk_tree_view_get_model (tree_view); 1384 1385 if (!gtk_tree_model_get_iter (model, &iter, tree_path)) { 1386 goto out; 1387 } 1388 1389 gtk_tree_model_get (model, &iter, 1390 PLACES_SIDEBAR_COLUMN_SECTION_TYPE, &section_type, 1391 PLACES_SIDEBAR_COLUMN_ROW_TYPE, &place_type, 1392 PLACES_SIDEBAR_COLUMN_INDEX, &position, 1393 -1); 1394 1395 if (section_type != SECTION_BOOKMARKS) { 1396 goto out; 1397 } 1398 1399 if (tree_pos == GTK_TREE_VIEW_DROP_AFTER && place_type != PLACES_HEADING) { 1400 /* heading already has position 0 */ 1401 position++; 1402 } 1403 1404 switch (info) { 1405 case GTK_TREE_MODEL_ROW: 1406 reorder_bookmarks (sidebar, position); 1407 success = TRUE; 1408 break; 1409 default: 1410 g_assert_not_reached (); 1411 break; 1412 } 1413 } else { 1414 GdkDragAction real_action; 1415 1416 /* file transfer requested */ 1417 real_action = gdk_drag_context_get_selected_action (context); 1418 1419 if (real_action == GDK_ACTION_ASK) { 1420 real_action = 1421 nautilus_drag_drop_action_ask (GTK_WIDGET (tree_view), 1422 gdk_drag_context_get_actions (context)); 1423 } 1424 1425 if (real_action > 0) { 1426 model = gtk_tree_view_get_model (tree_view); 1427 1428 gtk_tree_model_get_iter (model, &iter, tree_path); 1429 gtk_tree_model_get (model, &iter, 1430 PLACES_SIDEBAR_COLUMN_URI, &drop_uri, 1431 -1); 1432 1433 switch (info) { 1434 case TEXT_URI_LIST: 1435 selection_list = build_selection_list ((const gchar *) gtk_selection_data_get_data (selection_data)); 1436 uris = uri_list_from_selection (selection_list); 1437 nautilus_file_operations_copy_move (uris, NULL, drop_uri, 1438 real_action, GTK_WIDGET (tree_view), 1439 NULL, NULL); 1440 nautilus_drag_destroy_selection_list (selection_list); 1441 g_list_free (uris); 1442 success = TRUE; 1443 break; 1444 case GTK_TREE_MODEL_ROW: 1445 success = FALSE; 1446 break; 1447 default: 1448 g_assert_not_reached (); 1449 break; 1450 } 1451 1452 g_free (drop_uri); 1453 } 1454 } 1455 1456 out: 1457 sidebar->drop_occured = FALSE; 1458 free_drag_data (sidebar); 1459 gtk_drag_finish (context, success, FALSE, time); 1460 1461 gtk_tree_path_free (tree_path); 1462 } 1463 1464 static gboolean 1465 drag_drop_callback (GtkTreeView *tree_view, 1466 GdkDragContext *context, 1467 int x, 1468 int y, 1469 unsigned int time, 1470 NautilusPlacesSidebar *sidebar) 1471 { 1472 gboolean retval = FALSE; 1473 sidebar->drop_occured = TRUE; 1474 retval = get_drag_data (tree_view, context, time); 1475 g_signal_stop_emission_by_name (tree_view, "drag-drop"); 1476 return retval; 1477 } 1478 1479 /* Callback used when the file list's popup menu is detached */ 1480 static void 1481 bookmarks_popup_menu_detach_cb (GtkWidget *attach_widget, 1482 GtkMenu *menu) 1483 { 1484 NautilusPlacesSidebar *sidebar; 1485 1486 sidebar = NAUTILUS_PLACES_SIDEBAR (attach_widget); 1487 g_assert (NAUTILUS_IS_PLACES_SIDEBAR (sidebar)); 1488 1489 sidebar->popup_menu = NULL; 1490 sidebar->popup_menu_add_shortcut_item = NULL; 1491 sidebar->popup_menu_remove_item = NULL; 1492 sidebar->popup_menu_rename_item = NULL; 1493 sidebar->popup_menu_separator_item = NULL; 1494 sidebar->popup_menu_mount_item = NULL; 1495 sidebar->popup_menu_unmount_item = NULL; 1496 sidebar->popup_menu_eject_item = NULL; 1497 sidebar->popup_menu_rescan_item = NULL; 1498 sidebar->popup_menu_start_item = NULL; 1499 sidebar->popup_menu_stop_item = NULL; 1500 sidebar->popup_menu_empty_trash_item = NULL; 1501 sidebar->popup_menu_properties_separator_item = NULL; 1502 sidebar->popup_menu_properties_item = NULL; 1503 } 1504 1505 static void 1506 check_unmount_and_eject (GMount *mount, 1507 GVolume *volume, 1508 GDrive *drive, 1509 gboolean *show_unmount, 1510 gboolean *show_eject) 1511 { 1512 *show_unmount = FALSE; 1513 *show_eject = FALSE; 1514 1515 if (drive != NULL) { 1516 *show_eject = g_drive_can_eject (drive); 1517 } 1518 1519 if (volume != NULL) { 1520 *show_eject |= g_volume_can_eject (volume); 1521 } 1522 if (mount != NULL) { 1523 *show_eject |= g_mount_can_eject (mount); 1524 *show_unmount = g_mount_can_unmount (mount) && !*show_eject; 1525 } 1526 } 1527 1528 static void 1529 check_visibility (GMount *mount, 1530 GVolume *volume, 1531 GDrive *drive, 1532 gboolean *show_mount, 1533 gboolean *show_unmount, 1534 gboolean *show_eject, 1535 gboolean *show_rescan, 1536 gboolean *show_start, 1537 gboolean *show_stop) 1538 { 1539 *show_mount = FALSE; 1540 *show_rescan = FALSE; 1541 *show_start = FALSE; 1542 *show_stop = FALSE; 1543 1544 check_unmount_and_eject (mount, volume, drive, show_unmount, show_eject); 1545 1546 if (drive != NULL) { 1547 if (g_drive_is_media_removable (drive) && 1548 !g_drive_is_media_check_automatic (drive) && 1549 g_drive_can_poll_for_media (drive)) 1550 *show_rescan = TRUE; 1551 1552 *show_start = g_drive_can_start (drive) || g_drive_can_start_degraded (drive); 1553 *show_stop = g_drive_can_stop (drive); 1554 1555 if (*show_stop) 1556 *show_unmount = FALSE; 1557 } 1558 1559 if (volume != NULL) { 1560 if (mount == NULL) 1561 *show_mount = g_volume_can_mount (volume); 1562 } 1563 } 1564 1565 static void 1566 bookmarks_check_popup_sensitivity (NautilusPlacesSidebar *sidebar) 1567 { 1568 GtkTreeIter iter; 1569 PlaceType type; 1570 GDrive *drive = NULL; 1571 GVolume *volume = NULL; 1572 GMount *mount = NULL; 1573 GFile *location; 1574 NautilusDirectory *directory; 1575 gboolean show_mount; 1576 gboolean show_unmount; 1577 gboolean show_eject; 1578 gboolean show_rescan; 1579 gboolean show_start; 1580 gboolean show_stop; 1581 gboolean show_empty_trash; 1582 gboolean show_properties; 1583 char *uri = NULL; 1584 1585 type = PLACES_BUILT_IN; 1586 1587 if (sidebar->popup_menu == NULL) { 1588 return; 1589 } 1590 1591 if (get_selected_iter (sidebar, &iter)) { 1592 gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter, 1593 PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type, 1594 PLACES_SIDEBAR_COLUMN_DRIVE, &drive, 1595 PLACES_SIDEBAR_COLUMN_VOLUME, &volume, 1596 PLACES_SIDEBAR_COLUMN_MOUNT, &mount, 1597 PLACES_SIDEBAR_COLUMN_URI, &uri, 1598 -1); 1599 } 1600 1601 gtk_widget_set_visible (sidebar->popup_menu_add_shortcut_item, (type == PLACES_MOUNTED_VOLUME)); 1602 1603 gtk_widget_set_sensitive (sidebar->popup_menu_remove_item, (type == PLACES_BOOKMARK)); 1604 gtk_widget_set_sensitive (sidebar->popup_menu_rename_item, (type == PLACES_BOOKMARK)); 1605 gtk_widget_set_sensitive (sidebar->popup_menu_empty_trash_item, !nautilus_trash_monitor_is_empty ()); 1606 1607 check_visibility (mount, volume, drive, 1608 &show_mount, &show_unmount, &show_eject, &show_rescan, &show_start, &show_stop); 1609 1610 /* We actually want both eject and unmount since eject will unmount all volumes. 1611 * TODO: hide unmount if the drive only has a single mountable volume 1612 */ 1613 1614 show_empty_trash = (uri != NULL) && 1615 (!strcmp (uri, "trash:///")); 1616 1617 /* Only show properties for local mounts */ 1618 show_properties = (mount != NULL); 1619 if (mount != NULL) { 1620 location = g_mount_get_default_location (mount); 1621 directory = nautilus_directory_get (location); 1622 1623 show_properties = nautilus_directory_is_local (directory); 1624 1625 nautilus_directory_unref (directory); 1626 g_object_unref (location); 1627 } 1628 1629 gtk_widget_set_visible (sidebar->popup_menu_separator_item, 1630 show_mount || show_unmount || show_eject || show_empty_trash); 1631 gtk_widget_set_visible (sidebar->popup_menu_mount_item, show_mount); 1632 gtk_widget_set_visible (sidebar->popup_menu_unmount_item, show_unmount); 1633 gtk_widget_set_visible (sidebar->popup_menu_eject_item, show_eject); 1634 gtk_widget_set_visible (sidebar->popup_menu_rescan_item, show_rescan); 1635 gtk_widget_set_visible (sidebar->popup_menu_start_item, show_start); 1636 gtk_widget_set_visible (sidebar->popup_menu_stop_item, show_stop); 1637 gtk_widget_set_visible (sidebar->popup_menu_empty_trash_item, show_empty_trash); 1638 gtk_widget_set_visible (sidebar->popup_menu_properties_separator_item, show_properties); 1639 gtk_widget_set_visible (sidebar->popup_menu_properties_item, show_properties); 1640 1641 /* Adjust start/stop items to reflect the type of the drive */ 1642 gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_start_item), _("_Start")); 1643 gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_stop_item), _("_Stop")); 1644 if ((show_start || show_stop) && drive != NULL) { 1645 switch (g_drive_get_start_stop_type (drive)) { 1646 case G_DRIVE_START_STOP_TYPE_SHUTDOWN: 1647 /* start() for type G_DRIVE_START_STOP_TYPE_SHUTDOWN is normally not used */ 1648 gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_start_item), _("_Power On")); 1649 gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_stop_item), _("_Safely Remove Drive")); 1650 break; 1651 case G_DRIVE_START_STOP_TYPE_NETWORK: 1652 gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_start_item), _("_Connect Drive")); 1653 gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_stop_item), _("_Disconnect Drive")); 1654 break; 1655 case G_DRIVE_START_STOP_TYPE_MULTIDISK: 1656 gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_start_item), _("_Start Multi-disk Device")); 1657 gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_stop_item), _("_Stop Multi-disk Device")); 1658 break; 1659 case G_DRIVE_START_STOP_TYPE_PASSWORD: 1660 /* stop() for type G_DRIVE_START_STOP_TYPE_PASSWORD is normally not used */ 1661 gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_start_item), _("_Unlock Drive")); 1662 gtk_menu_item_set_label (GTK_MENU_ITEM (sidebar->popup_menu_stop_item), _("_Lock Drive")); 1663 break; 1664 1665 default: 1666 case G_DRIVE_START_STOP_TYPE_UNKNOWN: 1667 /* uses defaults set above */ 1668 break; 1669 } 1670 } 1671 1672 1673 g_free (uri); 1674 } 1675 1676 /* Callback used when the selection in the shortcuts tree changes */ 1677 static void 1678 bookmarks_selection_changed_cb (GtkTreeSelection *selection, 1679 NautilusPlacesSidebar *sidebar) 1680 { 1681 bookmarks_check_popup_sensitivity (sidebar); 1682 } 1683 1684 static void 1685 volume_mounted_cb (GVolume *volume, 1686 gboolean success, 1687 GObject *user_data) 1688 { 1689 GMount *mount; 1690 NautilusPlacesSidebar *sidebar; 1691 GFile *location; 1692 1693 sidebar = NAUTILUS_PLACES_SIDEBAR (user_data); 1694 1695 sidebar->mounting = FALSE; 1696 1697 mount = g_volume_get_mount (volume); 1698 if (mount != NULL) { 1699 location = g_mount_get_default_location (mount); 1700 1701 if (sidebar->go_to_after_mount_slot != NULL) { 1702 if ((sidebar->go_to_after_mount_flags & NAUTILUS_WINDOW_OPEN_FLAG_NEW_WINDOW) == 0) { 1703 nautilus_window_slot_open_location (sidebar->go_to_after_mount_slot, location, 1704 sidebar->go_to_after_mount_flags); 1705 } else { 1706 NautilusWindow *new, *cur; 1707 1708 cur = NAUTILUS_WINDOW (sidebar->window); 1709 new = nautilus_application_create_window (NAUTILUS_APPLICATION (g_application_get_default ()), 1710 gtk_window_get_screen (GTK_WINDOW (cur))); 1711 nautilus_window_go_to (new, location); 1712 } 1713 } 1714 1715 g_object_unref (G_OBJECT (location)); 1716 g_object_unref (G_OBJECT (mount)); 1717 } 1718 1719 if (sidebar->go_to_after_mount_slot) { 1720 g_object_remove_weak_pointer (G_OBJECT (sidebar->go_to_after_mount_slot), 1721 (gpointer *) &sidebar->go_to_after_mount_slot); 1722 sidebar->go_to_after_mount_slot = NULL; 1723 } 1724 } 1725 1726 static void 1727 drive_start_from_bookmark_cb (GObject *source_object, 1728 GAsyncResult *res, 1729 gpointer user_data) 1730 { 1731 GError *error; 1732 char *primary; 1733 char *name; 1734 1735 error = NULL; 1736 if (!g_drive_poll_for_media_finish (G_DRIVE (source_object), res, &error)) { 1737 if (error->code != G_IO_ERROR_FAILED_HANDLED) { 1738 name = g_drive_get_name (G_DRIVE (source_object)); 1739 primary = g_strdup_printf (_("Unable to start %s"), name); 1740 g_free (name); 1741 eel_show_error_dialog (primary, 1742 error->message, 1743 NULL); 1744 g_free (primary); 1745 } 1746 g_error_free (error); 1747 } 1748 } 1749 1750 static void 1751 open_selected_bookmark (NautilusPlacesSidebar *sidebar, 1752 GtkTreeModel *model, 1753 GtkTreeIter *iter, 1754 NautilusWindowOpenFlags flags) 1755 { 1756 NautilusWindowSlot *slot; 1757 GFile *location; 1758 char *uri; 1759 1760 if (!iter) { 1761 return; 1762 } 1763 1764 gtk_tree_model_get (model, iter, PLACES_SIDEBAR_COLUMN_URI, &uri, -1); 1765 1766 if (uri != NULL) { 1767 DEBUG ("Activating bookmark %s", uri); 1768 1769 location = g_file_new_for_uri (uri); 1770 /* Navigate to the clicked location */ 1771 if ((flags & NAUTILUS_WINDOW_OPEN_FLAG_NEW_WINDOW) == 0) { 1772 slot = nautilus_window_get_active_slot (sidebar->window); 1773 nautilus_window_slot_open_location (slot, location, flags); 1774 } else { 1775 NautilusWindow *cur, *new; 1776 1777 cur = NAUTILUS_WINDOW (sidebar->window); 1778 new = nautilus_application_create_window (NAUTILUS_APPLICATION (g_application_get_default ()), 1779 gtk_window_get_screen (GTK_WINDOW (cur))); 1780 nautilus_window_go_to (new, location); 1781 } 1782 g_object_unref (location); 1783 g_free (uri); 1784 1785 } else { 1786 GDrive *drive; 1787 GVolume *volume; 1788 NautilusWindowSlot *slot; 1789 1790 gtk_tree_model_get (model, iter, 1791 PLACES_SIDEBAR_COLUMN_DRIVE, &drive, 1792 PLACES_SIDEBAR_COLUMN_VOLUME, &volume, 1793 -1); 1794 1795 if (volume != NULL && !sidebar->mounting) { 1796 sidebar->mounting = TRUE; 1797 1798 g_assert (sidebar->go_to_after_mount_slot == NULL); 1799 1800 slot = nautilus_window_get_active_slot (sidebar->window); 1801 sidebar->go_to_after_mount_slot = slot; 1802 g_object_add_weak_pointer (G_OBJECT (sidebar->go_to_after_mount_slot), 1803 (gpointer *) &sidebar->go_to_after_mount_slot); 1804 1805 sidebar->go_to_after_mount_flags = flags; 1806 1807 nautilus_file_operations_mount_volume_full (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (sidebar))), 1808 volume, 1809 volume_mounted_cb, 1810 G_OBJECT (sidebar)); 1811 } else if (volume == NULL && drive != NULL && 1812 (g_drive_can_start (drive) || g_drive_can_start_degraded (drive))) { 1813 GMountOperation *mount_op; 1814 1815 mount_op = gtk_mount_operation_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (sidebar)))); 1816 g_drive_start (drive, G_DRIVE_START_NONE, mount_op, NULL, drive_start_from_bookmark_cb, NULL); 1817 g_object_unref (mount_op); 1818 } 1819 1820 if (drive != NULL) 1821 g_object_unref (drive); 1822 if (volume != NULL) 1823 g_object_unref (volume); 1824 } 1825 } 1826 1827 static void 1828 open_shortcut_from_menu (NautilusPlacesSidebar *sidebar, 1829 NautilusWindowOpenFlags flags) 1830 { 1831 GtkTreeModel *model; 1832 GtkTreeIter iter; 1833 GtkTreePath *path = NULL; 1834 1835 model = gtk_tree_view_get_model (sidebar->tree_view); 1836 gtk_tree_view_get_cursor (sidebar->tree_view, &path, NULL); 1837 1838 if (path != NULL && gtk_tree_model_get_iter (model, &iter, path)) { 1839 open_selected_bookmark (sidebar, model, &iter, flags); 1840 } 1841 1842 gtk_tree_path_free (path); 1843 } 1844 1845 static void 1846 open_shortcut_cb (GtkMenuItem *item, 1847 NautilusPlacesSidebar *sidebar) 1848 { 1849 open_shortcut_from_menu (sidebar, 0); 1850 } 1851 1852 static void 1853 open_shortcut_in_new_window_cb (GtkMenuItem *item, 1854 NautilusPlacesSidebar *sidebar) 1855 { 1856 open_shortcut_from_menu (sidebar, NAUTILUS_WINDOW_OPEN_FLAG_NEW_WINDOW); 1857 } 1858 1859 static void 1860 open_shortcut_in_new_tab_cb (GtkMenuItem *item, 1861 NautilusPlacesSidebar *sidebar) 1862 { 1863 open_shortcut_from_menu (sidebar, NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB); 1864 } 1865 1866 /* Add bookmark for the selected item */ 1867 static void 1868 add_bookmark (NautilusPlacesSidebar *sidebar) 1869 { 1870 GtkTreeModel *model; 1871 GtkTreeIter iter; 1872 char *uri; 1873 char *name; 1874 GFile *location; 1875 NautilusBookmark *bookmark; 1876 1877 model = gtk_tree_view_get_model (sidebar->tree_view); 1878 1879 if (get_selected_iter (sidebar, &iter)) { 1880 gtk_tree_model_get (model, &iter, 1881 PLACES_SIDEBAR_COLUMN_URI, &uri, 1882 PLACES_SIDEBAR_COLUMN_NAME, &name, 1883 -1); 1884 1885 if (uri == NULL) { 1886 return; 1887 } 1888 1889 location = g_file_new_for_uri (uri); 1890 bookmark = nautilus_bookmark_new (location, name); 1891 1892 if (!nautilus_bookmark_list_contains (sidebar->bookmarks, bookmark)) { 1893 nautilus_bookmark_list_append (sidebar->bookmarks, bookmark); 1894 } 1895 1896 g_object_unref (location); 1897 g_object_unref (bookmark); 1898 g_free (uri); 1899 g_free (name); 1900 } 1901 } 1902 1903 static void 1904 add_shortcut_cb (GtkMenuItem *item, 1905 NautilusPlacesSidebar *sidebar) 1906 { 1907 add_bookmark (sidebar); 1908 } 1909 1910 /* Rename the selected bookmark */ 1911 static void 1912 rename_selected_bookmark (NautilusPlacesSidebar *sidebar) 1913 { 1914 GtkTreeIter iter; 1915 GtkTreePath *path; 1916 GtkTreeViewColumn *column; 1917 GtkCellRenderer *cell; 1918 GList *renderers; 1919 PlaceType type; 1920 1921 if (get_selected_iter (sidebar, &iter)) { 1922 gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter, 1923 PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type, 1924 -1); 1925 1926 if (type != PLACES_BOOKMARK) { 1927 return; 1928 } 1929 1930 path = gtk_tree_model_get_path (GTK_TREE_MODEL (sidebar->store), &iter); 1931 column = gtk_tree_view_get_column (GTK_TREE_VIEW (sidebar->tree_view), 0); 1932 renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (column)); 1933 cell = g_list_nth_data (renderers, 6); 1934 g_list_free (renderers); 1935 g_object_set (cell, "editable", TRUE, NULL); 1936 gtk_tree_view_set_cursor_on_cell (GTK_TREE_VIEW (sidebar->tree_view), 1937 path, column, cell, TRUE); 1938 gtk_tree_path_free (path); 1939 } 1940 } 1941 1942 static void 1943 rename_shortcut_cb (GtkMenuItem *item, 1944 NautilusPlacesSidebar *sidebar) 1945 { 1946 rename_selected_bookmark (sidebar); 1947 } 1948 1949 /* Removes the selected bookmarks */ 1950 static void 1951 remove_selected_bookmarks (NautilusPlacesSidebar *sidebar) 1952 { 1953 GtkTreeIter iter; 1954 PlaceType type; 1955 int index; 1956 1957 if (!get_selected_iter (sidebar, &iter)) { 1958 return; 1959 } 1960 1961 gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter, 1962 PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type, 1963 -1); 1964 1965 if (type != PLACES_BOOKMARK) { 1966 return; 1967 } 1968 1969 gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter, 1970 PLACES_SIDEBAR_COLUMN_INDEX, &index, 1971 -1); 1972 1973 nautilus_bookmark_list_delete_item_at (sidebar->bookmarks, index); 1974 } 1975 1976 static void 1977 remove_shortcut_cb (GtkMenuItem *item, 1978 NautilusPlacesSidebar *sidebar) 1979 { 1980 remove_selected_bookmarks (sidebar); 1981 } 1982 1983 static void 1984 mount_shortcut_cb (GtkMenuItem *item, 1985 NautilusPlacesSidebar *sidebar) 1986 { 1987 GtkTreeIter iter; 1988 GVolume *volume; 1989 1990 if (!get_selected_iter (sidebar, &iter)) { 1991 return; 1992 } 1993 1994 gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter, 1995 PLACES_SIDEBAR_COLUMN_VOLUME, &volume, 1996 -1); 1997 1998 if (volume != NULL) { 1999 nautilus_file_operations_mount_volume (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (sidebar))), volume); 2000 g_object_unref (volume); 2001 } 2002 } 2003 2004 static void 2005 unmount_done (gpointer data) 2006 { 2007 NautilusWindow *window; 2008 2009 window = data; 2010 g_object_unref (window); 2011 } 2012 2013 static void 2014 show_unmount_progress_cb (GMountOperation *op, 2015 const gchar *message, 2016 gint64 time_left, 2017 gint64 bytes_left, 2018 gpointer user_data) 2019 { 2020 NautilusApplication *app = NAUTILUS_APPLICATION (g_application_get_default ()); 2021 2022 if (bytes_left == 0) { 2023 nautilus_application_notify_unmount_done (app, message); 2024 } else { 2025 nautilus_application_notify_unmount_show (app, message); 2026 } 2027 } 2028 2029 static void 2030 show_unmount_progress_aborted_cb (GMountOperation *op, 2031 gpointer user_data) 2032 { 2033 NautilusApplication *app = NAUTILUS_APPLICATION (g_application_get_default ()); 2034 nautilus_application_notify_unmount_done (app, NULL); 2035 } 2036 2037 static GMountOperation * 2038 get_unmount_operation (NautilusPlacesSidebar *sidebar) 2039 { 2040 GMountOperation *mount_op; 2041 2042 mount_op = gtk_mount_operation_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (sidebar)))); 2043 g_signal_connect (mount_op, "show-unmount-progress", 2044 G_CALLBACK (show_unmount_progress_cb), sidebar); 2045 g_signal_connect (mount_op, "aborted", 2046 G_CALLBACK (show_unmount_progress_aborted_cb), sidebar); 2047 2048 return mount_op; 2049 } 2050 2051 static void 2052 do_unmount (GMount *mount, 2053 NautilusPlacesSidebar *sidebar) 2054 { 2055 GMountOperation *mount_op; 2056 2057 if (mount != NULL) { 2058 mount_op = get_unmount_operation (sidebar); 2059 nautilus_file_operations_unmount_mount_full (NULL, mount, mount_op, FALSE, TRUE, 2060 unmount_done, 2061 g_object_ref (sidebar->window)); 2062 g_object_unref (mount_op); 2063 } 2064 } 2065 2066 static void 2067 do_unmount_selection (NautilusPlacesSidebar *sidebar) 2068 { 2069 GtkTreeIter iter; 2070 GMount *mount; 2071 2072 if (!get_selected_iter (sidebar, &iter)) { 2073 return; 2074 } 2075 2076 gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter, 2077 PLACES_SIDEBAR_COLUMN_MOUNT, &mount, 2078 -1); 2079 2080 if (mount != NULL) { 2081 do_unmount (mount, sidebar); 2082 g_object_unref (mount); 2083 } 2084 } 2085 2086 static void 2087 unmount_shortcut_cb (GtkMenuItem *item, 2088 NautilusPlacesSidebar *sidebar) 2089 { 2090 do_unmount_selection (sidebar); 2091 } 2092 2093 static void 2094 drive_eject_cb (GObject *source_object, 2095 GAsyncResult *res, 2096 gpointer user_data) 2097 { 2098 NautilusWindow *window; 2099 GError *error; 2100 char *primary; 2101 char *name; 2102 2103 window = user_data; 2104 g_object_unref (window); 2105 2106 error = NULL; 2107 if (!g_drive_eject_with_operation_finish (G_DRIVE (source_object), res, &error)) { 2108 if (error->code != G_IO_ERROR_FAILED_HANDLED) { 2109 name = g_drive_get_name (G_DRIVE (source_object)); 2110 primary = g_strdup_printf (_("Unable to eject %s"), name); 2111 g_free (name); 2112 eel_show_error_dialog (primary, 2113 error->message, 2114 NULL); 2115 g_free (primary); 2116 } 2117 g_error_free (error); 2118 } 2119 } 2120 2121 static void 2122 volume_eject_cb (GObject *source_object, 2123 GAsyncResult *res, 2124 gpointer user_data) 2125 { 2126 NautilusWindow *window; 2127 GError *error; 2128 char *primary; 2129 char *name; 2130 2131 window = user_data; 2132 g_object_unref (window); 2133 2134 error = NULL; 2135 if (!g_volume_eject_with_operation_finish (G_VOLUME (source_object), res, &error)) { 2136 if (error->code != G_IO_ERROR_FAILED_HANDLED) { 2137 name = g_volume_get_name (G_VOLUME (source_object)); 2138 primary = g_strdup_printf (_("Unable to eject %s"), name); 2139 g_free (name); 2140 eel_show_error_dialog (primary, 2141 error->message, 2142 NULL); 2143 g_free (primary); 2144 } 2145 g_error_free (error); 2146 } 2147 } 2148 2149 static void 2150 mount_eject_cb (GObject *source_object, 2151 GAsyncResult *res, 2152 gpointer user_data) 2153 { 2154 NautilusWindow *window; 2155 GError *error; 2156 char *primary; 2157 char *name; 2158 2159 window = user_data; 2160 g_object_unref (window); 2161 2162 error = NULL; 2163 if (!g_mount_eject_with_operation_finish (G_MOUNT (source_object), res, &error)) { 2164 if (error->code != G_IO_ERROR_FAILED_HANDLED) { 2165 name = g_mount_get_name (G_MOUNT (source_object)); 2166 primary = g_strdup_printf (_("Unable to eject %s"), name); 2167 g_free (name); 2168 eel_show_error_dialog (primary, 2169 error->message, 2170 NULL); 2171 g_free (primary); 2172 } 2173 g_error_free (error); 2174 } 2175 } 2176 2177 static void 2178 do_eject (GMount *mount, 2179 GVolume *volume, 2180 GDrive *drive, 2181 NautilusPlacesSidebar *sidebar) 2182 { 2183 GMountOperation *mount_op = get_unmount_operation (sidebar); 2184 2185 if (mount != NULL) { 2186 g_mount_eject_with_operation (mount, 0, mount_op, NULL, mount_eject_cb, 2187 g_object_ref (sidebar->window)); 2188 } else if (volume != NULL) { 2189 g_volume_eject_with_operation (volume, 0, mount_op, NULL, volume_eject_cb, 2190 g_object_ref (sidebar->window)); 2191 } else if (drive != NULL) { 2192 g_drive_eject_with_operation (drive, 0, mount_op, NULL, drive_eject_cb, 2193 g_object_ref (sidebar->window)); 2194 } 2195 2196 g_object_unref (mount_op); 2197 } 2198 2199 static void 2200 eject_shortcut_cb (GtkMenuItem *item, 2201 NautilusPlacesSidebar *sidebar) 2202 { 2203 GtkTreeIter iter; 2204 GMount *mount; 2205 GVolume *volume; 2206 GDrive *drive; 2207 2208 if (!get_selected_iter (sidebar, &iter)) { 2209 return; 2210 } 2211 2212 gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter, 2213 PLACES_SIDEBAR_COLUMN_MOUNT, &mount, 2214 PLACES_SIDEBAR_COLUMN_VOLUME, &volume, 2215 PLACES_SIDEBAR_COLUMN_DRIVE, &drive, 2216 -1); 2217 2218 do_eject (mount, volume, drive, sidebar); 2219 } 2220 2221 static gboolean 2222 eject_or_unmount_bookmark (NautilusPlacesSidebar *sidebar, 2223 GtkTreePath *path) 2224 { 2225 GtkTreeModel *model; 2226 GtkTreeIter iter; 2227 gboolean can_unmount, can_eject; 2228 GMount *mount; 2229 GVolume *volume; 2230 GDrive *drive; 2231 gboolean ret; 2232 2233 model = GTK_TREE_MODEL (sidebar->store); 2234 2235 if (!path) { 2236 return FALSE; 2237 } 2238 if (!gtk_tree_model_get_iter (model, &iter, path)) { 2239 return FALSE; 2240 } 2241 2242 gtk_tree_model_get (model, &iter, 2243 PLACES_SIDEBAR_COLUMN_MOUNT, &mount, 2244 PLACES_SIDEBAR_COLUMN_VOLUME, &volume, 2245 PLACES_SIDEBAR_COLUMN_DRIVE, &drive, 2246 -1); 2247 2248 ret = FALSE; 2249 2250 check_unmount_and_eject (mount, volume, drive, &can_unmount, &can_eject); 2251 /* if we can eject, it has priority over unmount */ 2252 if (can_eject) { 2253 do_eject (mount, volume, drive, sidebar); 2254 ret = TRUE; 2255 } else if (can_unmount) { 2256 do_unmount (mount, sidebar); 2257 ret = TRUE; 2258 } 2259 2260 if (mount != NULL) 2261 g_object_unref (mount); 2262 if (volume != NULL) 2263 g_object_unref (volume); 2264 if (drive != NULL) 2265 g_object_unref (drive); 2266 2267 return ret; 2268 } 2269 2270 static gboolean 2271 eject_or_unmount_selection (NautilusPlacesSidebar *sidebar) 2272 { 2273 GtkTreeIter iter; 2274 GtkTreePath *path; 2275 gboolean ret; 2276 2277 if (!get_selected_iter (sidebar, &iter)) { 2278 return FALSE; 2279 } 2280 2281 path = gtk_tree_model_get_path (GTK_TREE_MODEL (sidebar->store), &iter); 2282 if (path == NULL) { 2283 return FALSE; 2284 } 2285 2286 ret = eject_or_unmount_bookmark (sidebar, path); 2287 2288 gtk_tree_path_free (path); 2289 2290 return ret; 2291 } 2292 2293 static void 2294 drive_poll_for_media_cb (GObject *source_object, 2295 GAsyncResult *res, 2296 gpointer user_data) 2297 { 2298 GError *error; 2299 char *primary; 2300 char *name; 2301 2302 error = NULL; 2303 if (!g_drive_poll_for_media_finish (G_DRIVE (source_object), res, &error)) { 2304 if (error->code != G_IO_ERROR_FAILED_HANDLED) { 2305 name = g_drive_get_name (G_DRIVE (source_object)); 2306 primary = g_strdup_printf (_("Unable to poll %s for media changes"), name); 2307 g_free (name); 2308 eel_show_error_dialog (primary, 2309 error->message, 2310 NULL); 2311 g_free (primary); 2312 } 2313 g_error_free (error); 2314 } 2315 } 2316 2317 static void 2318 rescan_shortcut_cb (GtkMenuItem *item, 2319 NautilusPlacesSidebar *sidebar) 2320 { 2321 GtkTreeIter iter; 2322 GDrive *drive; 2323 2324 if (!get_selected_iter (sidebar, &iter)) { 2325 return; 2326 } 2327 2328 gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter, 2329 PLACES_SIDEBAR_COLUMN_DRIVE, &drive, 2330 -1); 2331 2332 if (drive != NULL) { 2333 g_drive_poll_for_media (drive, NULL, drive_poll_for_media_cb, NULL); 2334 } 2335 g_object_unref (drive); 2336 } 2337 2338 static void 2339 drive_start_cb (GObject *source_object, 2340 GAsyncResult *res, 2341 gpointer user_data) 2342 { 2343 GError *error; 2344 char *primary; 2345 char *name; 2346 2347 error = NULL; 2348 if (!g_drive_poll_for_media_finish (G_DRIVE (source_object), res, &error)) { 2349 if (error->code != G_IO_ERROR_FAILED_HANDLED) { 2350 name = g_drive_get_name (G_DRIVE (source_object)); 2351 primary = g_strdup_printf (_("Unable to start %s"), name); 2352 g_free (name); 2353 eel_show_error_dialog (primary, 2354 error->message, 2355 NULL); 2356 g_free (primary); 2357 } 2358 g_error_free (error); 2359 } 2360 } 2361 2362 static void 2363 start_shortcut_cb (GtkMenuItem *item, 2364 NautilusPlacesSidebar *sidebar) 2365 { 2366 GtkTreeIter iter; 2367 GDrive *drive; 2368 2369 if (!get_selected_iter (sidebar, &iter)) { 2370 return; 2371 } 2372 2373 gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter, 2374 PLACES_SIDEBAR_COLUMN_DRIVE, &drive, 2375 -1); 2376 2377 if (drive != NULL) { 2378 GMountOperation *mount_op; 2379 2380 mount_op = gtk_mount_operation_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (sidebar)))); 2381 2382 g_drive_start (drive, G_DRIVE_START_NONE, mount_op, NULL, drive_start_cb, NULL); 2383 2384 g_object_unref (mount_op); 2385 } 2386 g_object_unref (drive); 2387 } 2388 2389 static void 2390 drive_stop_cb (GObject *source_object, 2391 GAsyncResult *res, 2392 gpointer user_data) 2393 { 2394 NautilusWindow *window; 2395 GError *error; 2396 char *primary; 2397 char *name; 2398 2399 window = user_data; 2400 g_object_unref (window); 2401 2402 error = NULL; 2403 if (!g_drive_poll_for_media_finish (G_DRIVE (source_object), res, &error)) { 2404 if (error->code != G_IO_ERROR_FAILED_HANDLED) { 2405 name = g_drive_get_name (G_DRIVE (source_object)); 2406 primary = g_strdup_printf (_("Unable to stop %s"), name); 2407 g_free (name); 2408 eel_show_error_dialog (primary, 2409 error->message, 2410 NULL); 2411 g_free (primary); 2412 } 2413 g_error_free (error); 2414 } 2415 } 2416 2417 static void 2418 stop_shortcut_cb (GtkMenuItem *item, 2419 NautilusPlacesSidebar *sidebar) 2420 { 2421 GtkTreeIter iter; 2422 GDrive *drive; 2423 2424 if (!get_selected_iter (sidebar, &iter)) { 2425 return; 2426 } 2427 2428 gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter, 2429 PLACES_SIDEBAR_COLUMN_DRIVE, &drive, 2430 -1); 2431 2432 if (drive != NULL) { 2433 GMountOperation *mount_op = get_unmount_operation (sidebar); 2434 g_drive_stop (drive, G_MOUNT_UNMOUNT_NONE, mount_op, NULL, drive_stop_cb, 2435 g_object_ref (sidebar->window)); 2436 g_object_unref (mount_op); 2437 } 2438 g_object_unref (drive); 2439 } 2440 2441 static void 2442 empty_trash_cb (GtkMenuItem *item, 2443 NautilusPlacesSidebar *sidebar) 2444 { 2445 nautilus_file_operations_empty_trash (GTK_WIDGET (sidebar->window)); 2446 } 2447 2448 static gboolean 2449 find_prev_or_next_row (NautilusPlacesSidebar *sidebar, 2450 GtkTreeIter *iter, 2451 gboolean go_up) 2452 { 2453 GtkTreeModel *model = GTK_TREE_MODEL (sidebar->store); 2454 gboolean res; 2455 int place_type; 2456 2457 if (go_up) { 2458 res = gtk_tree_model_iter_previous (model, iter); 2459 } else { 2460 res = gtk_tree_model_iter_next (model, iter); 2461 } 2462 2463 if (res) { 2464 gtk_tree_model_get (model, iter, 2465 PLACES_SIDEBAR_COLUMN_ROW_TYPE, &place_type, 2466 -1); 2467 if (place_type == PLACES_HEADING) { 2468 if (go_up) { 2469 res = gtk_tree_model_iter_previous (model, iter); 2470 } else { 2471 res = gtk_tree_model_iter_next (model, iter); 2472 } 2473 } 2474 } 2475 2476 return res; 2477 } 2478 2479 static gboolean 2480 find_prev_row (NautilusPlacesSidebar *sidebar, GtkTreeIter *iter) 2481 { 2482 return find_prev_or_next_row (sidebar, iter, TRUE); 2483 } 2484 2485 static gboolean 2486 find_next_row (NautilusPlacesSidebar *sidebar, GtkTreeIter *iter) 2487 { 2488 return find_prev_or_next_row (sidebar, iter, FALSE); 2489 } 2490 2491 static void 2492 properties_cb (GtkMenuItem *item, 2493 NautilusPlacesSidebar *sidebar) 2494 { 2495 GtkTreeModel *model; 2496 GtkTreePath *path = NULL; 2497 GtkTreeIter iter; 2498 GList *list; 2499 NautilusFile *file; 2500 char *uri; 2501 2502 model = gtk_tree_view_get_model (sidebar->tree_view); 2503 gtk_tree_view_get_cursor (sidebar->tree_view, &path, NULL); 2504 2505 if (path == NULL || !gtk_tree_model_get_iter (model, &iter, path)) { 2506 gtk_tree_path_free (path); 2507 return; 2508 } 2509 2510 gtk_tree_model_get (model, &iter, PLACES_SIDEBAR_COLUMN_URI, &uri, -1); 2511 2512 if (uri != NULL) { 2513 2514 file = nautilus_file_get_by_uri (uri); 2515 list = g_list_prepend (NULL, nautilus_file_ref (file)); 2516 2517 nautilus_properties_window_present (list, GTK_WIDGET (sidebar), NULL); 2518 2519 nautilus_file_list_free (list); 2520 g_free (uri); 2521 } 2522 2523 gtk_tree_path_free (path); 2524 } 2525 2526 static gboolean 2527 nautilus_places_sidebar_focus (GtkWidget *widget, 2528 GtkDirectionType direction) 2529 { 2530 NautilusPlacesSidebar *sidebar = NAUTILUS_PLACES_SIDEBAR (widget); 2531 GtkTreePath *path; 2532 GtkTreeIter iter; 2533 gboolean res; 2534 2535 res = get_selected_iter (sidebar, &iter); 2536 2537 if (!res) { 2538 gtk_tree_model_get_iter_first (GTK_TREE_MODEL (sidebar->store), &iter); 2539 res = find_next_row (sidebar, &iter); 2540 if (res) { 2541 path = gtk_tree_model_get_path (GTK_TREE_MODEL (sidebar->store), &iter); 2542 gtk_tree_view_set_cursor (sidebar->tree_view, path, NULL, FALSE); 2543 gtk_tree_path_free (path); 2544 } 2545 } 2546 2547 return GTK_WIDGET_CLASS (nautilus_places_sidebar_parent_class)->focus (widget, direction); 2548 } 2549 2550 /* Handler for GtkWidget::key-press-event on the shortcuts list */ 2551 static gboolean 2552 bookmarks_key_press_event_cb (GtkWidget *widget, 2553 GdkEventKey *event, 2554 NautilusPlacesSidebar *sidebar) 2555 { 2556 guint modifiers; 2557 GtkTreeIter selected_iter; 2558 GtkTreePath *path; 2559 2560 if (!get_selected_iter (sidebar, &selected_iter)) { 2561 return FALSE; 2562 } 2563 2564 modifiers = gtk_accelerator_get_default_mod_mask (); 2565 2566 if ((event->keyval == GDK_KEY_Return || 2567 event->keyval == GDK_KEY_KP_Enter || 2568 event->keyval == GDK_KEY_ISO_Enter || 2569 event->keyval == GDK_KEY_space)) { 2570 NautilusWindowOpenFlags flags = 0; 2571 2572 if ((event->state & modifiers) == GDK_SHIFT_MASK) { 2573 flags = NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB; 2574 } else if ((event->state & modifiers) == GDK_CONTROL_MASK) { 2575 flags = NAUTILUS_WINDOW_OPEN_FLAG_NEW_WINDOW; 2576 } 2577 2578 open_selected_bookmark (sidebar, GTK_TREE_MODEL (sidebar->store), 2579 &selected_iter, flags); 2580 return TRUE; 2581 } 2582 2583 if (event->keyval == GDK_KEY_Down && 2584 (event->state & modifiers) == GDK_MOD1_MASK) { 2585 return eject_or_unmount_selection (sidebar); 2586 } 2587 2588 if (event->keyval == GDK_KEY_Up) { 2589 if (find_prev_row (sidebar, &selected_iter)) { 2590 path = gtk_tree_model_get_path (GTK_TREE_MODEL (sidebar->store), &selected_iter); 2591 gtk_tree_view_set_cursor (sidebar->tree_view, path, NULL, FALSE); 2592 gtk_tree_path_free (path); 2593 } 2594 return TRUE; 2595 } 2596 2597 if (event->keyval == GDK_KEY_Down) { 2598 if (find_next_row (sidebar, &selected_iter)) { 2599 path = gtk_tree_model_get_path (GTK_TREE_MODEL (sidebar->store), &selected_iter); 2600 gtk_tree_view_set_cursor (sidebar->tree_view, path, NULL, FALSE); 2601 gtk_tree_path_free (path); 2602 } 2603 return TRUE; 2604 } 2605 2606 if ((event->keyval == GDK_KEY_Delete 2607 || event->keyval == GDK_KEY_KP_Delete) 2608 && (event->state & modifiers) == 0) { 2609 remove_selected_bookmarks (sidebar); 2610 return TRUE; 2611 } 2612 2613 if ((event->keyval == GDK_KEY_F2) 2614 && (event->state & modifiers) == 0) { 2615 rename_selected_bookmark (sidebar); 2616 return TRUE; 2617 } 2618 2619 return FALSE; 2620 } 2621 2622 /* Constructs the popup menu for the file list if needed */ 2623 static void 2624 bookmarks_build_popup_menu (NautilusPlacesSidebar *sidebar) 2625 { 2626 GtkWidget *item; 2627 2628 if (sidebar->popup_menu) { 2629 return; 2630 } 2631 2632 sidebar->popup_menu = gtk_menu_new (); 2633 gtk_menu_attach_to_widget (GTK_MENU (sidebar->popup_menu), 2634 GTK_WIDGET (sidebar), 2635 bookmarks_popup_menu_detach_cb); 2636 2637 item = gtk_image_menu_item_new_with_mnemonic (_("_Open")); 2638 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), 2639 gtk_image_new_from_stock (GTK_STOCK_OPEN, GTK_ICON_SIZE_MENU)); 2640 g_signal_connect (item, "activate", 2641 G_CALLBACK (open_shortcut_cb), sidebar); 2642 gtk_widget_show (item); 2643 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item); 2644 2645 item = gtk_menu_item_new_with_mnemonic (_("Open in New _Tab")); 2646 sidebar->popup_menu_open_in_new_tab_item = item; 2647 g_signal_connect (item, "activate", 2648 G_CALLBACK (open_shortcut_in_new_tab_cb), sidebar); 2649 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item); 2650 gtk_widget_show (item); 2651 2652 item = gtk_menu_item_new_with_mnemonic (_("Open in New _Window")); 2653 g_signal_connect (item, "activate", 2654 G_CALLBACK (open_shortcut_in_new_window_cb), sidebar); 2655 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item); 2656 gtk_widget_show (item); 2657 2658 eel_gtk_menu_append_separator (GTK_MENU (sidebar->popup_menu)); 2659 2660 item = gtk_menu_item_new_with_mnemonic (_("_Add Bookmark")); 2661 sidebar->popup_menu_add_shortcut_item = item; 2662 g_signal_connect (item, "activate", 2663 G_CALLBACK (add_shortcut_cb), sidebar); 2664 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item); 2665 2666 item = gtk_image_menu_item_new_with_label (_("Remove")); 2667 sidebar->popup_menu_remove_item = item; 2668 gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item), 2669 gtk_image_new_from_stock (GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU)); 2670 g_signal_connect (item, "activate", 2671 G_CALLBACK (remove_shortcut_cb), sidebar); 2672 gtk_widget_show (item); 2673 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item); 2674 2675 item = gtk_menu_item_new_with_label (_("Rename...")); 2676 sidebar->popup_menu_rename_item = item; 2677 g_signal_connect (item, "activate", 2678 G_CALLBACK (rename_shortcut_cb), sidebar); 2679 gtk_widget_show (item); 2680 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item); 2681 2682 /* Mount/Unmount/Eject menu items */ 2683 2684 sidebar->popup_menu_separator_item = 2685 GTK_WIDGET (eel_gtk_menu_append_separator (GTK_MENU (sidebar->popup_menu))); 2686 2687 item = gtk_menu_item_new_with_mnemonic (_("_Mount")); 2688 sidebar->popup_menu_mount_item = item; 2689 g_signal_connect (item, "activate", 2690 G_CALLBACK (mount_shortcut_cb), sidebar); 2691 gtk_widget_show (item); 2692 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item); 2693 2694 item = gtk_menu_item_new_with_mnemonic (_("_Unmount")); 2695 sidebar->popup_menu_unmount_item = item; 2696 g_signal_connect (item, "activate", 2697 G_CALLBACK (unmount_shortcut_cb), sidebar); 2698 gtk_widget_show (item); 2699 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item); 2700 2701 item = gtk_menu_item_new_with_mnemonic (_("_Eject")); 2702 sidebar->popup_menu_eject_item = item; 2703 g_signal_connect (item, "activate", 2704 G_CALLBACK (eject_shortcut_cb), sidebar); 2705 gtk_widget_show (item); 2706 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item); 2707 2708 item = gtk_menu_item_new_with_mnemonic (_("_Detect Media")); 2709 sidebar->popup_menu_rescan_item = item; 2710 g_signal_connect (item, "activate", 2711 G_CALLBACK (rescan_shortcut_cb), sidebar); 2712 gtk_widget_show (item); 2713 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item); 2714 2715 item = gtk_menu_item_new_with_mnemonic (_("_Start")); 2716 sidebar->popup_menu_start_item = item; 2717 g_signal_connect (item, "activate", 2718 G_CALLBACK (start_shortcut_cb), sidebar); 2719 gtk_widget_show (item); 2720 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item); 2721 2722 item = gtk_menu_item_new_with_mnemonic (_("_Stop")); 2723 sidebar->popup_menu_stop_item = item; 2724 g_signal_connect (item, "activate", 2725 G_CALLBACK (stop_shortcut_cb), sidebar); 2726 gtk_widget_show (item); 2727 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item); 2728 2729 /* Empty Trash menu item */ 2730 2731 item = gtk_menu_item_new_with_mnemonic (_("Empty _Trash")); 2732 sidebar->popup_menu_empty_trash_item = item; 2733 g_signal_connect (item, "activate", 2734 G_CALLBACK (empty_trash_cb), sidebar); 2735 gtk_widget_show (item); 2736 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item); 2737 2738 /* Properties menu item */ 2739 2740 sidebar->popup_menu_properties_separator_item = 2741 GTK_WIDGET (eel_gtk_menu_append_separator (GTK_MENU (sidebar->popup_menu))); 2742 2743 item = gtk_menu_item_new_with_mnemonic (_("_Properties")); 2744 sidebar->popup_menu_properties_item = item; 2745 g_signal_connect (item, "activate", 2746 G_CALLBACK (properties_cb), sidebar); 2747 gtk_widget_show (item); 2748 gtk_menu_shell_append (GTK_MENU_SHELL (sidebar->popup_menu), item); 2749 2750 bookmarks_check_popup_sensitivity (sidebar); 2751 } 2752 2753 static void 2754 bookmarks_update_popup_menu (NautilusPlacesSidebar *sidebar) 2755 { 2756 bookmarks_build_popup_menu (sidebar); 2757 } 2758 2759 static void 2760 bookmarks_popup_menu (NautilusPlacesSidebar *sidebar, 2761 GdkEventButton *event) 2762 { 2763 bookmarks_update_popup_menu (sidebar); 2764 eel_pop_up_context_menu (GTK_MENU(sidebar->popup_menu), 2765 event); 2766 } 2767 2768 /* Callback used for the GtkWidget::popup-menu signal of the shortcuts list */ 2769 static gboolean 2770 bookmarks_popup_menu_cb (GtkWidget *widget, 2771 NautilusPlacesSidebar *sidebar) 2772 { 2773 bookmarks_popup_menu (sidebar, NULL); 2774 return TRUE; 2775 } 2776 2777 static gboolean 2778 bookmarks_button_release_event_cb (GtkWidget *widget, 2779 GdkEventButton *event, 2780 NautilusPlacesSidebar *sidebar) 2781 { 2782 GtkTreePath *path; 2783 GtkTreeIter iter; 2784 GtkTreeModel *model; 2785 GtkTreeView *tree_view; 2786 gboolean ret = FALSE; 2787 gboolean res; 2788 2789 path = NULL; 2790 2791 if (event->type != GDK_BUTTON_RELEASE) { 2792 return TRUE; 2793 } 2794 2795 if (clicked_eject_button (sidebar, &path)) { 2796 eject_or_unmount_bookmark (sidebar, path); 2797 gtk_tree_path_free (path); 2798 2799 return FALSE; 2800 } 2801 2802 tree_view = GTK_TREE_VIEW (widget); 2803 model = gtk_tree_view_get_model (tree_view); 2804 2805 if (event->window != gtk_tree_view_get_bin_window (tree_view)) { 2806 return FALSE; 2807 } 2808 2809 res = gtk_tree_view_get_path_at_pos (tree_view, (int) event->x, (int) event->y, 2810 &path, NULL, NULL, NULL); 2811 2812 if (!res || path == NULL) { 2813 return FALSE; 2814 } 2815 2816 res = gtk_tree_model_get_iter (model, &iter, path); 2817 if (!res) { 2818 gtk_tree_path_free (path); 2819 return FALSE; 2820 } 2821 2822 if (event->button == 1) { 2823 open_selected_bookmark (sidebar, model, &iter, 0); 2824 } else if (event->button == 2) { 2825 NautilusWindowOpenFlags flags = 0; 2826 2827 flags = (event->state & GDK_CONTROL_MASK) ? 2828 NAUTILUS_WINDOW_OPEN_FLAG_NEW_WINDOW : 2829 NAUTILUS_WINDOW_OPEN_FLAG_NEW_TAB; 2830 2831 open_selected_bookmark (sidebar, model, &iter, flags); 2832 ret = TRUE; 2833 } else if (event->button == 3) { 2834 PlaceType row_type; 2835 2836 gtk_tree_model_get (model, &iter, 2837 PLACES_SIDEBAR_COLUMN_ROW_TYPE, &row_type, 2838 -1); 2839 2840 if (row_type != PLACES_HEADING) { 2841 bookmarks_popup_menu (sidebar, event); 2842 } 2843 } 2844 2845 gtk_tree_path_free (path); 2846 2847 return ret; 2848 } 2849 2850 static void 2851 bookmarks_edited (GtkCellRenderer *cell, 2852 gchar *path_string, 2853 gchar *new_text, 2854 NautilusPlacesSidebar *sidebar) 2855 { 2856 GtkTreePath *path; 2857 GtkTreeIter iter; 2858 NautilusBookmark *bookmark; 2859 int index; 2860 2861 g_object_set (cell, "editable", FALSE, NULL); 2862 2863 path = gtk_tree_path_new_from_string (path_string); 2864 gtk_tree_model_get_iter (GTK_TREE_MODEL (sidebar->store), &iter, path); 2865 gtk_tree_model_get (GTK_TREE_MODEL (sidebar->store), &iter, 2866 PLACES_SIDEBAR_COLUMN_INDEX, &index, 2867 -1); 2868 gtk_tree_path_free (path); 2869 bookmark = nautilus_bookmark_list_item_at (sidebar->bookmarks, index); 2870 2871 if (bookmark != NULL) { 2872 nautilus_bookmark_set_custom_name (bookmark, new_text); 2873 } 2874 } 2875 2876 static void 2877 bookmarks_editing_canceled (GtkCellRenderer *cell, 2878 NautilusPlacesSidebar *sidebar) 2879 { 2880 g_object_set (cell, "editable", FALSE, NULL); 2881 } 2882 2883 static void 2884 trash_state_changed_cb (NautilusTrashMonitor *trash_monitor, 2885 gboolean state, 2886 gpointer data) 2887 { 2888 NautilusPlacesSidebar *sidebar; 2889 2890 sidebar = NAUTILUS_PLACES_SIDEBAR (data); 2891 2892 /* The trash icon changed, update the sidebar */ 2893 update_places (sidebar); 2894 2895 bookmarks_check_popup_sensitivity (sidebar); 2896 } 2897 2898 static gboolean 2899 tree_selection_func (GtkTreeSelection *selection, 2900 GtkTreeModel *model, 2901 GtkTreePath *path, 2902 gboolean path_currently_selected, 2903 gpointer user_data) 2904 { 2905 GtkTreeIter iter; 2906 PlaceType row_type; 2907 2908 gtk_tree_model_get_iter (model, &iter, path); 2909 gtk_tree_model_get (model, &iter, 2910 PLACES_SIDEBAR_COLUMN_ROW_TYPE, &row_type, 2911 -1); 2912 2913 if (row_type == PLACES_HEADING) { 2914 return FALSE; 2915 } 2916 2917 return TRUE; 2918 } 2919 2920 static void 2921 icon_cell_renderer_func (GtkTreeViewColumn *column, 2922 GtkCellRenderer *cell, 2923 GtkTreeModel *model, 2924 GtkTreeIter *iter, 2925 gpointer user_data) 2926 { 2927 PlaceType type; 2928 2929 gtk_tree_model_get (model, iter, 2930 PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type, 2931 -1); 2932 2933 if (type == PLACES_HEADING) { 2934 g_object_set (cell, 2935 "visible", FALSE, 2936 NULL); 2937 } else { 2938 g_object_set (cell, 2939 "visible", TRUE, 2940 NULL); 2941 } 2942 } 2943 2944 static void 2945 padding_cell_renderer_func (GtkTreeViewColumn *column, 2946 GtkCellRenderer *cell, 2947 GtkTreeModel *model, 2948 GtkTreeIter *iter, 2949 gpointer user_data) 2950 { 2951 PlaceType type; 2952 2953 gtk_tree_model_get (model, iter, 2954 PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type, 2955 -1); 2956 2957 if (type == PLACES_HEADING) { 2958 g_object_set (cell, 2959 "visible", FALSE, 2960 "xpad", 0, 2961 "ypad", 0, 2962 NULL); 2963 } else { 2964 g_object_set (cell, 2965 "visible", TRUE, 2966 "xpad", 3, 2967 "ypad", 3, 2968 NULL); 2969 } 2970 } 2971 2972 static void 2973 heading_cell_renderer_func (GtkTreeViewColumn *column, 2974 GtkCellRenderer *cell, 2975 GtkTreeModel *model, 2976 GtkTreeIter *iter, 2977 gpointer user_data) 2978 { 2979 PlaceType type; 2980 2981 gtk_tree_model_get (model, iter, 2982 PLACES_SIDEBAR_COLUMN_ROW_TYPE, &type, 2983 -1); 2984 2985 if (type == PLACES_HEADING) { 2986 g_object_set (cell, 2987 "visible", TRUE, 2988 NULL); 2989 } else { 2990 g_object_set (cell, 2991 "visible", FALSE, 2992 NULL); 2993 } 2994 } 2995 2996 static gint 2997 places_sidebar_sort_func (GtkTreeModel *model, 2998 GtkTreeIter *iter_a, 2999 GtkTreeIter *iter_b, 3000 gpointer user_data) 3001 { 3002 SectionType section_type_a, section_type_b; 3003 PlaceType place_type_a, place_type_b; 3004 gint retval = 0; 3005 3006 gtk_tree_model_get (model, iter_a, 3007 PLACES_SIDEBAR_COLUMN_SECTION_TYPE, &section_type_a, 3008 PLACES_SIDEBAR_COLUMN_ROW_TYPE, &place_type_a, 3009 -1); 3010 gtk_tree_model_get (model, iter_b, 3011 PLACES_SIDEBAR_COLUMN_SECTION_TYPE, &section_type_b, 3012 PLACES_SIDEBAR_COLUMN_ROW_TYPE, &place_type_b, 3013 -1); 3014 3015 /* fall back to the default order if we're not in the 3016 * XDG part of the computer section. 3017 */ 3018 if ((section_type_a == section_type_b) && 3019 (section_type_a == SECTION_COMPUTER) && 3020 (place_type_a == place_type_b) && 3021 (place_type_a == PLACES_XDG_DIR)) { 3022 gchar *name_a, *name_b; 3023 3024 gtk_tree_model_get (model, iter_a, 3025 PLACES_SIDEBAR_COLUMN_NAME, &name_a, 3026 -1); 3027 gtk_tree_model_get (model, iter_b, 3028 PLACES_SIDEBAR_COLUMN_NAME, &name_b, 3029 -1); 3030 3031 retval = g_utf8_collate (name_a, name_b); 3032 3033 g_free (name_a); 3034 g_free (name_b); 3035 } 3036 3037 return retval; 3038 } 3039 3040 static void 3041 update_hostname (NautilusPlacesSidebar *sidebar) 3042 { 3043 GVariant *variant; 3044 gsize len; 3045 const gchar *hostname; 3046 3047 if (sidebar->hostnamed_proxy == NULL) 3048 return; 3049 3050 variant = g_dbus_proxy_get_cached_property (sidebar->hostnamed_proxy, 3051 "PrettyHostname"); 3052 if (variant == NULL) { 3053 return; 3054 } 3055 3056 hostname = g_variant_get_string (variant, &len); 3057 if (len > 0 && 3058 g_strcmp0 (sidebar->hostname, hostname) != 0) { 3059 g_free (sidebar->hostname); 3060 sidebar->hostname = g_strdup (hostname); 3061 update_places (sidebar); 3062 } 3063 3064 g_variant_unref (variant); 3065 } 3066 3067 static void 3068 hostname_proxy_new_cb (GObject *source_object, 3069 GAsyncResult *res, 3070 gpointer user_data) 3071 { 3072 NautilusPlacesSidebar *sidebar = user_data; 3073 GError *error = NULL; 3074 3075 sidebar->hostnamed_proxy = g_dbus_proxy_new_for_bus_finish (res, &error); 3076 if (error != NULL) { 3077 g_debug ("Failed to create D-Bus proxy: %s", error->message); 3078 g_error_free (error); 3079 return; 3080 } 3081 3082 g_signal_connect_swapped (sidebar->hostnamed_proxy, 3083 "g-properties-changed", 3084 G_CALLBACK (update_hostname), 3085 sidebar); 3086 update_hostname (sidebar); 3087 } 3088 3089 static void 3090 nautilus_places_sidebar_init (NautilusPlacesSidebar *sidebar) 3091 { 3092 GtkTreeView *tree_view; 3093 GtkTreeViewColumn *col; 3094 GtkCellRenderer *cell; 3095 GtkTreeSelection *selection; 3096 3097 sidebar->volume_monitor = g_volume_monitor_get (); 3098 3099 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sidebar), 3100 GTK_POLICY_NEVER, 3101 GTK_POLICY_AUTOMATIC); 3102 gtk_scrolled_window_set_hadjustment (GTK_SCROLLED_WINDOW (sidebar), NULL); 3103 gtk_scrolled_window_set_vadjustment (GTK_SCROLLED_WINDOW (sidebar), NULL); 3104 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sidebar), GTK_SHADOW_IN); 3105 3106 gtk_style_context_set_junction_sides (gtk_widget_get_style_context (GTK_WIDGET (sidebar)), 3107 GTK_JUNCTION_RIGHT | GTK_JUNCTION_LEFT); 3108 3109 /* tree view */ 3110 tree_view = GTK_TREE_VIEW (gtk_tree_view_new ()); 3111 gtk_tree_view_set_headers_visible (tree_view, FALSE); 3112 3113 col = GTK_TREE_VIEW_COLUMN (gtk_tree_view_column_new ()); 3114 3115 /* initial padding */ 3116 cell = gtk_cell_renderer_text_new (); 3117 gtk_tree_view_column_pack_start (col, cell, FALSE); 3118 g_object_set (cell, 3119 "xpad", 6, 3120 NULL); 3121 3122 /* headings */ 3123 cell = gtk_cell_renderer_text_new (); 3124 gtk_tree_view_column_pack_start (col, cell, FALSE); 3125 gtk_tree_view_column_set_attributes (col, cell, 3126 "text", PLACES_SIDEBAR_COLUMN_HEADING_TEXT, 3127 NULL); 3128 g_object_set (cell, 3129 "weight", PANGO_WEIGHT_BOLD, 3130 "weight-set", TRUE, 3131 "ypad", 6, 3132 "xpad", 0, 3133 NULL); 3134 gtk_tree_view_column_set_cell_data_func (col, cell, 3135 heading_cell_renderer_func, 3136 sidebar, NULL); 3137 3138 /* icon padding */ 3139 cell = gtk_cell_renderer_text_new (); 3140 gtk_tree_view_column_pack_start (col, cell, FALSE); 3141 gtk_tree_view_column_set_cell_data_func (col, cell, 3142 padding_cell_renderer_func, 3143 sidebar, NULL); 3144 3145 /* icon renderer */ 3146 cell = gtk_cell_renderer_pixbuf_new (); 3147 g_object_set (cell, "follow-state", TRUE, NULL); 3148 gtk_tree_view_column_pack_start (col, cell, FALSE); 3149 gtk_tree_view_column_set_attributes (col, cell, 3150 "gicon", PLACES_SIDEBAR_COLUMN_GICON, 3151 NULL); 3152 gtk_tree_view_column_set_cell_data_func (col, cell, 3153 icon_cell_renderer_func, 3154 sidebar, NULL); 3155 3156 /* eject text renderer */ 3157 cell = gtk_cell_renderer_text_new (); 3158 gtk_tree_view_column_pack_start (col, cell, TRUE); 3159 gtk_tree_view_column_set_attributes (col, cell, 3160 "text", PLACES_SIDEBAR_COLUMN_NAME, 3161 "visible", PLACES_SIDEBAR_COLUMN_EJECT, 3162 NULL); 3163 g_object_set (cell, 3164 "ellipsize", PANGO_ELLIPSIZE_END, 3165 "ellipsize-set", TRUE, 3166 NULL); 3167 3168 /* eject icon renderer */ 3169 cell = gtk_cell_renderer_pixbuf_new (); 3170 sidebar->eject_icon_cell_renderer = cell; 3171 g_object_set (cell, 3172 "mode", GTK_CELL_RENDERER_MODE_ACTIVATABLE, 3173 "stock-size", GTK_ICON_SIZE_MENU, 3174 "xpad", EJECT_BUTTON_XPAD, 3175 /* align right, because for some reason gtk+ expands 3176 this even though we tell it not to. */ 3177 "xalign", 1.0, 3178 "follow-state", TRUE, 3179 NULL); 3180 gtk_tree_view_column_pack_start (col, cell, FALSE); 3181 gtk_tree_view_column_set_attributes (col, cell, 3182 "visible", PLACES_SIDEBAR_COLUMN_EJECT, 3183 "gicon", PLACES_SIDEBAR_COLUMN_EJECT_GICON, 3184 NULL); 3185 3186 /* normal text renderer */ 3187 cell = gtk_cell_renderer_text_new (); 3188 gtk_tree_view_column_pack_start (col, cell, TRUE); 3189 g_object_set (G_OBJECT (cell), "editable", FALSE, NULL); 3190 gtk_tree_view_column_set_attributes (col, cell, 3191 "text", PLACES_SIDEBAR_COLUMN_NAME, 3192 "visible", PLACES_SIDEBAR_COLUMN_NO_EJECT, 3193 "editable-set", PLACES_SIDEBAR_COLUMN_BOOKMARK, 3194 NULL); 3195 g_object_set (cell, 3196 "ellipsize", PANGO_ELLIPSIZE_END, 3197 "ellipsize-set", TRUE, 3198 NULL); 3199 3200 g_signal_connect (cell, "edited", 3201 G_CALLBACK (bookmarks_edited), sidebar); 3202 g_signal_connect (cell, "editing-canceled", 3203 G_CALLBACK (bookmarks_editing_canceled), sidebar); 3204 3205 /* this is required to align the eject buttons to the right */ 3206 gtk_tree_view_column_set_max_width (GTK_TREE_VIEW_COLUMN (col), NAUTILUS_ICON_SIZE_SMALLER); 3207 gtk_tree_view_append_column (tree_view, col); 3208 3209 sidebar->store = nautilus_shortcuts_model_new (sidebar); 3210 gtk_tree_view_set_tooltip_column (tree_view, PLACES_SIDEBAR_COLUMN_TOOLTIP); 3211 gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (sidebar->store), 3212 PLACES_SIDEBAR_COLUMN_NAME, 3213 GTK_SORT_ASCENDING); 3214 gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (sidebar->store), 3215 PLACES_SIDEBAR_COLUMN_NAME, 3216 places_sidebar_sort_func, 3217 sidebar, NULL); 3218 3219 gtk_tree_view_set_model (tree_view, GTK_TREE_MODEL (sidebar->store)); 3220 gtk_container_add (GTK_CONTAINER (sidebar), GTK_WIDGET (tree_view)); 3221 gtk_widget_show (GTK_WIDGET (tree_view)); 3222 gtk_tree_view_set_enable_search (tree_view, FALSE); 3223 3224 gtk_widget_show (GTK_WIDGET (sidebar)); 3225 sidebar->tree_view = tree_view; 3226 3227 gtk_tree_view_set_search_column (tree_view, PLACES_SIDEBAR_COLUMN_NAME); 3228 selection = gtk_tree_view_get_selection (tree_view); 3229 gtk_tree_selection_set_mode (selection, GTK_SELECTION_BROWSE); 3230 3231 gtk_tree_selection_set_select_function (selection, 3232 tree_selection_func, 3233 sidebar, 3234 NULL); 3235 3236 gtk_tree_view_enable_model_drag_source (GTK_TREE_VIEW (tree_view), 3237 GDK_BUTTON1_MASK, 3238 nautilus_shortcuts_source_targets, 3239 G_N_ELEMENTS (nautilus_shortcuts_source_targets), 3240 GDK_ACTION_MOVE); 3241 gtk_drag_dest_set (GTK_WIDGET (tree_view), 3242 0, 3243 nautilus_shortcuts_drop_targets, G_N_ELEMENTS (nautilus_shortcuts_drop_targets), 3244 GDK_ACTION_MOVE | GDK_ACTION_COPY | GDK_ACTION_LINK); 3245 3246 g_signal_connect (tree_view, "key-press-event", 3247 G_CALLBACK (bookmarks_key_press_event_cb), sidebar); 3248 3249 g_signal_connect (tree_view, "drag-motion", 3250 G_CALLBACK (drag_motion_callback), sidebar); 3251 g_signal_connect (tree_view, "drag-leave", 3252 G_CALLBACK (drag_leave_callback), sidebar); 3253 g_signal_connect (tree_view, "drag-data-received", 3254 G_CALLBACK (drag_data_received_callback), sidebar); 3255 g_signal_connect (tree_view, "drag-drop", 3256 G_CALLBACK (drag_drop_callback), sidebar); 3257 3258 g_signal_connect (selection, "changed", 3259 G_CALLBACK (bookmarks_selection_changed_cb), sidebar); 3260 g_signal_connect (tree_view, "popup-menu", 3261 G_CALLBACK (bookmarks_popup_menu_cb), sidebar); 3262 g_signal_connect (tree_view, "button-release-event", 3263 G_CALLBACK (bookmarks_button_release_event_cb), sidebar); 3264 3265 eel_gtk_tree_view_set_activate_on_single_click (sidebar->tree_view, 3266 TRUE); 3267 3268 g_signal_connect_swapped (gnome_background_preferences, "changed::" NAUTILUS_PREFERENCES_SHOW_DESKTOP, 3269 G_CALLBACK(desktop_setting_changed_callback), 3270 sidebar); 3271 3272 sidebar->hostname = g_strdup (_("Computer")); 3273 g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, 3274 G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, 3275 NULL, 3276 "org.freedesktop.hostname1", 3277 "/org/freedesktop/hostname1", 3278 "org.freedesktop.hostname1", 3279 NULL, 3280 hostname_proxy_new_cb, 3281 sidebar); 3282 3283 g_signal_connect_object (nautilus_trash_monitor_get (), 3284 "trash_state_changed", 3285 G_CALLBACK (trash_state_changed_cb), 3286 sidebar, 0); 3287 } 3288 3289 static void 3290 nautilus_places_sidebar_dispose (GObject *object) 3291 { 3292 NautilusPlacesSidebar *sidebar; 3293 3294 sidebar = NAUTILUS_PLACES_SIDEBAR (object); 3295 3296 sidebar->window = NULL; 3297 sidebar->tree_view = NULL; 3298 3299 g_free (sidebar->uri); 3300 sidebar->uri = NULL; 3301 3302 free_drag_data (sidebar); 3303 3304 if (sidebar->bookmarks_changed_id != 0) { 3305 g_signal_handler_disconnect (sidebar->bookmarks, 3306 sidebar->bookmarks_changed_id); 3307 sidebar->bookmarks_changed_id = 0; 3308 } 3309 3310 g_clear_object (&sidebar->store); 3311 3312 if (sidebar->go_to_after_mount_slot) { 3313 g_object_remove_weak_pointer (G_OBJECT (sidebar->go_to_after_mount_slot), 3314 (gpointer *) &sidebar->go_to_after_mount_slot); 3315 sidebar->go_to_after_mount_slot = NULL; 3316 } 3317 3318 g_signal_handlers_disconnect_by_func (nautilus_preferences, 3319 bookmarks_popup_menu_detach_cb, 3320 sidebar); 3321 3322 g_signal_handlers_disconnect_by_func (gnome_background_preferences, 3323 desktop_setting_changed_callback, 3324 sidebar); 3325 3326 if (sidebar->volume_monitor != NULL) { 3327 g_signal_handlers_disconnect_by_func (sidebar->volume_monitor, 3328 volume_added_callback, sidebar); 3329 g_signal_handlers_disconnect_by_func (sidebar->volume_monitor, 3330 volume_removed_callback, sidebar); 3331 g_signal_handlers_disconnect_by_func (sidebar->volume_monitor, 3332 volume_changed_callback, sidebar); 3333 g_signal_handlers_disconnect_by_func (sidebar->volume_monitor, 3334 mount_added_callback, sidebar); 3335 g_signal_handlers_disconnect_by_func (sidebar->volume_monitor, 3336 mount_removed_callback, sidebar); 3337 g_signal_handlers_disconnect_by_func (sidebar->volume_monitor, 3338 mount_changed_callback, sidebar); 3339 g_signal_handlers_disconnect_by_func (sidebar->volume_monitor, 3340 drive_disconnected_callback, sidebar); 3341 g_signal_handlers_disconnect_by_func (sidebar->volume_monitor, 3342 drive_connected_callback, sidebar); 3343 g_signal_handlers_disconnect_by_func (sidebar->volume_monitor, 3344 drive_changed_callback, sidebar); 3345 3346 g_clear_object (&sidebar->volume_monitor); 3347 } 3348 3349 g_clear_object (&sidebar->hostnamed_proxy); 3350 g_free (sidebar->hostname); 3351 sidebar->hostname = NULL; 3352 3353 G_OBJECT_CLASS (nautilus_places_sidebar_parent_class)->dispose (object); 3354 } 3355 3356 static void 3357 nautilus_places_sidebar_class_init (NautilusPlacesSidebarClass *class) 3358 { 3359 G_OBJECT_CLASS (class)->dispose = nautilus_places_sidebar_dispose; 3360 3361 GTK_WIDGET_CLASS (class)->style_set = nautilus_places_sidebar_style_set; 3362 GTK_WIDGET_CLASS (class)->focus = nautilus_places_sidebar_focus; 3363 } 3364 3365 static void 3366 nautilus_places_sidebar_set_parent_window (NautilusPlacesSidebar *sidebar, 3367 NautilusWindow *window) 3368 { 3369 NautilusWindowSlot *slot; 3370 NautilusApplication *app = NAUTILUS_APPLICATION (g_application_get_default ()); 3371 3372 sidebar->window = window; 3373 3374 slot = nautilus_window_get_active_slot (window); 3375 3376 sidebar->bookmarks = nautilus_application_get_bookmarks (app); 3377 sidebar->bookmarks_changed_id = 3378 g_signal_connect_swapped (sidebar->bookmarks, "changed", 3379 G_CALLBACK (update_places), 3380 sidebar); 3381 3382 g_signal_connect_object (sidebar->volume_monitor, "volume_added", 3383 G_CALLBACK (volume_added_callback), sidebar, 0); 3384 g_signal_connect_object (sidebar->volume_monitor, "volume_removed", 3385 G_CALLBACK (volume_removed_callback), sidebar, 0); 3386 g_signal_connect_object (sidebar->volume_monitor, "volume_changed", 3387 G_CALLBACK (volume_changed_callback), sidebar, 0); 3388 g_signal_connect_object (sidebar->volume_monitor, "mount_added", 3389 G_CALLBACK (mount_added_callback), sidebar, 0); 3390 g_signal_connect_object (sidebar->volume_monitor, "mount_removed", 3391 G_CALLBACK (mount_removed_callback), sidebar, 0); 3392 g_signal_connect_object (sidebar->volume_monitor, "mount_changed", 3393 G_CALLBACK (mount_changed_callback), sidebar, 0); 3394 g_signal_connect_object (sidebar->volume_monitor, "drive_disconnected", 3395 G_CALLBACK (drive_disconnected_callback), sidebar, 0); 3396 g_signal_connect_object (sidebar->volume_monitor, "drive_connected", 3397 G_CALLBACK (drive_connected_callback), sidebar, 0); 3398 g_signal_connect_object (sidebar->volume_monitor, "drive_changed", 3399 G_CALLBACK (drive_changed_callback), sidebar, 0); 3400 3401 update_places (sidebar); 3402 3403 g_signal_connect_object (window, "loading-uri", 3404 G_CALLBACK (loading_uri_callback), 3405 sidebar, 0); 3406 sidebar->uri = nautilus_window_slot_get_current_uri (slot); 3407 update_current_uri (sidebar); 3408 } 3409 3410 static void 3411 nautilus_places_sidebar_style_set (GtkWidget *widget, 3412 GtkStyle *previous_style) 3413 { 3414 NautilusPlacesSidebar *sidebar; 3415 3416 sidebar = NAUTILUS_PLACES_SIDEBAR (widget); 3417 3418 update_places (sidebar); 3419 } 3420 3421 GtkWidget * 3422 nautilus_places_sidebar_new (NautilusWindow *window) 3423 { 3424 NautilusPlacesSidebar *sidebar; 3425 3426 sidebar = g_object_new (nautilus_places_sidebar_get_type (), NULL); 3427 nautilus_places_sidebar_set_parent_window (sidebar, window); 3428 3429 return GTK_WIDGET (sidebar); 3430 } 3431 3432 3433 /* Drag and drop interfaces */ 3434 3435 /* GtkTreeDragSource::row_draggable implementation for the shortcuts filter model */ 3436 3437 static gboolean 3438 nautilus_shortcuts_model_row_draggable (GtkTreeDragSource *drag_source, 3439 GtkTreePath *path) 3440 { 3441 GtkTreeModel *model; 3442 GtkTreeIter iter; 3443 PlaceType place_type; 3444 SectionType section_type; 3445 3446 model = GTK_TREE_MODEL (drag_source); 3447 3448 gtk_tree_model_get_iter (model, &iter, path); 3449 gtk_tree_model_get (model, &iter, 3450 PLACES_SIDEBAR_COLUMN_ROW_TYPE, &place_type, 3451 PLACES_SIDEBAR_COLUMN_SECTION_TYPE, &section_type, 3452 -1); 3453 3454 if (place_type != PLACES_HEADING && section_type == SECTION_BOOKMARKS) 3455 return TRUE; 3456 3457 return FALSE; 3458 } 3459 3460 static void 3461 _nautilus_shortcuts_model_class_init (NautilusShortcutsModelClass *klass) 3462 { 3463 3464 } 3465 3466 static void 3467 _nautilus_shortcuts_model_init (NautilusShortcutsModel *model) 3468 { 3469 model->sidebar = NULL; 3470 } 3471 3472 static void 3473 _nautilus_shortcuts_model_drag_source_init (GtkTreeDragSourceIface *iface) 3474 { 3475 iface->row_draggable = nautilus_shortcuts_model_row_draggable; 3476 } 3477 3478 static GtkListStore * 3479 nautilus_shortcuts_model_new (NautilusPlacesSidebar *sidebar) 3480 { 3481 NautilusShortcutsModel *model; 3482 GType model_types[PLACES_SIDEBAR_COLUMN_COUNT] = { 3483 G_TYPE_INT, 3484 G_TYPE_STRING, 3485 G_TYPE_DRIVE, 3486 G_TYPE_VOLUME, 3487 G_TYPE_MOUNT, 3488 G_TYPE_STRING, 3489 G_TYPE_ICON, 3490 G_TYPE_INT, 3491 G_TYPE_BOOLEAN, 3492 G_TYPE_BOOLEAN, 3493 G_TYPE_BOOLEAN, 3494 G_TYPE_STRING, 3495 G_TYPE_ICON, 3496 G_TYPE_INT, 3497 G_TYPE_STRING 3498 }; 3499 3500 model = g_object_new (_nautilus_shortcuts_model_get_type (), NULL); 3501 model->sidebar = sidebar; 3502 3503 gtk_list_store_set_column_types (GTK_LIST_STORE (model), 3504 PLACES_SIDEBAR_COLUMN_COUNT, 3505 model_types); 3506 3507 return GTK_LIST_STORE (model); 3508 }