nautilus-application.c 50.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"
Alexander Larsson's avatar
Alexander Larsson committed
37 38
#include "nautilus-information-panel.h"
#include "nautilus-history-sidebar.h"
39
#include "nautilus-places-sidebar.h"
Alexander Larsson's avatar
Alexander Larsson committed
40 41 42
#include "nautilus-notes-viewer.h"
#include "nautilus-emblem-sidebar.h"
#include "nautilus-image-properties-page.h"
43 44 45
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
46 47
#include "nautilus-desktop-window.h"
#include "nautilus-first-time-druid.h"
48
#include "nautilus-main.h"
49 50
#include "nautilus-spatial-window.h"
#include "nautilus-navigation-window.h"
51 52
#include "nautilus-shell-interface.h"
#include "nautilus-shell.h"
53
#include "nautilus-window-bookmarks.h"
54
#include "nautilus-window-private.h"
55 56
#include "nautilus-window-manage-views.h"
#include <glib/gstdio.h>
57 58
#include <bonobo/bonobo-main.h>
#include <bonobo/bonobo-object.h>
59
#include <eel/eel-gtk-extensions.h>
Ramiro Estrugo's avatar
Ramiro Estrugo committed
60 61 62 63
#include <eel/eel-gtk-macros.h>
#include <eel/eel-stock-dialogs.h>
#include <eel/eel-string-list.h>
#include <eel/eel-string.h>
64
#include <gdk/gdkx.h>
65
#include <gtk/gtkinvisible.h>
66
#include <gtk/gtksignal.h>
67
#include <gtk/gtkwindow.h>
68
#include <libgnome/gnome-config.h>
69
#include <glib/gi18n.h>
70
#include <libgnome/gnome-util.h>
71
#include <libgnomeui/gnome-authentication-manager.h>
72
#include <libgnomeui/gnome-client.h>
Ramiro Estrugo's avatar
Ramiro Estrugo committed
73
#include <libgnomeui/gnome-messagebox.h>
74
#include <libgnomeui/gnome-stock-icons.h>
75
#include <libgnomevfs/gnome-vfs-mime-handlers.h>
76
#include <libgnomevfs/gnome-vfs-ops.h>
Ramiro Estrugo's avatar
Ramiro Estrugo committed
77
#include <libgnomevfs/gnome-vfs-utils.h>
Alexander Larsson's avatar
Alexander Larsson committed
78
#include <libgnomevfs/gnome-vfs-volume-monitor.h>
79 80 81 82
#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>
83
#include <libnautilus-private/nautilus-module.h>
84
#include <libnautilus-private/nautilus-undo-manager.h>
Alexander Larsson's avatar
Alexander Larsson committed
85
#include <libnautilus-private/nautilus-desktop-link-monitor.h>
86
#include <libnautilus-private/nautilus-directory-private.h>
Alexander Larsson's avatar
Alexander Larsson committed
87 88
#include <libnautilus-private/nautilus-signaller.h>
#include <libnautilus-extension/nautilus-menu-provider.h>
89
#include <bonobo-activation/bonobo-activation.h>
90
#ifdef HAVE_STARTUP_NOTIFICATION
91 92
#define SN_API_NOT_YET_FROZEN Yes_i_know_DO_IT
#include <libsn/sn-launchee.h>
93
#endif
94

95 96 97 98
/* Needed for the is_kdesktop_present check */
#include <gdk/gdkx.h>
#include <X11/Xlib.h>

99 100 101
#define FACTORY_IID	     "OAFIID:Nautilus_Factory"
#define SEARCH_LIST_VIEW_IID "OAFIID:Nautilus_File_Manager_Search_List_View"
#define SHELL_IID	     "OAFIID:Nautilus_Shell"
102
#define TREE_VIEW_IID         "OAFIID:Nautilus_File_Manager_Tree_View"
103

104 105
/* Keeps track of all the desktop windows. */
static GList *nautilus_application_desktop_windows;
106 107 108 109

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

110 111 112
/* Keeps track of all the object windows */
static GList *nautilus_application_spatial_window_list;

113 114
static void     desktop_changed_callback          (gpointer                  user_data);
static void     desktop_location_changed_callback (gpointer                  user_data);
Alexander Larsson's avatar
Alexander Larsson committed
115 116
static void     volume_unmounted_callback         (GnomeVFSVolumeMonitor    *monitor,
						   GnomeVFSVolume           *volume,
117
						   NautilusApplication      *application);
