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

/*
 *  Nautilus
 *
 *  Copyright (C) 1999, 2000 Red Hat, Inc.
 *  Copyright (C) 2000 Eazel, Inc.
 *
9
 *  This program 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
 *  This program 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 23 24 25 26
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 *  Author: Elliot Lee <sopwith@redhat.com>,
 *
 */

27
#include <config.h>
28
#include "nautilus-application.h"
29

30
#include <bonobo.h>
31 32
#include "file-manager/fm-icon-view.h"
#include "file-manager/fm-list-view.h"
33
#include <libnautilus-extensions/nautilus-gtk-macros.h>
34
#include <libnautilus-extensions/nautilus-stock-dialogs.h>
35
#include <libnautilus-extensions/nautilus-global-preferences.h>
36 37
#include <libnautilus-extensions/nautilus-file-utilities.h>
#include <libnautilus-extensions/nautilus-string-list.h>
38
#include <libnautilus-extensions/nautilus-undo-manager.h>
39
#include <liboaf/liboaf.h>
40

41
#include "nautilus-desktop-window.h"
42
#include "nautilus-first-time-druid.h"
43

44 45
#include <libnautilus-extensions/nautilus-icon-factory.h>

46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
static CORBA_boolean manufactures                                (PortableServer_Servant    servant,
								  const CORBA_char         *iid,
								  CORBA_Environment        *ev);
static CORBA_Object  create_object                               (PortableServer_Servant    servant,
								  const CORBA_char         *iid,
								  const Bonobo_stringlist  *params,
								  CORBA_Environment        *ev);
static void          nautilus_application_initialize             (NautilusApplication      *application);
static void          nautilus_application_initialize_class       (NautilusApplicationClass *klass);
static void          nautilus_application_destroy                (GtkObject                *object);
static void          nautilus_application_check_user_directories (NautilusApplication      *application);

NAUTILUS_DEFINE_CLASS_BOILERPLATE (NautilusApplication, nautilus_application, BONOBO_OBJECT_TYPE)

static POA_Bonobo_GenericFactory__epv factory_epv = {
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
61
	NULL,
62 63 64 65 66 67 68
	&manufactures,
	&create_object
};
static PortableServer_ServantBase__epv base_epv;
static POA_Bonobo_GenericFactory__vepv vepv = {
	&base_epv,
	&factory_epv
69 70 71
};

static CORBA_boolean
72 73 74
manufactures (PortableServer_Servant servant,
	      const CORBA_char *iid,
	      CORBA_Environment *ev)
75
{
76 77
	return strcmp (iid, "OAFIID:nautilus_file_manager_icon_view:42681b21-d5ca-4837-87d2-394d88ecc058") == 0
		|| strcmp (iid, "OAFIID:nautilus_file_manager_list_view:521e489d-0662-4ad7-ac3a-832deabe111c") == 0;
78 79 80
}

static CORBA_Object
81 82 83 84
create_object (PortableServer_Servant servant,
	       const CORBA_char *iid,
	       const Bonobo_stringlist *params,
	       CORBA_Environment *ev)
85
{
86
	FMDirectoryView *directory_view;
Darin Adler's avatar
Darin Adler committed
87
	NautilusView *view;
88

89 90 91 92
	if (strcmp (iid, "OAFIID:nautilus_file_manager_icon_view:42681b21-d5ca-4837-87d2-394d88ecc058") == 0) {
		directory_view = FM_DIRECTORY_VIEW (gtk_object_new (fm_icon_view_get_type (), NULL));
	} else if (strcmp (iid, "OAFIID:nautilus_file_manager_list_view:521e489d-0662-4ad7-ac3a-832deabe111c") == 0) {
		directory_view = FM_DIRECTORY_VIEW (gtk_object_new (fm_list_view_get_type (), NULL));
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
93
	} else {
94
		return CORBA_OBJECT_NIL;
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
95
	}
96
        
97
	view = fm_directory_view_get_nautilus_view (directory_view);
98
	return CORBA_Object_duplicate (bonobo_object_corba_objref (BONOBO_OBJECT (view)), ev);
99 100
}

101
static CORBA_Object
102 103 104
create_factory (PortableServer_POA poa,
		NautilusApplication *bonobo_object,
		CORBA_Environment *ev)
