static void
nautilus_bookmark_connect_file (NautilusBookmark *bookmark)
{
	if (bookmark->details->file != NULL) {
		DEBUG ("%s: file already connected, returning",
		       nautilus_bookmark_get_name (bookmark));
		return;
	}

	if (bookmark->details->exists) {
		DEBUG ("%s: creating file", nautilus_bookmark_get_name (bookmark));

		bookmark->details->file = nautilus_file_get (bookmark->details->location);
		g_assert (!nautilus_file_is_gone (bookmark->details->file));

		g_signal_connect_object (bookmark->details->file, "changed",
					 G_CALLBACK (bookmark_file_changed_callback), bookmark, 0);
	}

	if (bookmark->details->icon == NULL ||
	    bookmark->details->symbolic_icon == NULL) {
		nautilus_bookmark_set_icon_to_default (bookmark);
	}

	if (bookmark->details->file != NULL &&
	    nautilus_file_check_if_ready (bookmark->details->file, NAUTILUS_FILE_ATTRIBUTE_INFO)) {
		bookmark_set_name_from_ready_file (bookmark, bookmark->details->file);
	}

	if (bookmark->details->name == NULL) {
		bookmark->details->name = nautilus_compute_title_for_location (bookmark->details->location);
	}
}
static void
update_bookmark_from_text (void)
{
	if (text_changed) {
		NautilusBookmark *bookmark, *bookmark_in_list;
		char *name;
		GdkPixbuf *pixbuf;
		guint selected_row;
		GtkTreeIter iter;
		GFile *location;

		g_assert (GTK_IS_ENTRY (name_field));
		g_assert (GTK_IS_ENTRY (uri_field));

		location = g_file_new_for_uri (gtk_entry_get_text (GTK_ENTRY (uri_field)));
		
		bookmark = nautilus_bookmark_new_with_icon (location, gtk_entry_get_text (GTK_ENTRY (name_field)),
							    name_text_changed, NULL);
		
		g_object_unref (location);

		selected_row = get_selected_row ();

		/* turn off list updating 'cuz otherwise the list-reordering code runs
		 * after repopulate(), thus reordering the correctly-ordered list.
		 */
		g_signal_handler_block (bookmarks, 
					bookmark_list_changed_signal_id);
		nautilus_bookmark_list_delete_item_at (bookmarks, selected_row);
		nautilus_bookmark_list_insert_item (bookmarks, bookmark, selected_row);
		g_signal_handler_unblock (bookmarks, 
					  bookmark_list_changed_signal_id);
		g_object_unref (bookmark);

		/* We also have to update the bookmark pointer in the list
		   store. */
		gtk_tree_selection_get_selected (bookmark_selection,
						 NULL, &iter);
		g_signal_handler_block (bookmark_list_store,
					row_changed_signal_id);

		bookmark_in_list = nautilus_bookmark_list_item_at (bookmarks,
								   selected_row);

		name = nautilus_bookmark_get_name (bookmark_in_list);

		pixbuf = nautilus_bookmark_get_pixbuf (bookmark_in_list, GTK_ICON_SIZE_MENU);

		gtk_list_store_set (bookmark_list_store, &iter,
				    BOOKMARK_LIST_COLUMN_BOOKMARK, bookmark_in_list,
				    BOOKMARK_LIST_COLUMN_NAME, name,
				    BOOKMARK_LIST_COLUMN_ICON, pixbuf,
				    -1);
		g_signal_handler_unblock (bookmark_list_store,
					  row_changed_signal_id);

		gdk_pixbuf_unref (pixbuf);
		g_free (name);
	}
}
static void
bookmark_file_changed_callback (NautilusFile *file,
				NautilusBookmark *bookmark)
{
	GFile *location;

	g_assert (file == bookmark->details->file);

	DEBUG ("%s: file changed", nautilus_bookmark_get_name (bookmark));

	location = nautilus_file_get_location (file);

	if (!g_file_equal (bookmark->details->location, location) &&
	    !nautilus_file_is_in_trash (file)) {
		DEBUG ("%s: file got moved", nautilus_bookmark_get_name (bookmark));

		g_object_unref (bookmark->details->location);
		bookmark->details->location = g_object_ref (location);

		g_object_notify_by_pspec (G_OBJECT (bookmark), properties[PROP_LOCATION]);
		g_signal_emit (bookmark, signals[CONTENTS_CHANGED], 0);
	}

	g_object_unref (location);

	if (nautilus_file_is_gone (file) ||
	    nautilus_file_is_in_trash (file)) {
		/* The file we were monitoring has been trashed, deleted,
		 * or moved in a way that we didn't notice. We should make 
		 * a spanking new NautilusFile object for this 
		 * location so if a new file appears in this place 
		 * we will notice. However, we can't immediately do so
		 * because creating a new NautilusFile directly as a result
		 * of noticing a file goes away may trigger i/o on that file
		 * again, noticeing it is gone, leading to a loop.
		 * So, the new NautilusFile is created when the bookmark
		 * is used again. However, this is not really a problem, as
		 * we don't want to change the icon or anything about the
		 * bookmark just because its not there anymore.
		 */
		DEBUG ("%s: trashed", nautilus_bookmark_get_name (bookmark));
		nautilus_bookmark_disconnect_file (bookmark);
	} else {
		bookmark_set_name_from_ready_file (bookmark, file);
	}
}
void
nautilus_menus_append_bookmark_to_menu (NautilusWindow *window,
                                        NautilusBookmark *bookmark,
                                        const char *parent_path,
                                        const char *parent_id,
                                        guint index_in_parent,
                                        GtkActionGroup *action_group,
                                        guint merge_id,
                                        GCallback refresh_callback,
                                        NautilusBookmarkFailedCallback failed_callback)
{
    BookmarkHolder *bookmark_holder;
    char action_name[128];
    char *name;
    GdkPixbuf *pixbuf;
    GtkAction *action;

    g_assert (NAUTILUS_IS_WINDOW (window));
    g_assert (NAUTILUS_IS_BOOKMARK (bookmark));

    bookmark_holder = bookmark_holder_new (bookmark, window, refresh_callback, failed_callback);
    name = nautilus_bookmark_get_name (bookmark);

    /* Create menu item with pixbuf */
    pixbuf = nautilus_bookmark_get_pixbuf (bookmark, GTK_ICON_SIZE_MENU);

    g_snprintf (action_name, sizeof (action_name), "%s%d", parent_id, index_in_parent);

    action = gtk_action_new (action_name,
                             name,
                             _("Go to the location specified by this bookmark"),
                             NULL);

    g_object_set_data_full (G_OBJECT (action), "menu-icon",
                            g_object_ref (pixbuf),
                            g_object_unref);

    g_signal_connect_data (action, "activate",
                           G_CALLBACK (activate_bookmark_in_menu_item),
                           bookmark_holder,
                           bookmark_holder_free_cover, 0);

    gtk_action_group_add_action (action_group,
                                 GTK_ACTION (action));

    g_object_unref (action);

    gtk_ui_manager_add_ui (window->details->ui_manager,
                           merge_id,
                           parent_path,
                           action_name,
                           action_name,
                           GTK_UI_MANAGER_MENUITEM,
                           FALSE);

    g_object_unref (pixbuf);
    g_free (name);
}
static void
update_bookmark_from_text (NautilusBookmarksWindow *self)
{
	NautilusBookmark *bookmark, *bookmark_in_list;
	const char *name;
	GIcon *icon;
	guint selected_row;
	GtkTreeIter iter;
	GFile *location;

	if (!self->priv->text_changed ||
	    gtk_entry_get_text_length (GTK_ENTRY (self->priv->uri_field)) == 0) {
		return;
	}

	location = g_file_parse_name 
		(gtk_entry_get_text (GTK_ENTRY (self->priv->uri_field)));

	bookmark = nautilus_bookmark_new (location,
					  self->priv->name_text_changed ?
					  gtk_entry_get_text (GTK_ENTRY (self->priv->name_field)) : NULL,
					  NULL);
	g_object_unref (location);

	selected_row = get_selected_row (self);

	/* turn off list updating 'cuz otherwise the list-reordering code runs
	 * after repopulate(), thus reordering the correctly-ordered list.
	 */
	g_signal_handler_block (self->priv->bookmarks, self->priv->bookmarks_changed_id);
	nautilus_bookmark_list_delete_item_at (self->priv->bookmarks, selected_row);
	nautilus_bookmark_list_insert_item (self->priv->bookmarks, bookmark, selected_row);
	g_signal_handler_unblock (self->priv->bookmarks, self->priv->bookmarks_changed_id);
	g_object_unref (bookmark);

	/* We also have to update the bookmark pointer in the list
	   store. */
	gtk_tree_selection_get_selected (self->priv->selection, NULL, &iter);
	g_signal_handler_block (self->priv->model, self->priv->row_changed_id);

	bookmark_in_list = nautilus_bookmark_list_item_at (self->priv->bookmarks, selected_row);
	name = nautilus_bookmark_get_name (bookmark_in_list);
	icon = nautilus_bookmark_get_icon (bookmark_in_list);

	gtk_list_store_set (self->priv->model, &iter,
			    BOOKMARK_LIST_COLUMN_BOOKMARK, bookmark_in_list,
			    BOOKMARK_LIST_COLUMN_NAME, name,
			    BOOKMARK_LIST_COLUMN_ICON, icon,
			    -1);

	g_signal_handler_unblock (self->priv->model, self->priv->row_changed_id);
	g_object_unref (icon);
}
static void
nautilus_bookmark_set_icon_to_default (NautilusBookmark *bookmark)
{
	GIcon *icon, *symbolic_icon;
	char *uri;

	if (g_file_is_native (bookmark->details->location)) {
		symbolic_icon = get_native_icon (bookmark, TRUE);
		icon = get_native_icon (bookmark, FALSE);
	} else {
		uri = nautilus_bookmark_get_uri (bookmark);
		if (g_str_has_prefix (uri, EEL_SEARCH_URI)) {
			symbolic_icon = g_themed_icon_new (NAUTILUS_ICON_FOLDER_SAVED_SEARCH);
			icon = g_themed_icon_new (NAUTILUS_ICON_FULLCOLOR_FOLDER_SAVED_SEARCH);
		} else {
			symbolic_icon = g_themed_icon_new (NAUTILUS_ICON_FOLDER_REMOTE);
			icon = g_themed_icon_new (NAUTILUS_ICON_FULLCOLOR_FOLDER_REMOTE);
		}
		g_free (uri);
	}

	if (!bookmark->details->exists) {
		DEBUG ("%s: file does not exist, add emblem", nautilus_bookmark_get_name (bookmark));

		apply_warning_emblem (&icon, FALSE);
		apply_warning_emblem (&symbolic_icon, TRUE);
	}

	DEBUG ("%s: setting icon to default", nautilus_bookmark_get_name (bookmark));

	g_object_set (bookmark,
		      "icon", icon,
		      "symbolic-icon", symbolic_icon,
		      NULL);

	g_object_unref (icon);
	g_object_unref (symbolic_icon);
}
static void
nautilus_bookmark_set_exists (NautilusBookmark *bookmark,
			      gboolean exists)
{
	if (bookmark->details->exists == exists) {
		return;
	}

	bookmark->details->exists = exists;
	DEBUG ("%s: setting bookmark to exist: %d\n",
	       nautilus_bookmark_get_name (bookmark), exists);

	/* refresh icon */
	nautilus_bookmark_set_icon_to_default (bookmark);
}
static void
on_selection_changed (GtkTreeSelection *treeselection,
		      gpointer user_data)
{
	NautilusBookmark *selected;
	const char *name = NULL;
	char *entry_text = NULL;
	GFile *location;

	g_assert (GTK_IS_ENTRY (name_field));
	g_assert (GTK_IS_ENTRY (uri_field));

	selected = get_selected_bookmark ();

	if (selected) {
		name = nautilus_bookmark_get_name (selected);
		location = nautilus_bookmark_get_location (selected);
		entry_text = g_file_get_parse_name (location);

		g_object_unref (location);
	}
	
	/* Set the sensitivity of widgets that require a selection */
	gtk_widget_set_sensitive (remove_button, selected != NULL);
        gtk_widget_set_sensitive (jump_button, selected != NULL);
	gtk_widget_set_sensitive (name_field, selected != NULL);
	gtk_widget_set_sensitive (uri_field, selected != NULL);

	g_signal_handler_block (name_field, name_field_changed_signal_id);
	nautilus_entry_set_text (NAUTILUS_ENTRY (name_field),
				 name ? name : "");
	g_signal_handler_unblock (name_field, name_field_changed_signal_id);

	g_signal_handler_block (uri_field, uri_field_changed_signal_id);
	nautilus_entry_set_text (NAUTILUS_ENTRY (uri_field),
				 entry_text ? entry_text : "");
	g_signal_handler_unblock (uri_field, uri_field_changed_signal_id);

	text_changed = FALSE;
	name_text_changed = FALSE;

	g_free (entry_text);
}
static void
bookmark_set_name_from_ready_file (NautilusBookmark *self,
				   NautilusFile *file)
{
	gchar *display_name;

	if (self->details->has_custom_name) {
		return;
	}

	display_name = nautilus_file_get_display_name (self->details->file);

	if (nautilus_file_is_home (self->details->file)) {
		nautilus_bookmark_set_name_internal (self, _("Home"));
	} else if (g_strcmp0 (self->details->name, display_name) != 0) {
		nautilus_bookmark_set_name_internal (self, display_name);
		DEBUG ("%s: name changed to %s", nautilus_bookmark_get_name (self), display_name);
	}

	g_free (display_name);
}
static void
on_selection_changed (GtkTreeSelection *treeselection,
		      gpointer user_data)
{
	NautilusBookmark *selected;
	char *name = NULL, *uri = NULL;
	
	g_assert (GTK_IS_ENTRY (name_field));
	g_assert (GTK_IS_ENTRY (uri_field));

	selected = get_selected_bookmark ();

	if (selected) {
		name = nautilus_bookmark_get_name (selected);
		uri = nautilus_bookmark_get_uri (selected);
	}
	
	/* Set the sensitivity of widgets that require a selection */
	gtk_widget_set_sensitive (remove_button, selected != NULL);
        gtk_widget_set_sensitive (jump_button, selected != NULL);
	gtk_widget_set_sensitive (name_field, selected != NULL);
	gtk_widget_set_sensitive (uri_field, selected != NULL);

	g_signal_handler_block (name_field, name_field_changed_signal_id);
	nautilus_entry_set_text (NAUTILUS_ENTRY (name_field),
				 name ? name : "");
	g_signal_handler_unblock (name_field, name_field_changed_signal_id);

	g_signal_handler_block (uri_field, uri_field_changed_signal_id);
	nautilus_entry_set_text (NAUTILUS_ENTRY (uri_field),
				 uri ? uri : "");
	g_signal_handler_unblock (uri_field, uri_field_changed_signal_id);

	text_changed = FALSE;
	name_text_changed = FALSE;

	g_free (name);
	g_free (uri);
}
static void
nautilus_bookmark_disconnect_file (NautilusBookmark *bookmark)
{
	if (bookmark->details->file != NULL) {
		DEBUG ("%s: disconnecting file",
		       nautilus_bookmark_get_name (bookmark));

		g_signal_handlers_disconnect_by_func (bookmark->details->file,
						      G_CALLBACK (bookmark_file_changed_callback),
						      bookmark);
		g_clear_object (&bookmark->details->file);
	}

	if (bookmark->details->cancellable != NULL) {
		g_cancellable_cancel (bookmark->details->cancellable);
		g_clear_object (&bookmark->details->cancellable);
	}

	if (bookmark->details->exists_id != 0) {
		g_source_remove (bookmark->details->exists_id);
		bookmark->details->exists_id = 0;
	}
}
static void
on_selection_changed (GtkTreeSelection *treeselection,
		      gpointer user_data)
{
	NautilusBookmarksWindow *self = user_data;
	NautilusBookmark *selected;
	const char *name = NULL;
	char *entry_text = NULL;
	GFile *location;

	selected = get_selected_bookmark (self);

	if (selected) {
		name = nautilus_bookmark_get_name (selected);
		location = nautilus_bookmark_get_location (selected);
		entry_text = g_file_get_parse_name (location);

		g_object_unref (location);
	}

	update_widgets_sensitivity (self);

	g_signal_handler_block (self->priv->name_field, self->priv->name_changed_id);
	nautilus_entry_set_text (NAUTILUS_ENTRY (self->priv->name_field),
				 name ? name : "");
	g_signal_handler_unblock (self->priv->name_field, self->priv->name_changed_id);

	g_signal_handler_block (self->priv->uri_field, self->priv->uri_changed_id);
	nautilus_entry_set_text (NAUTILUS_ENTRY (self->priv->uri_field),
				 entry_text ? entry_text : "");
	g_signal_handler_unblock (self->priv->uri_field, self->priv->uri_changed_id);

	self->priv->text_changed = FALSE;
	self->priv->name_text_changed = FALSE;

	g_free (entry_text);
}
static void
repopulate (void)
{
	NautilusBookmark *selected;
	GtkListStore *store;
	GtkTreePath *path;
	GtkTreeRowReference *reference;
	guint index;

	g_assert (GTK_IS_TREE_VIEW (bookmark_list_widget));
	g_assert (NAUTILUS_IS_BOOKMARK_LIST (bookmarks));
	
	store = GTK_LIST_STORE (bookmark_list_store);

	selected = get_selected_bookmark ();

	g_signal_handler_block (bookmark_selection,
				selection_changed_id);
	g_signal_handler_block (bookmark_list_store,
				row_deleted_signal_id);
        g_signal_handler_block (bookmark_list_widget,
                                row_activated_signal_id);
        g_signal_handler_block (bookmark_list_widget,
                                key_pressed_signal_id);
        g_signal_handler_block (bookmark_list_widget,
                                button_pressed_signal_id);

	gtk_list_store_clear (store);
	
	g_signal_handler_unblock (bookmark_list_widget,
				  row_activated_signal_id);
        g_signal_handler_unblock (bookmark_list_widget,
                                  key_pressed_signal_id);
        g_signal_handler_unblock (bookmark_list_widget,
                                  button_pressed_signal_id);
	g_signal_handler_unblock (bookmark_list_store,
				  row_deleted_signal_id);
	g_signal_handler_unblock (bookmark_selection,
				  selection_changed_id);
	
	/* Fill the list in with the bookmark names. */
	g_signal_handler_block (store, row_changed_signal_id);

	reference = NULL;

	for (index = 0; index < nautilus_bookmark_list_length (bookmarks); ++index) {
		NautilusBookmark *bookmark;
		const char       *bookmark_name;
		GIcon            *bookmark_icon;
		GtkTreeIter       iter;

		bookmark = nautilus_bookmark_list_item_at (bookmarks, index);
		bookmark_name = nautilus_bookmark_get_name (bookmark);
		bookmark_icon = nautilus_bookmark_get_icon (bookmark);

		gtk_list_store_append (store, &iter);
		gtk_list_store_set (store, &iter, 
				    BOOKMARK_LIST_COLUMN_ICON, bookmark_icon,
				    BOOKMARK_LIST_COLUMN_NAME, bookmark_name,
				    BOOKMARK_LIST_COLUMN_BOOKMARK, bookmark,
				    BOOKMARK_LIST_COLUMN_STYLE, PANGO_STYLE_NORMAL,
				    -1);

		if (bookmark == selected) {
			/* save old selection */
			GtkTreePath *path;

			path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter);
			reference = gtk_tree_row_reference_new (GTK_TREE_MODEL (store), path);
			gtk_tree_path_free (path);
		}

		g_object_unref (bookmark_icon);
	}

	g_signal_handler_unblock (store, row_changed_signal_id);

	if (reference != NULL) {
		/* restore old selection */

		/* bookmarks_set_empty() will call the selection change handler,
 		 * so we block it here in case of selection change.
 		 */
		g_signal_handler_block (bookmark_selection, selection_changed_id);

		g_assert (index != 0);
		g_assert (gtk_tree_row_reference_valid (reference));

		path = gtk_tree_row_reference_get_path (reference);
		gtk_tree_selection_select_path (bookmark_selection, path);
		gtk_tree_row_reference_free (reference);
		gtk_tree_path_free (path);

		g_signal_handler_unblock (bookmark_selection, selection_changed_id);
	}

	bookmarks_set_empty (index == 0);	  
}