nautilus-application.c 55.5 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

James Willcox's avatar
James Willcox committed
32
#include "file-manager/fm-ditem-page.h"
33
#include "file-manager/fm-desktop-icon-view.h"
34
#include "file-manager/fm-icon-view.h"
35
#include "file-manager/fm-list-view.h"
36
#include "file-manager/fm-tree-view.h"
Christian Neumair's avatar
Christian Neumair committed
37 38 39
#if ENABLE_EMPTY_VIEW
#include "file-manager/fm-empty-view.h"
#endif /* ENABLE_EMPTY_VIEW */
Alexander Larsson's avatar
Alexander Larsson committed
40 41
#include "nautilus-information-panel.h"
#include "nautilus-history-sidebar.h"
42
#include "nautilus-places-sidebar.h"
Alexander Larsson's avatar
Alexander Larsson committed
43 44 45
#include "nautilus-notes-viewer.h"
#include "nautilus-emblem-sidebar.h"
#include "nautilus-image-properties-page.h"
46 47 48
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
Alexander Larsson's avatar
Alexander Larsson committed
49
#include <string.h>
50 51
#include "nautilus-desktop-window.h"
#include "nautilus-first-time-druid.h"
52
#include "nautilus-main.h"
53 54
#include "nautilus-spatial-window.h"
#include "nautilus-navigation-window.h"
55 56
#include "nautilus-shell-interface.h"
#include "nautilus-shell.h"
57
#include "nautilus-window-bookmarks.h"
Alexander Larsson's avatar
Alexander Larsson committed
58
#include "libnautilus-private/nautilus-file-operations.h"
59
#include "nautilus-window-private.h"
60
#include "nautilus-window-manage-views.h"
61
#include <libxml/xmlsave.h>
62
#include <glib/gstdio.h>
63
#include <glib/gi18n.h>
64
#include <gio/gio.h>
65 66
#include <bonobo/bonobo-main.h>
#include <bonobo/bonobo-object.h>
67
#include <eel/eel-gtk-extensions.h>
Ramiro Estrugo's avatar
Ramiro Estrugo committed
68 69
#include <eel/eel-gtk-macros.h>
#include <eel/eel-stock-dialogs.h>
70
#include <gdk/gdkx.h>
71
#include <gtk/gtkwindow.h>
72
#include <libgnome/gnome-config.h>
73
#include <libgnomeui/gnome-authentication-manager.h>
74
#include <libgnomeui/gnome-client.h>
Alexander Larsson's avatar
 
Alexander Larsson committed
75
#include <libnautilus-private/nautilus-debug-log.h>
76 77
#include <libnautilus-private/nautilus-file-utilities.h>
#include <libnautilus-private/nautilus-global-preferences.h>
78
#include <libnautilus-private/nautilus-module.h>
79
#include <libnautilus-private/nautilus-undo-manager.h>
Alexander Larsson's avatar
Alexander Larsson committed
80
#include <libnautilus-private/nautilus-desktop-link-monitor.h>
81
#include <libnautilus-private/nautilus-directory-private.h>
Alexander Larsson's avatar
Alexander Larsson committed
82 83
#include <libnautilus-private/nautilus-signaller.h>
#include <libnautilus-extension/nautilus-menu-provider.h>
84
#include <bonobo-activation/bonobo-activation.h>
85
#include <libnautilus-private/nautilus-autorun.h>
Alexander Larsson's avatar
Alexander Larsson committed
86

87
#ifdef HAVE_STARTUP_NOTIFICATION
88 89
#define SN_API_NOT_YET_FROZEN Yes_i_know_DO_IT
#include <libsn/sn-launchee.h>
90
#endif
91

92 93 94 95
/* Needed for the is_kdesktop_present check */
#include <gdk/gdkx.h>
#include <X11/Xlib.h>

96 97 98
#define FACTORY_IID	     "OAFIID:Nautilus_Factory"
#define SEARCH_LIST_VIEW_IID "OAFIID:Nautilus_File_Manager_Search_List_View"
#define SHELL_IID	     "OAFIID:Nautilus_Shell"
99
#define TREE_VIEW_IID         "OAFIID:Nautilus_File_Manager_Tree_View"
100

101 102
/* Keeps track of all the desktop windows. */
static GList *nautilus_application_desktop_windows;
103 104 105 106

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

107 108 109
/* Keeps track of all the object windows */
static GList *nautilus_application_spatial_window_list;

