[nautilus-actions] Defines a new 'base-window-willing-to-quit' stop-with-accumulator signal



commit e6452a1b4a4ca308908b095daffd9e189a5d4005
Author: Pierre Wieser <pwieser trychlos org>
Date:   Thu Feb 17 20:01:26 2011 +0100

    Defines a new 'base-window-willing-to-quit' stop-with-accumulator signal
    
    As other BaseWindow signals, the default object handler converts the signal to a virtual method.
    See also base-window.c for a comment about G_SIGNAL_RUN_LAST vs. G_SIGNAL_RUN_CLEANUP behaviors.

 ChangeLog                                    |    9 ++
 src/nact/base-window.c                       |  106 +++++++++++++++++++++++++-
 src/nact/base-window.h                       |    3 +-
 src/nact/nact-main-window.c                  |   33 +++++----
 src/nact/nact-marshal.def                    |    3 +
 src/nact/nact-menubar-maintainer.c           |   10 +++
 src/nact/nact-menubar-priv.h                 |    1 +
 src/nact/nact-menubar.c                      |    3 +
 src/nact/nautilus-actions-maintainer.actions |    2 +
 9 files changed, 152 insertions(+), 18 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index d0043d8..266da91 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2011-02-17 Pierre Wieser <pwieser trychlos org>
+
+	* src/nact/base-window.h:
+	* src/nact/base-window.c (class_init):
+	Defines a new 'base-window-willing-to-quit' stop-with-accumulator signal.
+
+	* src/nact/nact-main-window.c:
+	Connect to the signal instead of implementing a virtual method.
+
 2011-02-16 Pierre Wieser <pwieser trychlos org>
 
 	* src/core/na-iduplicable.c (interface_base_init):
diff --git a/src/nact/base-window.c b/src/nact/base-window.c
index f40ae34..3457e3a 100644
--- a/src/nact/base-window.c
+++ b/src/nact/base-window.c
@@ -39,6 +39,7 @@
 #include "base-application.h"
 #include "base-window.h"
 #include "base-gtk-utils.h"
+#include "nact-marshal.h"
 
 /* private class data
  */
@@ -97,6 +98,7 @@ enum {
 	INITIALIZE_GTK,
 	INITIALIZE_BASE,
 	ALL_WIDGETS_SHOWED,
+	WILLING_TO_QUIT,
 	LAST_SIGNAL
 };
 
@@ -131,8 +133,10 @@ static void     on_all_widgets_showed_class_handler( BaseWindow *window );
 static gboolean do_run( BaseWindow *window, GtkWindow *toplevel );
 static gboolean is_main_window( BaseWindow *window );
 static gboolean on_delete_event( GtkWidget *widget, GdkEvent *event, BaseWindow *window );
+static gboolean on_is_willing_to_quit_class_handler( BaseWindow *window );
 
 static void     record_connected_signal( BaseWindow *window, GObject *instance, gulong handler_id );
+static gboolean signal_accumulator_false_handled( GSignalInvocationHint *hint, GValue *return_accu, const GValue *handler_return, gpointer dummy);
 static gint     display_dlg( const BaseWindow *parent, GtkMessageType type_message, GtkButtonsType type_buttons, const gchar *primary, const gchar *secondary );
 
 GType
@@ -304,6 +308,45 @@ class_init( BaseWindowClass *klass )
 				g_cclosure_marshal_VOID__VOID,
 				G_TYPE_NONE,
 				0 );
+
+	/**
+	 * BaseWindow::base-window-willing-to-quit:
+	 *
+	 * The signal is emitted when the application is about to terminate,
+	 * to determine if all BaseWindow-derived windows are actually willing
+	 * to quit.
+	 *
+	 * If the window is not willing to quit, then the user handler should
+	 * return %FALSE to stop the signal emission.
+	 *
+	 * Returning %TRUE will let the signal be emitted to other connected
+	 * handlers, eventually authorizing the application to terminate.
+	 *
+	 * Notes about GLib signals.
+	 *
+	 * If the signal is defined as G_SIGNAL_RUN_CLEANUP, then the object
+	 * handler does not participate to the return value of the signal
+	 * (accumulator is not called). More this object handler is triggered
+	 * unconditionnally, event if a user handler has returned %FALSE to
+	 * stop the emission.
+	 *
+	 * Contrarily, if the signal is defined as G_SIGNAL_RUN_LAST, then the
+	 * object handler returned value is taken into account by the accumulator,
+	 * and can participate to the return value for the signal. If a user
+	 * handler returns FALSE to stop the emission, then the object handler
+	 * will not be triggered.
+	 */
+	st_signals[ WILLING_TO_QUIT ] =
+		g_signal_new_class_handler(
+				BASE_SIGNAL_WILLING_TO_QUIT,
+				G_TYPE_FROM_CLASS( klass ),
+				G_SIGNAL_RUN_LAST,
+				G_CALLBACK( on_is_willing_to_quit_class_handler ),
+				( GSignalAccumulator ) signal_accumulator_false_handled,
+				NULL,
+				nact_cclosure_marshal_BOOLEAN__VOID,
+				G_TYPE_BOOLEAN,
+				0 );
 }
 
 static void
