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

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

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

49 50 51 52 53 54 55 56
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,
57
				   CORBA_char *obj_iid,
58 59 60
				   CORBA_Environment * ev);
static CORBA_Object
impl_Nautilus_Application_create_object(impl_POA_Nautilus_Application *servant,
61
                                        CORBA_char *obj_iid,
62 63 64
					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
65 66 67
	NULL,			/* _private */
	(gpointer) &impl_Nautilus_Application__get_view_windows,
	(gpointer) &impl_Nautilus_Application_new_view_window
68 69

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

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

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

98 99 100 101 102
	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
103 104
	}

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

	return retval;
108 109
}

Gene Ragan's avatar
Gene Ragan committed
110

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

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

static CORBA_boolean
122 123 124
impl_Nautilus_Application_supports (impl_POA_Nautilus_Application * servant,
				    CORBA_char * obj_iid,
				    CORBA_Environment * ev)
125
{
126 127 128
	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;
129 130 131
}

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

140
	if (!impl_Nautilus_Application_supports (servant, obj_iid, ev)) {
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
141
		return CORBA_OBJECT_NIL;
142
	}
143
        
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
144 145 146 147 148
	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) {
149
		return impl_Nautilus_Application_new_view_window (servant, ev);
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
150
	} else {
151
		return CORBA_OBJECT_NIL;
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
152
	}
153
        
154 155
	view = fm_directory_view_get_nautilus_view (dir_view);
	return CORBA_Object_duplicate (bonobo_object_corba_objref (BONOBO_OBJECT (view)), ev);
156 157 158
}


159 160 161 162 163
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
164
	impl_POA_Nautilus_Application *newservant;
165

Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
166 167 168 169 170
	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);
171 172 173 174 175 176 177 178 179 180 181
}

static void nautilus_app_init		(NautilusApp		 *app);
static void nautilus_app_class_init	(NautilusAppClass	 *klass);
static void nautilus_app_destroy        (GtkObject *object);

static GtkObjectClass *app_parent_class = NULL;

GtkType
nautilus_app_get_type (void)
{
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201
	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;
202 203 204 205 206
}

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

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

Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
211 212
	object_class = (GtkObjectClass*) klass;
	object_class->destroy = nautilus_app_destroy;
213

Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
214
	app_parent_class = gtk_type_class (gtk_object_get_type ());
215

216
	/* Startup preferences.  This call is needed so that preferences have
217 218 219 220 221
	 * decent defaults.  Not calling this function would cause some
	 * preferences to have "not nice" defaults.  Things would still work
	 * because it is legal to use nautilus preferences implicitly. 
	 */
	nautilus_global_preferences_startup ();
222 223 224 225 226
}

static void
nautilus_app_init (NautilusApp *app)
{
227
	CORBA_Environment ev;
228 229
	CORBA_Object objref;
	Nautilus_Undo_Manager undo_manager;
230
	
231
	CORBA_exception_init (&ev);
232

233
	objref = impl_Nautilus_Application__create (bonobo_poa (), app, &ev);
234
	oaf_active_server_register ("OAFIID:ntl_file_manager_factory:bd1e1862-92d7-4391-963e-37583f0daef3",
235 236
				    objref);
	bonobo_object_construct (BONOBO_OBJECT(app), objref);
237

238
	/* Init undo manager */
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
239
	app->undo_manager = BONOBO_OBJECT (nautilus_undo_manager_new ());
240 241
	undo_manager = bonobo_object_corba_objref (BONOBO_OBJECT (app->undo_manager));

242 243 244
	/* Stash a global reference to the object */
	nautilus_undo_manager_stash_global_undo (undo_manager);

245 246
	/* 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
247

248
	CORBA_exception_free (&ev);
249 250 251
}

GtkObject *
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
252
nautilus_app_new (void)
253
{
254
	return gtk_object_new (nautilus_app_get_type (), NULL);
255 256 257
}

static void
258
nautilus_app_destroy (GtkObject *object)
259
{
260 261 262 263 264 265
	/* 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.
266 267
	 */
	nautilus_global_preferences_shutdown ();
268

269
	nautilus_bookmarks_exiting ();
270
	GTK_OBJECT_CLASS(app_parent_class)->destroy (object);
271 272
}

