nautilus-application.c 14.4 KB
Newer Older
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
1
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 3 4 5 6 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-extensions/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
	CORBA_Object objref;
225
	
226
	CORBA_exception_init (&ev);
227

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

233
	/* Create an undo manager */
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
234
	app->undo_manager = BONOBO_OBJECT (nautilus_undo_manager_new ());
235

236 237 238
	/* Attach undo manager to application so windows can use share_undo_manager. */
	nautilus_undo_manager_attach (NAUTILUS_UNDO_MANAGER (app->undo_manager),
				      GTK_OBJECT (app));
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
239

240
	CORBA_exception_free (&ev);
241 242 243
}

GtkObject *
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
244
nautilus_app_new (void)
245
{
246
	return gtk_object_new (nautilus_app_get_type (), NULL);
247 248 249
}

static void
250
nautilus_app_destroy (GtkObject *object)
251
{
252 253 254 255 256 257
	/* 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.
258 259
	 */
	nautilus_global_preferences_shutdown ();
260

261
	nautilus_bookmarks_exiting ();
262
	GTK_OBJECT_CLASS(app_parent_class)->destroy (object);
263 264
}

265

266
static void
267
display_caveat (GtkWindow *parent_window)
268
{
269 270 271 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
	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);

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

  	gnome_dialog_set_close (GNOME_DIALOG (dialog), TRUE);

319 320 321
	if (parent_window != NULL) {
		gnome_dialog_set_parent (GNOME_DIALOG (dialog), parent_window);
	}
322 323

	gtk_widget_show (GTK_WIDGET (dialog));
324 325
}

326 327 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
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);
}

379
void
380
nautilus_app_startup (NautilusApp *app,
381 382
		      gboolean manage_desktop,
		      const char *urls[])
383
{
384
	const char **p;
385
	NautilusWindow *window;
386
	NautilusWindow *first_window;
387

388 389 390 391 392
	/* Check the user's ~/.nautilus directories and post warnings if there
	 * are problems
	 */
	nautilus_app_check_user_directories (app);

393 394
	/* Set up the desktop. */
	if (manage_desktop) {
395 396
		gtk_widget_show (GTK_WIDGET (nautilus_desktop_window_new (app)));
	}
397

398 399 400 401 402 403 404 405 406 407 408
  	/* 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;
			}
		}
	}
409 410 411 412 413
	/* 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) {
414 415 416
		first_window = nautilus_app_create_window (app);
		nautilus_window_go_home (first_window);
	}
417

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

static void
433
nautilus_app_destroy_window (GtkObject *obj, NautilusApp *app)
434
{
435 436
	app->windows = g_slist_remove (app->windows, obj);
	if (app->windows == NULL) {
437
  		nautilus_app_quit();
438
	}
439 440 441 442 443
}

void 
nautilus_app_quit (void)
{
444
	gtk_main_quit ();
445 446 447
}

NautilusWindow *
448
nautilus_app_create_window (NautilusApp *app)
449
{
450
	NautilusWindow *window;
451
	
452 453
	window = NAUTILUS_WINDOW (gtk_object_new (nautilus_window_get_type (),
						  "app", BONOBO_OBJECT (app),
454 455 456 457
						  "app_id", "nautilus", NULL));
	
	gtk_signal_connect (GTK_OBJECT (window),
			    "destroy", nautilus_app_destroy_window, app);
458

Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
459
	/* Do not yet show the window. It will be shown later on if it can
460 461 462 463
	 * 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);
464

465
	return window;
466
}