105
{
106
	POA_Bonobo_GenericFactory *servant;
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
107

108 109
	servant = g_new0 (POA_Bonobo_GenericFactory, 1);
	servant->vepv = &vepv;
110 111
	POA_Bonobo_GenericFactory__init ((PortableServer_Servant) servant, ev);
	return bonobo_object_activate_servant (BONOBO_OBJECT (bonobo_object), servant);
112 113 114
}

static void
115
nautilus_application_initialize_class (NautilusApplicationClass *klass)
116
{
117
	GTK_OBJECT_CLASS (klass)->destroy = nautilus_application_destroy;
118 119 120
}

static void
121
nautilus_application_initialize (NautilusApplication *application)
122
{
123
	CORBA_Environment ev;
124
	CORBA_Object corba_object;
125
	
126 127 128
	/* Create an undo manager */
	application->undo_manager = nautilus_undo_manager_new ();

129
	CORBA_exception_init (&ev);
130

131 132
	corba_object = create_factory (bonobo_poa (), application, &ev);
	bonobo_object_construct (BONOBO_OBJECT (application), corba_object);
133

134
	CORBA_exception_free (&ev);
135 136
}

137 138
NautilusApplication *
nautilus_application_new (void)
139
{
140
	return NAUTILUS_APPLICATION (gtk_object_new (nautilus_application_get_type (), NULL));
141 142 143
}

static void
144
nautilus_application_destroy (GtkObject *object)
145
{
146 147
	/* Shut down preferences. This is needed so that the global
	 * preferences object and all its allocations are freed. Not
148 149 150
	 * calling this function would have NOT cause the user to lose
	 * preferences.  The only effect would be to leak those
	 * objects - which would be collected at exit() time anyway,
151
	 * but it adds noise to memory profile tool runs.
152 153
	 */
	nautilus_global_preferences_shutdown ();
154

155
	nautilus_bookmarks_exiting ();
156

157 158
	NAUTILUS_CALL_PARENT_CLASS (GTK_OBJECT_CLASS, destroy, (object));
}
159

160
static void
161
display_caveat (GtkWindow *parent_window)
162
{
163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
	GtkWidget *dialog;
	GtkWidget *frame;
	GtkWidget *pixmap;
	GtkWidget *hbox;
	GtkWidget *text;
	char *file_name;

	dialog = gnome_dialog_new (_("Nautilus: caveat"),
				   GNOME_STOCK_BUTTON_OK,
				   NULL);
  	gtk_container_set_border_width (GTK_CONTAINER (dialog), GNOME_PAD);
  	gtk_window_set_policy (GTK_WINDOW (dialog), FALSE, FALSE, FALSE);

  	hbox = gtk_hbox_new (FALSE, GNOME_PAD);
  	gtk_container_set_border_width (GTK_CONTAINER (hbox), GNOME_PAD);
  	gtk_widget_show (hbox);
  	gtk_box_pack_start (GTK_BOX (GNOME_DIALOG (dialog)->vbox), 
  			    hbox,
  			    FALSE, FALSE, 0);

	frame = gtk_frame_new (NULL);
	gtk_widget_show (frame);
	gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  	gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0);
	
Darin Adler's avatar
Darin Adler committed
188
	file_name = nautilus_pixmap_file ("About_Image.png");
189 190 191 192 193
	pixmap = gnome_pixmap_new_from_file (file_name);
	g_free (file_name);
	gtk_widget_show (pixmap);
	gtk_container_add (GTK_CONTAINER (frame), pixmap);

194 195 196 197 198 199 200 201 202
  	text = gtk_label_new
		(_("The Nautilus shell is under development; it's not "
  		   "ready for daily use. Many features, including some "
  		   "of the best ones, are not yet done, partly done, or "
  		   "unstable. The program doesn't look or act the way "
  		   "it will in version 1.0."
		   "\n\n"
		   "If you do decide to test this version of Nautilus, "
		   "beware. The program could do something "
John Sullivan's avatar
John Sullivan committed
203
		   "unpredictable and may even delete or overwrite "
204 205 206 207
		   "files on your computer."
		   "\n\n"
		   "For more information, visit http://nautilus.eazel.com."));
    	gtk_label_set_line_wrap (GTK_LABEL (text), TRUE);
208 209 210 211 212
	gtk_widget_show (text);
  	gtk_box_pack_start (GTK_BOX (hbox), text, FALSE, FALSE, 0);

  	gnome_dialog_set_close (GNOME_DIALOG (dialog), TRUE);

