A Full Example

This is a full app which uses the GNOME File Selector and bonobo to display a file.

Example 12. A Small Application for Viewing Text Files

/*
 * file-sel-demo.c: demonstrates how to use the file-sel
 *
 * Authors:
 *    Jacob Berkman  <jacob@ximian.com>
 *
 * Copyright 2001 Ximian, Inc.
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>

#include <bonobo/bonobo-exception.h>
#include <bonobo/bonobo-listener.h>
#include <bonobo/bonobo-main.h>
#include <bonobo/bonobo-widget.h>

#include <gtk/gtkbutton.h>
#include <gtk/gtkmain.h>
#include <gtk/gtkscrolledwindow.h>
#include <gtk/gtksignal.h>
#include <gtk/gtktable.h>
#include <gtk/gtktext.h>
#include <gtk/gtkwindow.h>

#include <libgnome/gnome-defs.h>

#include <libgnomeui/gnome-dialog.h>
#include <libgnomeui/gnome-dialog-util.h>
#include <libgnomeui/gnome-init.h>

#include <liboaf/oaf-mainloop.h>

static struct {
	Bonobo_EventSource es;
	GtkWidget *dialog;
	GtkWidget *toplevel;
	Bonobo_EventSource_ListenerId id;
	BonoboListener *listener;
} global = { CORBA_OBJECT_NIL };

static void
listener_cb (BonoboListener *listener, 
	     gchar *event_name,
	     CORBA_any *any,
	     CORBA_Environment *ev,
	     gpointer text)
{
	CORBA_sequence_CORBA_string *seq;
	char buf[BUFSIZ];
	static char *subtype;
	char *s, *file;
	int pos, fd, len;

	subtype = bonobo_event_subtype (event_name);

	gtk_widget_hide (global.dialog);

	if (!strcmp (subtype, "Cancel")) {
		g_free (subtype);
		return;
	}

	g_free (subtype);

	seq = any->_value;
	g_assert (seq->_length == 1);

	file = seq->_buffer[0];
	if (!strncasecmp (file, "file:", 5))
		file += 5;

	gtk_text_freeze (GTK_TEXT (text));
	gtk_editable_delete_text (GTK_EDITABLE (text), 0, -1);
	pos = 0;

	fd = open (file, O_RDONLY);
	if (fd == -1) {
		s = g_strdup_printf ("There was an error loading \"%s\": %s\n",
				     file, g_strerror (errno));
		gtk_editable_insert_text (GTK_EDITABLE (text),
					  s, strlen (s), &pos);
		g_free (s);
		gtk_text_thaw (GTK_TEXT (text));
		return;
	}

	/* this is not a gnome-vfs async demo */
	while ( 0 < (len = read (fd, buf, BUFSIZ))) {
		gtk_editable_insert_text (GTK_EDITABLE (text),
					  buf, len, &pos);
	}

	gtk_text_thaw (GTK_TEXT (text));
	return;	
}

static void
load_file (GtkWidget *button, GtkWidget *text)
{
	GtkWidget *filesel;
	char *moniker;

	Bonobo_Unknown     corba_control;
	CORBA_Environment  ev;

	if (global.dialog) {
		gtk_widget_show (global.dialog);
		gdk_window_raise (global.dialog->window);
		return;
	}

	moniker = "OAFIID:GNOME_FileSelector!"
		"AcceptDirectories=False;"
		"Application=file-sel-demo;"
		"LocalURIsOnly=True;"
		"MimeTypes=Text Files:text/plain:C Files:text/x-c;"
		"MultipleSelection=False";
	
	filesel = bonobo_widget_new_control (moniker, CORBA_OBJECT_NIL);
	if (!filesel) {
		global.dialog = gnome_error_dialog ("Could not create a File Selector.\n"
						    "Normally your app should use a gtk\n"
						    "file selector as a fallback.");
		gnome_dialog_run_and_close (GNOME_DIALOG (global.dialog));
		global.dialog = NULL;
		return;
	}

	corba_control = bonobo_widget_get_objref (BONOBO_WIDGET (filesel));

	CORBA_exception_init (&ev);
	global.es = Bonobo_Unknown_queryInterface (corba_control,
						   "IDL:Bonobo/EventSource:1.0",
						   &ev);
	if (BONOBO_EX (&ev)) {
		global.dialog = gnome_error_dialog ("There was an error querying for an\n"
						    "EventSource.  This shouldn't happen.");
		gnome_dialog_run_and_close (GNOME_DIALOG (global.dialog));

		bonobo_object_release_unref (corba_control, &ev);
		CORBA_exception_free (&ev); /* FIXME: is this necessary? */

		global.dialog = NULL;
		return;
	}

	global.listener = bonobo_listener_new (listener_cb, text);
	global.id = Bonobo_EventSource_addListenerWithMask (
		global.es, BONOBO_OBJREF (global.listener),
		"GNOME/FileSelector:ButtonClicked", 
		&ev);

	CORBA_exception_free (&ev);

	/* go and create the dialog */
	global.dialog = gtk_window_new (GTK_WINDOW_DIALOG);
	gtk_container_add (GTK_CONTAINER (global.dialog), filesel);

	/*gnome_window_icon_set_from_default (GTK_WINDOW (global.dialog))*/
	gtk_widget_set_usize (global.dialog, 560, 450);
	gtk_window_set_title (GTK_WINDOW (global.dialog), "Select a File to Open");
	gtk_window_set_modal (GTK_WINDOW (global.dialog), TRUE);
	gtk_window_set_transient_for (GTK_WINDOW (global.dialog),
				      GTK_WINDOW (global.toplevel));

	gtk_widget_show_all (global.dialog);
}