110 111
static void     desktop_changed_callback          (gpointer                  user_data);
static void     desktop_location_changed_callback (gpointer                  user_data);
112 113 114 115 116 117 118 119 120
static void     mount_removed_callback            (GVolumeMonitor            *monitor,
						   GMount                    *mount,
						   NautilusApplication       *application);
static void     mount_added_callback              (GVolumeMonitor            *monitor,
						   GMount                    *mount,
						   NautilusApplication       *application);
static void     volume_added_callback              (GVolumeMonitor           *monitor,
						    GVolume                  *volume,
						    NautilusApplication      *application);
121 122 123 124 125
static void     drive_connected_callback           (GVolumeMonitor           *monitor,
						    GDrive                   *drive,
						    NautilusApplication      *application);
static void     drive_listen_for_eject_button      (GDrive *drive, 
						    NautilusApplication *application);
126 127 128 129
static void     update_session                    (gpointer                  callback_data);
static void     init_session                      (void);
static gboolean is_kdesktop_present               (void);

130 131
static char    *save_session_to_file              (void);

132
BONOBO_CLASS_BOILERPLATE (NautilusApplication, nautilus_application,
133
			  BonoboGenericFactory, BONOBO_TYPE_GENERIC_FACTORY)
134 135

static CORBA_Object
136 137 138
create_object (PortableServer_Servant servant,
	       const CORBA_char *iid,
	       CORBA_Environment *ev)
139
{
140 141
	BonoboObject *object;
	NautilusApplication *application;
142

Alexander Larsson's avatar
Alexander Larsson committed
143
	if (strcmp (iid, SHELL_IID) == 0) {
144
		application = NAUTILUS_APPLICATION (bonobo_object_from_servant (servant));
145
		object = BONOBO_OBJECT (nautilus_shell_new (application));
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
146
	} else {
147
		object = CORBA_OBJECT_NIL;
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
148
	}
149

150
	return CORBA_Object_duplicate (BONOBO_OBJREF (object), ev);
151 152
}

153 154
GList *
nautilus_application_get_window_list (void)
155 156 157 158
{
	return nautilus_application_window_list;
}

159 160 161 162 163 164
GList *
nautilus_application_get_spatial_window_list (void)
{
	return nautilus_application_spatial_window_list;
}

165 166 167 168 169 170
unsigned int
nautilus_application_get_n_windows (void)
{
	return g_list_length (nautilus_application_window_list) +
	       g_list_length (nautilus_application_desktop_windows);
}
171

172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
static void
startup_volume_mount_cb (GObject *source_object,
			 GAsyncResult *res,
			 gpointer user_data)
{
	if (!g_volume_mount_finish (G_VOLUME (source_object), res, NULL)) {
		/* There was an error mounting the volume, so we
		   clear the automount part. This is otherwise done
		   when the mount is added to the volume monitor */
		g_object_set_data (source_object, "nautilus-automounted", GINT_TO_POINTER (0));
	}
}

static void
automount_all_volumes (NautilusApplication *application)
{
	GList *volumes, *l;
	GMount *mount;
	GVolume *volume;
		
	if (eel_preferences_get_boolean (NAUTILUS_PREFERENCES_MEDIA_AUTOMOUNT)) {
		/* automount all mountable volumes at start-up */
		volumes = g_volume_monitor_get_volumes (application->volume_monitor);
		for (l = volumes; l != NULL; l = l->next) {
			volume = l->data;
			
198 199
			if (!g_volume_should_automount (volume) ||
			    !g_volume_can_mount (volume)) {
200 201 202 203 204 205 206 207 208
				continue;
			}
			
			mount = g_volume_get_mount (volume);
			if (mount != NULL) {
				g_object_unref (mount);
				continue;
			}
			
209
			nautilus_inhibit_autorun_for_volume (volume);
210 211 212 213 214 215 216 217 218

			/* pass NULL as GMountOperation to avoid user interaction */
			g_volume_mount (volume, NULL, NULL, startup_volume_mount_cb, NULL);
		}
		eel_g_object_list_free (volumes);
	}
	
}