@@ -879,7 +922,7 @@ is_main_window( BaseWindow *window )
 }
 
 /*
- * Handler of "delete-event" message connected on the main window Gtk toplevel
+ * Handler of BASE_SIGNAL_WILLING_TO_QUIT signal
  *
  * Our own function does nothing, and let the signal be propagated
  * it so ends up in the default class handler for this signal
@@ -1043,6 +1086,45 @@ base_window_get_widget( const BaseWindow *window, const gchar *name )
 gboolean
 base_window_is_willing_to_quit( const BaseWindow *window )
 {
+	static const gchar *thisfn = "base_window_is_willing_to_quit";
+	gboolean willing_to_quit;
+	GValue instance_params = {0};
+	GValue return_value = {0};
+
+	willing_to_quit = TRUE;
+
+	g_return_val_if_fail( BASE_IS_WINDOW( window ), TRUE );
+
+	if( !window->private->dispose_has_run ){
+		g_debug( "%s: window=%p", thisfn, ( void * ) window );
+
+		g_value_init( &instance_params, G_TYPE_FROM_INSTANCE( window ));
+		g_value_set_instance( &instance_params, ( gpointer ) window );
+
+		g_value_init( &return_value, G_TYPE_BOOLEAN );
+		g_value_set_boolean( &return_value, TRUE );
+
+		g_signal_emitv( &instance_params, st_signals[WILLING_TO_QUIT], 0, &return_value );
+
+		willing_to_quit = g_value_get_boolean( &return_value );
+	}
+
+	return( willing_to_quit );
+}
+
+/*
+ * Handler of BASE_SIGNAL_WILLING_TO_QUIT message connected on the main window Gtk toplevel
+ *
+ * As other BaseWindow signals, the default object handler converts the
+ *  signal to a virtual method.
+ *
+ * Main window should handle this signal in order to trap application termination,
+ * returning %FALSE if it is not willing to quit.
+ */
+static gboolean
+on_is_willing_to_quit_class_handler( BaseWindow *window )
+{
+	static const gchar *thisfn = "base_window_on_is_willing_to_quit_class_handler";
 	gboolean willing_to;
 
 	willing_to = TRUE;
@@ -1050,15 +1132,35 @@ base_window_is_willing_to_quit( const BaseWindow *window )
 	g_return_val_if_fail( BASE_IS_WINDOW( window ), TRUE );
 
 	if( !window->private->dispose_has_run ){
+		g_debug( "%s: window=%p", thisfn, ( void * ) window );
 
 		if( BASE_WINDOW_GET_CLASS( window )->is_willing_to_quit ){
-			BASE_WINDOW_GET_CLASS( window )->is_willing_to_quit( window );
+			willing_to = BASE_WINDOW_GET_CLASS( window )->is_willing_to_quit( window );
 		}
 	}
 
 	return( willing_to );
 }
 
