nautilus-application.c 51.3 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
#include "nautilus-window-manage-views.h"
56
#include <libxml/xmlsave.h>
57
#include <glib/gstdio.h>
58 59
#include <bonobo/bonobo-main.h>
#include <bonobo/bonobo-object.h>
60
#include <eel/eel-gtk-extensions.h>
Ramiro Estrugo's avatar
Ramiro Estrugo committed
61 62 63 64
#include <eel/eel-gtk-macros.h>
#include <eel/eel-stock-dialogs.h>
#include <eel/eel-string-list.h>
#include <eel/eel-string.h>
65
#include <gdk/gdkx.h>
66
#include <gtk/gtkinvisible.h>
67
#include <gtk/gtksignal.h>
68
#include <gtk/gtkwindow.h>
69
#include <libgnome/gnome-config.h>
70
#include <glib/gi18n.h>
71
#include <libgnome/gnome-util.h>
72
#include <libgnomeui/gnome-authentication-manager.h>
73
#include <libgnomeui/gnome-client.h>
Ramiro Estrugo's avatar
Ramiro Estrugo committed
74
#include <libgnomeui/gnome-messagebox.h>
75
#include <libgnomeui/gnome-stock-icons.h>
76
#include <libgnomevfs/gnome-vfs-mime-handlers.h>
77
#include <libgnomevfs/gnome-vfs-ops.h>
Ramiro Estrugo's avatar
Ramiro Estrugo committed
78
#include <libgnomevfs/gnome-vfs-utils.h>
Alexander Larsson's avatar
Alexander Larsson committed
79
#include <libgnomevfs/gnome-vfs-volume-monitor.h>
Alexander Larsson's avatar
 
Alexander Larsson committed
80
#include <libnautilus-private/nautilus-debug-log.h>
81 82 83 84
#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>
85
#include <libnautilus-private/nautilus-module.h>
86
#include <libnautilus-private/nautilus-undo-manager.h>
Alexander Larsson's avatar
Alexander Larsson committed
87
#include <libnautilus-private/nautilus-desktop-link-monitor.h>
88
#include <libnautilus-private/nautilus-directory-private.h>
Alexander Larsson's avatar
Alexander Larsson committed
89 90
#include <libnautilus-private/nautilus-signaller.h>
#include <libnautilus-extension/nautilus-menu-provider.h>
91
#include <bonobo-activation/bonobo-activation.h>
92
#ifdef HAVE_STARTUP_NOTIFICATION
93 94
#define SN_API_NOT_YET_FROZEN Yes_i_know_DO_IT
#include <libsn/sn-launchee.h>
95
#endif
96

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

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

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

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

112 113 114
/* Keeps track of all the object windows */
static GList *nautilus_application_spatial_window_list;

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

127 128
static char    *save_session_to_file              (void);

129
BONOBO_CLASS_BOILERPLATE (NautilusApplication, nautilus_application,
130
			  BonoboGenericFactory, BONOBO_TYPE_GENERIC_FACTORY)
131 132

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

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

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

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

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

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

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

177 178
	application->shell = nautilus_shell_new (application);
	
179 180 181
	/* 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 */
182 183

	/* Watch for volume unmounts so we can close open windows */
Alexander Larsson's avatar
Alexander Larsson committed
184
	g_signal_connect_object (gnome_vfs_get_volume_monitor (), "volume_unmounted",
185
				 G_CALLBACK (volume_unmounted_callback), application, 0);
186 187
	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
188 189
	g_signal_connect_object (gnome_vfs_get_volume_monitor (), "volume_mounted",
				 G_CALLBACK (volume_mounted_callback), application, 0);
190

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

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

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

	application = g_object_new (NAUTILUS_TYPE_APPLICATION, NULL);
	
	bonobo_generic_factory_construct_noreg (BONOBO_GENERIC_FACTORY (application),
						FACTORY_IID,
						NULL);
	
	return application;
220 221 222
}

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

	application = NAUTILUS_APPLICATION (object);

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

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

238
	EEL_CALL_PARENT (BONOBO_OBJECT_CLASS, destroy, (object));
239
}
240

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

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

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

270
	failed_count = eel_string_list_get_length (directories);
271

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

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

291
		g_free (directories_as_string);