273

274
static void
275
display_caveat (GtkWindow *parent_window)
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 304 305 306 307
	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);

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

  	gnome_dialog_set_close (GNOME_DIALOG (dialog), TRUE);

  	gnome_dialog_set_parent (GNOME_DIALOG (dialog), parent_window);

	gtk_widget_show (GTK_WIDGET (dialog));
330 331
}

332
void
333 334 335
nautilus_app_startup (NautilusApp *app,
		      const char *initial_url,
		      gboolean handle_desktop)
336
{
337 338 339 340 341
	NautilusWindow *window;

	if (handle_desktop) {
		gtk_widget_show (GTK_WIDGET (nautilus_desktop_window_new (app)));
	}
342

343
  	/* Set default configuration */
344
  	window = nautilus_app_create_window (app);
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
345
  	bonobo_activate ();
346
  	nautilus_window_set_initial_state (window, initial_url);
347 348 349 350 351

	/* Show the "not ready for prime time" dialog after this
	 * window appears, so it's on top.
	 */
	if (getenv ("NAUTILUS_NO_CAVEAT_DIALOG") == NULL) {
352 353
	  	gtk_signal_connect (GTK_OBJECT (window), "show",
	  			    display_caveat, window);
354
  	}
355 356 357
}

static void
358
nautilus_app_destroy_window (GtkObject *obj, NautilusApp *app)
359
{
360 361
	app->windows = g_slist_remove (app->windows, obj);
	if (app->windows == NULL) {
362
  		nautilus_app_quit();
363
	}
364 365
}

366
/* FIXME: If we are really going to use this, it should probably be
367 368
 * moved to the gnome vfs public interface (which would change its
 * name to not include "debug").
369
 */
370 371 372
extern int gnome_vfs_debug_get_thread_count (void);
int quit_counter_hack;

373 374 375 376
/* FIXME: This waiting for quit is needed by anyone who uses gnome-vfs,
 * especially users or NautilusDirectory. So we need to provide it for
 * others who are not using NautilusApp.
 */
377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
static gboolean
nautilus_app_real_quit (void *unused)
{
	int count;

	count = gnome_vfs_debug_get_thread_count ();
	if (count == 0) {
		/* g_message ("no more gnome vfs threads, ready to quit"); */
		gtk_main_quit ();
		return FALSE;
	} 
	if (--quit_counter_hack == 0) {
		g_message ("gnome vfs threads not going away, trying to quit anyway");
		gtk_main_quit ();
		return FALSE;
	}
	/* g_message ("%d gnome vfs threads left, will try to quit later", count); */
394
	usleep(200000); /* 1/5 second */
395 396 397 398 399 400 401
	
	return TRUE;
}

void 
nautilus_app_quit (void)
{
402 403
	quit_counter_hack = 20; /* 20 * 1/5 second == 4 seconds */

404 405
	/* wait for gnome vfs slave threads to go away before quitting */
	gtk_idle_add ((GtkFunction)nautilus_app_real_quit, NULL);
406 407 408
}

NautilusWindow *
409
nautilus_app_create_window (NautilusApp *app)
410
{
411
	NautilusWindow *window;
412
	
413 414
	window = NAUTILUS_WINDOW (gtk_object_new (nautilus_window_get_type(),
						  "app", BONOBO_OBJECT(app),
415 416 417 418
						  "app_id", "nautilus", NULL));
	
	gtk_signal_connect (GTK_OBJECT (window),
			    "destroy", nautilus_app_destroy_window, app);
419

Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
420
	/* Do not yet show the window. It will be shown later on if it can
421 422 423 424
	 * 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);
425

426
	return window;
427
}