[nautilus-actions] Review construction process



commit 44c15ac03615b8fb39b9e6454f5f2742f98107a2
Author: Pierre Wieser <pwieser trychlos org>
Date:   Sun Jan 8 18:46:57 2012 +0100

    Review construction process

 ChangeLog                   |   12 ++
 src/nact/base-application.c |  258 +++++++++++++++++--------------------------
 src/nact/base-application.h |  122 +++++++++++++-------
 src/nact/base-window.c      |   93 ++++++++++++----
 src/nact/base-window.h      |   61 ++++------
 src/nact/nact-application.c |   72 +++++++++---
 6 files changed, 340 insertions(+), 278 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 1fc6406..4aac6d8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,17 @@
 2012-01-08 Pierre Wieser <pwieser trychlos org>
 
+	* src/nact/base-application.c:
+	* src/nact/base-application.h
+	(base_application_get_builder): Removed function.
+	Implements BaseIUnique interface.
+
+	* src/nact/base-window.c:
+	* src/nact/base-window.h:
+	Have a common builder at class level.
+	Gtk toplevel and BaseWindow are initialized when instance is constructed.
+
+	* src/nact/nact-application.c: Updated accordingly.
+
 	* src/nact/base-iunique.c:
 	* src/nact/base-iunique.h (base_iunique_init_with_name):
 	Function renamed from base_iunique_init_name().
diff --git a/src/nact/base-application.c b/src/nact/base-application.c
index d5667ea..b631242 100644
--- a/src/nact/base-application.c
+++ b/src/nact/base-application.c
@@ -34,10 +34,9 @@
 
 #include <glib/gi18n.h>
 #include <string.h>
-#include <unique/unique.h>
 
 #include "base-application.h"
