nautilus-bookmark-list.c 17.3 KB
Newer Older
1 2
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */

3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * Nautilus
 *
 * Copyright (C) 1999, 2000 Eazel, Inc.
 *
 * Nautilus is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * Nautilus is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * Authors: John Sullivan <sullivan@eazel.com>
 */
24

25 26
/* nautilus-bookmark-list.c - implementation of centralized list of bookmarks.
 */
27

28
#include <config.h>
29 30
#include "nautilus-bookmark-list.h"

Alexander Larsson's avatar
Alexander Larsson committed
31 32
#include <libnautilus-private/nautilus-file-utilities.h>
#include <libnautilus-private/nautilus-file.h>
33
#include <libnautilus-private/nautilus-icon-names.h>
34

35
#include <gio/gio.h>
36
#include <string.h>
37

38
#define MAX_BOOKMARK_LENGTH 80
39 40
#define LOAD_JOB 1
#define SAVE_JOB 2
41

42
enum {
43
	CHANGED,
44 45 46
	LAST_SIGNAL
};

47 48
static guint signals[LAST_SIGNAL];

49
/* forward declarations */
50

51 52
static void        nautilus_bookmark_list_load_file     (NautilusBookmarkList *bookmarks);
static void        nautilus_bookmark_list_save_file     (NautilusBookmarkList *bookmarks);
Alexander Larsson's avatar
Alexander Larsson committed
53

54
G_DEFINE_TYPE(NautilusBookmarkList, nautilus_bookmark_list, G_TYPE_OBJECT)
55 56 57 58 59

static NautilusBookmark *
new_bookmark_from_uri (const char *uri, const char *label)
{
	NautilusBookmark *new_bookmark;
Alexander Larsson's avatar
Alexander Larsson committed
60
	GFile *location;
61

Alexander Larsson's avatar
Alexander Larsson committed
62 63 64 65 66 67
	location = NULL;
	if (uri) {
		location = g_file_new_for_uri (uri);
	}
	
	new_bookmark = NULL;
68

69
	if (location) {
70
		new_bookmark = nautilus_bookmark_new (location, label);
71
		g_object_unref (location);
72
	}
73

Alexander Larsson's avatar
Alexander Larsson committed
74
	return new_bookmark;
75 76
}

Alexander Larsson's avatar
Alexander Larsson committed
77
static GFile *
78
nautilus_bookmark_list_get_legacy_file (void)
79
{
Alexander Larsson's avatar
Alexander Larsson committed
80 81 82 83 84 85 86 87 88 89 90
	char *filename;
	GFile *file;

	filename = g_build_filename (g_get_home_dir (),
				     ".gtk-bookmarks",
				     NULL);
	file = g_file_new_for_path (filename);

	g_free (filename);

	return file;
91
}
92

93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
static GFile *
nautilus_bookmark_list_get_file (void)
{
	char *filename;
	GFile *file;

	filename = g_build_filename (g_get_user_config_dir (),
				     "gtk-3.0",
				     "bookmarks",
				     NULL);
	file = g_file_new_for_path (filename);

	g_free (filename);

	return file;
}

110 111 112
/* Initialization.  */

static void
113 114 115 116 117 118
bookmark_in_list_changed_callback (NautilusBookmark     *bookmark,
				   NautilusBookmarkList *bookmarks)
{
	g_assert (NAUTILUS_IS_BOOKMARK (bookmark));
	g_assert (NAUTILUS_IS_BOOKMARK_LIST (bookmarks));

119
	/* save changes to the list */
120 121 122
	nautilus_bookmark_list_save_file (bookmarks);
}

123 124
static void
bookmark_in_list_notify (GObject *object,
125 126
			 GParamSpec *pspec,
			 NautilusBookmarkList *bookmarks)
127 128 129 130 131
{
	/* emit the changed signal without saving, as only appearance properties changed */
	g_signal_emit (bookmarks, signals[CHANGED], 0);
}

132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
static void
stop_monitoring_bookmark (NautilusBookmarkList *bookmarks,
			  NautilusBookmark     *bookmark)
{
	g_signal_handlers_disconnect_by_func (bookmark,
					      bookmark_in_list_changed_callback,
					      bookmarks);
}