213 214 215
	if (parent_window != NULL) {
		gnome_dialog_set_parent (GNOME_DIALOG (dialog), parent_window);
	}
216 217

	gtk_widget_show (GTK_WIDGET (dialog));
218 219
}

220
static void
221
nautilus_application_check_user_directories (NautilusApplication *application)
222
{
223 224 225
	char			*user_directory;
	char			*user_main_directory;
	char			*desktop_directory;
226 227
	NautilusStringList	*dir_list;
	
228
	g_assert (NAUTILUS_IS_APPLICATION (application));
229 230 231 232 233 234 235 236 237 238 239 240 241 242

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

	dir_list = nautilus_string_list_new ();
	
	/* FIXME bugzilla.eazel.com 1115: Need better name for "User Directory"
	 * and "User Data Directory".
	 */

	if (!g_file_test (user_directory, G_FILE_TEST_ISDIR)) {
		nautilus_string_list_insert (dir_list, "User Directory");
	}
243
	g_free (user_directory);
244 245 246 247
	    
	if (!g_file_test (user_main_directory, G_FILE_TEST_ISDIR)) {
		nautilus_string_list_insert (dir_list, "User Main Directory");
	}
248
	g_free (user_main_directory);
249 250 251 252
	    
	if (!g_file_test (desktop_directory, G_FILE_TEST_ISDIR)) {
		nautilus_string_list_insert (dir_list, "Desktop Directory");
	}
253
	g_free (desktop_directory);
254 255 256 257 258 259 260 261 262 263 264 265

	if (nautilus_string_list_get_length (dir_list) > 0) {
		char *dir_list_concatenated;
		char *error_string;

		dir_list_concatenated = nautilus_string_list_as_concatenated_string (dir_list, "\n");
		
		error_string = g_strdup_printf ("%s\n\n%s\n\n%s",
						"The following directories are missing:",
						dir_list_concatenated,
						"Please restart Nautilus to fix this problem.");

266
		nautilus_error_dialog (error_string, NULL);
267 268 269 270 271 272 273 274

		g_free (dir_list_concatenated);
		g_free (error_string);
	}

	nautilus_string_list_free (dir_list);
}

275
void
276 277 278
nautilus_application_startup (NautilusApplication *application,
			      gboolean manage_desktop,
			      const char *urls[])