219
static void
220
nautilus_application_instance_init (NautilusApplication *application)
221
{
222 223
	/* Create an undo manager */
	application->undo_manager = nautilus_undo_manager_new ();
224

225 226
	application->shell = nautilus_shell_new (application);
	
Alexander Larsson's avatar
Alexander Larsson committed
227 228 229 230
	/* register views */
	fm_icon_view_register ();
	fm_desktop_icon_view_register ();
	fm_list_view_register ();
Christian Neumair's avatar
Christian Neumair committed
231 232 233
#if ENABLE_EMPTY_VIEW
	fm_empty_view_register ();
#endif /* ENABLE_EMPTY_VIEW */
Alexander Larsson's avatar
Alexander Larsson committed
234 235

	/* register sidebars */
236
	nautilus_places_sidebar_register ();
Alexander Larsson's avatar
Alexander Larsson committed
237 238 239 240 241 242 243 244
	nautilus_information_panel_register ();
	fm_tree_view_register ();
	nautilus_history_sidebar_register ();
	nautilus_notes_viewer_register (); /* also property page */
	nautilus_emblem_sidebar_register ();

	/* register property pages */
	nautilus_image_properties_page_register ();
245 246
}

247 248
NautilusApplication *
nautilus_application_new (void)
249
{
250 251 252 253 254 255 256 257 258
	NautilusApplication *application;

	application = g_object_new (NAUTILUS_TYPE_APPLICATION, NULL);
	
	bonobo_generic_factory_construct_noreg (BONOBO_GENERIC_FACTORY (application),
						FACTORY_IID,
						NULL);
	
	return application;
259 260 261
}

static void
262
nautilus_application_destroy (BonoboObject *object)
263
{
264 265 266 267
	NautilusApplication *application;

	application = NAUTILUS_APPLICATION (object);

268
	nautilus_bookmarks_exiting ();
269
	
Alexander Larsson's avatar
Alexander Larsson committed
270
	g_object_unref (application->undo_manager);
271

Alexander Larsson's avatar
Alexander Larsson committed
272 273 274 275 276
	if (application->volume_monitor) {
		g_object_unref (application->volume_monitor);
		application->volume_monitor = NULL;
	}
	
277 278 279 280 281
	if (application->shell_registered) {
		bonobo_activation_unregister_active_server (SHELL_IID, BONOBO_OBJREF (application->shell));
	}
	bonobo_object_unref (application->shell);

282
	EEL_CALL_PARENT (BONOBO_OBJECT_CLASS, destroy, (object));
283
}
284

285 286
static gboolean
check_required_directories (NautilusApplication *application)
287
{
288 289
	char *user_directory;
	char *desktop_directory;
Alexander Larsson's avatar
Alexander Larsson committed
290 291 292
	GSList *directories;
	gboolean ret;

293
	g_assert (NAUTILUS_IS_APPLICATION (application));
294

Alexander Larsson's avatar
Alexander Larsson committed
295 296
	ret = TRUE;

297 298 299
	user_directory = nautilus_get_user_directory ();
	desktop_directory = nautilus_get_desktop_directory ();

Alexander Larsson's avatar
Alexander Larsson committed
300 301
	directories = NULL;

302
	if (!g_file_test (user_directory, G_FILE_TEST_IS_DIR)) {
Alexander Larsson's avatar
Alexander Larsson committed
303
		directories = g_slist_prepend (directories, user_directory);
304
	}
Alexander Larsson's avatar
Alexander Larsson committed
305

306
	if (!g_file_test (desktop_directory, G_FILE_TEST_IS_DIR)) {
Alexander Larsson's avatar
Alexander Larsson committed
307
		directories = g_slist_prepend (directories, desktop_directory);
308 309
	}

Alexander Larsson's avatar
Alexander Larsson committed
310 311 312 313 314 315 316 317 318
	if (directories != NULL) {
		int failed_count;
		GString *directories_as_string;
		GSList *l;
		char *error_string;
		const char *detail_string;
		GtkDialog *dialog;

		ret = FALSE;
319

Alexander Larsson's avatar
Alexander Larsson committed
320 321 322 323 324 325
		failed_count = g_slist_length (directories);

		directories_as_string = g_string_new ((const char *)directories->data);
		for (l = directories->next; l != NULL; l = l->next) {
			g_string_append_printf (directories_as_string, ", %s", (const char *)l->data);
		}
326

327
		if (failed_count == 1) {
328
			error_string = g_strdup_printf (_("Nautilus could not create the required folder \"%s\"."),
Alexander Larsson's avatar
Alexander Larsson committed
329
							directories_as_string->str);
330 331
			detail_string = _("Before running Nautilus, please create the following folder, or "
					  "set permissions such that Nautilus can create it.");
332
		} else {
333
			error_string = g_strdup_printf (_("Nautilus could not create the following required folders: "
Alexander Larsson's avatar
Alexander Larsson committed
334 335
							  "%s."), directories_as_string->str);
			detail_string = _("Before running Nautilus, please create these folders, or "
336
					  "set permissions such that Nautilus can create them.");
337
		}
Alexander Larsson's avatar
Alexander Larsson committed
338

339
		dialog = eel_show_error_dialog (error_string, detail_string, NULL);
340 341
		/* We need the main event loop so the user has a chance to see the dialog. */
		nautilus_main_event_loop_register (GTK_OBJECT (dialog));
342

Alexander Larsson's avatar
Alexander Larsson committed
343
		g_string_free (directories_as_string, TRUE);
344 345 346
		g_free (error_string);
	}

Alexander Larsson's avatar
Alexander Larsson committed
347 348 349
	g_slist_free (directories);
	g_free (user_directory);
	g_free (desktop_directory);
350

Alexander Larsson's avatar
Alexander Larsson committed
351
	return ret;
352 353
}