static void
stop_monitoring_one (gpointer data, gpointer user_data)
{
	g_assert (NAUTILUS_IS_BOOKMARK (data));
	g_assert (NAUTILUS_IS_BOOKMARK_LIST (user_data));

	stop_monitoring_bookmark (NAUTILUS_BOOKMARK_LIST (user_data), 
				  NAUTILUS_BOOKMARK (data));
}

static void
clear (NautilusBookmarkList *bookmarks)
{
	g_list_foreach (bookmarks->list, stop_monitoring_one, bookmarks);
155
	g_list_free_full (bookmarks->list, g_object_unref);
156 157 158 159 160
	bookmarks->list = NULL;
}

static void
do_finalize (GObject *object)
161
{
162 163 164 165
	if (NAUTILUS_BOOKMARK_LIST (object)->monitor != NULL) {
		g_file_monitor_cancel (NAUTILUS_BOOKMARK_LIST (object)->monitor);
		NAUTILUS_BOOKMARK_LIST (object)->monitor = NULL;
	}
166

167 168
	g_queue_free (NAUTILUS_BOOKMARK_LIST (object)->pending_ops);

169 170 171 172 173 174 175 176 177
	clear (NAUTILUS_BOOKMARK_LIST (object));

	G_OBJECT_CLASS (nautilus_bookmark_list_parent_class)->finalize (object);
}

static void
nautilus_bookmark_list_class_init (NautilusBookmarkListClass *class)
{
	GObjectClass *object_class = G_OBJECT_CLASS (class);
178

179
	object_class->finalize = do_finalize;
180

181 182
	signals[CHANGED] =
		g_signal_new ("changed",
183 184 185
		              G_TYPE_FROM_CLASS (object_class),
		              G_SIGNAL_RUN_LAST,
		              G_STRUCT_OFFSET (NautilusBookmarkListClass, 
186
					       changed),
187
		              NULL, NULL,
188
		              g_cclosure_marshal_VOID__VOID,
189
		              G_TYPE_NONE, 0);
190 191
}

Alexander Larsson's avatar
Alexander Larsson committed
192 193 194 195 196 197 198 199 200 201 202 203 204 205
static void
bookmark_monitor_changed_cb (GFileMonitor      *monitor,
			     GFile             *child,
			     GFile             *other_file,
			     GFileMonitorEvent  eflags,
			     gpointer           user_data)
{
	if (eflags == G_FILE_MONITOR_EVENT_CHANGED ||
	    eflags == G_FILE_MONITOR_EVENT_CREATED) {
		g_return_if_fail (NAUTILUS_IS_BOOKMARK_LIST (NAUTILUS_BOOKMARK_LIST (user_data)));
		nautilus_bookmark_list_load_file (NAUTILUS_BOOKMARK_LIST (user_data));
	}
}

206
static void
207
nautilus_bookmark_list_init (NautilusBookmarkList *bookmarks)
Alexander Larsson's avatar
Alexander Larsson committed
208 209
{
	GFile *file;
210

211 212
	bookmarks->pending_ops = g_queue_new ();

213
	nautilus_bookmark_list_load_file (bookmarks);
Alexander Larsson's avatar
Alexander Larsson committed
214 215

	file = nautilus_bookmark_list_get_file ();
Alexander Larsson's avatar
Alexander Larsson committed
216
	bookmarks->monitor = g_file_monitor_file (file, 0, NULL, NULL);
217 218
	g_file_monitor_set_rate_limit (bookmarks->monitor, 1000);

Alexander Larsson's avatar
Alexander Larsson committed
219 220 221 222
	g_signal_connect (bookmarks->monitor, "changed",
			  G_CALLBACK (bookmark_monitor_changed_cb), bookmarks);

	g_object_unref (file);
223 224
}

225 226
static void
insert_bookmark_internal (NautilusBookmarkList *bookmarks,
Alexander Larsson's avatar
Alexander Larsson committed
227 228
			  NautilusBookmark     *bookmark,
			  int                   index)
