nautilus-application.c 29.9 KB
Newer Older
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
1
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 3 4 5 6

/*
 *  Nautilus
 *
 *  Copyright (C) 1999, 2000 Red Hat, Inc.
7
 *  Copyright (C) 2000, 2001 Eazel, Inc.
8
 *
9
 *  Nautilus is free software; you can redistribute it and/or
10 11 12 13
 *  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.
 *
14
 *  Nautilus is distributed in the hope that it will be useful,
15 16 17 18 19
 *  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
20
 *  along with this program; if not, write to the Free Software
21 22
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
23
 *  Authors: Elliot Lee <sopwith@redhat.com>,
24
 *           Darin Adler <darin@bentspoon.com>
25 26 27
 *
 */

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

31
#include "file-manager/fm-desktop-icon-view.h"
32
#include "file-manager/fm-icon-view.h"
33
#include "file-manager/fm-list-view.h"
34
#include "file-manager/fm-search-list-view.h"
35 36
#include "nautilus-desktop-window.h"
#include "nautilus-first-time-druid.h"
37
#include "nautilus-main.h"
38 39 40 41
#include "nautilus-shell-interface.h"
#include "nautilus-shell.h"
#include <bonobo/bonobo-main.h>
#include <bonobo/bonobo-object.h>
42
#include <dirent.h>
Ramiro Estrugo's avatar
Ramiro Estrugo committed
43 44 45 46 47
#include <eel/eel-gtk-macros.h>
#include <eel/eel-stock-dialogs.h>
#include <eel/eel-string-list.h>
#include <eel/eel-string.h>
#include <eel/eel-vfs-extensions.h>
48
#include <gtk/gtksignal.h>
49
#include <libgnome/gnome-config.h>
50 51
#include <libgnome/gnome-i18n.h>
#include <libgnome/gnome-util.h>
52
#include <libgnomeui/gnome-client.h>
Ramiro Estrugo's avatar
Ramiro Estrugo committed
53
#include <libgnomeui/gnome-messagebox.h>
54
#include <libgnomeui/gnome-stock-icons.h>
55
#include <libgnomevfs/gnome-vfs-mime-handlers.h>
56
#include <libgnomevfs/gnome-vfs-ops.h>
Ramiro Estrugo's avatar
Ramiro Estrugo committed
57
#include <libgnomevfs/gnome-vfs-utils.h>
58 59 60 61 62 63 64
#include <libnautilus-private/nautilus-file-utilities.h>
#include <libnautilus-private/nautilus-global-preferences.h>
#include <libnautilus-private/nautilus-icon-factory.h>
#include <libnautilus-private/nautilus-metafile-factory.h>
#include <libnautilus-private/nautilus-sound.h>
#include <libnautilus-private/nautilus-undo-manager.h>
#include <libnautilus-private/nautilus-volume-monitor.h>
65
#include <libnautilus-private/nautilus-authn-manager.h>
66
#include <bonobo-activation/bonobo-activation.h>
67

68 69 70 71
/* Needed for the is_kdesktop_present check */
#include <gdk/gdkx.h>
#include <X11/Xlib.h>

72
#define FACTORY_IID	     "OAFIID:nautilus_factory:bd1e1862-92d7-4391-963e-37583f0daef3"
73
#define SEARCH_LIST_VIEW_IID "OAFIID:nautilus_file_manager_search_list_view:b186e381-198e-43cf-9c46-60b6bb35db0b"
74
#define SHELL_IID	     "OAFIID:nautilus_shell:cd5183b2-3913-4b74-9b8e-10528b0de08d"
75

76 77 78 79 80 81
/* Keeps track of the one and only desktop window. */
static NautilusDesktopWindow *nautilus_application_desktop_window;

/* Keeps track of all the nautilus windows. */
static GList *nautilus_application_window_list;

82 83 84 85 86 87 88 89 90 91 92 93 94
static gboolean need_to_show_first_time_druid     (void);
static void     desktop_changed_callback          (gpointer                  user_data);
static void     desktop_location_changed_callback (gpointer                  user_data);
static void     volume_mounted_callback           (NautilusVolumeMonitor    *monitor,
						   NautilusVolume           *volume,
						   NautilusApplication      *application);
