[nautilus-actions] Fix main window destroy process



commit 0d5e65151d9c18536e8033f4ad14bf81dc4853a7
Author: Pierre Wieser <pwieser trychlos org>
Date:   Mon Jan 30 05:46:13 2012 +0100

    Fix main window destroy process

 ChangeLog                   |   19 +++++
 src/nact/base-window.c      |   24 ++++++
 src/nact/base-window.h      |    1 +
 src/nact/nact-main-window.c |    9 +-
 src/nact/nact-match-list.c  |   12 ++-
 src/nact/nact-tree-model.c  |    5 +
 src/nact/nact-tree-view.c   |  175 +++++++++++++++++++++----------------------
 src/nact/nact-tree-view.h   |    8 ++
 8 files changed, 157 insertions(+), 96 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 0b24882..edf48ef 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2012-01-30 Pierre Wieser <pwieser trychlos org>
+
+	* src/nact/base-window.c:
+	* src/nact/base-window.h: Define a new BASE_PROP_DESTROY_ON_DISPOSE property.
+	When set, the underlying Gtk toplevel is destroyed when the BaseWindow is
+	unreffed.
+
+	* src/nact/nact-main-window.c (nact_main_window_new): Set the
+	DestroyOnDispose property.
+
+	* src/nact/nact-match-list.c (on_instance_finalized): Do not try to clear
+	the NactTreeModel after it has been finalized.
+
+	* src/nact/nact-tree-model.c (nact_tree_model_new): Improve comment.
+
+	* src/nact/nact-tree-view.c:
+	* src/nact/nact-tree-view.h(initialize_gtk): no more mimic a signal
+	handler.
+
 2012-01-29 Pierre Wieser <pwieser trychlos org>
 
 	* src/nact/nact-tree-model.c (nact_tree_model_new): Unref filter model.
diff --git a/src/nact/base-window.c b/src/nact/base-window.c
index 34ed57e..9dafbce 100644
--- a/src/nact/base-window.c
+++ b/src/nact/base-window.c
@@ -63,6 +63,7 @@ struct _BaseWindowPrivate {
 	gboolean         has_own_builder;
 	gchar           *toplevel_name;
 	gchar           *wsp_name;
+	gboolean         destroy_on_dispose;
 
 	/* internals
 	 */
@@ -83,6 +84,7 @@ enum {
 	BASE_PROP_HAS_OWN_BUILDER_ID,
 	BASE_PROP_TOPLEVEL_NAME_ID,
 	BASE_PROP_WSP_NAME_ID,
+	BASE_PROP_DESTROY_ON_DISPOSE_ID,
 
 	BASE_PROP_N_PROPERTIES
 };
@@ -243,6 +245,14 @@ class_init( BaseWindowClass *klass )
 					"",
 					G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE ));
 
+	g_object_class_install_property( object_class, BASE_PROP_DESTROY_ON_DISPOSE_ID,
+			g_param_spec_boolean(
+					BASE_PROP_DESTROY_ON_DISPOSE,
+					_( "Destroy the Gtk toplevel" ),
+					_( "Whether the embedded Gtk Toplevel should be destroyed at dispose time" ),
+					FALSE,
+					G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE ));
+
 	klass->private = g_new0( BaseWindowClassPrivate, 1 );
 
 	klass->private->builder = base_builder_new();
@@ -393,6 +403,10 @@ instance_get_property( GObject *object, guint property_id, GValue *value, GParam
 				g_value_set_string( value, self->private->wsp_name );
 				break;
 
+			case BASE_PROP_DESTROY_ON_DISPOSE_ID:
+				g_value_set_boolean( value, self->private->destroy_on_dispose );
+				break;
+
 			default:
 				G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, spec );
 				break;
@@ -438,6 +452,10 @@ instance_set_property( GObject *object, guint property_id, const GValue *value,
 				self->private->wsp_name = g_value_dup_string( value );
 				break;
 
+			case BASE_PROP_DESTROY_ON_DISPOSE_ID:
+				self->private->destroy_on_dispose = g_value_get_boolean( value );
+				break;
+
 			default:
 				G_OBJECT_WARN_INVALID_PROPERTY_ID( object, property_id, spec );
 				break;
@@ -520,6 +538,12 @@ instance_dispose( GObject *window )
 		}
 		g_list_free( priv->signals );
 