229
{
230 231
	bookmarks->list = g_list_insert (bookmarks->list, bookmark, index);

232
	g_signal_connect_object (bookmark, "contents-changed",
233
				 G_CALLBACK (bookmark_in_list_changed_callback), bookmarks, 0);
234 235 236 237
	g_signal_connect_object (bookmark, "notify::icon",
				 G_CALLBACK (bookmark_in_list_notify), bookmarks, 0);
	g_signal_connect_object (bookmark, "notify::name",
				 G_CALLBACK (bookmark_in_list_notify), bookmarks, 0);
238 239
}

240
/**
241
 * nautilus_bookmark_list_append:
242
 *
243 244
 * Append a bookmark to a bookmark list.
 * @bookmarks: NautilusBookmarkList to append to.
245 246 247
 * @bookmark: Bookmark to append a copy of.
 **/
void
248
nautilus_bookmark_list_append (NautilusBookmarkList *bookmarks, 
Alexander Larsson's avatar
Alexander Larsson committed
249
			       NautilusBookmark     *bookmark)
250
{
251
	g_return_if_fail (NAUTILUS_IS_BOOKMARK_LIST (bookmarks));
252 253
	g_return_if_fail (NAUTILUS_IS_BOOKMARK (bookmark));

254 255 256 257 258
	if (g_list_find_custom (bookmarks->list, bookmark,
				nautilus_bookmark_compare_with) != NULL) {
		return;
	}

Cosimo Cecchi's avatar
Cosimo Cecchi committed
259
	insert_bookmark_internal (bookmarks, g_object_ref (bookmark), -1);
260
	nautilus_bookmark_list_save_file (bookmarks);
261 262
}

263
/**
264
 * nautilus_bookmark_list_delete_item_at:
265
 * 
266
 * Delete the bookmark at the specified position.
267 268 269
 * @bookmarks: the list of bookmarks.
 * @index: index, must be less than length of list.
 **/
Alexander Larsson's avatar
Alexander Larsson committed
270
void
271
nautilus_bookmark_list_delete_item_at (NautilusBookmarkList *bookmarks, 
Alexander Larsson's avatar
Alexander Larsson committed
272
				       guint                 index)
273 274 275
{
	GList *doomed;

276
	g_return_if_fail (NAUTILUS_IS_BOOKMARK_LIST (bookmarks));
277
	g_return_if_fail (index < g_list_length (bookmarks->list));
278 279 280

	doomed = g_list_nth (bookmarks->list, index);
	bookmarks->list = g_list_remove_link (bookmarks->list, doomed);
281

282
	g_assert (NAUTILUS_IS_BOOKMARK (doomed->data));
283
	stop_monitoring_bookmark (bookmarks, NAUTILUS_BOOKMARK (doomed->data));
284
	g_object_unref (doomed->data);
Alexander Larsson's avatar
Alexander Larsson committed
285

286
	g_list_free_1 (doomed);
Alexander Larsson's avatar
Alexander Larsson committed
287

288
	nautilus_bookmark_list_save_file (bookmarks);
289 290
}

291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
/**
 * nautilus_bookmark_list_move_item:
 *
 * Move the item from the given position to the destination.
 * @index: the index of the first bookmark.
 * @destination: the index of the second bookmark.
 **/
void
nautilus_bookmark_list_move_item (NautilusBookmarkList *bookmarks,
				  guint index,
				  guint destination)
{
	GList *bookmark_item;

	if (index == destination) {
		return;
	}

	bookmark_item = g_list_nth (bookmarks->list, index);
	bookmarks->list = g_list_remove_link (bookmarks->list,
					      bookmark_item);

313 314 315
	bookmarks->list = g_list_insert (bookmarks->list,
					 bookmark_item->data,
					 destination);
316

317
	nautilus_bookmark_list_save_file (bookmarks);
318 319
}

320
/**
321
 * nautilus_bookmark_list_insert_item:
322
 * 
323
 * Insert a bookmark at a specified position.
324 325 326 327
 * @bookmarks: the list of bookmarks.
 * @index: the position to insert the bookmark at.
 * @new_bookmark: the bookmark to insert a copy of.
 **/
Alexander Larsson's avatar
Alexander Larsson committed
328
void
329
nautilus_bookmark_list_insert_item (NautilusBookmarkList *bookmarks,
Alexander Larsson's avatar
Alexander Larsson committed
330 331
				    NautilusBookmark     *new_bookmark,
				    guint                 index)