354
static Nautilus_URIList *
355
nautilus_make_uri_list_from_shell_strv (const char * const *strv)
356 357 358
{
	int length, i;
	Nautilus_URIList *uri_list;
Alexander Larsson's avatar
Alexander Larsson committed
359
	GFile *file;
360
	char *translated_uri;
361

362
	length = g_strv_length ((char **) strv);
363 364 365 366 367 368

	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++) {
Alexander Larsson's avatar
Alexander Larsson committed
369 370 371
		file = g_file_new_for_commandline_arg (strv[i]);
		translated_uri = g_file_get_uri (file);
		g_object_unref (file);
372 373 374
		uri_list->_buffer[i] = CORBA_string_dup (translated_uri);
		g_free (translated_uri);
		translated_uri = NULL;
375 376 377 378 379 380
	}
	CORBA_sequence_set_release (uri_list, CORBA_TRUE);

	return uri_list;
}

Alexander Larsson's avatar
Alexander Larsson committed
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
static void
menu_provider_items_updated_handler (NautilusMenuProvider *provider, GtkWidget* parent_window, gpointer data)
{

	g_signal_emit_by_name (nautilus_signaller_get_current (),
			       "popup_menu_changed");
}

static void
menu_provider_init_callback (void)
{
        GList *items;
        GList *providers;
        GList *l;

        providers = nautilus_module_get_extensions_for_type (NAUTILUS_TYPE_MENU_PROVIDER);
        items = NULL;

        for (l = providers; l != NULL; l = l->next) {
                NautilusMenuProvider *provider = NAUTILUS_MENU_PROVIDER (l->data);

		g_signal_connect_after (G_OBJECT (provider), "items_updated",
                           (GCallback)menu_provider_items_updated_handler,
                           NULL);
        }

        nautilus_module_extension_list_free (providers);
}

410 411 412
static void
finish_startup (NautilusApplication *application)
{
413 414
	GList *drives;

415 416 417
	/* initialize nautilus modules */
	nautilus_module_init ();

James Willcox's avatar
James Willcox committed
418
	nautilus_module_add_type (FM_TYPE_DITEM_PAGE);
Alexander Larsson's avatar
Alexander Larsson committed
419 420 421

	/* attach menu-provider module callback */
	menu_provider_init_callback ();
422
	
Alexander Larsson's avatar
Alexander Larsson committed
423 424
	/* Initialize the desktop link monitor singleton */
	nautilus_desktop_link_monitor_get ();
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450

	/* Watch for mounts so we can restore open windows This used
	 * to be for showing new window on mount, but is not used
	 * anymore */

	/* Watch for unmounts so we can close open windows */
	/* TODO-gio: This should be using the UNMOUNTED feature of GFileMonitor instead */
	application->volume_monitor = g_volume_monitor_get ();
	g_signal_connect_object (application->volume_monitor, "mount_removed",
				 G_CALLBACK (mount_removed_callback), application, 0);
	g_signal_connect_object (application->volume_monitor, "mount_pre_unmount",
				 G_CALLBACK (mount_removed_callback), application, 0);
	g_signal_connect_object (application->volume_monitor, "mount_added",
				 G_CALLBACK (mount_added_callback), application, 0);
	g_signal_connect_object (application->volume_monitor, "volume_added",
				 G_CALLBACK (volume_added_callback), application, 0);
	g_signal_connect_object (application->volume_monitor, "drive_connected",
				 G_CALLBACK (drive_connected_callback), application, 0);

	/* listen for eject button presses */
	drives = g_volume_monitor_get_connected_drives (application->volume_monitor);
	g_list_foreach (drives, (GFunc) drive_listen_for_eject_button, application);
	g_list_foreach (drives, (GFunc) g_object_unref, NULL);
	g_list_free (drives);

	automount_all_volumes (application);
451 452
}

