nautilus-application.c 14.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 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 <libnautilus/libnautilus.h>
31
#include <bonobo.h>
32 33
#include "file-manager/fm-icon-view.h"
#include "file-manager/fm-list-view.h"
34
#include <libgnomevfs/gnome-vfs-init.h>
35
#include <libnautilus-extensions/nautilus-gnome-extensions.h>
36
#include <libnautilus-extensions/nautilus-global-preferences.h>
37 38 39
#include <libnautilus-extensions/nautilus-file-utilities.h>
#include <libnautilus-extensions/nautilus-string-list.h>
#include <libnautilus-extensions/nautilus-gnome-extensions.h>
40
#include <libnautilus/nautilus-undo-manager.h>
41
#include <liboaf/liboaf.h>
42
#include "nautilus-desktop-window.h"
43

44
typedef struct {
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
45 46
	POA_Nautilus_Application servant;
 	NautilusApp *app;
47

Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
48
	Nautilus_ViewWindowList attr_view_windows;
49
} impl_POA_Nautilus_Application;
50

51 52 53 54 55 56 57 58
static Nautilus_ViewWindowList *
impl_Nautilus_Application__get_view_windows(impl_POA_Nautilus_Application* servant,
                                            CORBA_Environment * ev);
static Nautilus_ViewWindow
impl_Nautilus_Application_new_view_window(impl_POA_Nautilus_Application *servant,
                                          CORBA_Environment * ev);
static CORBA_boolean
impl_Nautilus_Application_supports(impl_POA_Nautilus_Application * servant,
59
				   CORBA_char *obj_iid,
60 61 62
				   CORBA_Environment * ev);
static CORBA_Object
impl_Nautilus_Application_create_object(impl_POA_Nautilus_Application *servant,
63
                                        CORBA_char *obj_iid,
64 65 66
					GNOME_stringlist * params,
					CORBA_Environment * ev);
static POA_Nautilus_Application__epv impl_Nautilus_Application_epv = {
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
67 68 69
	NULL,			/* _private */
	(gpointer) &impl_Nautilus_Application__get_view_windows,
	(gpointer) &impl_Nautilus_Application_new_view_window
70 71

};
72
static POA_Bonobo_GenericFactory__epv impl_Nautilus_Application_Bonobo_GenericFactory_epv = {
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
73 74 75
	NULL,			/* _private */
	(gpointer) &impl_Nautilus_Application_supports,
	(gpointer) &impl_Nautilus_Application_create_object
76 77
};
static PortableServer_ServantBase__epv impl_Nautilus_Application_base_epv = {
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
78 79 80
	NULL,			/* _private data */
	NULL,			/* finalize routine */
	NULL,			/* default_POA routine */
81 82
};
static POA_Nautilus_Application__vepv impl_Nautilus_Application_vepv = {
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
83 84 85 86
	&impl_Nautilus_Application_base_epv,
	&impl_Nautilus_Application_Bonobo_GenericFactory_epv,
	NULL,
	&impl_Nautilus_Application_epv,
87 88 89
};

static Nautilus_ViewWindowList *
90 91
impl_Nautilus_Application__get_view_windows(impl_POA_Nautilus_Application *servant,
                                            CORBA_Environment * ev)
92
{
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
93
	Nautilus_ViewWindowList *retval;
94 95
	int i;
	GSList *ltmp;
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
96

97 98
	retval = Nautilus_ViewWindowList__alloc ();
	retval->_length = g_slist_length (servant->app->windows);
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
99

100 101 102 103 104
	retval->_buffer = CORBA_sequence_Nautilus_ViewWindow_allocbuf (retval->_length);
	for(i = 0, ltmp = servant->app->windows; ltmp; ltmp = ltmp->next, i++) {
		CORBA_Object obj;
		obj = bonobo_object_corba_objref(NAUTILUS_WINDOW(ltmp->data)->ntl_viewwindow);
		retval->_buffer[i] = CORBA_Object_duplicate(obj, ev);
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
105 106
	}

107
	CORBA_sequence_set_release (retval, CORBA_TRUE);
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
108 109

	return retval;
110 111
}