static void
create_main_window (void)
{
	GtkWidget *table;
	GtkWidget *text;
	GtkWidget *button;
	GtkWidget *scroll;

	global.toplevel = gtk_window_new (GTK_WINDOW_TOPLEVEL);
	gtk_window_set_title (GTK_WINDOW (global.toplevel), 
			      "Lame File Selector Demo");
	gtk_widget_set_usize (global.toplevel, 400, 300);

	table = gtk_table_new (2, 2, FALSE);
	gtk_table_set_row_spacings (GTK_TABLE (table), 6);
	gtk_table_set_col_spacings (GTK_TABLE (table), 6);
	gtk_container_set_border_width (GTK_CONTAINER (table), 6);
	gtk_container_add (GTK_CONTAINER (global.toplevel), table);

	scroll = gtk_scrolled_window_new (NULL, NULL);
	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroll),
					GTK_POLICY_NEVER,
					GTK_POLICY_ALWAYS);
	gtk_table_attach (GTK_TABLE (table), scroll,
			  0, 2,
			  0, 1,
			  GTK_EXPAND | GTK_FILL,
			  GTK_EXPAND | GTK_FILL,
			  0, 0);
	
	text = gtk_text_new (NULL, NULL);
	gtk_container_add (GTK_CONTAINER (scroll), text);

	button = gtk_button_new_with_label ("Load File");
	gtk_table_attach (GTK_TABLE (table), button,
			  0, 1,
			  1, 2,
			  GTK_FILL,
			  0,
			  0, 0);

	gtk_signal_connect (GTK_OBJECT (button), "clicked",
			    GTK_SIGNAL_FUNC (load_file),
			    text);

	button = gtk_button_new_with_label ("Quit");
	gtk_table_attach (GTK_TABLE (table), button,
			  1, 2,
			  1, 2,
			  GTK_FILL,
			  0, 
			  0, 0);

	gtk_signal_connect (GTK_OBJECT (button), "clicked",
			    GTK_SIGNAL_FUNC (gtk_main_quit),
			    NULL);

	gtk_signal_connect (GTK_OBJECT (global.toplevel), "delete_event",
			    GTK_SIGNAL_FUNC (gtk_main_quit),
			    NULL);

	gtk_widget_show_all (global.toplevel);
}

static void
cleanup_objects (void)
{
	if (global.toplevel)
		gtk_widget_destroy (global.toplevel);

	if (global.dialog)
		gtk_widget_destroy (global.dialog);

	if (global.es != CORBA_OBJECT_NIL) {
		CORBA_Environment ev;
		
		CORBA_exception_init (&ev);
		if (global.id) {
			Bonobo_EventSource_removeListener (
				global.es, global.id, &ev);
		}
		bonobo_object_release_unref (global.es, &ev);
		CORBA_exception_free (&ev);
	}

	if (global.listener)
		bonobo_object_unref (BONOBO_OBJECT (global.listener));
}

int 
main (int argc, char *argv[])
{
	gnome_init ("file-sel-demo", "0.1", argc, argv);
	bonobo_init (oaf_init (argc, argv), NULL, NULL);

	create_main_window ();

	bonobo_main ();

	cleanup_objects ();

	return 0;
}