[nautilus-actions] Fix primary clipboard management



commit 2ae6fc3572fe360198727c0ab9e67fef4774b832
Author: Pierre Wieser <pwieser trychlos org>
Date:   Sat Jan 16 21:59:54 2010 +0100

    Fix primary clipboard management

 ChangeLog                                 |    8 ++
 TODO                                      |   30 ++---
 nautilus-actions/nact/nact-clipboard.c    |  190 ++++++++++++++++++-----------
 nautilus-actions/nact/nact-main-menubar.c |    5 +-
 4 files changed, 143 insertions(+), 90 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index b14babc..9a67616 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2009-01-16 Pierre Wieser <pwieser trychlos org>
+
+	Fix cut/copy/paste dynamic.
+
+	* nautilus-actions/nact/nact-clipboard.c
+	(nact_clipboard_primary_set): Copy data into a private dynamically allocated buffer.
+	(nact_clipboard_primary_get): Get data from the user_data buffer.
+
 2009-01-15 Pierre Wieser <pwieser trychlos org>
 
 	* nautilus-actions/nact/nact-iactions-list-bis.c:
diff --git a/TODO b/TODO
index 9685119..058bd27 100644
--- a/TODO
+++ b/TODO
@@ -107,29 +107,25 @@
   > remove in n-a-n
   > remove in action class
 
-- toolbar position should not be absolute, but relative
-
-- notebook page should be labeled 'Action' or 'Menu' depending of current item
-
-- what about between base_builder_instance_init and
+- optim: what about between base_builder_instance_init and
   base_application_v_initialize_default_icon ?
 
-- na_pivot_is_level_zero_writable: the provider which hosts the level-zero
-  list of items should be a configuration option
+- enhancement.config: na_pivot_is_level_zero_writable:
+  the provider which hosts the level-zero list of items should be a configuration option
 
-- dnd an action with several profiles loses the profiles: only one profile
-  stays after the dnd
+- enhancement.ui: review statusbar layout
 
-- review statusbar layout
+- enhancement.ui: review toolbars layout
 
-- review toolbars layout
+- enhancement.management: we should be able to fully export a configuration
+  this implies exporting menus and full tree
 
-- we should be able to fully export a configuration: this implies exporting
-  menus and full tree
+- enhancement.ui: rows implicitely selected should have a special display
+  (as a sort of 'transparent' selection)
 
-- unable to right-click on a multiple selection
+- enhancement.ui: notebook page should be labeled 'Action' or 'Menu' depending of current item
 
-- rows implicitely selected should have a special display
-  (as a sort of 'transparent' selection)
+- bug: toolbar position should not be absolute, but relative
 