Gene Ragan's avatar
Gene Ragan committed
112

113
static Nautilus_ViewWindow
114 115
impl_Nautilus_Application_new_view_window (impl_POA_Nautilus_Application *servant,
					   CORBA_Environment * ev)
116
{
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
117
	NautilusWindow *win;
118

Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
119 120
	win = nautilus_app_create_window (servant->app);
	return CORBA_Object_duplicate (bonobo_object_corba_objref (BONOBO_OBJECT (win)), ev);
121 122 123
}

static CORBA_boolean
124 125 126
impl_Nautilus_Application_supports (impl_POA_Nautilus_Application * servant,
				    CORBA_char * obj_iid,
				    CORBA_Environment * ev)
127
{
128 129 130
	return strcmp(obj_iid, "OAFIID:ntl_file_manager_icon_view:42681b21-d5ca-4837-87d2-394d88ecc058") == 0
		|| strcmp(obj_iid, "OAFIID:ntl_file_manager_list_view:521e489d-0662-4ad7-ac3a-832deabe111c") == 0
		|| strcmp(obj_iid, "OAFIID:ntl_window:88e8b2e4-b627-4221-b566-5ba32185c88d") == 0;
131 132 133
}

static CORBA_Object
134 135 136 137
impl_Nautilus_Application_create_object (impl_POA_Nautilus_Application *servant,
					 CORBA_char *obj_iid,
					 GNOME_stringlist * params,
					 CORBA_Environment * ev)
138
{
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
139
	FMDirectoryView *dir_view;
Darin Adler's avatar
Darin Adler committed
140
	NautilusView *view;
141

142
	if (!impl_Nautilus_Application_supports (servant, obj_iid, ev)) {
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
143
		return CORBA_OBJECT_NIL;
144
	}
145
        
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
146 147 148 149 150
	if (strcmp (obj_iid, "OAFIID:ntl_file_manager_icon_view:42681b21-d5ca-4837-87d2-394d88ecc058") == 0) {
		dir_view = FM_DIRECTORY_VIEW (gtk_object_new (fm_icon_view_get_type (), NULL));
	} else if (strcmp (obj_iid, "OAFIID:ntl_file_manager_list_view:521e489d-0662-4ad7-ac3a-832deabe111c") == 0) {
		dir_view = FM_DIRECTORY_VIEW (gtk_object_new (fm_list_view_get_type (), NULL));
	} else if (strcmp (obj_iid,"OAFIID:ntl_window:88e8b2e4-b627-4221-b566-5ba32185c88d") == 0) {
151
		return impl_Nautilus_Application_new_view_window (servant, ev);
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
152
	} else {
153
		return CORBA_OBJECT_NIL;
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
154
	}
155
        
156 157
	view = fm_directory_view_get_nautilus_view (dir_view);
	return CORBA_Object_duplicate (bonobo_object_corba_objref (BONOBO_OBJECT (view)), ev);
158 159 160
}


161 162 163 164 165
static CORBA_Object
impl_Nautilus_Application__create(PortableServer_POA poa,
                                  NautilusApp *app,
				  CORBA_Environment * ev)
{
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
166
	impl_POA_Nautilus_Application *newservant;
167

Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
168 169 170 171 172
	newservant = g_new0(impl_POA_Nautilus_Application, 1);
	newservant->servant.vepv = &impl_Nautilus_Application_vepv;
	newservant->servant.vepv->Bonobo_Unknown_epv = NAUTILUS_APP_CLASS(GTK_OBJECT(app)->klass)->unknown_epv;
	POA_Nautilus_Application__init((PortableServer_Servant) newservant, ev);
	return bonobo_object_activate_servant(BONOBO_OBJECT(app), newservant);
173 174
}

175 176 177 178
static void nautilus_app_init              (NautilusApp      *app);
static void nautilus_app_class_init        (NautilusAppClass *klass);
static void nautilus_app_destroy           (GtkObject        *object);
static void nautilus_app_check_user_directories (NautilusApp      *app);
179 180 181 182 183 184