-#include "base-window.h"
+#include "base-iunique.h"
 #include "egg-sm-client.h"
 
 /* private class data
@@ -67,9 +66,6 @@ struct _BaseApplicationPrivate {
 	EggSMClient  *sm_client;
 	gulong        sm_client_quit_handler_id;
 	gulong        sm_client_quit_requested_handler_id;
-	BaseBuilder  *builder;
-	BaseWindow   *main_window;
-	UniqueApp    *unique_app_handle;
 };
 
 /* instance properties
@@ -93,6 +89,8 @@ static GObjectClass *st_parent_class = NULL;
 
 static GType          register_type( void );
 static void           class_init( BaseApplicationClass *klass );
+static void           iunique_iface_init( BaseIUniqueInterface *iface, void *user_data );
+static const gchar   *iunique_get_application_name( const BaseIUnique *instance );
 static void           instance_init( GTypeInstance *instance, gpointer klass );
 static void           instance_get_property( GObject *object, guint property_id, GValue *value, GParamSpec *spec );
 static void           instance_set_property( GObject *object, guint property_id, const GValue *value, GParamSpec *spec );
@@ -102,16 +100,14 @@ static void           instance_finalize( GObject *application );
 static gboolean       init_i18n( BaseApplication *application );
 static gboolean       init_application_name( BaseApplication *application );
 static gboolean       init_gtk( BaseApplication *application );
-static gboolean       v_manage_options( const BaseApplication *application );
-static gboolean       init_unique_app( BaseApplication *application );
-#if 0
-static UniqueResponse on_unique_message_received( UniqueApp *app, UniqueCommand command, UniqueMessageData *message, guint time, gpointer user_data );
-#endif
+static gboolean       v_manage_options( BaseApplication *application );
+static gboolean       init_unique_manager( BaseApplication *application );
 static gboolean       init_session_manager( BaseApplication *application );
 static void           session_manager_client_quit_cb( EggSMClient *client, BaseApplication *application );
 static void           session_manager_client_quit_requested_cb( EggSMClient *client, BaseApplication *application );
 static gboolean       init_icon_name( BaseApplication *application );
-static gboolean       init_builder( BaseApplication *application );
+static gboolean       v_init_application( BaseApplication *application );
+static gboolean       v_create_windows( BaseApplication *application );
 
 GType
 base_application_get_type( void )
@@ -143,12 +139,20 @@ register_type( void )
 		( GInstanceInitFunc ) instance_init
 	};
 
+	static const GInterfaceInfo iunique_iface_info = {
+		( GInterfaceInitFunc ) iunique_iface_init,
+		NULL,
+		NULL
+	};
+
 	g_debug( "%s", thisfn );
 
 	g_type_init();
 
 	type = g_type_register_static( G_TYPE_OBJECT, "BaseApplication", &info, 0 );
 
+	g_type_add_interface_static( type, BASE_IUNIQUE_TYPE, &iunique_iface_info );
+
 	return( type );
 }
 
@@ -171,70 +175,90 @@ class_init( BaseApplicationClass *klass )
 	g_object_class_install_property( object_class, BASE_PROP_ARGC_ID,
 			g_param_spec_int(
 					BASE_PROP_ARGC,
-					"Arguments count",
-					"The count of command-line arguments",
+					_( "Arguments count" ),
+					_( "The count of command-line arguments" ),
 					0, 65535, 0,
 					G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE ));
 
 	g_object_class_install_property( object_class, BASE_PROP_ARGV_ID,
 			g_param_spec_boxed(
 					BASE_PROP_ARGV,
-					"Arguments",
-					"The array of command-line arguments",
+					_( "Arguments" ),
+					_( "The array of command-line arguments" ),
 					G_TYPE_STRV,
 					G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE ));
 
 	g_object_class_install_property( object_class, BASE_PROP_OPTIONS_ID,
 			g_param_spec_pointer(
 					BASE_PROP_OPTIONS,
-					"Option entries",
-					"The array of command-line option definitions",
+					_( "Option entries" ),
+					_( "The array of command-line option definitions" ),
 					G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE ));
 
 	g_object_class_install_property( object_class, BASE_PROP_APPLICATION_NAME_ID,
 			g_param_spec_string(
 					BASE_PROP_APPLICATION_NAME,
-					"Application name",
-					"The name of the application",
+					_( "Application name" ),
+					_( "The name of the application" ),
 					"",
 					G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE ));
 
 	g_object_class_install_property( object_class, BASE_PROP_DESCRIPTION_ID,
 			g_param_spec_string(
 					BASE_PROP_DESCRIPTION,
-					"Description",
-					"A short description to be displayed in the first line of --help output",
+					_( "Description" ),
+					_( "A short description to be displayed in the first line of --help output" ),
 					"",
 					G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE ));
 
 	g_object_class_install_property( object_class, BASE_PROP_ICON_NAME_ID,
 			g_param_spec_string(
 					BASE_PROP_ICON_NAME,
-					"Icon name",
-					"The name of the icon of the application",
+					_( "Icon name" ),
+					_( "The name of the icon of the application" ),
 					"",
 					G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE ));
 
 	g_object_class_install_property( object_class, BASE_PROP_UNIQUE_NAME_ID,
 			g_param_spec_string(
 					BASE_PROP_UNIQUE_NAME,
-					"UniqueApp name",
-					"The Unique name of the application",
+					_( "UniqueApp name" ),
+					_( "The Unique name of the application" ),
 					"",
 					G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE ));
 
 	g_object_class_install_property( object_class, BASE_PROP_CODE_ID,
 			g_param_spec_int(
 					BASE_PROP_CODE,
-					"Return code",
-					"The return code of the application",
-					0, 127, 0,
+					_( "Return code" ),
+					_( "The return code of the application" ),
+					-127, 127, 0,
 					G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE ));
 
 	klass->private = g_new0( BaseApplicationClassPrivate, 1 );
 
 	klass->manage_options = NULL;
-	klass->main_window_new = NULL;
+	klass->init_application = NULL;
+	klass->create_windows = NULL;
+}
+
+static void
+iunique_iface_init( BaseIUniqueInterface *iface, void *user_data )
+{
+	static const gchar *thisfn = "base_application_iunique_iface_init";
+
+	g_debug( "%s: iface=%p, user_data=%p", thisfn, ( void * ) iface, ( void * ) user_data );
+
+	iface->get_application_name = iunique_get_application_name;
+}
+
+static const gchar *
+iunique_get_application_name( const BaseIUnique *instance )
+{
+	g_return_val_if_fail( BASE_IS_IUNIQUE( instance ), NULL );
+	g_return_val_if_fail( BASE_IS_APPLICATION( instance ), NULL );
+
+	return( BASE_APPLICATION( instance )->private->application_name );
 }
 
 static void
@@ -378,14 +402,6 @@ instance_dispose( GObject *application )
 
 		self->private->dispose_has_run = TRUE;
 
-		if( UNIQUE_IS_APP( self->private->unique_app_handle )){
-			g_object_unref( self->private->unique_app_handle );
-		}
-
-		if( GTK_IS_BUILDER( self->private->builder )){
-			g_object_unref( self->private->builder );
-		}
-
 		if( self->private->sm_client_quit_handler_id &&
 			g_signal_handler_is_connected( self->private->sm_client, self->private->sm_client_quit_handler_id )){
 				g_signal_handler_disconnect( self->private->sm_client, self->private->sm_client_quit_handler_id  );
@@ -453,7 +469,9 @@ base_application_run( BaseApplication *application, int argc, GStrv argv )
 {
 	static const gchar *thisfn = "base_application_run";
 	BaseApplicationPrivate *priv;
+#if 0
 	GtkWindow *gtk_toplevel;
+#endif
 
 	g_return_val_if_fail( BASE_IS_APPLICATION( application ), BASE_EXIT_CODE_START_FAIL );
 
@@ -468,46 +486,22 @@ base_application_run( BaseApplication *application, int argc, GStrv argv )
 
 		priv->argc = argc;
 		priv->argv = g_strdupv( argv );
+#if 0
 		priv->main_window = NULL;
+#endif
 		priv->code = BASE_EXIT_CODE_OK;
 
 		if( init_i18n( application ) &&
 			init_application_name( application ) &&
 			init_gtk( application ) &&
 			v_manage_options( application ) &&
-			init_unique_app( application ) &&
+			init_unique_manager( application ) &&
 			init_session_manager( application ) &&
 			init_icon_name( application ) &&
-			init_builder( application )){
-
-
-			if( BASE_APPLICATION_GET_CLASS( application )->main_window_new ){
-				priv->main_window =
-						( BaseWindow * ) BASE_APPLICATION_GET_CLASS( application )->main_window_new( application, &priv->code );
-			} else {
-				priv->code = BASE_EXIT_CODE_MAIN_WINDOW;
-			}
-
-			if( priv->main_window ){
-				g_return_val_if_fail( BASE_IS_WINDOW( priv->main_window ), BASE_EXIT_CODE_START_FAIL );
+			v_init_application( application ) &&
+			v_create_windows( application )){
 
-				if( base_window_init( priv->main_window )){
-					gtk_toplevel = base_window_get_gtk_toplevel( priv->main_window );
-					g_return_val_if_fail( gtk_toplevel, BASE_EXIT_CODE_START_FAIL );
-					g_return_val_if_fail( GTK_IS_WINDOW( gtk_toplevel ), BASE_EXIT_CODE_START_FAIL );
-
-					if( priv->unique_app_handle ){
-						unique_app_watch_window( priv->unique_app_handle, gtk_toplevel );
-					}
-
-					g_debug( "%s: invoking base_window_run", thisfn );
-					priv->code = base_window_run( priv->main_window );
-
-				} else {
-					g_debug( "%s: base_window_init has returned FALSE", thisfn );
-					priv->code = BASE_EXIT_CODE_INIT_FAIL;
-				}
-			}
+			gtk_main();
 		}
 	}
 
@@ -620,7 +614,7 @@ init_gtk( BaseApplication *application )
 }
 
 static gboolean
-v_manage_options( const BaseApplication *application )
+v_manage_options( BaseApplication *application )
 {
 	static const gchar *thisfn = "base_application_v_manage_options";
 	gboolean ret;
@@ -637,79 +631,27 @@ v_manage_options( const BaseApplication *application )
 }
 
 /*
- * Relying on libunique to detect another instance already running.
- *
- * A replacement is available with GLib 2.28 in GApplication, but only
- * GLib 2.30 (Fedora 16) provides a "non-unique" property.
+ * Initialize BaseIUnique interface for the instance
  */
 static gboolean