Alexander Larsson's avatar
Alexander Larsson committed
118 119 120
static void     volume_mounted_callback           (GnomeVFSVolumeMonitor    *monitor,
						   GnomeVFSVolume           *volume,
						   NautilusApplication      *application);
121 122 123 124
static void     update_session                    (gpointer                  callback_data);
static void     init_session                      (void);
static gboolean is_kdesktop_present               (void);

125 126
static char    *save_session_to_file              (void);

127
BONOBO_CLASS_BOILERPLATE (NautilusApplication, nautilus_application,
128
			  BonoboGenericFactory, BONOBO_TYPE_GENERIC_FACTORY)
129 130

static CORBA_Object
131 132 133
create_object (PortableServer_Servant servant,
	       const CORBA_char *iid,
	       CORBA_Environment *ev)
134
{
135 136
	BonoboObject *object;
	NautilusApplication *application;
137

Alexander Larsson's avatar
Alexander Larsson committed
138
	if (strcmp (iid, SHELL_IID) == 0) {
139
		application = NAUTILUS_APPLICATION (bonobo_object_from_servant (servant));
140
		object = BONOBO_OBJECT (nautilus_shell_new (application));
141 142
	} 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
143
	} else {
144
		object = CORBA_OBJECT_NIL;
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
145
	}
146

147
	return CORBA_Object_duplicate (BONOBO_OBJREF (object), ev);
148 149
}

150 151
GList *
nautilus_application_get_window_list (void)
152 153 154 155
{
	return nautilus_application_window_list;
}

156 157 158 159 160 161
GList *
nautilus_application_get_spatial_window_list (void)
{
	return nautilus_application_spatial_window_list;
}

162 163 164 165 166 167
unsigned int
nautilus_application_get_n_windows (void)
{
	return g_list_length (nautilus_application_window_list) +
	       g_list_length (nautilus_application_desktop_windows);
}
168

169
static void
170
nautilus_application_instance_init (NautilusApplication *application)
171
{
172 173
	/* Create an undo manager */
	application->undo_manager = nautilus_undo_manager_new ();
174

175 176
	application->shell = nautilus_shell_new (application);
	
177 178 179
	/* Watch for volume mounts so we can restore open windows
	 * This used to be for showing new window on mount, but is not
	 * used anymore */
180 181

	/* Watch for volume unmounts so we can close open windows */
Alexander Larsson's avatar
Alexander Larsson committed
182
	g_signal_connect_object (gnome_vfs_get_volume_monitor (), "volume_unmounted",
183
				 G_CALLBACK (volume_unmounted_callback), application, 0);
184 185
	g_signal_connect_object (gnome_vfs_get_volume_monitor (), "volume_pre_unmount",
				 G_CALLBACK (volume_unmounted_callback), application, 0);
Alexander Larsson's avatar
Alexander Larsson committed
186 187
	g_signal_connect_object (gnome_vfs_get_volume_monitor (), "volume_mounted",
				 G_CALLBACK (volume_mounted_callback), application, 0);
188

Alexander Larsson's avatar
Alexander Larsson committed
189 190 191 192 193 194
	/* register views */
	fm_icon_view_register ();
	fm_desktop_icon_view_register ();
	fm_list_view_register ();

	/* register sidebars */
195
	nautilus_places_sidebar_register ();
Alexander Larsson's avatar
Alexander Larsson committed
196 197 198 199 200 201 202 203
	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 ();
204 205
}

206 207
NautilusApplication *
nautilus_application_new (void)
208
{
209 210 211 212 213 214 215 216 217
	NautilusApplication *application;

	application = g_object_new (NAUTILUS_TYPE_APPLICATION, NULL);
	
	bonobo_generic_factory_construct_noreg (BONOBO_GENERIC_FACTORY (application),
						FACTORY_IID,
						NULL);
	
	return application;
218 219 220
}