static void     volume_unmounted_callback         (NautilusVolumeMonitor    *monitor,
						   NautilusVolume           *volume,
						   NautilusApplication      *application);
static void     update_session                    (gpointer                  callback_data);
static void     init_session                      (void);
static gboolean is_kdesktop_present               (void);

95 96
BONOBO_CLASS_BOILERPLATE (NautilusApplication, nautilus_application,
			  BonoboGenericFactory, BONOBO_GENERIC_FACTORY_TYPE)
97 98

static CORBA_Object
99 100 101
create_object (PortableServer_Servant servant,
	       const CORBA_char *iid,
	       CORBA_Environment *ev)
102
{
103
	BonoboObject *object;
104
	FMDirectoryView *directory_view;
105
	NautilusApplication *application;
106

107
	if (strcmp (iid, NAUTILUS_ICON_VIEW_IID) == 0) {
108
		directory_view = FM_DIRECTORY_VIEW (g_object_new (fm_icon_view_get_type (), NULL));
109
		object = BONOBO_OBJECT (fm_directory_view_get_nautilus_view (directory_view));
110
	} else if (strcmp (iid, NAUTILUS_DESKTOP_ICON_VIEW_IID) == 0) {
111
		directory_view = FM_DIRECTORY_VIEW (g_object_new (fm_desktop_icon_view_get_type (), NULL));
112
		object = BONOBO_OBJECT (fm_directory_view_get_nautilus_view (directory_view));
113
	} else if (strcmp (iid, NAUTILUS_LIST_VIEW_IID) == 0) {
114
		directory_view = FM_DIRECTORY_VIEW (g_object_new (fm_list_view_get_type (), NULL));
115
		object = BONOBO_OBJECT (fm_directory_view_get_nautilus_view (directory_view));
116
	} else if (strcmp (iid, SEARCH_LIST_VIEW_IID) == 0) {
117
		directory_view = FM_DIRECTORY_VIEW (g_object_new (fm_search_list_view_get_type (), NULL));
118
		object = BONOBO_OBJECT (fm_directory_view_get_nautilus_view (directory_view));
119
	} else if (strcmp (iid, SHELL_IID) == 0) {
120
		application = NAUTILUS_APPLICATION (bonobo_object_from_servant (servant));
121
		object = BONOBO_OBJECT (nautilus_shell_new (application));
122 123
	} else if (strcmp (iid, METAFILE_FACTORY_IID) == 0) {
		object = BONOBO_OBJECT (nautilus_metafile_factory_get_instance ());
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
124
	} else {
125
		object = CORBA_OBJECT_NIL;
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
126
	}
127

128
	return CORBA_Object_duplicate (BONOBO_OBJREF (object), ev);
129 130
}

131 132
GList *
nautilus_application_get_window_list (void)
133 134 135 136
{
	return nautilus_application_window_list;
}

137
static void
138
nautilus_application_instance_init (NautilusApplication *application)
139
{
140 141
	/* Create an undo manager */
	application->undo_manager = nautilus_undo_manager_new ();
142

143
	/* Watch for volume mounts so we can restore open windows */
144 145
	g_signal_connect (nautilus_volume_monitor_get (), "volume_mounted",
			  G_CALLBACK (volume_mounted_callback), application);
146 147

	/* Watch for volume unmounts so we can close open windows */
148 149
	g_signal_connect (nautilus_volume_monitor_get (), "volume_unmounted",
			  G_CALLBACK (volume_unmounted_callback), application);
150 151
}

152 153
NautilusApplication *
nautilus_application_new (void)
154
{
155 156 157 158 159 160 161 162 163
	NautilusApplication *application;

	application = g_object_new (NAUTILUS_TYPE_APPLICATION, NULL);
	
	bonobo_generic_factory_construct_noreg (BONOBO_GENERIC_FACTORY (application),
						FACTORY_IID,
						NULL);
	
	return application;
164 165 166
}

static void
167
nautilus_application_destroy (BonoboObject *object)
168
{
169 170 171 172
	NautilusApplication *application;

	application = NAUTILUS_APPLICATION (object);

173
	nautilus_bookmarks_exiting ();
174
	
175
	bonobo_object_unref (application->undo_manager);
176

177
	EEL_CALL_PARENT (BONOBO_OBJECT_CLASS, destroy, (object));
178
}
179