332
{
333
	g_return_if_fail (NAUTILUS_IS_BOOKMARK_LIST (bookmarks));
334
	g_return_if_fail (index <= g_list_length (bookmarks->list));
335

Cosimo Cecchi's avatar
Cosimo Cecchi committed
336
	insert_bookmark_internal (bookmarks, g_object_ref (new_bookmark), index);
337
	nautilus_bookmark_list_save_file (bookmarks);
338 339
}

340
/**
341
 * nautilus_bookmark_list_item_at:
342 343 344 345 346 347 348
 * 
 * Get the bookmark at the specified position.
 * @bookmarks: the list of bookmarks.
 * @index: index, must be less than length of list.
 * 
 * Return value: the bookmark at position @index in @bookmarks.
 **/
349
NautilusBookmark *
350
nautilus_bookmark_list_item_at (NautilusBookmarkList *bookmarks, guint index)
351
{
352
	g_return_val_if_fail (NAUTILUS_IS_BOOKMARK_LIST (bookmarks), NULL);
353
	g_return_val_if_fail (index < g_list_length (bookmarks->list), NULL);
354

355
	return NAUTILUS_BOOKMARK (g_list_nth_data (bookmarks->list, index));
356 357
}

358
/**
359
 * nautilus_bookmark_list_item_with_location:
360
 *
361
 * Get the bookmark with the specified location, if any
362
 * @bookmarks: the list of bookmarks.
363
 * @location: a #GFile
364
 * @index: location where to store bookmark index, or %NULL
365
 *
366
 * Return value: the bookmark with location @location, or %NULL.
367 368
 **/
NautilusBookmark *
369
nautilus_bookmark_list_item_with_location (NautilusBookmarkList *bookmarks,
370 371
					   GFile                *location,
					   guint                *index)
372 373
{
	GList *node;
374
	GFile *bookmark_location;
375 376
	NautilusBookmark *bookmark;
	gboolean found = FALSE;
377
	guint idx;
378 379

	g_return_val_if_fail (NAUTILUS_IS_BOOKMARK_LIST (bookmarks), NULL);
380
	g_return_val_if_fail (G_IS_FILE (location), NULL);
381

382 383
	idx = 0;

384 385
	for (node = bookmarks->list; node != NULL; node = node->next) {
		bookmark = node->data;
386
		bookmark_location = nautilus_bookmark_get_location (bookmark);
387

388
		if (g_file_equal (location, bookmark_location)) {
389 390 391
			found = TRUE;
		}

392
		g_object_unref (bookmark_location);
393 394

		if (found) {
395 396 397
			if (index) {
				*index = idx;
			}
398 399
			return bookmark;
		}
400 401

		idx++;
402 403 404 405 406
	}

	return NULL;
}

407
/**
408
 * nautilus_bookmark_list_length:
409 410 411 412 413 414 415
 * 
 * Get the number of bookmarks in the list.
 * @bookmarks: the list of bookmarks.
 * 
 * Return value: the length of the bookmark list.
 **/
guint
416
nautilus_bookmark_list_length (NautilusBookmarkList *bookmarks)
417
{
418
	g_return_val_if_fail (NAUTILUS_IS_BOOKMARK_LIST(bookmarks), 0);
419

420
	return g_list_length (bookmarks->list);
421 422
}

423
static void
424 425 426 427
process_next_op (NautilusBookmarkList *bookmarks);

static void
op_processed_cb (NautilusBookmarkList *self)
428
{
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
	g_queue_pop_tail (self->pending_ops);

	if (!g_queue_is_empty (self->pending_ops)) {
		process_next_op (self);
	}
}

static void
load_callback (GObject *source,
	       GAsyncResult *res,
	       gpointer user_data)
{
	NautilusBookmarkList *self = NAUTILUS_BOOKMARK_LIST (source);
	gchar *contents;
	char **lines;
	int i;

	contents = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));

	if (contents == NULL) {
		return;
	}

	lines = g_strsplit (contents, "\n", -1);
	for (i = 0; lines[i]; i++) {
		/* Ignore empty or invalid lines that cannot be parsed properly */
		if (lines[i][0] != '\0' && lines[i][0] != ' ') {
			/* gtk 2.7/2.8 might have labels appended to bookmarks which are separated by a space */
			/* we must seperate the bookmark uri and the potential label */
			char *space, *label;

			label = NULL;
			space = strchr (lines[i], ' ');
			if (space) {
				*space = '\0';
				label = g_strdup (space + 1);
465
			}
466

467 468 469
			insert_bookmark_internal (self, new_bookmark_from_uri (lines[i], label), -1);
			g_free (label);
		}
Alexander Larsson's avatar
Alexander Larsson committed
470
	}