-- after cut, the pasted content is not updated
+- bug: dnd an action with several profiles loses the profiles: only one profile
+  stays after the dnd
diff --git a/nautilus-actions/nact/nact-clipboard.c b/nautilus-actions/nact/nact-clipboard.c
index 6669423..65713b6 100644
--- a/nautilus-actions/nact/nact-clipboard.c
+++ b/nautilus-actions/nact/nact-clipboard.c
@@ -65,21 +65,21 @@ typedef struct {
 	NactClipboardDndData;
 
 typedef struct {
-	guint    nb_actions;
-	guint    nb_profiles;
-	guint    nb_menus;
-	GList   *items;
-	gint     mode;
+	GList *items;
+	gint   mode;
+	guint  nb_actions;
+	guint  nb_profiles;
+	guint  nb_menus;
 }
-	NactClipboardPrimaryData;
+	PrimaryData;
 
 struct NactClipboardPrivate {
-	gboolean                  dispose_has_run;
-	BaseWindow               *window;
-	GtkClipboard             *dnd;
-	GtkClipboard             *primary;
-	NactClipboardPrimaryData *primary_data;
-	gboolean                  primary_got;
+	gboolean      dispose_has_run;
+	BaseWindow   *window;
+	GtkClipboard *dnd;
+	GtkClipboard *primary;
+	PrimaryData  *primary_data;
+	gboolean      primary_got;
 };
 
 #define NACT_CLIPBOARD_ATOM				gdk_atom_intern( "_NACT_CLIPBOARD", FALSE )
@@ -120,7 +120,9 @@ static gchar *export_objects( NactClipboard *clipboard, GList *objects, const gc
 static gchar *export_row_object( NactClipboard *clipboard, NAObject *object, const gchar *dest_folder, GList **exported );
 
 static void   get_from_primary_clipboard_callback( GtkClipboard *gtk_clipboard, GtkSelectionData *selection_data, guint info, NactClipboard *clipboard );
+static void   clear_primary_clipboard( NactClipboard *clipboard );
 static void   clear_primary_clipboard_callback( GtkClipboard *gtk_clipboard, NactClipboard *clipboard );
+static void   dump_primary_clipboard( NactClipboard *clipboard );
 
 static gchar *clipboard_mode_to_string( gint mode );
 
@@ -196,6 +198,7 @@ instance_init( GTypeInstance *instance, gpointer klass )
 	display = gdk_display_get_default();
 	self->private->dnd = gtk_clipboard_get_for_display( display, NACT_CLIPBOARD_ATOM );
 	self->private->primary = gtk_clipboard_get_for_display( display, GDK_SELECTION_CLIPBOARD );
+	self->private->primary_data = NULL;
 }
 
 static void
@@ -232,6 +235,11 @@ instance_finalize( GObject *window )
 	g_assert( NACT_IS_CLIPBOARD( window ));
 	self = NACT_CLIPBOARD( window );
 
+	if( self->private->primary_data ){
+		clear_primary_clipboard( self );
+		g_free( self->private->primary_data );
+	}
+
 	g_free( self->private );
 
 	/* chain call to parent class */
@@ -351,6 +359,7 @@ nact_clipboard_dnd_get_data( NactClipboard *clipboard, gboolean *copy_data )
 				*copy_data = data->copy;
 			}
 		}
+		gtk_selection_data_free( selection );
 	}
 
 	return( rows );
@@ -414,6 +423,7 @@ nact_clipboard_dnd_drag_end( NactClipboard *clipboard )
 				export_rows( clipboard, data->rows, data->folder );
 			}
 		}
+		gtk_selection_data_free( selection );
 	}
 }
 
@@ -607,7 +617,7 @@ void
 nact_clipboard_primary_set( NactClipboard *clipboard, GList *items, gint mode )
 {
 	static const gchar *thisfn = "nact_clipboard_primary_set";
-	NactClipboardPrimaryData *data;
+	PrimaryData *user_data;
 	GList *it;
 
 	g_debug( "%s: clipboard=%p, items=%p (count=%d), mode=%d",
@@ -616,29 +626,38 @@ nact_clipboard_primary_set( NactClipboard *clipboard, GList *items, gint mode )
 
 	if( !clipboard->private->dispose_has_run ){
 
-		g_return_if_fail( clipboard->private->primary_data == NULL );
+		user_data = clipboard->private->primary_data;
+
+		if( user_data == NULL ){
+			user_data = g_new0( PrimaryData, 1 );
+			clipboard->private->primary_data = user_data;
+			g_debug( "%s: allocating PrimaryData=%p", thisfn, ( void * ) user_data );
 
-		data = g_new0( NactClipboardPrimaryData, 1 );
+		} else {
+			clear_primary_clipboard( clipboard );
+		}
 
 		na_object_item_count_items( items,
-				( gint * ) &data->nb_menus, ( gint * ) &data->nb_actions, ( gint * ) &data->nb_profiles, FALSE );
+				( gint * ) &user_data->nb_menus,
+				( gint * ) &user_data->nb_actions,
+				( gint * ) &user_data->nb_profiles,
+				FALSE );
 
 		for( it = items ; it ; it = it->next ){
-			data->items = g_list_prepend( data->items, na_object_duplicate( it->data ));
+			user_data->items =
+					g_list_prepend( user_data->items, na_object_duplicate( it->data ));
 		}
-		data->items = g_list_reverse( data->items );
-
-		data->mode = mode;
+		user_data->items = g_list_reverse( user_data->items );
 
-		clipboard->private->primary_data = data;
-		clipboard->private->primary_got = FALSE;
-		g_debug( "%s: data=%p (NactClipboardPrimaryData)", thisfn, ( void * ) data );
+		user_data->mode = mode;
 
 		gtk_clipboard_set_with_data( clipboard->private->primary,
 				clipboard_formats, G_N_ELEMENTS( clipboard_formats ),
 				( GtkClipboardGetFunc ) get_from_primary_clipboard_callback,
 				( GtkClipboardClearFunc ) clear_primary_clipboard_callback,
 				clipboard );
+
+		clipboard->private->primary_got = FALSE;
 	}
 }
 