180 181
static gboolean
check_required_directories (NautilusApplication *application)
182
{
183 184 185 186 187 188
	char *user_directory;
	char *desktop_directory;
	EelStringList *directories;
	char *directories_as_string;
	char *error_string;
	char *dialog_title;
189
	GtkDialog *dialog;
190
	int failed_count;
191
	
192
	g_assert (NAUTILUS_IS_APPLICATION (application));
193 194 195 196

	user_directory = nautilus_get_user_directory ();
	desktop_directory = nautilus_get_desktop_directory ();

197
	directories = eel_string_list_new (TRUE);
198
	
199
	if (!g_file_test (user_directory, G_FILE_TEST_IS_DIR)) {
200
		eel_string_list_insert (directories, user_directory);
201
	}
202
	g_free (user_directory);	    
203
	    
204
	if (!g_file_test (desktop_directory, G_FILE_TEST_IS_DIR)) {
205
		eel_string_list_insert (directories, desktop_directory);
206
	}
207
	g_free (desktop_directory);
208

209
	failed_count = eel_string_list_get_length (directories);
210

211
	if (failed_count != 0) {
212
		directories_as_string = eel_string_list_as_string (directories, "\n", EEL_STRING_LIST_ALL_STRINGS);
213

214 215
		if (failed_count == 1) {
			dialog_title = g_strdup (_("Couldn't Create Required Folder"));
216 217 218
			error_string = g_strdup_printf (_("Nautilus could not create the required folder \"%s\". "
							  "Before running Nautilus, please create this folder, or "
							  "set permissions such that Nautilus can create it."),
219
							directories_as_string);
220 221
		} else {
			dialog_title = g_strdup (_("Couldn't Create Required Folders"));
222 223 224 225
			error_string = g_strdup_printf (_("Nautilus could not create the following required folders:\n\n"
							  "%s\n\n"
							  "Before running Nautilus, please create these folders, or "
							  "set permissions such that Nautilus can create them."),
226
							directories_as_string);
227 228
		}
		
Ramiro Estrugo's avatar
Ramiro Estrugo committed
229
		dialog = eel_show_error_dialog (error_string, dialog_title, NULL);
230 231
		/* We need the main event loop so the user has a chance to see the dialog. */
		nautilus_main_event_loop_register (GTK_OBJECT (dialog));
232

233
		g_free (directories_as_string);
234
		g_free (error_string);
235
		g_free (dialog_title);
236 237
	}

238
	eel_string_list_free (directories);
239 240

	return failed_count == 0;
241 242
}

243 244 245 246 247 248 249 250 251 252
static int
nautilus_strv_length (const char * const *strv)
{
	const char * const *p;

	for (p = strv; *p != NULL; p++) { }
	return p - strv;
}

static Nautilus_URIList *
253
nautilus_make_uri_list_from_shell_strv (const char * const *strv)
254 255 256
{
	int length, i;
	Nautilus_URIList *uri_list;
257
	char *translated_uri;
258 259 260 261 262 263 264 265

	length = nautilus_strv_length (strv);

	uri_list = Nautilus_URIList__alloc ();
	uri_list->_maximum = length;
	uri_list->_length = length;
	uri_list->_buffer = CORBA_sequence_Nautilus_URI_allocbuf (length);
	for (i = 0; i < length; i++) {
Ramiro Estrugo's avatar
Ramiro Estrugo committed
266
		translated_uri = eel_make_uri_from_shell_arg (strv[i]);
267 268 269
		uri_list->_buffer[i] = CORBA_string_dup (translated_uri);
		g_free (translated_uri);
		translated_uri = NULL;
270 271 272 273 274 275
	}
	CORBA_sequence_set_release (uri_list, CORBA_TRUE);

	return uri_list;
}