+		/* at least the main window should have this property set
+		 */
+		if( priv->destroy_on_dispose ){
+			gtk_widget_destroy( GTK_WIDGET( priv->gtk_toplevel ));
+		}
+
 #if 0
 		if( is_main_window( BASE_WINDOW( window ))){
 			g_debug( "%s: quitting main window", thisfn );
diff --git a/src/nact/base-window.h b/src/nact/base-window.h
index ff472f8..5c94805 100644
--- a/src/nact/base-window.h
+++ b/src/nact/base-window.h
@@ -189,6 +189,7 @@ typedef struct {
 #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"
+#define BASE_PROP_DESTROY_ON_DISPOSE			"base-prop-window-destroy-on-dispose"
 
 /**
  * Signals defined by the BaseWindow class.
diff --git a/src/nact/nact-main-window.c b/src/nact/nact-main-window.c
index cd82299..b2f90f4 100644
--- a/src/nact/nact-main-window.c
+++ b/src/nact/nact-main-window.c
@@ -787,10 +787,11 @@ nact_main_window_new( const NactApplication *application )
 	g_return_val_if_fail( NACT_IS_APPLICATION( application ), NULL );
 
 	window = g_object_new( NACT_TYPE_MAIN_WINDOW,
-			BASE_PROP_APPLICATION,    application,
-			BASE_PROP_XMLUI_FILENAME, st_xmlui_filename,
-			BASE_PROP_TOPLEVEL_NAME,  st_toplevel_name,
-			BASE_PROP_WSP_NAME,       st_wsp_name,
+			BASE_PROP_APPLICATION,        application,
+			BASE_PROP_XMLUI_FILENAME,     st_xmlui_filename,
+			BASE_PROP_TOPLEVEL_NAME,      st_toplevel_name,
+			BASE_PROP_WSP_NAME,           st_wsp_name,
+			BASE_PROP_DESTROY_ON_DISPOSE, TRUE,
 			NULL );
 
 	if( !base_window_init( BASE_WINDOW( window ))){
diff --git a/src/nact/nact-match-list.c b/src/nact/nact-match-list.c
index 31d2dbf..ca33f8e 100644
--- a/src/nact/nact-match-list.c
+++ b/src/nact/nact-match-list.c
@@ -1067,8 +1067,6 @@ static void
 on_instance_finalized( MatchListData *data, BaseWindow *window )
 {
 	static const gchar *thisfn = "nact_match_list_on_instance_finalized";
-	GtkTreeModel *model;
-	GtkTreeSelection *selection;
 
 	g_return_if_fail( data != NULL );
 
@@ -1079,10 +1077,16 @@ on_instance_finalized( MatchListData *data, BaseWindow *window )
 
 	g_object_set_data( G_OBJECT( window ), data->tab_name, NULL );
 
-	model = gtk_tree_view_get_model( data->listview );
-	selection = gtk_tree_view_get_selection( data->listview );
+	/* This function is called when the NactMainWindow is about to be finalized.
+	 * At this time, the NactTreeModel has already been finalized.
+	 * It is so too late to try to clear it...
+	 */
+#if 0
+	GtkTreeModel *model = gtk_tree_view_get_model( data->listview );
+	GtkTreeSelection *selection = gtk_tree_view_get_selection( data->listview );
 	gtk_tree_selection_unselect_all( selection );
 	gtk_list_store_clear( GTK_LIST_STORE( model ));
+#endif
 
 	g_free( data->tab_name );
 	g_free( data->item_header );
diff --git a/src/nact/nact-tree-model.c b/src/nact/nact-tree-model.c
index 2749fc1..20ae21a 100644
--- a/src/nact/nact-tree-model.c
+++ b/src/nact/nact-tree-model.c
@@ -300,6 +300,11 @@ instance_finalize( GObject *object )
  *
  * The returned reference is owned by the #GtkTreeView, which will automatically
  * take care of g_object_unref() its tree model when destroying its widget.
+ *
+ * Called from NactTreeView::initialize_gtk() method
+ *   [..]
+ *     which happens to be eventually called from NactMainWindow::on_initialize_gtk()
+ *     signal handler.
  */
 NactTreeModel *
 nact_tree_model_new( BaseWindow *window, GtkTreeView *treeview, NactTreeMode mode )
diff --git a/src/nact/nact-tree-view.c b/src/nact/nact-tree-view.c
index 488eff7..058203d 100644
--- a/src/nact/nact-tree-view.c
+++ b/src/nact/nact-tree-view.c
@@ -65,25 +65,8 @@ struct _NactTreeViewPrivate {
 	gboolean       notify_allowed;
 
 	/* runtime data
-	 *
-	 * Rationale:
-	 *
-	 * In Gtk2, we used to nact_tree_view_new() from
-	 * nact_main_window:on_instance_constructed().
-	 * This let us connect to on-base-initialize-gtk signal before it was
-	 * emitted, and so initialize the treeview on the handler.
-	 *
-	 * With Gtk3, we have to wait until the Gtk hierarchy of NactMainWindow
-	 * be actually built in order to be able to access to the embedded
-	 * GtkTreeView. As a consequence, nact_tree_view_new() has to be delayed
-	 * until nact_main_window_on_initialize_gtk().
-	 *
-	 * And so we no more can rely on the on-base-initialize-gtk signal to
-	 * initialize the view. So force a call to the handler from
-	 * on_base_initialize_view() handler.
 	 */
 	GtkTreeView   *tree_view;
-	gboolean       gtk_initialized;
 };
 
 /* instance properties
@@ -141,7 +124,7 @@ static void       instance_constructed( GObject *object );
 static void       instance_dispose( GObject *application );
 static void       instance_finalize( GObject *application );
 
-static void       on_base_initialize_gtk( BaseWindow *window, GtkWindow *toplevel, gpointer user_data );
+static void       initialize_gtk( NactTreeView *view );
 static void       on_base_initialize_view( BaseWindow *window, gpointer user_data );
 static void       on_base_all_widgets_showed( BaseWindow *window, gpointer user_data );
 static gboolean   on_button_press_event( GtkWidget *widget, GdkEventButton *event, BaseWindow *window );
@@ -487,7 +470,6 @@ instance_init( GTypeInstance *instance, gpointer klass )
 	self->private = g_new0( NactTreeViewPrivate, 1 );
 
 	self->private->dispose_has_run = FALSE;
-	self->private->gtk_initialized = FALSE;
 }
 
 static void
@@ -599,6 +581,8 @@ instance_constructed( GObject *object )
 				G_CALLBACK( on_base_all_widgets_showed ));
 
 		g_object_set_data( G_OBJECT( priv->window ), WINDOW_DATA_TREE_VIEW, object );
+
+		initialize_gtk( NACT_TREE_VIEW( object ));
 	}
 }
 
@@ -624,9 +608,6 @@ instance_dispose( GObject *object )
 		gtk_tree_store_clear( ts_model );
 		g_debug( "%s: tree store cleared", thisfn );
 
-		g_debug( "%s: nact_tree_model_ref_count=%d", thisfn, G_OBJECT( model )->ref_count );
-		g_object_unref( model );
-
 		if( self->private->mode == TREE_MODE_EDITION ){
 			nact_tree_ieditable_terminate( NACT_TREE_IEDITABLE( self ));
 		}
@@ -670,6 +651,9 @@ instance_finalize( GObject *instance )
  * Returns: a newly allocated NactTreeView object, which will be owned
  * by the caller. It is useless to unref it as it will automatically
  * auto-destroys itself at @window finalization.
+ *
+ * This function is called from NactMainWindow::on_base_initialize_gtk()
+ * signal handler, thus only once during the application life.
  */
 NactTreeView *
 nact_tree_view_new( BaseWindow *window, GtkContainer *parent, const gchar *treeview_name, NactTreeMode mode )
@@ -692,11 +676,15 @@ nact_tree_view_new( BaseWindow *window, GtkContainer *parent, const gchar *treev
 	return( view );
 }
 
+/*
+ * called from instance_constructed()
+ *   from nact_tree_view_new()
+ *     from NactMainWindow::on_base_initialize_gtk() signal handler
+ */
 static void
-on_base_initialize_gtk( BaseWindow *window, GtkWindow *toplevel, gpointer user_data )
+initialize_gtk( NactTreeView *items_view )
 {
-	static const gchar *thisfn = "nact_tree_view_on_base_initialize_gtk";
-	NactTreeView *items_view;
+	static const gchar *thisfn = "nact_tree_view_initialize_gtk";
 	GtkTreeView *treeview;
 	GtkWidget *label;
 	GtkTreeViewColumn *column;
@@ -704,56 +692,48 @@ on_base_initialize_gtk( BaseWindow *window, GtkWindow *toplevel, gpointer user_d
 	GtkTreeSelection *selection;
 	GList *renderers;
 
-	items_view = NACT_TREE_VIEW( g_object_get_data( G_OBJECT( window ), WINDOW_DATA_TREE_VIEW ));
-
-	if( !items_view->private->dispose_has_run ){
-		g_debug( "%s: window=%p (%s), toplevel=%p (%s), user_data=%p",
-				thisfn, ( void * ) window, G_OBJECT_TYPE_NAME( window ),
-				( void * ) toplevel, G_OBJECT_TYPE_NAME( toplevel ), ( void * ) user_data );
+	g_debug( "%s: items_view=%p", thisfn, ( void * ) items_view );
 
-		treeview = GTK_TREE_VIEW( get_tree_view( items_view ));
-		nact_tree_model_new( window, treeview, items_view->private->mode );
+	treeview = GTK_TREE_VIEW( get_tree_view( items_view ));
+	nact_tree_model_new( items_view->private->window, treeview, items_view->private->mode );
 
-		/* associates the ItemsView to the label */
-		label = na_gtk_utils_find_widget_by_name( items_view->private->parent, "ActionsListLabel" );
-		gtk_label_set_mnemonic_widget( GTK_LABEL( label ), GTK_WIDGET( treeview ));
+	/* associates the ItemsView to the label */
+	label = na_gtk_utils_find_widget_by_name( items_view->private->parent, "ActionsListLabel" );
+	gtk_label_set_mnemonic_widget( GTK_LABEL( label ), GTK_WIDGET( treeview ));
 
-		/* create visible columns on the tree view
-		 */
-		column = gtk_tree_view_column_new_with_attributes(
-				"icon",
-				gtk_cell_renderer_pixbuf_new(),
-				"pixbuf", TREE_COLUMN_ICON,
-				NULL );
-		gtk_tree_view_append_column( treeview, column );
-
-		renderer = gtk_cell_renderer_text_new();
-		column = gtk_tree_view_column_new_with_attributes(
-				"label",
-				renderer,
-				"text", TREE_COLUMN_LABEL,
-				NULL );
-		gtk_tree_view_column_set_sort_column_id( column, TREE_COLUMN_LABEL );
-		gtk_tree_view_append_column( treeview, column );
-
-		/* allow multiple selection
-		 */
-		selection = gtk_tree_view_get_selection( treeview );
-		gtk_tree_selection_set_mode( selection, GTK_SELECTION_MULTIPLE );
+	/* create visible columns on the tree view
+	 */
+	column = gtk_tree_view_column_new_with_attributes(
+			"icon",
+			gtk_cell_renderer_pixbuf_new(),
+			"pixbuf", TREE_COLUMN_ICON,
+			NULL );
+	gtk_tree_view_append_column( treeview, column );
 
-		/* misc properties
-		 */
-		gtk_tree_view_set_enable_tree_lines( treeview, TRUE );
+	renderer = gtk_cell_renderer_text_new();
+	column = gtk_tree_view_column_new_with_attributes(
+			"label",
+			renderer,
+			"text", TREE_COLUMN_LABEL,
+			NULL );
+	gtk_tree_view_column_set_sort_column_id( column, TREE_COLUMN_LABEL );
+	gtk_tree_view_append_column( treeview, column );
 
-		if( items_view->private->mode == TREE_MODE_EDITION ){
-			column = gtk_tree_view_get_column( treeview, TREE_COLUMN_LABEL );
-			renderers = gtk_cell_layout_get_cells( GTK_CELL_LAYOUT( column ));
-			renderer = GTK_CELL_RENDERER( renderers->data );
-			gtk_tree_view_column_set_cell_data_func(
-					column, renderer, ( GtkTreeCellDataFunc ) display_label, items_view, NULL );
-		}
+	/* allow multiple selection
+	 */
+	selection = gtk_tree_view_get_selection( treeview );
+	gtk_tree_selection_set_mode( selection, GTK_SELECTION_MULTIPLE );
 
-		items_view->private->gtk_initialized = TRUE;
+	/* misc properties
+	 */
+	gtk_tree_view_set_enable_tree_lines( treeview, TRUE );
+
+	if( items_view->private->mode == TREE_MODE_EDITION ){
+		column = gtk_tree_view_get_column( treeview, TREE_COLUMN_LABEL );
+		renderers = gtk_cell_layout_get_cells( GTK_CELL_LAYOUT( column ));
+		renderer = GTK_CELL_RENDERER( renderers->data );
+		gtk_tree_view_column_set_cell_data_func(
+				column, renderer, ( GtkTreeCellDataFunc ) display_label, items_view, NULL );
 	}
 }
 
@@ -767,26 +747,31 @@ on_base_initialize_view( BaseWindow *window, gpointer user_data )
 
 	items_view = NACT_TREE_VIEW( g_object_get_data( G_OBJECT( window ), WINDOW_DATA_TREE_VIEW ));
 
-	if( !items_view->private->gtk_initialized ){
-		on_base_initialize_gtk( window, base_window_get_gtk_toplevel( window ), NULL );
-	}
-
 	if( !items_view->private->dispose_has_run ){
+
 		g_debug( "%s: window=%p (%s), user_data=%p",
-				thisfn, ( void * ) window, G_OBJECT_TYPE_NAME( window ), ( void * ) user_data );
+				thisfn,
+				( void * ) window, G_OBJECT_TYPE_NAME( window ),
+				( void * ) user_data );
 
 		treeview = GTK_TREE_VIEW( get_tree_view( items_view ));
 		items_view->private->tree_view = treeview;
 
 		/* monitors the selection */
 		selection = gtk_tree_view_get_selection( treeview );
-		base_window_signal_connect( window,
-				G_OBJECT( selection ), "changed", G_CALLBACK( on_selection_changed ));
+		base_window_signal_connect(
+				window,
+				G_OBJECT( selection ),
+				"changed",
+				G_CALLBACK( on_selection_changed ));
 
 		/* delay all other signal connections until the widget be realized
 		 */
-		base_window_signal_connect( window,
-				G_OBJECT( treeview ), "realize", G_CALLBACK( on_tree_view_realized ));
+		base_window_signal_connect(
+				window,
+				G_OBJECT( treeview ),
+				"realize",
+				G_CALLBACK( on_tree_view_realized ));
 
 		if( items_view->private->mode == TREE_MODE_EDITION ){
 			nact_tree_ieditable_initialize( NACT_TREE_IEDITABLE( items_view ), treeview, window );
@@ -918,19 +903,31 @@ on_tree_view_realized( GtkWidget *treeview, BaseWindow *window )
 	g_debug( "nact_tree_view_on_tree_view_realized" );
 
 	/* expand/collapse with the keyboard */
-	base_window_signal_connect( window,
-			G_OBJECT( treeview ), "key-press-event", G_CALLBACK( on_key_pressed_event ));
+	base_window_signal_connect(
+			window,
+			G_OBJECT( treeview ),
+			"key-press-event",
+			G_CALLBACK( on_key_pressed_event ));
 
 	/* monitors whether the focus is on the view */
-	base_window_signal_connect( window,
-			G_OBJECT( treeview ), "focus-in-event", G_CALLBACK( on_focus_in ));
-
-	base_window_signal_connect( window,
-			G_OBJECT( treeview ), "focus-out-event", G_CALLBACK( on_focus_out ));
+	base_window_signal_connect(
+			window,
+			G_OBJECT( treeview ),
+			"focus-in-event",
+			G_CALLBACK( on_focus_in ));
+
+	base_window_signal_connect(
+			window,
+			G_OBJECT( treeview ),
+			"focus-out-event",
+			G_CALLBACK( on_focus_out ));
 
 	/* monitors mouse events */
-	base_window_signal_connect( window,
-			G_OBJECT( treeview ), "button-press-event", G_CALLBACK( on_button_press_event ));
+	base_window_signal_connect(
+			window,
+			G_OBJECT( treeview ),
+			"button-press-event",
+			G_CALLBACK( on_button_press_event ));
 
 	/* force the treeview to have the focus at start
 	 * and select the first row if it exists
@@ -1305,7 +1302,9 @@ get_selected_items( NactTreeView *view )
 static GtkWidget *
 get_tree_view( NactTreeView *items_view )
 {
-	return( na_gtk_utils_find_widget_by_name( items_view->private->parent, items_view->private->widget_name ));
+	return( na_gtk_utils_find_widget_by_name(
+			items_view->private->parent,
+			items_view->private->widget_name ));
 }
 
 static void
diff --git a/src/nact/nact-tree-view.h b/src/nact/nact-tree-view.h
index 88a9955..e4b4770 100644
--- a/src/nact/nact-tree-view.h
+++ b/src/nact/nact-tree-view.h
@@ -38,6 +38,14 @@
  * @include: nact-tree-view.h
  *
  * This is a convenience class to manage a read-only items tree view.
+ *
+ * The NactTreeView encapsulates the GtkTreeView which displays the items
+ * list on the left of the main pane.
+ *
+ * It is instanciated from NactMainWindow::on_initialize_gtk().
+ *
+ * A pointer to this NactTreeView is attached to the NactMainWindow at
+ * construction time.
  */
 
 #include <api/na-object-item.h>



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