static GtkObjectClass *app_parent_class = NULL;

GtkType
nautilus_app_get_type (void)
{
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
	static GtkType App_type = 0;

	if (!App_type)
	{
		static const GtkTypeInfo App_info =
		{
			"NautilusApp",
			sizeof (NautilusApp),
			sizeof (NautilusAppClass),
			(GtkClassInitFunc) nautilus_app_class_init,
			(GtkObjectInitFunc) nautilus_app_init,
			/* reserved_1 */ NULL,
			/* reserved_2 */ NULL,
			(GtkClassInitFunc) NULL,
      		};

		App_type = gtk_type_unique (bonobo_object_get_type (), &App_info);
	}

	return App_type;
205 206 207 208 209
}

static void
nautilus_app_class_init (NautilusAppClass *klass)
{
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
210
	GtkObjectClass *object_class;
211

Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
212
	klass->unknown_epv = bonobo_object_get_epv();
213

Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
214 215
	object_class = (GtkObjectClass*) klass;
	object_class->destroy = nautilus_app_destroy;
216

Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
217
	app_parent_class = gtk_type_class (gtk_object_get_type ());
218 219 220 221 222
}

static void
nautilus_app_init (NautilusApp *app)
{
223
	CORBA_Environment ev;
224 225
	CORBA_Object objref;
	Nautilus_Undo_Manager undo_manager;
226
	
227
	CORBA_exception_init (&ev);
228

229
	objref = impl_Nautilus_Application__create (bonobo_poa (), app, &ev);
230
	oaf_active_server_register ("OAFIID:ntl_file_manager_factory:bd1e1862-92d7-4391-963e-37583f0daef3",
231 232
				    objref);
	bonobo_object_construct (BONOBO_OBJECT(app), objref);
233

234
	/* Init undo manager */
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
235
	app->undo_manager = BONOBO_OBJECT (nautilus_undo_manager_new ());
236 237
	undo_manager = bonobo_object_corba_objref (BONOBO_OBJECT (app->undo_manager));

238 239 240
	/* Stash a global reference to the object */
	nautilus_undo_manager_stash_global_undo (undo_manager);

241 242
	/* Add it to the application object */
	nautilus_attach_undo_manager (GTK_OBJECT (app), undo_manager);
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
243

244
	CORBA_exception_free (&ev);
245 246 247
}

GtkObject *
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
248
nautilus_app_new (void)
249
{
250
	return gtk_object_new (nautilus_app_get_type (), NULL);
251 252 253
}

static void
254
nautilus_app_destroy (GtkObject *object)
255
{
256 257 258 259 260 261
	/* Shut down preferences.  This is needed so that the global
	 * preferences object and all its allocations are freed.  Not
	 * 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,
	 * but it adds noice to memory profile tool runs.
262 263
	 */
	nautilus_global_preferences_shutdown ();
264

265
	nautilus_bookmarks_exiting ();
266
	GTK_OBJECT_CLASS(app_parent_class)->destroy (object);
267 268
}

269

270
static void
271
display_caveat (GtkWindow *parent_window)
272
{
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
	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);
	
	file_name = gnome_pixmap_file ("nautilus/About_Image.png");
	pixmap = gnome_pixmap_new_from_file (file_name);
	g_free (file_name);
	gtk_widget_show (pixmap);
	gtk_container_add (GTK_CONTAINER (frame), pixmap);

304 305 306 307 308 309 310 311 312
  	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
313
		   "unpredictable and may even delete or overwrite "
314 315 316 317
		   "files on your computer."
		   "\n\n"
		   "For more information, visit http://nautilus.eazel.com."));
    	gtk_label_set_line_wrap (GTK_LABEL (text), TRUE);
318 319 320 321 322
	gtk_widget_show (text);
  	gtk_box_pack_start (GTK_BOX (hbox), text, FALSE, FALSE, 0);

  	gnome_dialog_set_close (GNOME_DIALOG (dialog), TRUE);