471 472 473 474 475

	g_signal_emit (self, signals[CHANGED], 0);
	op_processed_cb (self);

	g_strfreev (lines);
476 477 478
}

static void
479 480 481
load_io_thread (GSimpleAsyncResult *result,
		GObject *object,
		GCancellable *cancellable)
482 483
{
	GFile *file;
484 485
	gchar *contents;
	GError *error = NULL;
486 487

	file = nautilus_bookmark_list_get_file ();
488
	if (!g_file_query_exists (file, NULL)) {
William Jon McCann's avatar
William Jon McCann committed
489
		g_object_unref (file);
490 491
		file = nautilus_bookmark_list_get_legacy_file ();
	}
492

493
	g_file_load_contents (file, NULL, &contents, NULL, NULL, &error);
William Jon McCann's avatar
William Jon McCann committed
494
	g_object_unref (file);
495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510

	if (error != NULL) {
		if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) {
			g_warning ("Could not load bookmark file: %s\n", error->message);
		}
		g_error_free (error);
	} else {
		g_simple_async_result_set_op_res_gpointer (result, contents, g_free);
	}
}

static void
load_file_async (NautilusBookmarkList *self)
{
	GSimpleAsyncResult *result;

511 512 513
	/* Wipe out old list. */
	clear (self);

514 515 516 517 518 519
	result = g_simple_async_result_new (G_OBJECT (self), 
					    load_callback, NULL, NULL);
	g_simple_async_result_run_in_thread (result, load_io_thread,
					     G_PRIORITY_DEFAULT, NULL);
	g_object_unref (result);
}
Alexander Larsson's avatar
Alexander Larsson committed
520

521 522 523 524 525 526 527 528 529 530 531
static void
save_callback (GObject *source,
	       GAsyncResult *res,
	       gpointer user_data)
{
	NautilusBookmarkList *self = NAUTILUS_BOOKMARK_LIST (source);
	GFile *file;

	/* re-enable bookmark file monitoring */
	file = nautilus_bookmark_list_get_file ();
	self->monitor = g_file_monitor_file (file, 0, NULL, NULL);
Alexander Larsson's avatar
Alexander Larsson committed
532
	g_object_unref (file);
533 534 535 536 537 538

	g_file_monitor_set_rate_limit (self->monitor, 1000);
	g_signal_connect (self->monitor, "changed",
			  G_CALLBACK (bookmark_monitor_changed_cb), self);

	op_processed_cb (self);
539 540
}

541
static void
542 543 544
save_io_thread (GSimpleAsyncResult *result,
		GObject *object,
		GCancellable *cancellable)
545
{
546 547
	gchar *contents, *path;
	GFile *parent, *file;
548
	GError *error = NULL;
549

550 551 552 553 554 555 556 557 558 559 560 561
	file = nautilus_bookmark_list_get_file ();
	parent = g_file_get_parent (file);
	path = g_file_get_path (parent);
	g_mkdir_with_parents (path, 0700);
	g_free (path);
	g_object_unref (parent);

	contents = g_simple_async_result_get_op_res_gpointer (result);
	g_file_replace_contents (file, 
				 contents, strlen (contents),
				 NULL, FALSE, 0, NULL,
				 NULL, &error);
562

563 564 565 566 567 568 569
	if (error != NULL) {
		g_warning ("Unable to replace contents of the bookmarks file: %s",
			   error->message);
		g_error_free (error);
	}

	g_object_unref (file);
570
}
571 572