279
{
280 281 282
	OAF_RegistrationResult result;
	const char *message, *detailed_message;
	GnomeDialog *dialog;
283
	const char **p;
284
	NautilusWindow *window;
285
	NautilusWindow *first_window;
286

287 288 289 290 291 292 293 294
	/* check if this is the first time running the program by seeing
	   if the user_main_directory exists; if not, run the first time druid 
	   instead of launching the application */
	if (!nautilus_user_main_directory_exists()) {
		nautilus_first_time_druid_show(application, manage_desktop, urls);
		return;
	}	

295 296 297 298 299 300 301 302 303 304 305 306
	/* Try to register the file manager view factory with OAF. */
	result = oaf_active_server_register
		("OAFIID:nautilus_file_manager_factory:bd1e1862-92d7-4391-963e-37583f0daef3",
		 bonobo_object_corba_objref (BONOBO_OBJECT (application)));
	switch (result) {
	case OAF_REG_SUCCESS:
		/* We are registered with OAF and all is right with the world. */
		message = NULL;
		break;
	case OAF_REG_NOT_LISTED:
		/* Can't register myself due to trouble locating the
		 * nautilus.oafinfo file. This has happened when you
307 308 309
		 * launch Nautilus with an LD_LIBRARY_PATH that
		 * doesn't include the directory containg the oaf
		 * library. It could also happen if the
310 311 312 313 314 315 316 317
		 * nautilus.oafinfo file was not present for some
		 * 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. "
			    "Rebooting the computer or installing "
			    "Nautilus again may fix the problem.");
318
		/* FIXME: The guesses and stuff here are lame. */
319 320 321
		detailed_message = _("Nautilus can't be used now. "
				     "Rebooting the computer or installing "
				     "Nautilus again may fix the problem. "
322 323 324 325 326 327 328 329
				     "OAF couldn't locate the nautilus.oafinfo file. "
				     "One cause of this seems to be an LD_LIBRARY_PATH "
				     "that does not include the oaf library's directory. "
				     "Another possible cause would be bad install "
				     "with a missing nautilus.oafinfo file. "
				     "Sometimes killing oafd and gconfd fixes "
				     "the problem, but we don't know why. "
				     "We need a much less confusing message here for Nautilus 1.0.");
330 331
		break;
	case OAF_REG_ALREADY_ACTIVE:
332 333 334 335 336 337
		/* Another copy of Nautilus is already running. */
		/* FIXME: We want to "glom on" to this old copy. */
		message = _("Nautilus is already running. "
			    "Soon, instead of presenting this dialog, "
			    "the already-running copy of Nautilus will "
			    "respond by opening windows.");
338 339 340 341 342 343 344 345 346 347 348
		detailed_message = NULL;
		break;
	default:
		/* This should never happen. */
		g_warning ("bad error code from oaf_active_server_register");
	case OAF_REG_ERROR:
		/* Some misc. error (can never happen with current
		 * version of OAF). Show dialog and terminate the
		 * program.
		 */
		message = _("Nautilus can't be used now, due to an unexpected error.");
349 350
		detailed_message = _("Nautilus can't be used now, due to an unexpected error "
				     "from OAF when attempting to register the file manager view server.");
351 352 353 354 355 356 357 358 359 360 361 362
		break;
	}
	if (message != NULL) {
		dialog = nautilus_error_dialog_with_details
			(message, detailed_message, NULL);
		gtk_signal_connect (GTK_OBJECT (dialog), "destroy",
				    gtk_main_quit, NULL);
		return;
	}

	/* Check the user's ~/.nautilus directories and post warnings
	 * if there are problems
363
	 */
364
	nautilus_application_check_user_directories (application);
365

366 367
	/* Set up the desktop. */
	if (manage_desktop) {
368
		gtk_widget_show (GTK_WIDGET (nautilus_desktop_window_new (application)));
369
	}
370

371 372 373 374
  	/* Create the other windows. */
	first_window = NULL;
	if (urls != NULL) {
		for (p = urls; *p != NULL; p++) {
375
			window = nautilus_application_create_window (application);
376 377 378 379 380 381
			nautilus_window_goto_uri (window, *p);
			if (first_window == NULL) {
				first_window = window;
			}
		}
	}
382 383 384 385 386
	/* FIXME bugzilla.eazel.com 1051: Change this logic back so it won't
	 * make a new window when asked to manage the desktop, once we have
	 * a way to get rid of the desktop.
	 */
	if (/* !manage_desktop && */ first_window == NULL) {
387
		first_window = nautilus_application_create_window (application);
388 389
		nautilus_window_go_home (first_window);
	}
390

391
	/* Show the "not ready for prime time" dialog after the first
392 393
	 * window appears, so it's on top.
	 */
394 395 396
	/* FIXME bugzilla.eazel.com 1256: It's not on top of the
         * windows other than the first one.
	 */
Darin Adler's avatar
Darin Adler committed
397
	if (g_getenv ("NAUTILUS_NO_CAVEAT_DIALOG") == NULL) {
398 399 400 401 402 403
	  	if (first_window == NULL) {
			display_caveat (NULL);
		} else {
			gtk_signal_connect (GTK_OBJECT (first_window), "show",
					    display_caveat, first_window);
		}
404
  	}
405 406 407
}

static void
408
nautilus_application_destroy_window (GtkObject *obj, NautilusApplication *application)
409
{
410 411 412
	application->windows = g_slist_remove (application->windows, obj);
	if (application->windows == NULL) {
  		nautilus_application_quit();
413
	}
414 415 416
}

void 
417
nautilus_application_quit (void)
418
{
419
	gtk_main_quit ();
420 421 422
}

NautilusWindow *
423
nautilus_application_create_window (NautilusApplication *application)
424
{
425
	NautilusWindow *window;
426 427

	g_return_val_if_fail (NAUTILUS_IS_APPLICATION (application), NULL);
428
	
429
	window = NAUTILUS_WINDOW (gtk_object_new (nautilus_window_get_type (),
430
						  "app", GTK_OBJECT (application),
431 432
						  "app_id", "nautilus", NULL));
	gtk_signal_connect (GTK_OBJECT (window),
433 434 435 436
			    "destroy", nautilus_application_destroy_window,
			    application);

	application->windows = g_slist_prepend (application->windows, window);
437

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

443
	return window;
444
}