276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
static void
migrate_old_nautilus_files (void)
{
	char *new_desktop_dir, *np;
	char *old_desktop_dir, *op;
	char *old_desktop_dir_new_name;
	struct stat buf;
	DIR *dir;
	struct dirent *de;
	
	old_desktop_dir = g_strconcat (g_get_home_dir (), "/.nautilus/desktop", NULL);
	if (stat (old_desktop_dir, &buf) == -1) {
		g_free (old_desktop_dir);
		return;
	}
	if (!S_ISLNK (buf.st_mode)){
		dir = opendir (old_desktop_dir);
		if (dir == NULL) {
			g_free (old_desktop_dir);
			return;
		}
	
		new_desktop_dir = nautilus_get_desktop_directory ();
		
		while ((de = readdir (dir)) != NULL){
			if (de->d_name [0] == '.'){
				if (de->d_name [0] == 0)
					continue;
				
				if (de->d_name [1] == '.' && de->d_name [2] == 0)
					continue;
			}
	
			op = g_strconcat (old_desktop_dir, "/", de->d_name, NULL);
			np = g_strconcat (new_desktop_dir, "/", de->d_name, NULL);
	
			rename (op, np);
	
			g_free (op);
			g_free (np);
		}

		closedir (dir);

		g_free (new_desktop_dir);
	}

	/* In case we miss something */
	old_desktop_dir_new_name = g_strconcat (old_desktop_dir, "-old", NULL);
	rename (old_desktop_dir, old_desktop_dir_new_name);
	g_free (old_desktop_dir_new_name);

	g_free (old_desktop_dir);
}

331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359
static gint
create_starthere_link_callback (gpointer data)
{
	char *desktop_path;
	char *desktop_link_file;
	char *cmd;
	
	/* Create default services icon on the desktop */
	desktop_path = nautilus_get_desktop_directory ();
	desktop_link_file = nautilus_make_path (desktop_path,
						"starthere.desktop");

	cmd = g_strconcat ("/bin/cp ",
			   NAUTILUS_DATADIR,
			   "/starthere-link.desktop ",
			   desktop_link_file,
			   NULL);

	if (system (cmd) != 0) {
		g_warning ("Failed to execute command '%s'\n", cmd);
	}
	
	g_free (desktop_path);
	g_free (desktop_link_file);
	g_free (cmd);
	
	return FALSE;
}

360 361 362 363
static void
finish_startup (NautilusApplication *application)
{
	/* initialize the sound machinery */
364
	nautilus_sound_init ();
365

366
	/* initialize URI authentication manager */
367
	nautilus_authentication_manager_init ();
368

369
	/* Make the desktop work with old Nautilus. */
370 371 372
	migrate_old_nautilus_files ();
}

373
void
374
nautilus_application_startup (NautilusApplication *application,
375
			      gboolean kill_shell,
376
			      gboolean restart_shell,
377
			      gboolean no_default_window,
378
			      gboolean no_desktop,
379
			      gboolean do_first_time_druid_check,
380
			      const char *geometry,
381
			      const char *urls[])