static void
221
nautilus_application_destroy (BonoboObject *object)
222
{
223 224 225 226
	NautilusApplication *application;

	application = NAUTILUS_APPLICATION (object);

227
	nautilus_bookmarks_exiting ();
228
	
Alexander Larsson's avatar
Alexander Larsson committed
229
	g_object_unref (application->undo_manager);
230

231 232 233 234 235
	if (application->shell_registered) {
		bonobo_activation_unregister_active_server (SHELL_IID, BONOBO_OBJREF (application->shell));
	}
	bonobo_object_unref (application->shell);

236
	EEL_CALL_PARENT (BONOBO_OBJECT_CLASS, destroy, (object));
237
}
238

239 240
static gboolean
check_required_directories (NautilusApplication *application)
241
{
242 243 244 245 246
	char *user_directory;
	char *desktop_directory;
	EelStringList *directories;
	char *directories_as_string;
	char *error_string;
247
	char *detail_string;
248
	GtkDialog *dialog;
249
	int failed_count;
250
	
251
	g_assert (NAUTILUS_IS_APPLICATION (application));
252 253 254 255

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

256
	directories = eel_string_list_new (TRUE);
257
	
258
	if (!g_file_test (user_directory, G_FILE_TEST_IS_DIR)) {
259
		eel_string_list_insert (directories, user_directory);
260
	}
261
	g_free (user_directory);	    
262
	    
263
	if (!g_file_test (desktop_directory, G_FILE_TEST_IS_DIR)) {
264
		eel_string_list_insert (directories, desktop_directory);
265
	}
266
	g_free (desktop_directory);
267

268
	failed_count = eel_string_list_get_length (directories);
269

270
	if (failed_count != 0) {
271
		directories_as_string = eel_string_list_as_string (directories, ", ", EEL_STRING_LIST_ALL_STRINGS);
272

273
		if (failed_count == 1) {
274
			error_string = g_strdup_printf (_("Nautilus could not create the required folder \"%s\"."),
275
							directories_as_string);
276 277
			detail_string = _("Before running Nautilus, please create the following folder, or "
					  "set permissions such that Nautilus can create it.");
278
		} else {
279 280 281 282
			error_string = g_strdup_printf (_("Nautilus could not create the following required folders: "
							  "%s."), directories_as_string);
  			detail_string = _("Before running Nautilus, please create these folders, or "
					  "set permissions such that Nautilus can create them.");
283 284
		}
		
285
		dialog = eel_show_error_dialog (error_string, detail_string, NULL);
286 287
		/* We need the main event loop so the user has a chance to see the dialog. */
		nautilus_main_event_loop_register (GTK_OBJECT (dialog));
288

289
		g_free (directories_as_string);
290 291 292
		g_free (error_string);
	}

293
	eel_string_list_free (directories);
294 295

	return failed_count == 0;
296 297
}

298
static Nautilus_URIList *
299
nautilus_make_uri_list_from_shell_strv (const char * const *strv)
300 301 302
{
	int length, i;
	Nautilus_URIList *uri_list;
303
	char *translated_uri;
304

305
	length = g_strv_length ((char **) strv);
306 307 308 309 310 311

	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++) {
312
		translated_uri = gnome_vfs_make_uri_from_shell_arg (strv[i]);
313 314 315
		uri_list->_buffer[i] = CORBA_string_dup (translated_uri);
		g_free (translated_uri);
		translated_uri = NULL;
316 317 318 319 320 321
	}
	CORBA_sequence_set_release (uri_list, CORBA_TRUE);

	return uri_list;
}

322 323 324
static void
migrate_old_nautilus_files (void)
{
325 326 327 328 329 330
	char *new_desktop_dir;
	char *old_desktop_dir;
	char *migrated_file;
	char *link_name;
	char *link_path;
	int fd;
331
	
332
	old_desktop_dir = nautilus_get_gmc_desktop_directory ();
333 334
	if (!g_file_test (old_desktop_dir, G_FILE_TEST_IS_DIR) ||
	    g_file_test (old_desktop_dir, G_FILE_TEST_IS_SYMLINK)) {
335 336 337
		g_free (old_desktop_dir);
		return;
	}
338 339 340
	migrated_file = g_build_filename (old_desktop_dir, ".migrated", NULL);
	if (!g_file_test (migrated_file, G_FILE_TEST_EXISTS)) {
		link_name = g_filename_from_utf8 (_("Link To Old Desktop"), -1, NULL, NULL, NULL);
341
		new_desktop_dir = nautilus_get_desktop_directory ();
342
		link_path = g_build_filename (new_desktop_dir, link_name, NULL);
343
	
344 345 346 347
		
		symlink ("../.gnome-desktop", link_path);
		
		g_free (link_name);
348
		g_free (new_desktop_dir);
349
		g_free (link_path);
350

351 352 353 354 355
		fd = creat (migrated_file, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
		if (fd >= 0) {
			close (fd);
		}
		
356 357 358
		eel_show_info_dialog (_("A link called \"Link To Old Desktop\" has been created on the desktop."),
				      _("The location of the desktop directory has changed in GNOME 2.4. "
					"You can open the link and move over the files you want, then delete the link."),
359 360
				      NULL);
	}
361
	g_free (old_desktop_dir);
362
	g_free (migrated_file);
363 364
}

Alexander Larsson's avatar
Alexander Larsson committed
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
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);
}