+/*
+ * the first handler which returns FALSE stops the emission
+ * this is used on BASE_SIGNAL_WILLING_TO_QUIT signal
+ */
+static gboolean
+signal_accumulator_false_handled( GSignalInvocationHint *hint, GValue *return_accu, const GValue *handler_return, gpointer dummy)
+{
+	static const gchar *thisfn = "base_window_signal_accumulator_false_handled";
+	gboolean continue_emission;
+	gboolean willing_to_quit;
+
+	willing_to_quit = g_value_get_boolean( handler_return );
+	g_value_set_boolean( return_accu, willing_to_quit );
+	continue_emission = willing_to_quit;
+
+	g_debug( "%s: willing_to handler returns %s", thisfn, willing_to_quit ? "True":"False" );
+	return( continue_emission );
+}
+
 /**
  * base_window_display_error_dlg:
  * @parent: the #BaseWindow parent, may be %NULL.
diff --git a/src/nact/base-window.h b/src/nact/base-window.h
index 0de35f4..7384399 100644
--- a/src/nact/base-window.h
+++ b/src/nact/base-window.h
@@ -203,7 +203,7 @@ typedef struct {
 /**
  * Signals defined by the BaseWindow class.
  *
- * All signals of this class have the same behavior:
+ * All signals of this class share the same behavior:
  *
  * - the message is sent to all derived classes, which are free to
  *   connect to the signal in order to implement their own code;
@@ -219,6 +219,7 @@ typedef struct {
 #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"
 
 GType            base_window_get_type( void );
 
diff --git a/src/nact/nact-main-window.c b/src/nact/nact-main-window.c
index 52077db..70770c1 100644
--- a/src/nact/nact-main-window.c
+++ b/src/nact/nact-main-window.c
@@ -201,7 +201,7 @@ static gboolean   confirm_for_giveup_from_menu( const NactMainWindow *window );
 static void       load_or_reload_items( NactMainWindow *window );
 
 /* application termination */
-static gboolean   base_is_willing_to_quit( const BaseWindow *window );
+static gboolean   on_base_is_willing_to_quit( const BaseWindow *window, gconstpointer user_data );
 static gboolean   on_delete_event( GtkWidget *toplevel, GdkEvent *event, NactMainWindow *window );
 static gboolean   warn_modified( NactMainWindow *window );
 
@@ -340,7 +340,6 @@ class_init( NactMainWindowClass *klass )
 {
 	static const gchar *thisfn = "nact_main_window_class_init";
 	GObjectClass *object_class;
-	BaseWindowClass *base_class;
 
 	g_debug( "%s: klass=%p", thisfn, ( void * ) klass );
 
@@ -390,9 +389,6 @@ class_init( NactMainWindowClass *klass )
 
 	klass->private = g_new0( NactMainWindowClassPrivate, 1 );
 
-	base_class = BASE_WINDOW_CLASS( klass );
-	base_class->is_willing_to_quit = base_is_willing_to_quit;
-
 	/**
 	 * NactMainWindow::main-item-updated:
 	 *
@@ -881,6 +877,11 @@ on_base_initialize_base_window( NactMainWindow *window, gpointer user_data )
 		base_window_signal_connect( BASE_WINDOW( window ),
 				G_OBJECT( base_window_get_gtk_toplevel( BASE_WINDOW( window ))),
 				"delete-event", G_CALLBACK( on_delete_event ));
+
+		/* is willing to quit ?
+		 */
+		base_window_signal_connect( BASE_WINDOW( window ),
+				G_OBJECT( window ), BASE_SIGNAL_WILLING_TO_QUIT, G_CALLBACK( on_base_is_willing_to_quit ));
 	}
 }
 
@@ -1326,24 +1327,26 @@ nact_main_window_quit( NactMainWindow *window )
 	return( terminated );
 }
 
+/*
+ * signal handler
+ * should return %FALSE if it is not willing to quit
+ * this will also stop the emission of the signal (i.e. the first FALSE wins)
+ */
 static gboolean