static void
573
save_file_async (NautilusBookmarkList *self)
574
{
575
	GSimpleAsyncResult *result;
576
	GString *bookmark_string;
577 578 579 580
	gchar *contents;
	GList *l;

	bookmark_string = g_string_new (NULL);
Alexander Larsson's avatar
Alexander Larsson committed
581 582

	/* temporarily disable bookmark file monitoring when writing file */
583 584 585
	if (self->monitor != NULL) {
		g_file_monitor_cancel (self->monitor);
		self->monitor = NULL;
Alexander Larsson's avatar
Alexander Larsson committed
586
	}
587

588
	for (l = self->list; l; l = l->next) {
Alexander Larsson's avatar
Alexander Larsson committed
589 590 591 592 593 594
		NautilusBookmark *bookmark;

		bookmark = NAUTILUS_BOOKMARK (l->data);

		/* make sure we save label if it has one for compatibility with GTK 2.7 and 2.8 */
		if (nautilus_bookmark_get_has_custom_name (bookmark)) {
595 596
			const char *label;
			char *uri;
Alexander Larsson's avatar
Alexander Larsson committed
597 598
			label = nautilus_bookmark_get_name (bookmark);
			uri = nautilus_bookmark_get_uri (bookmark);
599 600
			g_string_append_printf (bookmark_string,
						"%s %s\n", uri, label);
Alexander Larsson's avatar
Alexander Larsson committed
601 602 603 604
			g_free (uri);
		} else {
			char *uri;
			uri = nautilus_bookmark_get_uri (bookmark);
605
			g_string_append_printf (bookmark_string, "%s\n", uri);
Alexander Larsson's avatar
Alexander Larsson committed
606
			g_free (uri);
607
		}
608
	}
609

610 611 612 613
	result = g_simple_async_result_new (G_OBJECT (self),
					    save_callback, NULL, NULL);
	contents = g_string_free (bookmark_string, FALSE);
	g_simple_async_result_set_op_res_gpointer (result, contents, g_free);
614

615 616 617
	g_simple_async_result_run_in_thread (result, save_io_thread,
					     G_PRIORITY_DEFAULT, NULL);
	g_object_unref (result);
618 619 620 621 622 623
}

static void
process_next_op (NautilusBookmarkList *bookmarks)
{
	gint op;
624

625
	op = GPOINTER_TO_INT (g_queue_peek_tail (bookmarks->pending_ops));
626

627
	if (op == LOAD_JOB) {
628
		load_file_async (bookmarks);
629
	} else {
630
		save_file_async (bookmarks);
631 632
	}
}
633

634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658
/**
 * nautilus_bookmark_list_load_file:
 * 
 * Reads bookmarks from file, clobbering contents in memory.
 * @bookmarks: the list of bookmarks to fill with file contents.
 **/
static void
nautilus_bookmark_list_load_file (NautilusBookmarkList *bookmarks)
{
	g_queue_push_head (bookmarks->pending_ops, GINT_TO_POINTER (LOAD_JOB));

	if (g_queue_get_length (bookmarks->pending_ops) == 1) {
		process_next_op (bookmarks);
	}
}

/**
 * nautilus_bookmark_list_save_file:
 * 
 * Save bookmarks to disk.
 * @bookmarks: the list of bookmarks to save.
 **/
static void
nautilus_bookmark_list_save_file (NautilusBookmarkList *bookmarks)
{
659
	g_signal_emit (bookmarks, signals[CHANGED], 0);
660 661 662 663 664 665 666 667

	g_queue_push_head (bookmarks->pending_ops, GINT_TO_POINTER (SAVE_JOB));

	if (g_queue_get_length (bookmarks->pending_ops) == 1) {
		process_next_op (bookmarks);
	}
}

668 669 670 671
gboolean
nautilus_bookmark_list_can_bookmark_location (NautilusBookmarkList *list,
					      GFile                *location)
{
672
	if (nautilus_bookmark_list_item_with_location (list, location, NULL)) {
673 674 675 676 677 678
		return FALSE;
	}

	return !nautilus_is_home_directory (location);
}

679 680 681 682 683 684 685 686 687 688 689 690 691 692
/**
 * nautilus_bookmark_list_new:
 * 
 * Create a new bookmark_list, with contents read from disk.
 * 
 * Return value: A pointer to the new widget.
 **/
NautilusBookmarkList *
nautilus_bookmark_list_new (void)
{
	NautilusBookmarkList *list;

	list = NAUTILUS_BOOKMARK_LIST (g_object_new (NAUTILUS_TYPE_BOOKMARK_LIST, NULL));

693
	return list;
694
}