382
{
383 384
	CORBA_Environment ev;
	Nautilus_Shell shell;
385
	Bonobo_RegistrationResult result;
386
	const char *message, *detailed_message;
387
	GtkDialog *dialog;
388
	Nautilus_URIList *url_list;
389
	const CORBA_char *corba_geometry;
390 391 392
	int num_failures;

	num_failures = 0;
393

394
	/* Check the user's ~/.nautilus directories and post warnings
395
	 * if there are problems.
396
	 */
397
	if (!kill_shell && !check_required_directories (application)) {
398 399
		return;
	}
400

401 402
	/* Run the first time startup druid if needed. */
	if (do_first_time_druid_check && need_to_show_first_time_druid ()) {
403 404 405 406 407 408
		/* Do this at idle time, once nautilus has initialized
		 * itself. Otherwise we may spawn a second nautilus
		 * process when looking for a metadata factory..
		 */
		g_idle_add (create_starthere_link_callback, NULL);
		nautilus_set_first_time_file_flag ();
409
	}
410

411 412
	CORBA_exception_init (&ev);

413
	/* Start up the factory. */
414
	while (TRUE) {
415
		/* Try to register the file manager view factory. */
416 417
		result = bonobo_activation_active_server_register
			(FACTORY_IID, BONOBO_OBJREF (application));
418

419
		switch (result) {
420 421
		case Bonobo_ACTIVATION_REG_SUCCESS:
			/* We are registered and all is right with the world. */
422
			finish_startup (application);
423
		case Bonobo_ACTIVATION_REG_ALREADY_ACTIVE:
424
			/* Another copy of nautilus already is running and registered. */
425
			message = NULL;
426
			detailed_message = NULL;
427
			break;
428
		case Bonobo_ACTIVATION_REG_NOT_LISTED:
429
			/* Can't register myself due to trouble locating the
430
			 * Nautilus_Shell.server file. This has happened when you
431
			 * launch Nautilus with an LD_LIBRARY_PATH that
432
			 * doesn't include the directory containing the oaf
433
			 * library. It could also happen if the
434
			 * Nautilus_Shell.server file was not present for some
435 436 437 438 439
			 * reason. Sometimes killing oafd and gconfd fixes
			 * this problem but we don't exactly understand why,
			 * since neither of the above causes explain it.
			 */
			message = _("Nautilus can't be used now. "
440
				    "Running the command \"bonobo-slay\""
441 442 443
				    " from the console may fix the problem. If not,"
				    " you can try rebooting the computer or"
				    " installing Nautilus again.");
444
			/* FIXME bugzilla.gnome.org 42536: The guesses and stuff here are lame. */
445
			detailed_message = _("Nautilus can't be used now. "
446
					     "Running the command \"bonobo-slay\" "
447 448 449 450
					     "from the console may fix the problem. If not, "
					     "you can try rebooting the computer or "
					     "installing Nautilus again.\n\n"
					     "Bonobo couldn't locate the Nautilus_shell.server file. "
451
					     "One cause of this seems to be an LD_LIBRARY_PATH "
452
					     "that does not include the bonobo-activation library's directory. "
453
					     "Another possible cause would be bad install "
454
					     "with a missing Nautilus_Shell.server file.\n\n"
455
					     "Running \"bonobo-slay\" will kill all "
456
					     "Bonobo Activation and GConf processes, which may be needed by "
457
					     "other applications.\n\n"
458
					     "Sometimes killing bonobo-activation-server and gconfd fixes "
459
					     "the problem, but we don't know why.\n\n"
460
					     "We have also seen this error when a faulty "
461
					     "version of bonobo-activation was installed.");
462 463 464
			break;
		default:
			/* This should never happen. */
465
			g_warning ("bad error code from bonobo_activation_active_server_register");
466
		case Bonobo_ACTIVATION_REG_ERROR:
467
			/* Some misc. error (can never happen with current
468
			 * version of bonobo-activation). Show dialog and terminate the
469 470
			 * program.
			 */
471
			/* FIXME bugzilla.gnome.org 42537: Looks like this does happen with the
472
			 * current OAF. I guess I read the code wrong. Need to figure out when and make a
473 474
			 * good message.
			 */
475 476
			message = _("Nautilus can't be used now, due to an unexpected error.");
			detailed_message = _("Nautilus can't be used now, due to an unexpected error "
477
					     "from Bonobo when attempting to register the file manager view server.");
478 479
			break;
		}
480 481 482

		/* Get the shell object. */
		if (message == NULL) {
483
			shell = bonobo_activation_activate_from_id (SHELL_IID, 0, NULL, NULL);
484 485 486 487 488 489 490
			if (!CORBA_Object_is_nil (shell, &ev)) {
				break;
			}

			/* If we couldn't find ourselves it's a bad problem so
			 * we better stop looping.
			 */
491
			if (result == Bonobo_ACTIVATION_REG_SUCCESS) {
492
				/* FIXME bugzilla.gnome.org 42538: When can this happen? */
493 494
				message = _("Nautilus can't be used now, due to an unexpected error.");
				detailed_message = _("Nautilus can't be used now, due to an unexpected error "
495 496
						     "from Bonobo when attempting to locate the factory."
						     "Killing bonobo-activation-server and restarting Nautilus may help fix the problem.");
497 498 499 500 501
			} else {
				num_failures++;
				if (num_failures > 20) {
					message = _("Nautilus can't be used now, due to an unexpected error.");
					detailed_message = _("Nautilus can't be used now, due to an unexpected error "
502 503
							     "from Bonobo when attempting to locate the shell object. "
							     "Killing bonobo-activation-server and restarting Nautilus may help fix the problem.");
504 505
					
				}
506 507 508
			}
		}

509
		if (message != NULL) {
Ramiro Estrugo's avatar
Ramiro Estrugo committed
510
			dialog = eel_show_error_dialog_with_details (message, NULL, detailed_message, NULL);
511 512
			/* We need the main event loop so the user has a chance to see the dialog. */
			nautilus_main_event_loop_register (GTK_OBJECT (dialog));
513
			goto out;
514 515 516
		}
	}

517 518
	if (kill_shell) {
		Nautilus_Shell_quit (shell, &ev);
519 520
	} else if (restart_shell) {
		Nautilus_Shell_restart (shell, &ev);
521
	} else {
522
		/* If KDE desktop is running, then force no_desktop */
523
		if (is_kdesktop_present ()) {
524
			no_desktop = TRUE;
525
		}
526
		
527
		if (!no_desktop && eel_preferences_get_boolean (NAUTILUS_PREFERENCES_SHOW_DESKTOP)) {
528 529
			Nautilus_Shell_start_desktop (shell, &ev);
		}
530 531
		
		/* Monitor the preference to show or hide the desktop */
532
		eel_preferences_add_callback_while_alive (NAUTILUS_PREFERENCES_SHOW_DESKTOP,
Darin Adler's avatar
Darin Adler committed
533 534 535
							  desktop_changed_callback,
							  application,
							  G_OBJECT (application));
536

537 538
		/* Monitor the preference to have the desktop */
		/* point to the Unix home folder */
539
		eel_preferences_add_callback_while_alive (NAUTILUS_PREFERENCES_DESKTOP_IS_HOME_DIR,
Darin Adler's avatar
Darin Adler committed
540 541 542
							  desktop_location_changed_callback,
							  NULL,
							  G_OBJECT (application));
543

544 545 546 547
		/* CORBA C mapping doesn't allow NULL to be passed
		   for string parameters */
		corba_geometry = (geometry != NULL) ? geometry : "";

548 549
	  	/* Create the other windows. */
		if (urls != NULL) {
550
			url_list = nautilus_make_uri_list_from_shell_strv (urls);
551
			Nautilus_Shell_open_windows (shell, url_list, corba_geometry, &ev);
552
			CORBA_free (url_list);
553
		} else if (!no_default_window) {
554
			Nautilus_Shell_open_default_window (shell, corba_geometry, &ev);
555
		}
556 557 558
		
		/* Add ourselves to the session */
		init_session ();
559
	}
560

561
	/* We're done with the shell now, so let it go. */
562 563 564 565 566
	/* HACK: Don't bother releasing the shell in the case where we
	 * just told it to quit -- that just leads to hangs and does
	 * no good. We could probably fix this in some fancier way if
	 * we could figure out a better lifetime rule.
	 */
567
	if (!(kill_shell || restart_shell)) {
568
		bonobo_object_release_unref (shell, NULL);
569
	}
570

571
 out:
572
	CORBA_exception_free (&ev);
573 574 575
}