453 454 455 456 457 458 459 460 461 462 463 464 465
static void
initialize_kde_trash_hack (void)
{
	char *trash_dir;
	char *desktop_dir, *desktop_uri, *kde_trash_dir;
	char *dir, *basename;
	char *kde_conf_file;
	char *key;
	gboolean def;
	
	trash_dir = NULL;

	desktop_uri = nautilus_get_desktop_directory_uri_no_create ();
Alexander Larsson's avatar
Alexander Larsson committed
466
	desktop_dir = g_filename_from_uri (desktop_uri, NULL, NULL);
467 468 469 470 471 472 473 474 475 476 477
	g_free (desktop_uri);
	
	if (g_file_test (desktop_dir, G_FILE_TEST_EXISTS)) {
		/* Look for trash directory */
		kde_conf_file = g_build_filename (g_get_home_dir(), ".kde/share/config/kdeglobals", NULL);
		key = g_strconcat ("=", kde_conf_file, "=/Paths/Trash", NULL);
		kde_trash_dir = gnome_config_get_string_with_default (key, &def);
		gnome_config_drop_file (kde_conf_file);
		g_free (kde_conf_file);
		g_free (key);

478 479 480 481 482 483 484 485
		if (kde_trash_dir == NULL) {
			kde_conf_file = "/usr/share/config/kdeglobals";
			key = g_strconcat ("=", kde_conf_file, "=/Paths/Trash", NULL);
			kde_trash_dir = gnome_config_get_string_with_default (key, &def);
			gnome_config_drop_file (kde_conf_file);
			g_free (key);
		}

486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507
		if (kde_trash_dir != NULL) {
			basename = g_path_get_basename (kde_trash_dir);
			g_free (kde_trash_dir);
			
			dir = g_build_filename (desktop_dir, basename, NULL);

			if (g_file_test (dir, G_FILE_TEST_IS_DIR)) {
				trash_dir = g_strdup (basename);
			} 
			g_free (basename);
			g_free (dir);
		} 

		if (trash_dir != NULL) {
			nautilus_set_kde_trash_name (trash_dir);
		}

		g_free (trash_dir);
	}
	g_free (desktop_dir);
}

Alexander Larsson's avatar
Alexander Larsson committed
508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524

static Bonobo_RegistrationResult
nautilus_bonobo_activation_register_for_display (const char    *iid,
						 Bonobo_Unknown ref)
{
	const char *display_name;
	GSList *reg_env ;
	Bonobo_RegistrationResult result;
	
	display_name = gdk_display_get_name (gdk_display_get_default());
	reg_env = bonobo_activation_registration_env_set (NULL,
							  "DISPLAY", display_name);
	result = bonobo_activation_register_active_server (iid, ref, reg_env);
	bonobo_activation_registration_env_free (reg_env);
	return result;
}

525
void
526
nautilus_application_startup (NautilusApplication *application,
527
			      gboolean kill_shell,
528
			      gboolean restart_shell,
529
			      gboolean no_default_window,
530
			      gboolean no_desktop,
531
			      gboolean do_first_time_druid_check,
Alexander Larsson's avatar
Alexander Larsson committed
532
			      gboolean browser_window,
533
			      const char *startup_id,
534
			      const char *geometry,
535
			      const char *session_to_load,
536
			      const char *urls[])
