nautilus-application.c 30 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
		return 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
	g_signal_connect (nautilus_volume_monitor_get (),
145
			    "volume_mounted",
146
			    G_CALLBACK (volume_mounted_callback),
147 148 149
			    application);

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

156 157
NautilusApplication *
nautilus_application_new (void)
158
{
159 160 161 162 163 164 165 166 167
	NautilusApplication *application;

	application = g_object_new (NAUTILUS_TYPE_APPLICATION, NULL);
	
	bonobo_generic_factory_construct_noreg (BONOBO_GENERIC_FACTORY (application),
						FACTORY_IID,
						NULL);
	
	return application;
168 169 170
}

static void
171
nautilus_application_destroy (BonoboObject *object)
172
{
173 174 175 176
	NautilusApplication *application;

	application = NAUTILUS_APPLICATION (object);

177
	nautilus_bookmarks_exiting ();
178
	
179 180
	bonobo_object_unref (BONOBO_OBJECT (application->undo_manager));

181
	EEL_CALL_PARENT (BONOBO_OBJECT_CLASS, destroy, (object));
182
}
183

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

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

201
	directories = eel_string_list_new (TRUE);
202
	
203
	if (!g_file_test (user_directory, G_FILE_TEST_IS_DIR)) {
204
		eel_string_list_insert (directories, user_directory);
205
	}
206
	g_free (user_directory);	    
207
	    
208
	if (!g_file_test (desktop_directory, G_FILE_TEST_IS_DIR)) {
209
		eel_string_list_insert (directories, desktop_directory);
210
	}
211
	g_free (desktop_directory);
212

213
	failed_count = eel_string_list_get_length (directories);
214

215
	if (failed_count != 0) {
216
		directories_as_string = eel_string_list_as_string (directories, "\n", EEL_STRING_LIST_ALL_STRINGS);
217

218 219
		if (failed_count == 1) {
			dialog_title = g_strdup (_("Couldn't Create Required Folder"));
220 221 222
			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."),
223
							directories_as_string);
224 225
		} else {
			dialog_title = g_strdup (_("Couldn't Create Required Folders"));
226 227 228 229
			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."),
230
							directories_as_string);
231 232
		}
		
Ramiro Estrugo's avatar
Ramiro Estrugo committed
233
		dialog = eel_show_error_dialog (error_string, dialog_title, NULL);
234 235
		/* We need the main event loop so the user has a chance to see the dialog. */
		nautilus_main_event_loop_register (GTK_OBJECT (dialog));
236

237
		g_free (directories_as_string);
238
		g_free (error_string);
239
		g_free (dialog_title);
240 241
	}

242
	eel_string_list_free (directories);
243 244

	return failed_count == 0;
245 246
}

247 248 249 250 251 252 253 254 255 256
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 *
257
nautilus_make_uri_list_from_shell_strv (const char * const *strv)
258 259 260
{
	int length, i;
	Nautilus_URIList *uri_list;
261
	char *translated_uri;
262 263 264 265 266 267 268 269

	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
270
		translated_uri = eel_make_uri_from_shell_arg (strv[i]);
271 272 273
		uri_list->_buffer[i] = CORBA_string_dup (translated_uri);
		g_free (translated_uri);
		translated_uri = NULL;
274 275 276 277 278 279
	}
	CORBA_sequence_set_release (uri_list, CORBA_TRUE);

	return uri_list;
}

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 331 332 333 334
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);
}

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 360 361 362 363
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;
}

364 365 366 367
static void
finish_startup (NautilusApplication *application)
{
	/* initialize the sound machinery */
368
	nautilus_sound_init ();
369

370
	/* initialize URI authentication manager */
371
	nautilus_authentication_manager_init ();
372

373
	/* Make the desktop work with old Nautilus. */
374 375 376
	migrate_old_nautilus_files ();
}

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

	num_failures = 0;
397

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