static void
576 577
nautilus_application_create_desktop_window (NautilusApplication *application)
{
578 579
	g_return_if_fail (nautilus_application_desktop_window == NULL);
	g_return_if_fail (NAUTILUS_IS_APPLICATION (application));
580

581 582
	nautilus_application_desktop_window = nautilus_desktop_window_new (application);
	gtk_widget_show (GTK_WIDGET (nautilus_application_desktop_window));
583 584 585 586
}

void
nautilus_application_open_desktop (NautilusApplication *application)
587
{
588 589
	if (nautilus_application_desktop_window == NULL) {
		nautilus_application_create_desktop_window (application);
590 591 592 593 594 595
	}
}

void
nautilus_application_close_desktop (void)
{
596
	if (nautilus_application_desktop_window != NULL) {
597
		gtk_widget_destroy (GTK_WIDGET (nautilus_application_desktop_window));
598
		nautilus_application_desktop_window = NULL;
599
	}
600 601
}

602 603 604
void
nautilus_application_close_all_windows (void)
{
605
	while (nautilus_application_window_list != NULL) {
606 607 608 609
		nautilus_window_close (NAUTILUS_WINDOW (nautilus_application_window_list->data));
	}
}

610
static void
611
nautilus_application_destroyed_window (GtkObject *object, NautilusApplication *application)
612
{
613
	nautilus_application_window_list = g_list_remove (nautilus_application_window_list, object);
614 615
}

616 617 618 619 620 621 622 623 624 625 626 627 628
static gboolean
nautilus_window_delete_event_callback (GtkWidget *widget,
				       GdkEvent *event,
				       gpointer user_data)
{
	NautilusWindow *window;

	window = NAUTILUS_WINDOW (widget);
	nautilus_window_close (window);

	return TRUE;
}				       