292 293 294
		g_free (error_string);
	}

295
	eel_string_list_free (directories);
296 297

	return failed_count == 0;
298 299
}

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

307
	length = g_strv_length ((char **) strv);
308 309 310 311 312 313

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

	return uri_list;
}

324 325 326
static void
migrate_old_nautilus_files (void)
{
327 328 329 330 331 332
	char *new_desktop_dir;
	char *old_desktop_dir;
	char *migrated_file;
	char *link_name;
	char *link_path;
	int fd;
333
	
334
	old_desktop_dir = nautilus_get_gmc_desktop_directory ();
335 336
	if (!g_file_test (old_desktop_dir, G_FILE_TEST_IS_DIR) ||
	    g_file_test (old_desktop_dir, G_FILE_TEST_IS_SYMLINK)) {
337 338 339
		g_free (old_desktop_dir);
		return;
	}
340 341 342
	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);
343
		new_desktop_dir = nautilus_get_desktop_directory ();
344
		link_path = g_build_filename (new_desktop_dir, link_name, NULL);
345
	
346 347 348 349
		
		symlink ("../.gnome-desktop", link_path);
		
		g_free (link_name);
350
		g_free (new_desktop_dir);
351
		g_free (link_path);
352

353 354 355 356 357
		fd = creat (migrated_file, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
		if (fd >= 0) {
			close (fd);
		}
		
358 359 360
		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."),
361 362
				      NULL);
	}
363
	g_free (old_desktop_dir);
364
	g_free (migrated_file);
365 366
}

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

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

James Willcox's avatar
James Willcox committed
402
	nautilus_module_add_type (FM_TYPE_DITEM_PAGE);
Alexander Larsson's avatar
Alexander Larsson committed
403 404 405

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

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

	/* Initialize the desktop link monitor singleton */
	nautilus_desktop_link_monitor_get ();
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 440 441
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);

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

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

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

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

	num_failures = 0;
513

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

521 522
	initialize_kde_trash_hack ();

523 524
	CORBA_exception_init (&ev);

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

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

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

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

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

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

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

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

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

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

683
 out:
684
	CORBA_exception_free (&ev);
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 753 754

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

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

764
	g_return_if_fail (nautilus_application_desktop_windows == NULL);
765
	g_return_if_fail (NAUTILUS_IS_APPLICATION (application));
766

767 768 769 770 771 772
	if (create_in_progress) {
		return;
	}

	create_in_progress = TRUE;

773 774 775 776
	display = gdk_display_get_default ();
	screens = gdk_display_get_n_screens (display);

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

	create_in_progress = FALSE;
801 802 803 804
}

void
nautilus_application_open_desktop (NautilusApplication *application)
805
{
806 807
	if (nautilus_application_desktop_windows == NULL) {
		nautilus_application_create_desktop_windows (application);
808 809 810
		
		/* Make sure we update the session when the desktop is created */
		update_session (gnome_master_client ());
811 812 813 814 815 816
	}
}

void
nautilus_application_close_desktop (void)
{
817 818 819 820 821
	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;
822 823 824

		/* Make sure we update the session when the desktop goes away */
		update_session (gnome_master_client ());
825
	}
826 827
}

828
void
829
nautilus_application_close_all_navigation_windows (void)
830
{
831 832 833 834 835 836 837 838 839 840 841 842
	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);
		}
843
	}
844
	g_list_free (list_copy);
845 846
}

847 848
static NautilusSpatialWindow *
nautilus_application_get_existing_spatial_window (const char *location)
849
{
850 851 852 853 854 855 856
	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));
857 858
		if (window_location != NULL &&
		    strcmp (location, window_location) == 0) {
859 860 861 862 863 864
			g_free (window_location);
			return NAUTILUS_SPATIAL_WINDOW (l->data);
		}
		g_free (window_location);
	}
	return NULL;
865 866
}

867 868
static NautilusSpatialWindow *
find_parent_spatial_window (NautilusSpatialWindow *window)
869
{
870 871 872 873
	NautilusFile *file;
	NautilusFile *parent_file;
	char *location;
	char *desktop_directory;
874

875
	location = nautilus_window_get_location (NAUTILUS_WINDOW (window));
Alexander Larsson's avatar