537
{
538 539
	CORBA_Environment ev;
	Nautilus_Shell shell;
540
	Bonobo_RegistrationResult result;
541
	const char *message, *detailed_message;
542
	GtkDialog *dialog;
543
	Nautilus_URIList *url_list;
544
	const CORBA_char *corba_startup_id;
545
	const CORBA_char *corba_geometry;
546 547 548
	int num_failures;

	num_failures = 0;
549

550
	/* Check the user's ~/.nautilus directories and post warnings
551
	 * if there are problems.
552
	 */
553
	if (!kill_shell && !check_required_directories (application)) {
554 555
		return;
	}
556

557 558
	initialize_kde_trash_hack ();

559 560
	CORBA_exception_init (&ev);

561
	/* Start up the factory. */
562
	while (TRUE) {
563
		/* Try to register the file manager view factory. */
564
		result = nautilus_bonobo_activation_register_for_display
565
			(SHELL_IID, BONOBO_OBJREF (application->shell));
566

567
		switch (result) {
568 569
		case Bonobo_ACTIVATION_REG_SUCCESS:
			/* We are registered and all is right with the world. */
570
			application->shell_registered = TRUE;
571
			finish_startup (application);
572 573 574
			message = NULL;
			detailed_message = NULL;
			break;
575
		case Bonobo_ACTIVATION_REG_ALREADY_ACTIVE:
576
			/* Another copy of nautilus already is running and registered. */
577
			message = NULL;
578
			detailed_message = NULL;
579
			break;
580
		case Bonobo_ACTIVATION_REG_NOT_LISTED:
581
			/* Can't register myself due to trouble locating the
582
			 * Nautilus_Shell.server file. This has happened when you
583
			 * launch Nautilus with an LD_LIBRARY_PATH that
584
			 * doesn't include the directory containing the oaf
585
			 * library. It could also happen if the
586
			 * Nautilus_Shell.server file was not present for some
587 588 589 590 591
			 * 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. "
592
				    "Running the command \"bonobo-slay\""
593 594 595
				    " from the console may fix the problem. If not,"
				    " you can try rebooting the computer or"
				    " installing Nautilus again.");
596
			/* FIXME bugzilla.gnome.org 42536: The guesses and stuff here are lame. */
597
			detailed_message = _("Nautilus can't be used now. "
598
					     "Running the command \"bonobo-slay\" "
599 600 601 602
					     "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. "
603
					     "One cause of this seems to be an LD_LIBRARY_PATH "
604
					     "that does not include the bonobo-activation library's directory. "
605
					     "Another possible cause would be bad install "
606
					     "with a missing Nautilus_Shell.server file.\n\n"
607
					     "Running \"bonobo-slay\" will kill all "
608
					     "Bonobo Activation and GConf processes, which may be needed by "
609
					     "other applications.\n\n"
610
					     "Sometimes killing bonobo-activation-server and gconfd fixes "
611
					     "the problem, but we don't know why.\n\n"
612
					     "We have also seen this error when a faulty "
613
					     "version of bonobo-activation was installed.");
614 615 616
			break;
		default:
			/* This should never happen. */
617
			g_warning ("bad error code from bonobo_activation_active_server_register");
618
		case Bonobo_ACTIVATION_REG_ERROR:
619
			/* Some misc. error (can never happen with current
620
			 * version of bonobo-activation). Show dialog and terminate the
621 622
			 * program.
			 */
623
			/* FIXME bugzilla.gnome.org 42537: Looks like this does happen with the
624
			 * current OAF. I guess I read the code wrong. Need to figure out when and make a
625 626
			 * good message.
			 */
627 628
			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 "
629
					     "from Bonobo when attempting to register the file manager view server.");
630 631
			break;
		}
632 633 634

		/* Get the shell object. */
		if (message == NULL) {
635
			shell = bonobo_activation_activate_from_id (SHELL_IID, Bonobo_ACTIVATION_FLAG_EXISTING_ONLY, NULL, NULL);
636 637 638 639 640 641 642
			if (!CORBA_Object_is_nil (shell, &ev)) {
				break;
			}

			/* If we couldn't find ourselves it's a bad problem so
			 * we better stop looping.
			 */
643
			if (result == Bonobo_ACTIVATION_REG_SUCCESS) {
644
				/* FIXME bugzilla.gnome.org 42538: When can this happen? */
645 646
				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 "
647
						     "from Bonobo when attempting to locate the factory. "
648
						     "Killing bonobo-activation-server and restarting Nautilus may help fix the problem.");
649 650 651 652 653
			} 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 "
654 655
							     "from Bonobo when attempting to locate the shell object. "
							     "Killing bonobo-activation-server and restarting Nautilus may help fix the problem.");
656 657
					
				}
658 659 660
			}
		}

661
		if (message != NULL) {
662
			dialog = eel_show_error_dialog_with_details (message, NULL, detailed_message, NULL);
663 664
			/* We need the main event loop so the user has a chance to see the dialog. */
			nautilus_main_event_loop_register (GTK_OBJECT (dialog));
665
			goto out;
666 667 668
		}
	}