629
NautilusWindow *
630
nautilus_application_create_window (NautilusApplication *application)
631
{
632
	NautilusWindow *window;
633 634

	g_return_val_if_fail (NAUTILUS_IS_APPLICATION (application), NULL);
635
	
636
	window = NAUTILUS_WINDOW (gtk_widget_new (nautilus_window_get_type (),
Darin Adler's avatar
Darin Adler committed
637
						  "app", G_OBJECT (application),
638
						  "app_id", "nautilus", NULL));
639
	
640
	g_signal_connect (window, 
641 642
			  "delete_event", G_CALLBACK (nautilus_window_delete_event_callback),
			  NULL);
643

644
	g_signal_connect (window,
645 646
			  "destroy", G_CALLBACK (nautilus_application_destroyed_window),
			  application);
647

648
	nautilus_application_window_list = g_list_prepend (nautilus_application_window_list, window);
649

Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
650
	/* Do not yet show the window. It will be shown later on if it can
651 652 653
	 * successfully display its initial URI. Otherwise it will be destroyed
	 * without ever having seen the light of day.
	 */
654

655
	return window;
656
}
657

658 659 660 661
/* callback for changing the directory the desktop points to */
static void
desktop_location_changed_callback (gpointer user_data)
{
662 663 664
	if (nautilus_application_desktop_window != NULL) {
		nautilus_desktop_window_update_directory
			(nautilus_application_desktop_window);
665
	}
666 667
}

668 669 670 671 672 673 674
/* callback for showing or hiding the desktop based on the user's preference */
static void
desktop_changed_callback (gpointer user_data)
{
	NautilusApplication *application;
	
	application = NAUTILUS_APPLICATION (user_data);
675
	if ( eel_preferences_get_boolean (NAUTILUS_PREFERENCES_SHOW_DESKTOP)) {
676 677 678 679
		nautilus_application_open_desktop (application);
	} else {
		nautilus_application_close_desktop ();
	}
680 681 682 683 684

	/* Can't make this function just watch the preference
	 * itself changing since ordering is important
	 */
	update_session (gnome_master_client ());
685 686
}

Ramiro Estrugo's avatar
Ramiro Estrugo committed
687 688 689 690 691 692
/*
 * need_to_show_first_time_druid
 *
 * Determine whether Nautilus needs to show the first time druid.
 * 
 * Note that the flag file indicating whether the druid has been
693
 * presented is: ~/.nautilus/first-time-flag.
Ramiro Estrugo's avatar
Ramiro Estrugo committed
694 695
 *
 * Another alternative could be to use preferences to store this flag
Darin Adler's avatar
Darin Adler committed
696
 * However, there because of bug 41229 this is not yet possible.
Ramiro Estrugo's avatar
Ramiro Estrugo committed
697 698
 *
 * Also, for debugging purposes, it is convenient to have just one file
699
 * to kill in order to test the startup druid:
Ramiro Estrugo's avatar
Ramiro Estrugo committed
700
 *
701
 * rm -f ~/.nautilus/first-time-flag
Ramiro Estrugo's avatar
Ramiro Estrugo committed
702 703 704 705 706 707 708 709 710 711 712
 *
 * In order to accomplish the same thing with preferences, you would have
 * to either kill ALL your preferences or spend time digging in ~/.gconf
 * xml files finding the right one.
 */
static gboolean
need_to_show_first_time_druid (void)
{
	gboolean result;
	char *user_directory;
	char *druid_flag_file_name;
713
	
Ramiro Estrugo's avatar
Ramiro Estrugo committed
714 715
	user_directory = nautilus_get_user_directory ();

716
	druid_flag_file_name = g_strconcat (user_directory, "/first-time-flag", NULL);
717
	result = !g_file_test (druid_flag_file_name, G_FILE_TEST_EXISTS);
Ramiro Estrugo's avatar
Ramiro Estrugo committed
718 719
	g_free (druid_flag_file_name);

720 721 722 723
	/* we changed the name of the flag for version 1.0, so we should
	 * check for and delete the old one, if the new one didn't exist 
	 */
	if (result) {
724 725
		druid_flag_file_name = g_strconcat (user_directory, "/first-time-wizard-flag", NULL);
		unlink (druid_flag_file_name);
726 727 728
		g_free (druid_flag_file_name);
	}
	g_free (user_directory); 
Ramiro Estrugo's avatar
Ramiro Estrugo committed
729 730
	return result;
}
731 732 733 734 735

