nautilus-application.c 55.4 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 198 199 200 201 202 203 204 205 206 207 208 209
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;
			
			/* TODO: only do this for local volumes */
			
			if (!g_volume_can_mount (volume)) {
				continue;
			}
			
			mount = g_volume_get_mount (volume);
			if (mount != NULL) {
				g_object_unref (mount);
				continue;
			}
			
210
			nautilus_inhibit_autorun_for_volume (volume);
211 212 213 214 215 216 217 218 219

			/* 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);
	}
	
}

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

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

	/* register sidebars */
237
	nautilus_places_sidebar_register ();
Alexander Larsson's avatar
Alexander Larsson committed
238 239 240 241 242 243 244 245
	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 ();
246 247
}

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

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

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

	application = NAUTILUS_APPLICATION (object);

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

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

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

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

294
	g_assert (NAUTILUS_IS_APPLICATION (application));
295

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

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

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

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

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

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

		ret = FALSE;
320

Alexander Larsson's avatar
Alexander Larsson committed
321 322 323 324 325 326
		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);
		}
327

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

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

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

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

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

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

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

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

	return uri_list;
}

Alexander Larsson's avatar
Alexander Larsson committed
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 410
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);
}

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

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

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

	/* attach menu-provider module callback */
	menu_provider_init_callback ();
423
	
Alexander Larsson's avatar
Alexander Larsson committed
424 425
	/* Initialize the desktop link monitor singleton */
	nautilus_desktop_link_monitor_get ();
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 451

	/* 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);
452 453
}

454 455 456 457 458 459 460 461 462 463 464 465 466
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
467
	desktop_dir = g_filename_from_uri (desktop_uri, NULL, NULL);
468 469 470 471 472 473 474 475 476 477 478
	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);

479 480 481 482 483 484 485 486
		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);
		}

487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
		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
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525

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;
}

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

	num_failures = 0;
550

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

558 559
	initialize_kde_trash_hack ();

560 561
	CORBA_exception_init (&ev);

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

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

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

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

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

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

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

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

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

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

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

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

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)
{
737
	char selection_name[32];
738 739 740 741
	GdkAtom selection_atom;
	Window selection_owner;
	GtkWidget *selection_widget;

742
	g_snprintf (selection_name, sizeof (selection_name), "_NET_DESKTOP_MANAGER_S%d", screen);
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 790
	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;
}

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

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

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

	create_in_progress = TRUE;

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

	for (i = 0; i < screens; i++) {
813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833
		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);
		}
834
	}
835 836

	create_in_progress = FALSE;
837 838 839 840
}

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

void
nautilus_application_close_desktop (void)
{
853 854 855 856 857
	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;
858 859 860

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

864
void
865
nautilus_application_close_all_navigation_windows (void)
866
{
867 868 869 870 871 872 873 874 875 876 877 878
	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);
		}
879
	}
880
	g_list_free (list_copy);
881 882
}

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

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

892
		window_location = nautilus_window_get_location (NAUTILUS_WINDOW (l->data));
Alexander Larsson's avatar
Alexander Larsson committed
893 894 895 896 897 898
		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);
899 900 901
		}
	}
	return NULL;
902 903
}

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

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

918