nautilus-application.c 12 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 29 30
#include "ntl-app.h"

#include "ntl-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

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

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

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

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

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

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

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

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

	return retval;
107 108
}

Gene Ragan's avatar
Gene Ragan committed
109

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

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

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

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

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


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

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

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
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
	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;
201 202 203 204 205
}

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

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

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

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

215
	/* Startup preferences.  This call is needed so that preferences have
216 217 218 219 220
	 * 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 ();
221 222 223 224 225
}

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

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

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

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

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

247
	CORBA_exception_free (&ev);
248 249 250
}

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

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

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

272
static void
273
display_prototype_caveat (void)
274 275 276 277
{
	/* Inform the user that Nautilus has a long way to go
	 * before they should be expecting it to work well.
	 */
278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
	if (getenv ("NAUTILUS_NO_CAVEAT_DIALOG") == NULL) {
		/* Before you change this code back to use gnome_warning_dialog
		 * or nautilus_warning_dialog, you better test it. See bug 963.
		 */
		nautilus_simple_dialog
			(NULL,
			 _("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 unpredictable and may even "
			   "delete or overwrite files on your computer."
			   "\n\n"
			   "For more information, visit http://nautilus.eazel.com."),
			 _("Nautilus: caveat"),
			 GNOME_STOCK_BUTTON_OK, NULL);
298
	}
299 300
}

301
void
302
nautilus_app_startup(NautilusApp *app, const char *initial_url)
303
{
304
	NautilusWindow *mainwin;
305

306
	/* Put up (modal) caveat. */
307
	display_prototype_caveat ();
308

309
  	/* Set default configuration */
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
310 311
  	mainwin = nautilus_app_create_window (app);
  	bonobo_activate ();
312
  	nautilus_window_set_initial_state (mainwin, initial_url);
313 314 315
}

static void
316
nautilus_app_destroy_window (GtkObject *obj, NautilusApp *app)
317
{
318 319
	app->windows = g_slist_remove (app->windows, obj);
	if (app->windows == NULL) {
320
  		nautilus_app_quit();
321
	}
322 323
}

324 325 326
/* FIXME: If we are really going to use this, it should probably be
 * moved to the gnome vfs public interface.
 */
327 328 329
extern int gnome_vfs_debug_get_thread_count (void);
int quit_counter_hack;

330 331 332 333
/* 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.
 */
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350
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); */
351
	usleep(200000); /* 1/5 second */
352 353 354 355 356 357 358 359 360 361
	
	return TRUE;
}

void 
nautilus_app_quit (void)
{
	quit_counter_hack = 20;
	/* wait for gnome vfs slave threads to go away before quitting */
	gtk_idle_add ((GtkFunction)nautilus_app_real_quit, NULL);
362 363 364
}

NautilusWindow *
365
nautilus_app_create_window (NautilusApp *app)
366
{
367
	NautilusWindow *window;
368
	
369 370 371 372 373
	window = NAUTILUS_WINDOW (gtk_object_new (nautilus_window_get_type(), "app", BONOBO_OBJECT(app),
						  "app_id", "nautilus", NULL));
	
	gtk_signal_connect (GTK_OBJECT (window),
			    "destroy", nautilus_app_destroy_window, app);
374

Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
375
	/* Do not yet show the window. It will be shown later on if it can
376 377 378 379
	 * 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);
380

381
	return window;
382
}