static void
volume_mounted_callback (NautilusVolumeMonitor *monitor, NautilusVolume *volume,
			 NautilusApplication *application)
{
736 737 738 739 740 741 742 743
	NautilusWindow *window;
	char *uri;
	
	if (volume == NULL || application == NULL) {
		return;
	}
	
	/* Open a window to the CD if the user has set that preference. */
744
	if (nautilus_volume_get_device_type (volume) == NAUTILUS_DEVICE_CDROM_DRIVE
745 746
		&& gnome_config_get_bool ("/magicdev/Options/do_fileman_window=true")) {		
		window = nautilus_application_create_window (application);
747
		uri = gnome_vfs_get_uri_from_local_path (nautilus_volume_get_mount_path (volume));
748 749 750
		nautilus_window_go_to (window, uri);
		g_free (uri);
	}
751 752
}

753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779
static gboolean
window_can_be_closed (NautilusWindow *window)
{
	if (!NAUTILUS_IS_DESKTOP_WINDOW (window)) {
		return TRUE;
	}
	
	return FALSE;
}

static gboolean
is_last_closable_window (NautilusWindow *window)
{
	GList *node, *window_list;
	
	window_list = nautilus_application_get_window_list ();
	
	for (node = window_list; node != NULL; node = node->next) {
		if (window != NAUTILUS_WINDOW (node->data) && window_can_be_closed (NAUTILUS_WINDOW (node->data))) {
			return FALSE;
		}
	}
	
	return TRUE;
}


780 781 782 783 784 785 786 787
/* Called whenever a volume is unmounted. Check and see if there are any windows open
 * displaying contents on the volume. If there are, close them.
 * It would also be cool to save open window and position info.
 */
static void
volume_unmounted_callback (NautilusVolumeMonitor *monitor, NautilusVolume *volume,
			   NautilusApplication *application)
{
788
	GList *window_list, *node, *close_list;
789
	NautilusWindow *window;
790 791
	char *uri;
	char *path;
792 793 794 795
		
	close_list = NULL;
	
	/* Check and see if any of the open windows are displaying contents from the unmounted volume */
796
	window_list = nautilus_application_get_window_list ();
797
	
798 799
	/* Construct a list of windows to be closed. Do not add the non-closable windows to the list. */
	for (node = window_list; node != NULL; node = node->next) {
800
		window = NAUTILUS_WINDOW (node->data);
801
		if (window != NULL && window_can_be_closed (window)) {
802 803
			uri = nautilus_window_get_location (window);
			path = gnome_vfs_get_local_path_from_uri (uri);
804
			if (eel_str_has_prefix (path, nautilus_volume_get_mount_path (volume))) {
805
				close_list = g_list_prepend (close_list, window);
806
			}
807 808
			g_free (path);
			g_free (uri);
809 810
		}
	}
811 812
		
	/* Handle the windows in the close list. */
813
	for (node = close_list; node != NULL; node = node->next) {
814 815 816 817 818 819 820
		window = NAUTILUS_WINDOW (node->data);
		if (is_last_closable_window (window)) {
			/* Don't close the last or only window. Try to redirect to the default home directory. */		 	
			nautilus_window_go_home (window);
		} else {
			nautilus_window_close (window);
		}
821
	}
822
		
823
	g_list_free (close_list);
824 825
}

826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842

static void
removed_from_session (GnomeClient *client, gpointer data)
{
	nautilus_main_event_loop_quit ();
}

static gint
save_session (GnomeClient *client, gint phase, GnomeSaveStyle save_style, gint shutdown,
	      GnomeInteractStyle interact_style, gint fast, gpointer data)
{
	return TRUE;
}

static void
set_session_restart (GnomeClient *client, gboolean restart)
{
843 844 845
	static char *restart_argv[] = { "nautilus", "--no-default-window", 0 };

	gnome_client_set_restart_command (client, 2, restart_argv);
846
	gnome_client_set_priority (client, 40);
847 848

	if (restart && g_getenv ("NAUTILUS_DEBUG") == NULL) {