669 670
	if (kill_shell) {
		Nautilus_Shell_quit (shell, &ev);
671 672
	} else if (restart_shell) {
		Nautilus_Shell_restart (shell, &ev);
673
	} else {
674
		/* If KDE desktop is running, then force no_desktop */
675
		if (is_kdesktop_present ()) {
676
			no_desktop = TRUE;
677
		}
678
		
679
		if (!no_desktop && eel_preferences_get_boolean (NAUTILUS_PREFERENCES_SHOW_DESKTOP)) {
680 681
			Nautilus_Shell_start_desktop (shell, &ev);
		}
682 683
		
		/* Monitor the preference to show or hide the desktop */
684
		eel_preferences_add_callback_while_alive (NAUTILUS_PREFERENCES_SHOW_DESKTOP,
Darin Adler's avatar
Darin Adler committed
685 686 687
							  desktop_changed_callback,
							  application,
							  G_OBJECT (application));
688

689 690
		/* Monitor the preference to have the desktop */
		/* point to the Unix home folder */
691
		eel_preferences_add_callback_while_alive (NAUTILUS_PREFERENCES_DESKTOP_IS_HOME_DIR,
Darin Adler's avatar
Darin Adler committed
692 693 694
							  desktop_location_changed_callback,
							  NULL,
							  G_OBJECT (application));
695

696 697
		/* CORBA C mapping doesn't allow NULL to be passed
		   for string parameters */
698 699
		corba_geometry   = (geometry   != NULL) ? geometry   : "";
		corba_startup_id = (startup_id != NULL) ? startup_id : "";
700

701 702
	  	/* Create the other windows. */
		if (urls != NULL) {
703
			url_list = nautilus_make_uri_list_from_shell_strv (urls);
704
			Nautilus_Shell_open_windows (shell, url_list, corba_startup_id, corba_geometry, browser_window, &ev);
705
			CORBA_free (url_list);
706
		} else if (!no_default_window) {
707
			g_assert (session_to_load == NULL);
708
			Nautilus_Shell_open_default_window (shell, corba_startup_id, corba_geometry, browser_window, &ev);
709
		}
710 711 712 713

		if (session_to_load != NULL) {
			Nautilus_Shell_load_session (shell, session_to_load, &ev);
		}
714 715 716
		
		/* Add ourselves to the session */
		init_session ();
717
	}
718

719
 out:
720
	CORBA_exception_free (&ev);
721 722
}

723 724 725 726 727 728 729 730 731 732 733 734 735

static void 
selection_get_cb (GtkWidget          *widget,
		  GtkSelectionData   *selection_data,
		  guint               info,
		  guint               time)
{
	/* No extra targets atm */
}

static GtkWidget *
get_desktop_manager_selection (GdkDisplay *display, int screen)
{
736
	char selection_name[32];
737 738 739 740
	GdkAtom selection_atom;
	Window selection_owner;
	GtkWidget *selection_widget;

741
	g_snprintf (selection_name, sizeof (selection_name), "_NET_DESKTOP_MANAGER_S%d", screen);
742 743 744 745 746 747 748 749 750 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 780 781 782 783 784 785 786 787 788 789
	selection_atom = gdk_atom_intern (selection_name, FALSE);

	selection_owner = XGetSelectionOwner (GDK_DISPLAY_XDISPLAY (display),
					      gdk_x11_atom_to_xatom_for_display (display, 
										 selection_atom));
	if (selection_owner != None) {
		return NULL;
	}
	
	selection_widget = gtk_invisible_new_for_screen (gdk_display_get_screen (display, screen));
	/* We need this for gdk_x11_get_server_time() */
	gtk_widget_add_events (selection_widget, GDK_PROPERTY_CHANGE_MASK);

	if (gtk_selection_owner_set_for_display (display,
						 selection_widget,
						 selection_atom,
						 gdk_x11_get_server_time (selection_widget->window))) {
		
		g_signal_connect (selection_widget, "selection_get",
				  G_CALLBACK (selection_get_cb), NULL);
		return selection_widget;
	}

	gtk_widget_destroy (selection_widget);
	
	return NULL;
}

static void
desktop_unrealize_cb (GtkWidget        *widget,
		      GtkWidget        *selection_widget)
{
	gtk_widget_destroy (selection_widget);
}

static gboolean
selection_clear_event_cb (GtkWidget	        *widget,
			  GdkEventSelection     *event,
			  NautilusDesktopWindow *window)
{
	gtk_widget_destroy (GTK_WIDGET (window));
	
	nautilus_application_desktop_windows =
		g_list_remove (nautilus_application_desktop_windows, window);

	return TRUE;
}