@@ -656,9 +675,9 @@ GList *
 nact_clipboard_primary_get( NactClipboard *clipboard, gboolean *relabel )
 {
 	static const gchar *thisfn = "nact_clipboard_primary_get";
-	GtkSelectionData *selection;
-	NactClipboardPrimaryData *data;
 	GList *items = NULL;
+	GtkSelectionData *selection;
+	PrimaryData *user_data;
 	GList *it;
 	NAObject *obj;
 
@@ -671,20 +690,24 @@ nact_clipboard_primary_get( NactClipboard *clipboard, gboolean *relabel )
 		selection = gtk_clipboard_wait_for_contents( clipboard->private->primary, NACT_CLIPBOARD_NACT_ATOM );
 
 		if( selection ){
-			data = ( NactClipboardPrimaryData * ) selection->data;
-			g_debug( "%s: data=%p (NactClipboardPrimaryData)", thisfn, ( void * ) data );
+			user_data = ( PrimaryData * ) selection->data;
+			g_debug( "%s: retrieving PrimaryData=%p", thisfn, ( void * ) user_data );
+
+			if( user_data ){
+				for( it = user_data->items ; it ; it = it->next ){
+					obj = na_object_duplicate( it->data );
+					na_object_set_origin( obj, NULL );
+					items = g_list_prepend( items, obj );
+				}
+				items = g_list_reverse( items );
 
-			for( it = data->items ; it ; it = it->next ){
-				obj = na_object_duplicate( it->data );
-				na_object_set_origin( obj, NULL );
-				items = g_list_prepend( items, obj );
-			}
-			items = g_list_reverse( items );
+				*relabel = (( user_data->mode == CLIPBOARD_MODE_CUT && clipboard->private->primary_got ) ||
+								user_data->mode == CLIPBOARD_MODE_COPY );
 
-			*relabel = (( data->mode == CLIPBOARD_MODE_CUT && clipboard->private->primary_got ) ||
-							data->mode == CLIPBOARD_MODE_COPY );
+				clipboard->private->primary_got = TRUE;
+			}
 
-			clipboard->private->primary_got = TRUE;
+			gtk_selection_data_free( selection );
 		}
 	}
 