-base_is_willing_to_quit( const BaseWindow *window )
+on_base_is_willing_to_quit( const BaseWindow *window, gconstpointer user_data )
 {
-	static const gchar *thisfn = "nact_main_window_is_willing_to_quit";
+	static const gchar *thisfn = "nact_main_window_on_base_is_willing_to_quit";
 	gboolean willing_to;
 
-	g_debug( "%s: window=%p", thisfn, ( void * ) window );
+	g_return_val_if_fail( NACT_IS_MAIN_WINDOW( window ), TRUE );
 
 	willing_to = TRUE;
 
-	if( NACT_MAIN_WINDOW( window )->private->is_tree_modified ){
-		willing_to = nact_confirm_logout_run( NACT_MAIN_WINDOW( window ));
-	}
+	if( !NACT_MAIN_WINDOW( window )->private->dispose_has_run ){
+		g_debug( "%s (virtual): window=%p", thisfn, ( void * ) window );
 
-	/* call parent class */
-	if( willing_to ){
-		if( BASE_WINDOW_CLASS( st_parent_class )->is_willing_to_quit ){
-			willing_to = BASE_WINDOW_CLASS( st_parent_class )->is_willing_to_quit( window );
+		if( NACT_MAIN_WINDOW( window )->private->is_tree_modified ){
+			willing_to = nact_confirm_logout_run( NACT_MAIN_WINDOW( window ));
 		}
 	}
 
diff --git a/src/nact/nact-marshal.def b/src/nact/nact-marshal.def
index 4623a90..c88f1dd 100644
--- a/src/nact/nact-marshal.def
+++ b/src/nact/nact-marshal.def
@@ -1,3 +1,6 @@
+# BaseWindow:: BASE_SIGNAL_WILLING_TO_QUIT
+BOOLEAN:VOID
+#
 # NactTreeView:: TREE_SIGNAL_COUNT_CHANGED
 VOID:BOOLEAN,INT,INT,INT
 #
diff --git a/src/nact/nact-menubar-maintainer.c b/src/nact/nact-menubar-maintainer.c
index 4b226b7..75dc15f 100644
--- a/src/nact/nact-menubar-maintainer.c
+++ b/src/nact/nact-menubar-maintainer.c
@@ -116,3 +116,13 @@ nact_menubar_maintainer_on_dump_clipboard( GtkAction *action, BaseWindow *window
 {
 	nact_clipboard_dump( nact_main_window_get_clipboard( NACT_MAIN_WINDOW( window )));
 }
+
+/*
+ * Test a miscellaneous function
+ */
+void
+nact_menubar_maintainer_on_test_function( GtkAction *action, BaseWindow *window )
+{
+	gboolean is_willing = base_window_is_willing_to_quit( BASE_WINDOW( window ));
+	g_debug( "nact_menubar_maintainer_on_test_function: willing_to=%s", is_willing ? "True":"False" );
+}
diff --git a/src/nact/nact-menubar-priv.h b/src/nact/nact-menubar-priv.h
index 64c98c2..e49d021 100644
--- a/src/nact/nact-menubar-priv.h
+++ b/src/nact/nact-menubar-priv.h
@@ -158,6 +158,7 @@ void nact_menubar_maintainer_on_dump_selection       ( GtkAction *action, BaseWi
 void nact_menubar_maintainer_on_brief_tree_store_dump( GtkAction *action, BaseWindow *window );
 void nact_menubar_maintainer_on_list_modified_items  ( GtkAction *action, BaseWindow *window );
 void nact_menubar_maintainer_on_dump_clipboard       ( GtkAction *action, BaseWindow *window );
+void nact_menubar_maintainer_on_test_function        ( GtkAction *action, BaseWindow *window );
 
 void nact_menubar_tools_on_update_sensitivities( const NactMenubar *bar );
 
diff --git a/src/nact/nact-menubar.c b/src/nact/nact-menubar.c
index bf5c92b..59dd682 100644
--- a/src/nact/nact-menubar.c
+++ b/src/nact/nact-menubar.c
@@ -150,6 +150,9 @@ static const GtkActionEntry entries[] = {
 				/* i18n: tooltip displayed in the status bar when selecting the DumpClipboard item */
 				N_( "Dump the content of the clipboard object" ),
 				G_CALLBACK( nact_menubar_maintainer_on_dump_clipboard ) },
+		{ "FunctionTest", NULL, "_Test a function", NULL,
+				"Test a function (see nact-menubar-maintainer.c",
+				G_CALLBACK( nact_menubar_maintainer_on_test_function ) },
 
 		{ "HelpItem" , GTK_STOCK_HELP, N_( "Contents" ), "F1",
 				/* i18n: tooltip displayed in the status bar when selecting the Help item */
diff --git a/src/nact/nautilus-actions-maintainer.actions b/src/nact/nautilus-actions-maintainer.actions
index 9dca50e..98a1a65 100644
--- a/src/nact/nautilus-actions-maintainer.actions
+++ b/src/nact/nautilus-actions-maintainer.actions
@@ -7,6 +7,7 @@
                 <menuitem action="BriefTreeStoreDumpItem" />
                 <menuitem action="ListModifiedItems" />
                 <menuitem action="DumpClipboard" />
+                <menuitem action="FunctionTest" />
             </menu>
         </placeholder>
     </menubar>
@@ -16,5 +17,6 @@
                 <toolitem action="BriefTreeStoreDumpItem" />
                 <toolitem action="ListModifiedItems" />
                 <toolitem action="DumpClipboard" />
+                <toolitem action="FunctionTest" />
     </toolbar>
 </ui>



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