790
static void
791
nautilus_application_create_desktop_windows (NautilusApplication *application)
792
{
793
	static gboolean create_in_progress = FALSE;
794 795
	GdkDisplay *display;
	NautilusDesktopWindow *window;
796
	GtkWidget *selection_widget;
797
	int screens, i;
798

799
	g_return_if_fail (nautilus_application_desktop_windows == NULL);
800
	g_return_if_fail (NAUTILUS_IS_APPLICATION (application));
801

802 803 804 805 806 807
	if (create_in_progress) {
		return;
	}

	create_in_progress = TRUE;

808 809 810 811
	display = gdk_display_get_default ();
	screens = gdk_display_get_n_screens (display);

	for (i = 0; i < screens; i++) {
812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832
		selection_widget = get_desktop_manager_selection (display, i);
		if (selection_widget != NULL) {
			window = nautilus_desktop_window_new (application,
							      gdk_display_get_screen (display, i));
			
			g_signal_connect (selection_widget, "selection_clear_event",
					  G_CALLBACK (selection_clear_event_cb), window);
			
			g_signal_connect (window, "unrealize",
					  G_CALLBACK (desktop_unrealize_cb), selection_widget);
			
			/* We realize it immediately so that the NAUTILUS_DESKTOP_WINDOW_ID
			   property is set so gnome-settings-daemon doesn't try to set the
			   background. And we do a gdk_flush() to be sure X gets it. */
			gtk_widget_realize (GTK_WIDGET (window));
			gdk_flush ();

			
			nautilus_application_desktop_windows =
				g_list_prepend (nautilus_application_desktop_windows, window);
		}
833
	}
834 835

	create_in_progress = FALSE;
836 837 838 839
}

void
nautilus_application_open_desktop (NautilusApplication *application)
840
{
841 842
	if (nautilus_application_desktop_windows == NULL) {
		nautilus_application_create_desktop_windows (application);
843 844 845
		
		/* Make sure we update the session when the desktop is created */
		update_session (gnome_master_client ());
846 847 848 849 850 851
	}
}

void
nautilus_application_close_desktop (void)
{
852 853 854 855 856
	if (nautilus_application_desktop_windows != NULL) {
		g_list_foreach (nautilus_application_desktop_windows,
				(GFunc) gtk_widget_destroy, NULL);
		g_list_free (nautilus_application_desktop_windows);
		nautilus_application_desktop_windows = NULL;
857 858 859

		/* Make sure we update the session when the desktop goes away */
		update_session (gnome_master_client ());
860
	}
861 862
}

863
void
864
nautilus_application_close_all_navigation_windows (void)
865
{
866 867 868 869 870 871 872 873 874 875 876 877
	GList *list_copy;
	GList *l;
	
	list_copy = g_list_copy (nautilus_application_window_list);
	for (l = list_copy; l != NULL; l = l->next) {
		NautilusWindow *window;
		
		window = NAUTILUS_WINDOW (l->data);
		
		if (NAUTILUS_IS_NAVIGATION_WINDOW (window)) {
			nautilus_window_close (window);
		}
878
	}
879
	g_list_free (list_copy);
880 881
}

882
static NautilusSpatialWindow *
Alexander Larsson's avatar
Alexander Larsson committed
883
nautilus_application_get_existing_spatial_window (GFile *location)
884
{
885
	GList *l;
Alexander Larsson's avatar
Alexander Larsson committed
886

887 888
	for (l = nautilus_application_get_spatial_window_list ();
	     l != NULL; l = l->next) {
Alexander Larsson's avatar
Alexander Larsson committed
889 890
		GFile *window_location;

891
		window_location = nautilus_window_get_location (NAUTILUS_WINDOW (l->data));
Alexander Larsson's avatar
Alexander Larsson committed
892 893 894 895 896 897
		if (window_location != NULL) {
			if (g_file_equal (location, window_location)) {
				g_object_unref (window_location);
				return NAUTILUS_SPATIAL_WINDOW (l->data);
			}
			g_object_unref (window_location);
898 899 900
		}
	}
	return NULL;
901 902
}

903 904
static NautilusSpatialWindow *
find_parent_spatial_window (NautilusSpatialWindow *window)
905
{
906 907
	NautilusFile *file;
	NautilusFile *parent_file;
Alexander Larsson's avatar
Alexander Larsson committed
908
	GFile *location;
909

910
	location = nautilus_window_get_location (NAUTILUS_WINDOW (window));
Alexander Larsson's avatar
Alexander Larsson committed
911 912 913
	if (location == NULL) {
		return NULL;
	}
914
	file = nautilus_file_get (location);
915
	g_object_unref (location);