-init_unique_app( BaseApplication *application )
+init_unique_manager( BaseApplication *application )
 {
-	static const gchar *thisfn = "base_application_init_unique_app";
+	static const gchar *thisfn = "base_application_init_unique_manager";
 	gboolean ret;
-	BaseApplicationPrivate *priv;
-	gboolean is_first;
-	gchar *msg;
 
 	g_debug( "%s: application=%p", thisfn, ( void * ) application );
 
-	ret = TRUE;
-	priv = application->private;
+	ret = base_iunique_init_with_name(
+			BASE_IUNIQUE( application ),
+			application->private->unique_app_name );
 
-	if( priv->unique_app_name && strlen( priv->unique_app_name )){
-
-			priv->unique_app_handle = unique_app_new( priv->unique_app_name, NULL );
-			is_first = !unique_app_is_running( priv->unique_app_handle );
-
-			if( !is_first ){
-				unique_app_send_message( priv->unique_app_handle, UNIQUE_ACTIVATE, NULL );
-				/* i18n: application name */
-				msg = g_strdup_printf(
-						_( "Another instance of %s is already running.\n"
-							"Please switch back to it." ),
-						priv->application_name );
-				base_window_display_error_dlg( NULL, _( "The application is not unique" ), msg );
-				g_free( msg );
-				ret = FALSE;
-				priv->code = BASE_EXIT_CODE_UNIQUE_APP;
-#if 0
-			/* default from libunique is actually to activate the first window
-			 * so we rely on the default..
-			 */
-			} else {
-				g_signal_connect(
-						priv->unique_app_handle,
-						"message-received",
-						G_CALLBACK( on_unique_message_received ),
-						application );
-#endif
-			}
+	if( !ret ){
+		application->private->code = BASE_EXIT_CODE_UNIQUE_APP;
 	}
 
 	return( ret );
 }
 
-#if 0
-static UniqueResponse
-on_unique_message_received(
-		UniqueApp *app, UniqueCommand command, UniqueMessageData *message, guint time, gpointer user_data )
-{
-	static const gchar *thisfn = "base_application_check_for_unique_app";
-	UniqueResponse resp = UNIQUE_RESPONSE_OK;
-
-	switch( command ){
-		case UNIQUE_ACTIVATE:
-			g_debug( "%s: received message UNIQUE_ACTIVATE", thisfn );
-			break;
-		default:
-			resp = UNIQUE_RESPONSE_PASSTHROUGH;
-			break;
-	}
-
-	return( resp );
-}
-#endif
-
 /*
  * Relying on session manager to have a chance to save the modifications
  * before exiting a session
@@ -760,12 +702,14 @@ session_manager_client_quit_cb( EggSMClient *client, BaseApplication *applicatio
 
 		g_debug( "%s: client=%p, application=%p", thisfn, ( void * ) client, ( void * ) application );
 
+#if 0
 		if( application->private->main_window ){
 
 				g_return_if_fail( BASE_IS_WINDOW( application->private->main_window ));
 				g_object_unref( application->private->main_window );
 				application->private->main_window = NULL;
 		}
+#endif
 	}
 }
 
@@ -784,11 +728,13 @@ session_manager_client_quit_requested_cb( EggSMClient *client, BaseApplication *
 
 		g_debug( "%s: client=%p, application=%p", thisfn, ( void * ) client, ( void * ) application );
 
+#if 0
 		if( application->private->main_window ){
 
 				g_return_if_fail( BASE_IS_WINDOW( application->private->main_window ));
 				willing_to = base_window_is_willing_to_quit( application->private->main_window );
 		}
+#endif
 	}
 
 	egg_sm_client_will_quit( client, willing_to );
@@ -821,62 +767,58 @@ init_icon_name( BaseApplication *application )
 	return( TRUE );
 }
 
-/*
- * allocate a default builder
- */
 static gboolean
-init_builder( BaseApplication *application )
+v_init_application( BaseApplication *application )
 {
-	static const gchar *thisfn = "base_application_init_builder";
+	static const gchar *thisfn = "base_application_v_init_application";
+	gboolean ret;
 
 	g_debug( "%s: application=%p", thisfn, ( void * ) application );
 
-	/* allocate the common BaseBuilder instance
-	 */
-	application->private->builder = base_builder_new();
+	ret = TRUE;
 
-	return( TRUE );
+	if( BASE_APPLICATION_GET_CLASS( application )->init_application ){
+		ret = BASE_APPLICATION_GET_CLASS( application )->init_application( application );
+	}
+
+	return( ret );
 }
 
-/**
- * base_application_get_application_name:
- * @application: this #BaseApplication instance.
- *
- * Returns: the application name as a newly allocated string which should
- * be be g_free() by the caller.
- */
-gchar *
-base_application_get_application_name( const BaseApplication *application )
+static gboolean
+v_create_windows( BaseApplication *application )
 {
-	gchar *name = NULL;
+	static const gchar *thisfn = "base_application_v_create_windows";
+	gboolean ret;
 
-	g_return_val_if_fail( BASE_IS_APPLICATION( application ), NULL );
+	g_debug( "%s: application=%p", thisfn, ( void * ) application );
 
-	if( !application->private->dispose_has_run ){
+	ret = TRUE;
 
-		name = g_strdup( application->private->application_name );
+	if( BASE_APPLICATION_GET_CLASS( application )->create_windows ){
+		ret = BASE_APPLICATION_GET_CLASS( application )->create_windows( application );
 	}
 
-	return( name );
+	return( ret );
 }
 
 /**
- * base_application_get_builder:
+ * base_application_get_application_name:
  * @application: this #BaseApplication instance.
  *
- * Returns: the default #BaseBuilder object for the application.
+ * Returns: the application name as a newly allocated string which should
+ * be be g_free() by the caller.
  */
-BaseBuilder *
-base_application_get_builder( const BaseApplication *application )
+gchar *
+base_application_get_application_name( const BaseApplication *application )
 {
-	BaseBuilder *builder = NULL;
+	gchar *name = NULL;
 
 	g_return_val_if_fail( BASE_IS_APPLICATION( application ), NULL );
 
 	if( !application->private->dispose_has_run ){
 
-		builder = application->private->builder;
+		name = g_strdup( application->private->application_name );
 	}
 
-	return( builder );
+	return( name );
 }
diff --git a/src/nact/base-application.h b/src/nact/base-application.h
index 1970d7e..774d350 100644
--- a/src/nact/base-application.h
+++ b/src/nact/base-application.h
@@ -64,8 +64,8 @@
  *   </programlisting>
  * </example>
  *
- * main                 BaseApplication      NactApplication
- * ===================  ===================  ===================
+ * main                 BaseApplication      NactApplication      BaseWindow           NactWindow
+ * ===================  ===================  ===================  ===================  ===================
  * appli = nact_application_new()
  *                                           appli = g_object_new()
  *                                           set properties
@@ -79,37 +79,49 @@
  *                      init application name
  *                      init gtk with command-line options
  *                      manage command-line options
+ *                                           manage specific command-line options
+ *                                           calling parent class if ok to continue
+ *                                           setting application code else
  *                      init unique manager
+ *                        unique app name must have been set at this time
+ *                        application name should have been set at this time
  *                      init session manager
  *                      init icon name
- *                      init common builder
- *                      foreach window to display
- *                        create window
- *                        create gtk toplevel
- *                        unique watch toplevel
- *                        run the window
- *                      ret = last window return code
+ *                      create window(s)
+ *                                           foreach window to create
+ *                                             create BaseWindow-derived window
+ *                                                                on class init
+ *                                                                  init common builder
+ *                                                                on constructed
+ *                                                                  load and init gtk toplevel
+ *                                                                  init window
+ *                                                                  show gtk toplevel
+ *                                                                  run window
+ *                                                                                     [...]
+ *                      run the main loop
+ *                        must be explicitely quitted by application main window
+ *                        after having set the application return code
  * g_object_unref( appli )
  * return( ret )
  *
  * At any time, a function may preset the exit code of the application just by
- * setting the @BASE_PROP_CODE property. Unless it also asks to quit immediately
- * by returning %FALSE, another function may always set another exit code after
- * that.
+ * setting the @BASE_PROP_CODE property. Note that unless it also asks to quit
+ * immediately by returning %FALSE, another function may always set another exit
+ * code after that.
  */
 
-#include "base-builder.h"
+#include "glib-object.h"
 
 G_BEGIN_DECLS
 
-#define BASE_APPLICATION_TYPE           ( base_application_get_type())
-#define BASE_APPLICATION( o )           ( G_TYPE_CHECK_INSTANCE_CAST( o, BASE_APPLICATION_TYPE, BaseApplication ))
-#define BASE_APPLICATION_CLASS( k )     ( G_TYPE_CHECK_CLASS_CAST( k, BASE_APPLICATION_TYPE, BaseApplicationClass ))
-#define BASE_IS_APPLICATION( o )        ( G_TYPE_CHECK_INSTANCE_TYPE( o, BASE_APPLICATION_TYPE ))
-#define BASE_IS_APPLICATION_CLASS( k )  ( G_TYPE_CHECK_CLASS_TYPE(( k ), BASE_APPLICATION_TYPE ))
-#define BASE_APPLICATION_GET_CLASS( o ) ( G_TYPE_INSTANCE_GET_CLASS(( o ), BASE_APPLICATION_TYPE, BaseApplicationClass ))
+#define BASE_APPLICATION_TYPE                ( base_application_get_type())
+#define BASE_APPLICATION( object )           ( G_TYPE_CHECK_INSTANCE_CAST( object, BASE_APPLICATION_TYPE, BaseApplication ))
+#define BASE_APPLICATION_CLASS( klass )      ( G_TYPE_CHECK_CLASS_CAST( klass, BASE_APPLICATION_TYPE, BaseApplicationClass ))
+#define BASE_IS_APPLICATION( object )        ( G_TYPE_CHECK_INSTANCE_TYPE( object, BASE_APPLICATION_TYPE ))
+#define BASE_IS_APPLICATION_CLASS( klass )   ( G_TYPE_CHECK_CLASS_TYPE(( klass ), BASE_APPLICATION_TYPE ))
+#define BASE_APPLICATION_GET_CLASS( object ) ( G_TYPE_INSTANCE_GET_CLASS(( object ), BASE_APPLICATION_TYPE, BaseApplicationClass ))
 
-typedef struct _BaseApplicationPrivate      BaseApplicationPrivate;
+typedef struct _BaseApplicationPrivate       BaseApplicationPrivate;
 
 typedef struct {
 	/*< private >*/
@@ -118,7 +130,7 @@ typedef struct {
 }
 	BaseApplication;
 
-typedef struct _BaseApplicationClassPrivate BaseApplicationClassPrivate;
+typedef struct _BaseApplicationClassPrivate  BaseApplicationClassPrivate;
 
 /**
  * BaseApplicationClass:
@@ -143,30 +155,55 @@ typedef struct {
 	 *
 	 * This let the derived class an opportunity to manage command-line
 	 * arguments. Unless it decides to stop the execution of the program,
-	 * the derived class should call the parent class method in order to
-	 * let it manage its own options.
+	 * the derived class should call the parent class method (would it be
+	 * defined) in order to let it manage its own options.
 	 *
 	 * The derived class may set the exit code of the application by
 	 * setting the @BASE_PROP_CODE property of @appli.
 	 *
 	 * Returns: %TRUE to continue execution, %FALSE to stop it.
 	 */
-	gboolean  ( *manage_options ) ( const BaseApplication *appli );
+	gboolean  ( *manage_options ) ( BaseApplication *appli );
 
 	/**
-	 * main_window_new:
+	 * init_application:
 	 * @appli: this #BaseApplication -derived instance.
 	 *
 	 * This is invoked by the BaseApplication base class to let the derived
-	 * class do its own initializations and create its main window.
+	 * class do its own initializations.
+	 *
+	 * Versus initializations which occur at instanciation time, this method
+	 * let the application terminate its initializatin process, after command-line
+	 * arguments have been managed, and before creating any window.
+	 *
+	 * Unless it decides to stop the execution of the program,
+	 * the derived class should call the parent class method (would it be
+	 * defined) in order to let it manage its own options.
+	 *
+	 * The derived class may set the exit code of the application by
+	 * setting the @BASE_PROP_CODE property of @appli.
+	 *
+	 * Returns: %TRUE to continue execution, %FALSE to stop it.
+	 */
+	gboolean ( *init_application )( BaseApplication *appli );
+
+	/**
+	 * create_windows:
+	 * @appli: this #BaseApplication -derived instance.
+	 *
+	 * This is invoked by the BaseApplication base class to let the derived
+	 * class create its startup windows. This may include a spash window,
+	 * a main window, some secondary or toolbox windows, and so on.
 	 *
 	 * This is a pure virtual method. Only the most derived class
-	 * main_window_new() method is invoked.
+	 * create_windows() method is invoked.
 	 *
-	 * Returns: the main window of the application, as a #BaseWindow
-	 * -derived object. It may or may not have already been initialized.
+	 * The derived class may set the exit code of the application by
+	 * setting the @BASE_PROP_CODE property of @appli.
+	 *
+	 * Returns: %TRUE to continue execution, %FALSE to stop it.
 	 */
-	GObject * ( *main_window_new )( const BaseApplication *appli, int *code );
+	gboolean ( *create_windows )( BaseApplication *appli );
 }
 	BaseApplicationClass;
 
@@ -185,14 +222,14 @@ typedef struct {
  * @BASE_PROP_UNIQUE_NAME:      unique name of the application (if not empty)
  * @BASE_PROP_CODE:             return code of the application
  */
-#define BASE_PROP_ARGC						"base-application-argc"
-#define BASE_PROP_ARGV						"base-application-argv"
-#define BASE_PROP_OPTIONS					"base-application-options"
-#define BASE_PROP_APPLICATION_NAME			"base-application-name"
-#define BASE_PROP_DESCRIPTION				"base-application-description"
-#define BASE_PROP_ICON_NAME					"base-application-icon-name"
-#define BASE_PROP_UNIQUE_NAME				"base-application-unique-name"
-#define BASE_PROP_CODE						"base-application-code"
+#define BASE_PROP_ARGC						"base-prop-application-argc"
+#define BASE_PROP_ARGV						"base-prop-application-argv"
+#define BASE_PROP_OPTIONS					"base-prop-application-options"
+#define BASE_PROP_APPLICATION_NAME			"base-prop-application-name"
+#define BASE_PROP_DESCRIPTION				"base-prop-application-description"
+#define BASE_PROP_ICON_NAME					"base-prop-application-icon-name"
+#define BASE_PROP_UNIQUE_NAME				"base-prop-application-unique-name"
+#define BASE_PROP_CODE						"base-prop-application-code"
 
 typedef enum {
 	BASE_EXIT_CODE_START_FAIL = -1,
@@ -200,7 +237,7 @@ typedef enum {
 	BASE_EXIT_CODE_NO_APPLICATION_NAME,		/* no application name has been set by the derived class */
 	BASE_EXIT_CODE_ARGS,					/* unable to interpret command-line options */
 	BASE_EXIT_CODE_UNIQUE_APP,				/* another instance is already running */
-	BASE_EXIT_CODE_MAIN_WINDOW,
+	BASE_EXIT_CODE_WINDOW,					/* unable to create a startup window */
 	BASE_EXIT_CODE_INIT_FAIL,
 	BASE_EXIT_CODE_PROGRAM,
 	/*
@@ -211,12 +248,11 @@ typedef enum {
 }
 	BaseExitCode;
 
-GType        base_application_get_type( void );
+GType  base_application_get_type            ( void );
 
-int          base_application_run( BaseApplication *application, int argc, GStrv argv );
+int    base_application_run                 ( BaseApplication *application, int argc, GStrv argv );
 
-gchar       *base_application_get_application_name( const BaseApplication *application );
-BaseBuilder *base_application_get_builder         ( const BaseApplication *application );
+gchar *base_application_get_application_name( const BaseApplication *application );
 
 G_END_DECLS
 
diff --git a/src/nact/base-window.c b/src/nact/base-window.c
index 4f7e982..2831e34 100644
--- a/src/nact/base-window.c
+++ b/src/nact/base-window.c
@@ -39,6 +39,7 @@
 #include <core/na-gtk-utils.h>
 
 #include "base-application.h"
+#include "base-builder.h"
 #include "base-window.h"
 #include "base-gtk-utils.h"
 #include "base-marshal.h"
@@ -46,7 +47,7 @@
 /* private class data
  */
 struct _BaseWindowClassPrivate {
-	void *empty;						/* so that gcc -pedantic is happy */
+	BaseBuilder     *builder;			/* common builder */
 };
 
 /* private instance data
@@ -120,6 +121,8 @@ static void     instance_finalize( GObject *window );
 
 /* initialization process
  */
+static void     setup_parent_vs_application( BaseWindow *window );
+static void     init_gtk_toplevel( BaseWindow *window );
 static gboolean setup_builder( const BaseWindow *window );
 static gboolean load_gtk_toplevel( const BaseWindow *window );
 static gboolean is_gtk_toplevel_initialized( const BaseWindow *window, GtkWindow *gtk_toplevel );
@@ -195,27 +198,13 @@ class_init( BaseWindowClass *klass )
 	object_class->dispose = instance_dispose;
 	object_class->finalize = instance_finalize;
 
-	g_object_class_install_property( object_class, BASE_PROP_PARENT_ID,
-			g_param_spec_pointer(
-					BASE_PROP_PARENT,
-					_( "Parent BaseWindow" ),
-					_( "A pointer (not a reference) to the BaseWindow parent of this BaseWindow" ),
-					G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE ));
-
-	g_object_class_install_property( object_class, BASE_PROP_APPLICATION_ID,
-			g_param_spec_pointer(
-					BASE_PROP_APPLICATION,
-					_( "BaseApplication" ),
-					_( "A pointer (not a reference) to the BaseApplication instance" ),
-					G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE ));
-
 	g_object_class_install_property( object_class, BASE_PROP_XMLUI_FILENAME_ID,
 			g_param_spec_string(
 					BASE_PROP_XMLUI_FILENAME,
 					_( "XML UI filename" ),
 					_( "The filename which contains the XML UI definition" ),
 					"",
-					G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE ));
+					G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE ));
 
 	g_object_class_install_property( object_class, BASE_PROP_HAS_OWN_BUILDER_ID,
 			g_param_spec_boolean(
@@ -223,7 +212,7 @@ class_init( BaseWindowClass *klass )
 					_( "Has its own GtkBuilder" ),
 					_( "Whether this BaseWindow reallocates a new GtkBuilder each time it is opened" ),
 					FALSE,
-					G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE ));
+					G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE ));
 
 	g_object_class_install_property( object_class, BASE_PROP_TOPLEVEL_NAME_ID,
 			g_param_spec_string(
@@ -231,7 +220,21 @@ class_init( BaseWindowClass *klass )
 					_( "Toplevel name" ),
 					_( "The internal GtkBuildable name of the toplevel window" ),
 					"",
-					G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE ));
+					G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE ));
+
+	g_object_class_install_property( object_class, BASE_PROP_APPLICATION_ID,
+			g_param_spec_pointer(
+					BASE_PROP_APPLICATION,
+					_( "BaseApplication" ),
+					_( "A pointer (not a reference) to the BaseApplication instance" ),
+					G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE ));
+
+	g_object_class_install_property( object_class, BASE_PROP_PARENT_ID,
+			g_param_spec_pointer(
+					BASE_PROP_PARENT,
+					_( "Parent BaseWindow" ),
+					_( "A pointer (not a reference) to the BaseWindow parent of this BaseWindow" ),
+					G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE ));
 
 	g_object_class_install_property( object_class, BASE_PROP_WSP_NAME_ID,
 			g_param_spec_string(
@@ -243,6 +246,8 @@ class_init( BaseWindowClass *klass )
 
 	klass->private = g_new0( BaseWindowClassPrivate, 1 );
 
+	klass->private->builder = base_builder_new();
+
 	klass->initialize_gtk_toplevel = do_initialize_gtk_toplevel;
 	klass->initialize_base_window = do_initialize_base_window;
 	klass->all_widgets_showed = NULL;
@@ -464,25 +469,66 @@ instance_set_property( GObject *object, guint property_id, const GValue *value,
 	}
 }
 
+/*
+ * it is time here to initialize the Gtk toplevel if this has not already
+ * been done - We do this early in the build process, and this may trigger
+ * some error conditions (mainly if the toplevel name is not found in the
+ * xml ui filename)
+ */
 static void
 instance_constructed( GObject *window )
 {
 	static const gchar *thisfn = "base_window_instance_constructed";
 	BaseWindow *self;
+	BaseWindowPrivate *priv;
 
 	g_return_if_fail( BASE_IS_WINDOW( window ));
 
 	self = BASE_WINDOW( window );
+	priv = self->private;
 
-	if( !self->private->dispose_has_run ){
-		g_debug( "%s: window=%p (%s)", thisfn, ( void * ) window, G_OBJECT_TYPE_NAME( window ));
-
-		g_debug( "%s: application=%p", thisfn, ( void * ) self->private->application );
+	if( !priv->dispose_has_run ){
 
 		/* chain up to the parent class */
 		if( G_OBJECT_CLASS( st_parent_class )->constructed ){
 			G_OBJECT_CLASS( st_parent_class )->constructed( window );
 		}
+
+		g_debug( "%s: window=%p (%s)", thisfn, ( void * ) window, G_OBJECT_TYPE_NAME( window ));
+
+		setup_parent_vs_application( self );
+		init_gtk_toplevel( self );
+		base_window_run( self );
+
+	}
+}
+
+static void
+setup_parent_vs_application( BaseWindow *window )
+{
+	if( !window->private->application ){
+		g_return_if_fail( window->private->parent );
+		g_return_if_fail( BASE_IS_WINDOW( window->private->parent ));
+
+		window->private->application = window->private->parent->private->application;
+	}
+
+	g_return_if_fail( BASE_IS_APPLICATION( window->private->application ));
+}
+
+static void
+init_gtk_toplevel( BaseWindow *window )
+{
+	if( setup_builder( window ) &
+		load_gtk_toplevel( window )){
+
+		g_return_if_fail( GTK_IS_WINDOW( window->private->gtk_toplevel ));
+
+		if( !is_gtk_toplevel_initialized( window, window->private->gtk_toplevel )){
+
+			g_signal_emit_by_name( window, BASE_SIGNAL_INITIALIZE_GTK, window->private->gtk_toplevel );
+			set_gtk_toplevel_initialized( window, window->private->gtk_toplevel, TRUE );
+		}
 	}
 }
 
@@ -669,8 +715,7 @@ setup_builder( const BaseWindow *window )
 	if( window->private->has_own_builder ){
 		window->private->builder = base_builder_new();
 	} else {
-		g_return_val_if_fail( BASE_IS_APPLICATION( window->private->application ), FALSE );
-		window->private->builder = base_application_get_builder( window->private->application );
+		window->private->builder = BASE_WINDOW_GET_CLASS( window )->private->builder;
 	}
 
 	/* load the XML definition from the UI file
diff --git a/src/nact/base-window.h b/src/nact/base-window.h
index 7932f7b..cd11d32 100644
--- a/src/nact/base-window.h
+++ b/src/nact/base-window.h
@@ -37,41 +37,24 @@
  * @short_description: the BaseWindow base window class definition
  * @include: base-window.h
  *
- * This is a base class which encapsulates a Gtk+ windows.
- * It works together with the BaseApplication class to run a Gtk+
- * application.
+ * This is a base class which manages a Gtk+ toplevel.
  *
- * Note that two properties of #BaseApplication may be overriden on a
- * per-#BaseWindow basis. These are :
- *
- * - the #GtkBuilder UI manager
- *   the application has one global UI manager, but each window may
- *   have its own, provided that it is willing to reallocate a new
- *   one each time the window is opened.
+ * One global UI manager is allocated at #BaseWindow class level.
+ * Each window may have its own, provided that it is willing to
+ * reinstanciate a new builder each time the window is opened.
  *
  *   Cf. http://bugzilla.gnome.org/show_bug.cgi?id=589746 against
  *   Gtk+ 2.16 : a GtkFileChooserWidget embedded in a GtkAssistant is
  *   not displayed when run more than once. As a work-around, reload
- *   the XML ui each time we run an assistant !
- *
- * - the filename which handled the window XML definition
- *   the application provides with one global default file, but each
- *   window may decide to provide its own.
- *
- *   Cf. http://bugzilla.gnome.org/show_bug.cgi?id=579345 against
- *   GtkBuilder : duplicate ids are no more allowed in a file. But we
- *   require this ability to have the same widget definition
- *   (ActionsList) in main window and export assistant.
- *   As a work-around, we have XML definition of export assistant in
- *   its own file.
- *   Another work-around could have be to let the IActionsList
- *   interface asks from the actual widget name to its implementor...
+ *   the XML ui in a new builder each time we run an assistant !
  *
- * Note also that having its own builder implies loading in it the required
- * XML file which holds the needed UI definition, and so even it this
+ * Note that having its own builder implies loading in it the required
+ * XML file which holds the needed UI definition, and so even if this
  * same XML file has already been load in the common builder.
  */
 
+#include <gtk/gtk.h>
+
 #include "base-application.h"
 
 G_BEGIN_DECLS
@@ -192,13 +175,19 @@ typedef struct {
 /**
  * Properties defined by the BaseWindow class.
  * They should be provided at object instanciation time.
+ *
+ * Either PARENT or APPLICATION must be provided at instanciation time.
+ * Instanciation time also requires:
+ * - XMLUI_FILENAME
+ * - TOPLEVEL_NAME
+ * - HAS_OWN_BUILDER
  */
-#define BASE_PROP_PARENT						"base-window-parent"
-#define BASE_PROP_APPLICATION					"base-window-application"
-#define BASE_PROP_XMLUI_FILENAME				"base-window-xmlui-filename"
-#define BASE_PROP_HAS_OWN_BUILDER				"base-window-has-own-builder"
-#define BASE_PROP_TOPLEVEL_NAME					"base-window-toplevel-name"
-#define BASE_PROP_WSP_NAME						"base-window-wsp-name"
+#define BASE_PROP_PARENT						"base-prop-window-parent"
+#define BASE_PROP_APPLICATION					"base-prop-window-application"
+#define BASE_PROP_XMLUI_FILENAME				"base-prop-window-xmlui-filename"
+#define BASE_PROP_HAS_OWN_BUILDER				"base-prop-window-has-own-builder"
+#define BASE_PROP_TOPLEVEL_NAME					"base-prop-window-toplevel-name"
+#define BASE_PROP_WSP_NAME						"base-prop-window-wsp-name"
 
 /**
  * Signals defined by the BaseWindow class.
@@ -216,10 +205,10 @@ typedef struct {
  * as a signal handler or as a virtual method if it is a class derived from
  * BaseWindow.
  */
-#define BASE_SIGNAL_INITIALIZE_GTK				"base-window-initialize-gtk"
-#define BASE_SIGNAL_INITIALIZE_WINDOW			"base-window-initialize-window"
-#define BASE_SIGNAL_ALL_WIDGETS_SHOWED			"base-window-all-widgets-showed"
-#define BASE_SIGNAL_WILLING_TO_QUIT				"base-window-willing-to-quit"
+#define BASE_SIGNAL_INITIALIZE_GTK				"base-signal-window-initialize-gtk"
+#define BASE_SIGNAL_INITIALIZE_WINDOW			"base-signal-window-initialize-window"
+#define BASE_SIGNAL_ALL_WIDGETS_SHOWED			"base-signal-window-all-widgets-showed"
+#define BASE_SIGNAL_WILLING_TO_QUIT				"base-signal-window-willing-to-quit"
 
 GType            base_window_get_type( void );
 
diff --git a/src/nact/nact-application.c b/src/nact/nact-application.c
index 89064ff..12183cc 100644
--- a/src/nact/nact-application.c
+++ b/src/nact/nact-application.c
@@ -77,8 +77,10 @@ static void     class_init( NactApplicationClass *klass );
 static void     instance_init( GTypeInstance *instance, gpointer klass );
 static void     instance_dispose( GObject *application );
 static void     instance_finalize( GObject *application );
-static gboolean appli_manage_options( const BaseApplication *application );
-static GObject *appli_main_window_new( const BaseApplication *application, int *code );
+
+static gboolean appli_manage_options( BaseApplication *application );
+static gboolean appli_init_application( BaseApplication *application );
+static gboolean appli_create_windows( BaseApplication *application );
 
 GType
 nact_application_get_type( void )
@@ -136,7 +138,8 @@ class_init( NactApplicationClass *klass )
 
 	appli_class = BASE_APPLICATION_CLASS( klass );
 	appli_class->manage_options = appli_manage_options;
-	appli_class->main_window_new = appli_main_window_new;
+	appli_class->init_application = appli_init_application;
+	appli_class->create_windows = appli_create_windows;
 }
 
 static void
@@ -231,7 +234,7 @@ nact_application_new( void )
  * overriden to manage command-line options
  */
 static gboolean
-appli_manage_options( const BaseApplication *application )
+appli_manage_options( BaseApplication *application )
 {
 	static const gchar *thisfn = "nact_application_appli_manage_options";
 	gboolean ret;
@@ -265,27 +268,62 @@ appli_manage_options( const BaseApplication *application )
 }
 
 /*
- * create the main window
+ * initialize the application
  */
-static GObject *
-appli_main_window_new( const BaseApplication *application, int *code )
+static gboolean
+appli_init_application( BaseApplication *application )
 {
-	static const gchar *thisfn = "nact_application_appli_main_window_new";
-	NactApplication *appli;
-	NactMainWindow *main_window;
+	static const gchar *thisfn = "nact_application_appli_init_application";
+	gboolean ret;
+	NactApplicationPrivate *priv;
 
-	g_return_val_if_fail( NACT_IS_APPLICATION( application ), NULL );
+	g_return_val_if_fail( NACT_IS_APPLICATION( application ), FALSE );
+
+	g_debug( "%s: application=%p", thisfn, ( void * ) application );
+
+	ret = TRUE;
+	priv = NACT_APPLICATION( application )->private;
+
+	/* create the NAPivot object (loading the plugins and so on)
+	 * after having dealt with command-line arguments
+	 */
+	priv->updater = na_updater_new();
+	na_pivot_set_loadable( NA_PIVOT( priv->updater ), PIVOT_LOAD_ALL );
+
+	/* call parent class */
+	if( ret && BASE_APPLICATION_CLASS( st_parent_class )->manage_options ){
+		ret = BASE_APPLICATION_CLASS( st_parent_class )->manage_options( application );
+	}
 
-	g_debug( "%s: application=%p, code=%p (%d)", thisfn, ( void * ) application, ( void * ) code, *code );
+	return( ret );
+}
 
-	appli = NACT_APPLICATION( application );
+/*
+ * create application startup windows
+ */
+static gboolean
+appli_create_windows( BaseApplication *application )
+{
+	static const gchar *thisfn = "nact_application_appli_create_windows";
+	gboolean ret;
+	NactMainWindow *window;
 
-	appli->private->updater = na_updater_new();
-	na_pivot_set_loadable( NA_PIVOT( appli->private->updater ), PIVOT_LOAD_ALL );
+	g_return_val_if_fail( NACT_IS_APPLICATION( application ), FALSE );
 
-	main_window = nact_main_window_new( appli );
+	g_debug( "%s: application=%p", thisfn, ( void * ) application );
 
-	return( G_OBJECT( main_window ));
+	/* creating main window
+	 */
+	window = nact_main_window_new( NACT_APPLICATION( application ));
+	if( window ){
+		g_return_val_if_fail( NACT_IS_MAIN_WINDOW( window ), FALSE );
+		ret = TRUE;
+	} else {
+		ret = FALSE;
+		g_object_set( G_OBJECT( application ), BASE_PROP_CODE, BASE_EXIT_CODE_WINDOW, NULL );
+	}
+
+	return( ret );
 }
 
 /**



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]