394 395 396
static void
finish_startup (NautilusApplication *application)
{
397 398 399
	/* initialize nautilus modules */
	nautilus_module_init ();

James Willcox's avatar
James Willcox committed
400
	nautilus_module_add_type (FM_TYPE_DITEM_PAGE);
Alexander Larsson's avatar
Alexander Larsson committed
401 402 403

	/* attach menu-provider module callback */
	menu_provider_init_callback ();
404
	
405
	/* initialize URI authentication manager */
406
	gnome_authentication_manager_init ();
407

408
	/* Make the desktop work with old Nautilus. */
409
	migrate_old_nautilus_files ();
Alexander Larsson's avatar
Alexander Larsson committed
410 411 412

	/* Initialize the desktop link monitor singleton */
	nautilus_desktop_link_monitor_get ();
413 414
}

415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
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 ();
	desktop_dir = gnome_vfs_get_local_path_from_uri (desktop_uri);
	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);

440 441 442 443 444 445 446 447
		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);
		}

448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
		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
470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486

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

487
void
488
nautilus_application_startup (NautilusApplication *application,
489
			      gboolean kill_shell,
490
			      gboolean restart_shell,
491
			      gboolean no_default_window,
492
			      gboolean no_desktop,
493
			      gboolean do_first_time_druid_check,
Alexander Larsson's avatar
Alexander Larsson committed
494
			      gboolean browser_window,
495
			      const char *startup_id,
496
			      const char *geometry,
497
			      const char *session_to_load,
498
			      const char *urls[])