323 324 325
	if (parent_window != NULL) {
		gnome_dialog_set_parent (GNOME_DIALOG (dialog), parent_window);
	}
326 327

	gtk_widget_show (GTK_WIDGET (dialog));
328 329
}

330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
static void
nautilus_app_check_user_directories (NautilusApp *app)
{
	const char		*user_directory;
	const char		*user_main_directory;
	const char		*desktop_directory;
	NautilusStringList	*dir_list;
	
	g_assert (app != NULL);
	g_assert (NAUTILUS_IS_APP (app));

	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");
	}
	    
	if (!g_file_test (user_main_directory, G_FILE_TEST_ISDIR)) {
		nautilus_string_list_insert (dir_list, "User Main Directory");
	}
	    
	if (!g_file_test (desktop_directory, G_FILE_TEST_ISDIR)) {
		nautilus_string_list_insert (dir_list, "Desktop Directory");
	}

	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.");

		nautilus_error_dialog (error_string);

		g_free (dir_list_concatenated);
		g_free (error_string);
	}

	nautilus_string_list_free (dir_list);
}

383
void
384
nautilus_app_startup (NautilusApp *app,
385 386
		      gboolean manage_desktop,
		      const char *urls[])
387
{
388
	const char **p;
389
	NautilusWindow *window;
390
	NautilusWindow *first_window;
391

392 393 394 395 396
	/* Check the user's ~/.nautilus directories and post warnings if there
	 * are problems
	 */
	nautilus_app_check_user_directories (app);

397 398
	/* Set up the desktop. */
	if (manage_desktop) {
399 400
		gtk_widget_show (GTK_WIDGET (nautilus_desktop_window_new (app)));
	}
401

402 403 404 405 406 407 408 409 410 411 412
  	/* Create the other windows. */
	first_window = NULL;
	if (urls != NULL) {
		for (p = urls; *p != NULL; p++) {
			window = nautilus_app_create_window (app);
			nautilus_window_goto_uri (window, *p);
			if (first_window == NULL) {
				first_window = window;
			}
		}
	}
413 414 415 416 417
	/* 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) {
418 419 420
		first_window = nautilus_app_create_window (app);
		nautilus_window_go_home (first_window);
	}
421

422
	/* Show the "not ready for prime time" dialog after the first
423 424
	 * window appears, so it's on top.
	 */
John Sullivan's avatar
John Sullivan committed
425
	/* FIXME bugzilla.eazel.com 1256: It's not on top of the other windows. */
Darin Adler's avatar
Darin Adler committed
426
	if (g_getenv ("NAUTILUS_NO_CAVEAT_DIALOG") == NULL) {
427 428 429 430 431 432
	  	if (first_window == NULL) {
			display_caveat (NULL);
		} else {
			gtk_signal_connect (GTK_OBJECT (first_window), "show",
					    display_caveat, first_window);
		}
433
  	}
434 435 436
}

static void
437
nautilus_app_destroy_window (GtkObject *obj, NautilusApp *app)
438
{
439 440
	app->windows = g_slist_remove (app->windows, obj);
	if (app->windows == NULL) {
441
  		nautilus_app_quit();
442
	}
443 444 445 446 447
}

void 
nautilus_app_quit (void)
{
448 449
	gnome_vfs_shutdown ();
	gtk_main_quit ();
450 451 452
}

NautilusWindow *
453
nautilus_app_create_window (NautilusApp *app)
454
{
455
	NautilusWindow *window;
456
	
457 458
	window = NAUTILUS_WINDOW (gtk_object_new (nautilus_window_get_type (),
						  "app", BONOBO_OBJECT (app),
459 460 461 462
						  "app_id", "nautilus", NULL));
	
	gtk_signal_connect (GTK_OBJECT (window),
			    "destroy", nautilus_app_destroy_window, app);
463

Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
464
	/* Do not yet show the window. It will be shown later on if it can
465 466 467 468
	 * successfully display its initial URI. Otherwise it will be destroyed
	 * without ever having seen the light of day.
	 */
	app->windows = g_slist_prepend (app->windows, window);
469

470
	return window;
471
}