405 406
	/* Run the first time startup druid if needed. */
	if (do_first_time_druid_check && need_to_show_first_time_druid ()) {
407 408 409 410 411 412
		/* 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 ();
413
	}
414

415 416
	CORBA_exception_init (&ev);

417
	/* Start up the factory. */
418
	while (TRUE) {
419
		/* Try to register the file manager view factory. */
420 421 422
		result = bonobo_activation_active_server_register (
			FACTORY_IID, BONOBO_OBJREF (application));

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

		/* Get the shell object. */
		if (message == NULL) {
487
			shell = bonobo_activation_activate_from_id (SHELL_IID, 0, NULL, NULL);
488 489 490 491 492 493 494
			if (!CORBA_Object_is_nil (shell, &ev)) {
				break;
			}

			/* If we couldn't find ourselves it's a bad problem so
			 * we better stop looping.
			 */
495
			if (result == Bonobo_ACTIVATION_REG_SUCCESS) {
496
				/* FIXME bugzilla.gnome.org 42538: When can this happen? */
497 498
				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 "
499 500
						     "from Bonobo when attempting to locate the factory."
						     "Killing bonobo-activation-server and restarting Nautilus may help fix the problem.");
501 502 503 504 505
			} 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 "
506 507
							     "from Bonobo when attempting to locate the shell object. "
							     "Killing bonobo-activation-server and restarting Nautilus may help fix the problem.");
508 509
					
				}
510 511 512
			}
		}

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

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

541 542
		/* Monitor the preference to have the desktop */
		/* point to the Unix home folder */
543
		eel_preferences_add_callback_while_alive (NAUTILUS_PREFERENCES_DESKTOP_IS_HOME_DIR,
Darin Adler's avatar
Darin Adler committed
544 545 546
							  desktop_location_changed_callback,
							  NULL,
							  G_OBJECT (application));
547

548 549 550 551
		/* CORBA C mapping doesn't allow NULL to be passed
		   for string parameters */
		corba_geometry = (geometry != NULL) ? geometry : "";

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

565
	/* We're done with the shell now, so let it go. */
566 567 568 569 570
	/* 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.
	 */
571
	if (!(kill_shell || restart_shell)) {
572
		bonobo_object_release_unref (shell, NULL);
573
	}
574

575
 out:
576
	CORBA_exception_free (&ev);
577 578 579
}

static void
580 581
nautilus_application_create_desktop_window (NautilusApplication *application)
{
582 583
	g_return_if_fail (nautilus_application_desktop_window == NULL);
	g_return_if_fail (NAUTILUS_IS_APPLICATION (application));
584

585 586
	nautilus_application_desktop_window = nautilus_desktop_window_new (application);
	gtk_widget_show (GTK_WIDGET (nautilus_application_desktop_window));
587 588 589 590
}

void
nautilus_application_open_desktop (NautilusApplication *application)
591
{
592 593
	if (nautilus_application_desktop_window == NULL) {
		nautilus_application_create_desktop_window (application);
594 595 596 597 598 599
	}
}

void
nautilus_application_close_desktop (void)
{
600
	if (nautilus_application_desktop_window != NULL) {
601
		gtk_widget_destroy (GTK_WIDGET (nautilus_application_desktop_window));
602
		nautilus_application_desktop_window = NULL;
603
	}
604 605
}

606 607 608
void
nautilus_application_close_all_windows (void)
{
609
	while (nautilus_application_window_list != NULL) {
610 611 612 613
		nautilus_window_close (NAUTILUS_WINDOW (nautilus_application_window_list->data));
	}
}

614
static void
615
nautilus_application_destroyed_window (GtkObject *object, NautilusApplication *application)
616
{
617
	nautilus_application_window_list = g_list_remove (nautilus_application_window_list, object);
618 619
}

620 621 622 623 624 625 626 627 628 629 630 631 632
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;
}				       

633
NautilusWindow *
634
nautilus_application_create_window (NautilusApplication *application)
635
{
636
	NautilusWindow *window;
637 638

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

648
	g_signal_connect (window,
649
			    "destroy", G_CALLBACK (nautilus_application_destroyed_window),
650 651
			    application);

652
	nautilus_application_window_list = g_list_prepend (nautilus_application_window_list, window);
653

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

659
	return window;
660
}
661

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