499
{
500 501
	CORBA_Environment ev;
	Nautilus_Shell shell;
502
	Bonobo_RegistrationResult result;
503
	const char *message, *detailed_message;
504
	GtkDialog *dialog;
505
	Nautilus_URIList *url_list;
506
	const CORBA_char *corba_startup_id;
507
	const CORBA_char *corba_geometry;
508 509 510
	int num_failures;

	num_failures = 0;
511

512
	/* Check the user's ~/.nautilus directories and post warnings
513
	 * if there are problems.
514
	 */
515
	if (!kill_shell && !check_required_directories (application)) {
516 517
		return;
	}
518

519 520
	initialize_kde_trash_hack ();

521 522
	CORBA_exception_init (&ev);

523
	/* Start up the factory. */
524
	while (TRUE) {
525
		/* Try to register the file manager view factory. */
526
		result = nautilus_bonobo_activation_register_for_display
527
			(SHELL_IID, BONOBO_OBJREF (application->shell));
528

529
		switch (result) {
530 531
		case Bonobo_ACTIVATION_REG_SUCCESS:
			/* We are registered and all is right with the world. */
532
			application->shell_registered = TRUE;
533
			finish_startup (application);
534 535 536
			message = NULL;
			detailed_message = NULL;
			break;
537
		case Bonobo_ACTIVATION_REG_ALREADY_ACTIVE:
538
			/* Another copy of nautilus already is running and registered. */
539
			message = NULL;
540
			detailed_message = NULL;
541
			break;
542
		case Bonobo_ACTIVATION_REG_NOT_LISTED:
543
			/* Can't register myself due to trouble locating the
544
			 * Nautilus_Shell.server file. This has happened when you
545
			 * launch Nautilus with an LD_LIBRARY_PATH that
546
			 * doesn't include the directory containing the oaf
547
			 * library. It could also happen if the
548
			 * Nautilus_Shell.server file was not present for some
549 550 551 552 553
			 * 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. "
554
				    "Running the command \"bonobo-slay\""
555 556 557
				    " from the console may fix the problem. If not,"
				    " you can try rebooting the computer or"
				    " installing Nautilus again.");
558
			/* FIXME bugzilla.gnome.org 42536: The guesses and stuff here are lame. */
559
			detailed_message = _("Nautilus can't be used now. "
560
					     "Running the command \"bonobo-slay\" "
561 562 563 564
					     "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. "
565
					     "One cause of this seems to be an LD_LIBRARY_PATH "
566
					     "that does not include the bonobo-activation library's directory. "
567
					     "Another possible cause would be bad install "
568
					     "with a missing Nautilus_Shell.server file.\n\n"
569
					     "Running \"bonobo-slay\" will kill all "
570
					     "Bonobo Activation and GConf processes, which may be needed by "
571
					     "other applications.\n\n"
572
					     "Sometimes killing bonobo-activation-server and gconfd fixes "
573
					     "the problem, but we don't know why.\n\n"
574
					     "We have also seen this error when a faulty "
575
					     "version of bonobo-activation was installed.");
576 577 578
			break;
		default:
			/* This should never happen. */
579
			g_warning ("bad error code from bonobo_activation_active_server_register");
580
		case Bonobo_ACTIVATION_REG_ERROR:
581
			/* Some misc. error (can never happen with current
582
			 * version of bonobo-activation). Show dialog and terminate the
583 584
			 * program.
			 */
585
			/* FIXME bugzilla.gnome.org 42537: Looks like this does happen with the
586
			 * current OAF. I guess I read the code wrong. Need to figure out when and make a
587 588
			 * good message.
			 */
589 590
			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 "
591
					     "from Bonobo when attempting to register the file manager view server.");
592 593
			break;
		}
594 595 596

		/* Get the shell object. */
		if (message == NULL) {
597
			shell = bonobo_activation_activate_from_id (SHELL_IID, Bonobo_ACTIVATION_FLAG_EXISTING_ONLY, NULL, NULL);
598 599 600 601 602 603 604
			if (!CORBA_Object_is_nil (shell, &ev)) {
				break;
			}

			/* If we couldn't find ourselves it's a bad problem so
			 * we better stop looping.
			 */
605
			if (result == Bonobo_ACTIVATION_REG_SUCCESS) {
606
				/* FIXME bugzilla.gnome.org 42538: When can this happen? */
607 608
				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 "
609 610
						     "from Bonobo when attempting to locate the factory."
						     "Killing bonobo-activation-server and restarting Nautilus may help fix the problem.");
611 612 613 614 615
			} 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 "
616 617
							     "from Bonobo when attempting to locate the shell object. "
							     "Killing bonobo-activation-server and restarting Nautilus may help fix the problem.");
618 619
					
				}
620 621 622
			}
		}

623
		if (message != NULL) {
624
			dialog = eel_show_error_dialog_with_details (message, NULL, detailed_message, NULL);
625 626
			/* We need the main event loop so the user has a chance to see the dialog. */
			nautilus_main_event_loop_register (GTK_OBJECT (dialog));
627
			goto out;
628 629 630
		}
	}