@@ -700,8 +723,7 @@ nact_clipboard_primary_get( NactClipboard *clipboard, gboolean *relabel )
 void
 nact_clipboard_primary_counts( NactClipboard *clipboard, guint *actions, guint *profiles, guint *menus )
 {
-	GtkSelectionData *selection;
-	NactClipboardPrimaryData *data;
+	PrimaryData *user_data;
 
 	g_return_if_fail( NACT_IS_CLIPBOARD( clipboard ));
 	g_return_if_fail( actions && profiles && menus );
@@ -712,14 +734,12 @@ nact_clipboard_primary_counts( NactClipboard *clipboard, guint *actions, guint *
 		*profiles = 0;
 		*menus = 0;
 
-		selection = gtk_clipboard_wait_for_contents( clipboard->private->primary, NACT_CLIPBOARD_NACT_ATOM );
-
-		if( selection ){
-			data = ( NactClipboardPrimaryData * ) selection->data;
+		user_data = clipboard->private->primary_data;
+		if( user_data ){
 
-			*actions = data->nb_actions;
-			*profiles = data->nb_profiles;
-			*menus = data->nb_menus;
+			*actions = user_data->nb_actions;
+			*profiles = user_data->nb_profiles;
+			*menus = user_data->nb_menus;
 		}
 	}
 }
@@ -728,39 +748,49 @@ static void
 get_from_primary_clipboard_callback( GtkClipboard *gtk_clipboard, GtkSelectionData *selection_data, guint info, NactClipboard *clipboard )
 {
 	static const gchar *thisfn = "nact_clipboard_get_from_primary_clipboard_callback";
-	NactClipboardPrimaryData *data;
+	PrimaryData *user_data;
 	gchar *buffer;
 
 	g_debug( "%s: gtk_clipboard=%p, selection_data=%p, target=%s, info=%d, clipboard=%p",
 			thisfn, ( void * ) gtk_clipboard,
 			( void * ) selection_data, gdk_atom_name( selection_data->target ), info, ( void * ) clipboard );
 
-	data = clipboard->private->primary_data;
+	user_data = clipboard->private->primary_data;
 
 	if( info == NACT_CLIPBOARD_FORMAT_TEXT_PLAIN ){
-		buffer = export_objects( clipboard, data->items, NULL );
+		buffer = export_objects( clipboard, user_data->items, NULL );
 		gtk_selection_data_set( selection_data, selection_data->target, 8, ( const guchar * ) buffer, strlen( buffer ));
 		g_free( buffer );
 
 	} else {
-		gtk_selection_data_set( selection_data, selection_data->target, 8, ( const guchar * ) data, sizeof( NactClipboardPrimaryData ));
+		gtk_selection_data_set( selection_data, selection_data->target, 8, ( const guchar * ) user_data, sizeof( PrimaryData ));
 	}
 }
 
 static void
-clear_primary_clipboard_callback( GtkClipboard *gtk_clipboard, NactClipboard *clipboard )
+clear_primary_clipboard( NactClipboard *clipboard )
 {
-	static const gchar *thisfn = "nact_clipboard_clear_primary_clipboard_callback";
-	NactClipboardPrimaryData *data;
+	static const gchar *thisfn = "nact_clipboard_clear_primary_clipboard";
+	PrimaryData *user_data;
 
-	g_debug( "%s: gtk_clipboard=%p, clipboard=%p",
-			thisfn, ( void * ) gtk_clipboard, ( void * ) clipboard );
+	g_debug( "%s: clipboard=%p", thisfn, ( void * ) clipboard );
 
-	data = clipboard->private->primary_data;
-	g_list_foreach( data->items, ( GFunc ) g_object_unref, NULL );
-	g_list_free( data->items );
-	g_free( data );
-	clipboard->private->primary_data = NULL;
+	user_data = clipboard->private->primary_data;
+	g_return_if_fail( user_data != NULL );
+
+	g_list_foreach( user_data->items, ( GFunc ) g_object_unref, NULL );
+	g_list_free( user_data->items );
+	user_data->items = NULL;
+	user_data->nb_menus = 0;
+	user_data->nb_actions = 0;
+	user_data->nb_profiles = 0;
+
+	clipboard->private->primary_got = FALSE;
+}
+
+static void
+clear_primary_clipboard_callback( GtkClipboard *gtk_clipboard, NactClipboard *clipboard )
+{
 }
 
 /**
@@ -773,8 +803,6 @@ void
 nact_clipboard_dump( NactClipboard *clipboard )
 {
 	static const gchar *thisfn = "nact_clipboard_dump";
-	gchar *mode;
-	GList *it;
 
 	g_return_if_fail( NACT_IS_CLIPBOARD( clipboard ));
 
@@ -786,22 +814,42 @@ nact_clipboard_dump( NactClipboard *clipboard )
 		g_debug( "%s: primary_data=%p", thisfn, ( void * ) clipboard->private->primary_data );
 
 		if( clipboard->private->primary_data ){
-			g_debug( "%s:  primary_data->nb_actions=%d", thisfn, clipboard->private->primary_data->nb_actions );
-			g_debug( "%s: primary_data->nb_profiles=%d", thisfn, clipboard->private->primary_data->nb_profiles );
-			g_debug( "%s:    primary_data->nb_menus=%d", thisfn, clipboard->private->primary_data->nb_menus );
-			g_debug( "%s:       primary_data->items=%p (count=%d)",
+			dump_primary_clipboard( clipboard );
+		}
+	}
+}
+
+static void
+dump_primary_clipboard( NactClipboard *clipboard )
+{
+	static const gchar *thisfn = "nact_clipboard_dump_primary";
+	PrimaryData *user_data;
+	gchar *mode;
+	GList *it;
+
+	g_return_if_fail( NACT_IS_CLIPBOARD( clipboard ));
+
+	if( !clipboard->private->dispose_has_run ){
+
+		user_data = clipboard->private->primary_data;
+
+		if( user_data ){
+			g_debug( "%s:           user_data->nb_actions=%d", thisfn, user_data->nb_actions );
+			g_debug( "%s:          user_data->nb_profiles=%d", thisfn, user_data->nb_profiles );
+			g_debug( "%s:             user_data->nb_menus=%d", thisfn, user_data->nb_menus );
+			g_debug( "%s:                user_data->items=%p (count=%d)",
 					thisfn,
-					( void * ) clipboard->private->primary_data->items,
-					clipboard->private->primary_data->items ? g_list_length( clipboard->private->primary_data->items ) : 0 );
-			mode = clipboard_mode_to_string( clipboard->private->primary_data->mode );
-			g_debug( "%s:       primary_data->mode=%d (%s)", thisfn, clipboard->private->primary_data->mode, mode );
+					( void * ) user_data->items,
+					user_data->items ? g_list_length( user_data->items ) : 0 );
+			mode = clipboard_mode_to_string( user_data->mode );
+			g_debug( "%s:                 user_data->mode=%d (%s)", thisfn, user_data->mode, mode );
 			g_free( mode );
-			for( it = clipboard->private->primary_data->items ; it ; it = it->next ){
+			for( it = user_data->items ; it ; it = it->next ){
 				na_object_object_dump( NA_OBJECT( it->data ));
 			}
 		}
 
-		g_debug( "%s:  primary_got=%s", thisfn, clipboard->private->primary_got ? "True":"False" );
+		g_debug( "%s: clipboard->private->primary_got=%s", thisfn, clipboard->private->primary_got ? "True":"False" );
 	}
 }
 
diff --git a/nautilus-actions/nact/nact-main-menubar.c b/nautilus-actions/nact/nact-main-menubar.c
index ac9bc28..fb4f767 100644
--- a/nautilus-actions/nact/nact-main-menubar.c
+++ b/nautilus-actions/nact/nact-main-menubar.c
@@ -647,6 +647,7 @@ on_update_sensitivities( NactMainWindow *window, gpointer user_data )
 	mis = ( MenubarIndicatorsStruct * ) g_object_get_data( G_OBJECT( window ), MENUBAR_PROP_INDICATORS );
 	is_clipboard_empty = ( mis->clipboard_menus + mis->clipboard_actions + mis->clipboard_profiles == 0 );
 	count_selected = selected_items ? g_list_length( selected_items ) : 0;
+	g_debug( "%s: count_selected=%d", thisfn, count_selected );
 
 	/* new menu / new action
 	 * new item will be inserted just before beginning of selection
@@ -704,7 +705,7 @@ on_update_sensitivities( NactMainWindow *window, gpointer user_data )
 	 * and that all parents are writable (as implies a delete operation)
 	 */
 	cut_enabled = mis->treeview_has_focus || mis->popup_handler;
-	cut_enabled &= count_selected;
+	cut_enabled &= count_selected > 0;
 	are_parents_writable = TRUE;
 	for( is = selected_items ; is ; is = is->next ){
 		parent_item = ( NAObject * ) na_object_get_parent( is->data );
@@ -723,7 +724,7 @@ on_update_sensitivities( NactMainWindow *window, gpointer user_data )
 
 	/* copy only requires a non-empty selection */
 	copy_enabled = mis->treeview_has_focus || mis->popup_handler;
-	copy_enabled &= count_selected;
+	copy_enabled &= count_selected > 0;
 	enable_item( window, "CopyItem", copy_enabled );
 
 	/* paste enabled if



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