672 673 674 675 676 677 678
/* 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);
679
	if ( eel_preferences_get_boolean (NAUTILUS_PREFERENCES_SHOW_DESKTOP)) {
680 681 682 683
		nautilus_application_open_desktop (application);
	} else {
		nautilus_application_close_desktop ();
	}
684 685 686 687 688

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

Ramiro Estrugo's avatar
Ramiro Estrugo committed
691 692 693 694 695 696
/*
 * 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
697
 * presented is: ~/.nautilus/first-time-flag.
Ramiro Estrugo's avatar
Ramiro Estrugo committed
698 699 700 701 702
 *
 * Another alternative could be to use preferences to store this flag
 * However, there because of bug 1229 this is not yet possible.
 *
 * Also, for debugging purposes, it is convenient to have just one file
703
 * to kill in order to test the startup druid:
Ramiro Estrugo's avatar
Ramiro Estrugo committed
704
 *
705
 * rm -f ~/.nautilus/first-time-flag
Ramiro Estrugo's avatar
Ramiro Estrugo committed
706 707 708 709 710 711 712 713 714 715 716
 *
 * 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;
717
	
Ramiro Estrugo's avatar
Ramiro Estrugo committed
718 719
	user_directory = nautilus_get_user_directory ();

720
	druid_flag_file_name = g_strconcat (user_directory, "/first-time-flag", NULL);
721
	result = !g_file_test (druid_flag_file_name, G_FILE_TEST_EXISTS);
Ramiro Estrugo's avatar
Ramiro Estrugo committed
722 723
	g_free (druid_flag_file_name);

724 725 726 727
	/* 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) {
728 729
		druid_flag_file_name = g_strconcat (user_directory, "/first-time-wizard-flag", NULL);
		unlink (druid_flag_file_name);
730 731 732
		g_free (druid_flag_file_name);
	}
	g_free (user_directory); 
Ramiro Estrugo's avatar
Ramiro Estrugo committed
733 734
	return result;
}
735 736 737 738 739

static void
volume_mounted_callback (NautilusVolumeMonitor *monitor, NautilusVolume *volume,
			 NautilusApplication *application)
{
740 741 742 743 744 745 746 747
	NautilusWindow *window;
	char *uri;
	
	if (volume == NULL || application == NULL) {
		return;
	}
	
	/* Open a window to the CD if the user has set that preference. */
748
	if (nautilus_volume_get_device_type (volume) == NAUTILUS_DEVICE_CDROM_DRIVE
749 750
		&& gnome_config_get_bool ("/magicdev/Options/do_fileman_window=true")) {		
		window = nautilus_application_create_window (application);
751
		uri = gnome_vfs_get_uri_from_local_path (nautilus_volume_get_mount_path (volume));
752 753 754
		nautilus_window_go_to (window, uri);
		g_free (uri);
	}
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 780 781 782 783
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;
}


784 785 786 787 788 789 790 791
/* 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)
{
792
	GList *window_list, *node, *close_list;
793
	NautilusWindow *window;
794 795
	char *uri;
	char *path;
796 797 798 799
		
	close_list = NULL;
	
	/* Check and see if any of the open windows are displaying contents from the unmounted volume */
800
	window_list = nautilus_application_get_window_list ();
801
	
802 803
	/* 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) {
804
		window = NAUTILUS_WINDOW (node->data);
805
		if (window != NULL && window_can_be_closed (window)) {
806 807
			uri = nautilus_window_get_location (window);
			path = gnome_vfs_get_local_path_from_uri (uri);
808
			if (eel_str_has_prefix (path, nautilus_volume_get_mount_path (volume))) {
809
				close_list = g_list_prepend (close_list, window);
810
			}
811 812
			g_free (path);
			g_free (uri);
813 814
		}
	}
815 816
		
	/* Handle the windows in the close list. */
817
	for (node = close_list; node != NULL; node = node->next) {
818 819 820 821 822 823 824
		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);
		}
825
	}
826
		
827
	g_list_free (close_list);
828 829
}

830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846

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)
{
847 848 849
	static char *restart_argv[] = { "nautilus", "--no-default-window", 0 };

	gnome_client_set_restart_command (client, 2, restart_argv);
850
	gnome_client_set_priority (client, 40);
John Harper's avatar