631 632
	if (kill_shell) {
		Nautilus_Shell_quit (shell, &ev);
633 634
	} else if (restart_shell) {
		Nautilus_Shell_restart (shell, &ev);
635
	} else {
636
		/* If KDE desktop is running, then force no_desktop */
637
		if (is_kdesktop_present ()) {
638
			no_desktop = TRUE;
639
		}
640
		
641
		if (!no_desktop && eel_preferences_get_boolean (NAUTILUS_PREFERENCES_SHOW_DESKTOP)) {
642 643
			Nautilus_Shell_start_desktop (shell, &ev);
		}
644 645
		
		/* Monitor the preference to show or hide the desktop */
646
		eel_preferences_add_callback_while_alive (NAUTILUS_PREFERENCES_SHOW_DESKTOP,
Darin Adler's avatar
Darin Adler committed
647 648 649
							  desktop_changed_callback,
							  application,
							  G_OBJECT (application));
650

651 652
		/* Monitor the preference to have the desktop */
		/* point to the Unix home folder */
653
		eel_preferences_add_callback_while_alive (NAUTILUS_PREFERENCES_DESKTOP_IS_HOME_DIR,
Darin Adler's avatar
Darin Adler committed
654 655 656
							  desktop_location_changed_callback,
							  NULL,
							  G_OBJECT (application));
657

658 659
		/* CORBA C mapping doesn't allow NULL to be passed
		   for string parameters */
660 661
		corba_geometry   = (geometry   != NULL) ? geometry   : "";
		corba_startup_id = (startup_id != NULL) ? startup_id : "";
662

663 664
	  	/* Create the other windows. */
		if (urls != NULL) {
665
			url_list = nautilus_make_uri_list_from_shell_strv (urls);
666
			Nautilus_Shell_open_windows (shell, url_list, corba_startup_id, corba_geometry, browser_window, &ev);
667
			CORBA_free (url_list);
668
		} else if (!no_default_window) {
669
			g_assert (session_to_load == NULL);
670
			Nautilus_Shell_open_default_window (shell, corba_startup_id, corba_geometry, browser_window, &ev);
671
		}
672 673 674 675

		if (session_to_load != NULL) {
			Nautilus_Shell_load_session (shell, session_to_load, &ev);
		}
676 677 678
		
		/* Add ourselves to the session */
		init_session ();
679
	}
680

681
 out:
682
	CORBA_exception_free (&ev);
683 684
}

685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752

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)
{
	char *selection_name;
	GdkAtom selection_atom;
	Window selection_owner;
	GtkWidget *selection_widget;

	selection_name = g_strdup_printf ("_NET_DESKTOP_MANAGER_S%d", screen);
	selection_atom = gdk_atom_intern (selection_name, FALSE);
	g_free (selection_name);

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

753
static void
754
nautilus_application_create_desktop_windows (NautilusApplication *application)
755
{
756
	static gboolean create_in_progress = FALSE;
757 758
	GdkDisplay *display;
	NautilusDesktopWindow *window;
759
	GtkWidget *selection_widget;
760
	int screens, i;
761

762
	g_return_if_fail (nautilus_application_desktop_windows == NULL);
763
	g_return_if_fail (NAUTILUS_IS_APPLICATION (application));
764

765 766 767 768 769 770
	if (create_in_progress) {
		return;
	}

	create_in_progress = TRUE;

771 772 773 774
	display = gdk_display_get_default ();
	screens = gdk_display_get_n_screens (display);

	for (i = 0; i < screens; i++) {
775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795
		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);
		}
796
	}
797 798

	create_in_progress = FALSE;
799 800 801 802
}

void
nautilus_application_open_desktop (NautilusApplication *application)
803
{
804 805
	if (nautilus_application_desktop_windows == NULL) {
		nautilus_application_create_desktop_windows (application);
806 807 808 809 810 811
	}
}

void
nautilus_application_close_desktop (void)
{
812 813 814 815 816
	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;
817
	}
818 819
}

820
void
821
nautilus_application_close_all_navigation_windows (void)
822
{
823 824 825 826 827 828 829 830 831 832 833 834
	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);
		}
835
	}
836
	g_list_free (list_copy);
837 838
}

839 840
static NautilusSpatialWindow *
nautilus_application_get_existing_spatial_window (const char *location)
841
{
842 843 844 845 846 847 848
	GList *l;
	
	for (l = nautilus_application_get_spatial_window_list ();
	     l != NULL; l = l->next) {
		char *window_location;
		
		window_location = nautilus_window_get_location (NAUTILUS_WINDOW (l->data));
849 850
		if (window_location != NULL &&
		    strcmp (location, window_location) == 0) {
851 852 853 854 855 856
			g_free (window_location);
			return NAUTILUS_SPATIAL_WINDOW (l->data);
		}
		g_free (window_location);
	}
	return NULL;
857 858
}

859 860
static NautilusSpatialWindow *
find_parent_spatial_window (NautilusSpatialWindow *window)
861
{
862 863 864 865
	NautilusFile *file;
	NautilusFile *parent_file;
	char *location;
	char *desktop_directory;
866

867
	location = nautilus_window_get_location (NAUTILUS_WINDOW (window));
Alexander Larsson's avatar
Alexander Larsson committed
868 869 870
	if (location == NULL) {
		return NULL;
	}
871 872
	file = nautilus_file_get (location);
	g_free (location);
873

874 875 876
	if (!file) {
		return NULL;
	}