nautilus-application.c 13.1 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;
Darin Adler's avatar
Darin Adler committed
137
	NautilusView *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

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

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

331
void
332
nautilus_app_startup(NautilusApp *app, const char *initial_url)
333
{
334
	NautilusWindow *mainwin;
335

336
  	/* Set default configuration */
Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
337 338
  	mainwin = nautilus_app_create_window (app);
  	bonobo_activate ();
339
  	nautilus_window_set_initial_state (mainwin, initial_url);
340 341 342 343 344 345 346 347

	/* Show the "not ready for prime time" dialog after this
	 * window appears, so it's on top.
	 */
	if (getenv ("NAUTILUS_NO_CAVEAT_DIALOG") == NULL) {
	  	gtk_signal_connect (GTK_OBJECT (mainwin), "show",
	  			    display_caveat, mainwin);
  	}
348 349 350
}

static void
351
nautilus_app_destroy_window (GtkObject *obj, NautilusApp *app)
352
{
353 354
	app->windows = g_slist_remove (app->windows, obj);
	if (app->windows == NULL) {
355
  		nautilus_app_quit();
356
	}
357 358
}

359 360 361
/* FIXME: If we are really going to use this, it should probably be
 * moved to the gnome vfs public interface.
 */
362 363 364
extern int gnome_vfs_debug_get_thread_count (void);
int quit_counter_hack;

365 366 367 368
/* 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.
 */
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
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); */
386
	usleep(200000); /* 1/5 second */
387 388 389 390 391 392 393 394 395 396
	
	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);
397 398 399
}

NautilusWindow *
400
nautilus_app_create_window (NautilusApp *app)
401
{
402
	NautilusWindow *window;
403
	
404 405 406 407 408
	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);
409

Gene Z. Ragan's avatar
CVS:  
Gene Z. Ragan committed
410
	/* Do not yet show the window. It will be shown later on if it can
411 412 413 414
	 * 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);
415

416
	return window;
417
}