Re: [PATCH] Improve activation behavior of multiple files, part 1



On Mi, 2005-10-19 at 11:54 +0200, Alexander Larsson wrote:
> On Tue, 2005-10-04 at 13:10 +0200, Christian Neumair wrote:
> > The attached two patches change the Nautilus semantics for dealing with
> > multiple files. The trick is to be notified about all activation URIs
> > and decide what to do with the individual files later. We can then
> > cumulate multiple files and pass them to the same application handler.
> > 
> > From quickly taking a look at the patch it looks like we sometimes leak
> > the activation->files list, this can be resolved right before the
> > commit, though.
> (review)

It's frustrating. I fail to see why the refcount is hosed after the file
activation. I'm sending what I have now back to the list for review.
Using gdb and printf-debugging didn't yield anything.

-- 
Christian Neumair <chris gnome-de org>
Index: file-manager/fm-directory-view.c
===================================================================
RCS file: /cvs/gnome/nautilus/src/file-manager/fm-directory-view.c,v
retrieving revision 1.718
diff -u -p -r1.718 fm-directory-view.c
--- file-manager/fm-directory-view.c	14 Nov 2005 14:56:12 -0000	1.718
+++ file-manager/fm-directory-view.c	18 Nov 2005 17:53:10 -0000
@@ -271,12 +271,13 @@ typedef enum {
 
 typedef struct {
 	FMDirectoryView *view;
-	NautilusFile *file;
+	GList *files;
+	NautilusFileListHandle *files_handle;
+	NautilusFileListCallback callback;
 	NautilusWindowOpenMode mode;
 	NautilusWindowOpenFlags flags;
-	NautilusFileCallback callback;
-	gboolean mounted;
-	gboolean mounting;
+	gboolean mount_success;
+	unsigned int pending_mounts;
 	gboolean cancelled;
 } ActivateParameters;
 
@@ -347,7 +348,7 @@ static void     fm_directory_view_select
 static void     monitor_file_for_open_with                     (FMDirectoryView      *view,
 								NautilusFile         *file);
 static void     create_scripts_directory                       (void);
-static void     activate_activation_uri_ready_callback         (NautilusFile         *file,
+static void     activate_activation_uris_ready_callback        (GList                *files,
 								gpointer              callback_data);
 static gboolean can_show_default_app                           (FMDirectoryView *view,
 								NautilusFile *file);
@@ -7340,13 +7341,9 @@ cancel_activate (gpointer callback_data)
 
 	parameters->cancelled = TRUE;
 	
-	if (!parameters->mounting) {
-		nautilus_file_cancel_call_when_ready (parameters->file, 
-						      parameters->callback, 
-						      parameters);
-		
-		nautilus_file_unref (parameters->file);
-		
+	if (parameters->pending_mounts == 0) {
+		nautilus_file_list_cancel_call_when_ready (parameters->files_handle);
+		nautilus_file_list_free (parameters->files);
 		g_free (parameters);
 	}
 }
@@ -7384,11 +7381,19 @@ stop_activate (ActivateParameters *param
 }
 
 static void
-activate_callback (NautilusFile *file, gpointer callback_data)
+activate_callback (GList *files, gpointer callback_data)
 {
 	ActivateParameters *parameters;
 	FMDirectoryView *view;
-	char *orig_uri, *uri, *file_uri;
+	NautilusFile *file;
+	GList *launch_desktop_files;
+	GList *launch_from_command_files;
+	GList *launch_files;
+	GList *launch_in_terminal_files;
+	GList *open_in_app_files;
+	GList *open_in_view_files;
+	GList *l;
+	char *uri;
 	char *executable_path, *quoted_path, *name;
 	char *old_working_dir;
 	ActivationAction action;
@@ -7400,64 +7405,150 @@ activate_callback (NautilusFile *file, g
 
 	view = FM_DIRECTORY_VIEW (parameters->view);
 
-	if (!activate_check_mime_types (view, file, TRUE)
-	    || nautilus_file_get_file_info_result (file) == GNOME_VFS_ERROR_CANCELLED) {
-		nautilus_file_unref (file);
-		g_free (parameters);
-		
-		return;
-	}
+	screen = gtk_widget_get_screen (GTK_WIDGET (view));
 
-	orig_uri = uri = nautilus_file_get_activation_uri (file);
+	launch_desktop_files = NULL;
+	launch_from_command_files = NULL;
+	launch_files = NULL;
+	launch_in_terminal_files = NULL;
+	open_in_app_files = NULL;
+	open_in_view_files = NULL;
 
-	action = get_activation_action (file);
+	for (l = files; l != NULL; l = l->next) {
+		file = NAUTILUS_FILE (l->data);
 
-	screen = gtk_widget_get_screen (GTK_WIDGET (view));
+		if (!activate_check_mime_types (view, file, TRUE) ||
+		    nautilus_file_get_file_info_result (file) == GNOME_VFS_ERROR_CANCELLED) {
+			continue;
+		}
 
-	if (action == ACTIVATION_ACTION_ASK) {
-		/* Special case for executable text files, since it might be
-		 * dangerous & unexpected to launch these.
-		 */
-		action = get_executable_text_file_action (view, file);
+		action = get_activation_action (file);
+		if (action == ACTIVATION_ACTION_ASK) {
+			/* Special case for executable text files, since it might be
+			 * dangerous & unexpected to launch these.
+			 */
+			action = get_executable_text_file_action (view, file);
+		}
+
+		switch (action) {
+		case ACTIVATION_ACTION_LAUNCH_DESKTOP_FILE :
+			launch_desktop_files = g_list_prepend (launch_desktop_files, file);
+			break;
+		case ACTIVATION_ACTION_LAUNCH_APPLICATION_FROM_COMMAND :
+			launch_from_command_files = g_list_prepend (launch_from_command_files, file);
+			break;
+		case ACTIVATION_ACTION_LAUNCH :
+			launch_files = g_list_prepend (launch_files, file);
+			break;
+		case ACTIVATION_ACTION_LAUNCH_IN_TERMINAL :
+			launch_in_terminal_files = g_list_prepend (launch_in_terminal_files, file);
+			break;
+		case ACTIVATION_ACTION_OPEN_IN_VIEW :
+			open_in_view_files = g_list_prepend (open_in_view_files, file);
+			break;
+		case ACTIVATION_ACTION_OPEN_IN_APPLICATION :
+			open_in_app_files = g_list_prepend (open_in_app_files, file);
+			break;
+		case ACTIVATION_ACTION_DO_NOTHING :
+			break;
+		case ACTIVATION_ACTION_ASK :
+			g_assert_not_reached ();
+			break;
+		}
 	}
-	
-	switch (action) {
-	case ACTIVATION_ACTION_LAUNCH_DESKTOP_FILE :
-		file_uri = nautilus_file_get_uri (file);
+
+
+	launch_desktop_files = g_list_reverse (launch_desktop_files);
+	for (l = launch_desktop_files; l != NULL; l = l->next) {
+		file = NAUTILUS_FILE (l->data);
+
+		uri = nautilus_file_get_uri (file);
 		nautilus_launch_desktop_file (
-				screen, file_uri, NULL,
+				screen, uri, NULL,
 				fm_directory_view_get_containing_window (view));
-		g_free (file_uri);		 
-		break;
-	case ACTIVATION_ACTION_LAUNCH_APPLICATION_FROM_COMMAND :
-		uri += strlen (NAUTILUS_COMMAND_SPECIFIER);
-		nautilus_launch_application_from_command (screen, NULL, uri, NULL, FALSE);
-		break;
-	case ACTIVATION_ACTION_LAUNCH :
-	case ACTIVATION_ACTION_LAUNCH_IN_TERMINAL :
+		g_free (uri);
+	}
+
+	launch_from_command_files = g_list_reverse (launch_from_command_files);
+	for (l = launch_from_command_files; l != NULL; l = l->next) {
+		file = NAUTILUS_FILE (l->data);
+
+		uri = nautilus_file_get_activation_uri (file);
+		nautilus_launch_application_from_command (
+				screen, NULL, uri + strlen (NAUTILUS_COMMAND_SPECIFIER),
+				NULL, FALSE);
+		g_free (uri);
+	}
+
+	old_working_dir = NULL;
+	if (launch_files != NULL || launch_in_terminal_files != NULL) {
 		old_working_dir = change_to_view_directory (view);
+	}
+
+	launch_files = g_list_reverse (launch_files);
+	for (l = launch_files; l != NULL; l = l->next) {
+		file = NAUTILUS_FILE (l->data);
 
+		uri = nautilus_file_get_activation_uri (file);
 		executable_path = gnome_vfs_get_local_path_from_uri (uri);
 		quoted_path = g_shell_quote (executable_path);
 		name = nautilus_file_get_name (file);
-		nautilus_launch_application_from_command 
-			(screen, name, quoted_path, NULL,
-			 (action == ACTIVATION_ACTION_LAUNCH_IN_TERMINAL) /* use terminal */ );
+		nautilus_launch_application_from_command (screen, name, quoted_path, NULL, FALSE);
 		g_free (name);
 		g_free (quoted_path);
+		g_free (executable_path);
+		g_free (uri);
+			
+	}
+
+	launch_in_terminal_files = g_list_reverse (launch_in_terminal_files);
+	for (l = launch_in_terminal_files; l != NULL; l = l->next) {
+		file = NAUTILUS_FILE (l->data);
 
+		uri = nautilus_file_get_activation_uri (file);
+		executable_path = gnome_vfs_get_local_path_from_uri (uri);
+		quoted_path = g_shell_quote (executable_path);
+		name = nautilus_file_get_name (file);
+		nautilus_launch_application_from_command (screen, name, quoted_path, NULL, TRUE);
+		g_free (name);
+		g_free (quoted_path);
+		g_free (executable_path);
+		g_free (uri);
+	}
+
+	if (old_working_dir != NULL) {
 		chdir (old_working_dir);
 		g_free (old_working_dir);
-		g_free (executable_path);
-		
-		break;
-	case ACTIVATION_ACTION_OPEN_IN_VIEW :
-		open_location (view, uri, parameters->mode, parameters->flags);
-		break;
-	case ACTIVATION_ACTION_OPEN_IN_APPLICATION :
+	}
+
+	open_in_view_files = g_list_reverse (open_in_view_files);
+	if (g_list_length (open_in_view_files) < 2 ||
+	    fm_directory_view_confirm_multiple_windows (view, g_list_length (open_in_view_files))) {
+		NautilusWindowOpenFlags flags;
+
+		flags = parameters->flags;
+		if (g_list_length (open_in_view_files) > 1) {
+			flags |= NAUTILUS_WINDOW_OPEN_FLAG_NEW_WINDOW;
+		}
+
+		for (l = open_in_view_files; l != NULL; l = l->next) {
+			/* The ui should ask for navigation or object windows
+			 * depending on what the current one is */
+			file = NAUTILUS_FILE (l->data);
+
+			uri = nautilus_file_get_activation_uri (file);
+			open_location (view, uri, parameters->mode, flags);
+			g_free (uri);
+		}
+	}
+
+	open_in_app_files = g_list_reverse (open_in_app_files);
+	for (l = open_in_app_files; l != NULL; l = l->next) {
+		file = NAUTILUS_FILE (l->data);
+
 		nautilus_launch_show_file
 			(file, fm_directory_view_get_containing_window (view));
-		
+
 		if ((parameters->flags & NAUTILUS_WINDOW_OPEN_FLAG_CLOSE_BEHIND) != 0) {
 			if (nautilus_window_info_get_window_type (view->details->window) == NAUTILUS_WINDOW_SPATIAL) {
 				nautilus_window_info_close (view->details->window);
@@ -7467,21 +7558,20 @@ activate_callback (NautilusFile *file, g
 		/* We should not add trash and directory uris.*/
 		if ((!nautilus_file_is_in_trash (file)) && 
 		    (!nautilus_file_is_directory (file))) {
-			file_uri = nautilus_file_get_uri (file);
-			egg_recent_model_add (nautilus_recent_get_model (), file_uri);
-			g_free (file_uri);
+			uri = nautilus_file_get_uri (file);
+			egg_recent_model_add (nautilus_recent_get_model (), uri);
+			g_free (uri);
 		}
-		break;
-	case ACTIVATION_ACTION_DO_NOTHING :
-		break;
-	case ACTIVATION_ACTION_ASK :
-		g_assert_not_reached ();
-		break;
 	}
 
-	nautilus_file_unref (file);
+	g_list_free (launch_desktop_files);
+	g_list_free (launch_from_command_files);
+	g_list_free (launch_files);
+	g_list_free (launch_in_terminal_files);
+	g_list_free (open_in_view_files);
+	g_list_free (open_in_app_files);
 
-	g_free (orig_uri);
+	nautilus_file_list_free (parameters->files);
 	g_free (parameters);
 }
 
@@ -7495,79 +7585,126 @@ activation_drive_mounted_callback (gbool
 
 	parameters = callback_data;
 
-	parameters->mounted = TRUE;
-	parameters->mounting = FALSE;
-	
-	if (succeeded && !parameters->cancelled) {
-		activate_activation_uri_ready_callback (parameters->file,
-							parameters);
-	} else {
-		if (!parameters->cancelled) {
-			stop_activate (parameters);
+	parameters->mount_success &= succeeded;
 
-			eel_show_error_dialog_with_details (error, NULL,
-							    _("Mount Error"),
-			                                    detailed_error, 
-							    NULL);
-		}
-		
-		nautilus_file_unref (parameters->file);
-		
+	if (!succeeded) {
+		eel_show_error_dialog_with_details (error, NULL,
+						    _("Mount Error"),
+						    detailed_error, 
+						    NULL);
+	}
+
+	if (--parameters->pending_mounts > 0) {
+		/* wait for other mounts to finish... */
+		return;
+	}
+
+	if (parameters->cancelled || !parameters->mount_success) {
+		stop_activate (parameters);
+
+		nautilus_file_list_cancel_call_when_ready (parameters->files_handle);
+		nautilus_file_list_free (parameters->files);
 		g_free (parameters);
+		return;
 	}
+
+	/* all drives were mounted successfully */
+	activate_activation_uris_ready_callback (parameters->files,
+						 parameters);
 }
 
+static void
+mount_foreach (gpointer drive,
+	       gpointer callback_data)
+{
+	gnome_vfs_drive_mount (drive, activation_drive_mounted_callback, callback_data);
+}
 
 static void
-activate_activation_uri_ready_callback (NautilusFile *file, gpointer callback_data)
+activate_activation_uris_ready_callback (GList *files,
+					 gpointer callback_data)
 {
 	ActivateParameters *parameters;
+	GList *not_yet_mounted;
+	GList *l;
+	NautilusFile *file;
 	NautilusFile *actual_file;
 	NautilusFileAttributes attributes;
 	GnomeVFSDrive *drive;
 	char *uri;
 	
 	parameters = callback_data;
+	not_yet_mounted = NULL;
+
+	/* we can safely unref them here, since the files
+	 * list also holds a reference */
+	nautilus_file_list_free (parameters->files);
+	parameters->files = NULL;
+
+	for (l = files; l != NULL; l = l->next) {
+		file = NAUTILUS_FILE (l->data);
+
+		if (nautilus_file_get_file_info_result (file) == GNOME_VFS_ERROR_CANCELLED) {
+			continue;
+		}
+
+		if (nautilus_file_is_broken_symbolic_link (file)) {
+			report_broken_symbolic_link (parameters->view, file);
+			continue;
+		}
+
+		parameters->files = g_list_prepend (parameters->files, nautilus_file_ref (file));
+
+		if (!parameters->mount_success && nautilus_file_has_drive (file)) {
+			drive = nautilus_file_get_drive (file);
+			if (drive != NULL &&
+			    !gnome_vfs_drive_is_mounted (drive)) {
+				not_yet_mounted = g_list_prepend (not_yet_mounted, drive);
+				parameters->pending_mounts++;
+			}
+		}
+	}
+
+	parameters->files = g_list_reverse (parameters->files);
+
+	if (parameters->files == NULL) {
+		g_assert (not_yet_mounted == NULL);
 
-	if (nautilus_file_is_broken_symbolic_link (file)) {
 		stop_activate (parameters);
-		report_broken_symbolic_link (parameters->view, file);
-		nautilus_file_unref (parameters->file);
+		nautilus_file_list_cancel_call_when_ready (parameters->files_handle);
 		g_free (parameters);
+		g_list_free (not_yet_mounted);
 		return;
 	}
 
-	if (nautilus_file_get_file_info_result (file) == GNOME_VFS_ERROR_CANCELLED) {
-		stop_activate (parameters);
-		nautilus_file_unref (parameters->file);
-		g_free (parameters);
+	if (not_yet_mounted != NULL) {
+		not_yet_mounted = g_list_reverse (not_yet_mounted);
+		g_list_foreach (not_yet_mounted, mount_foreach, callback_data);
+		g_list_free (not_yet_mounted);
+
+		/* activation_drive_mounted_callback will reveal whether all mounts were successful */
+		parameters->mount_success = TRUE;
 		return;
 	}
 
-	if (!parameters->mounted && nautilus_file_has_drive (file)) {
-		drive = nautilus_file_get_drive (file);
-		if (drive != NULL &&
-		    !gnome_vfs_drive_is_mounted (drive)) {
-			parameters->mounting = TRUE;
-			gnome_vfs_drive_mount (drive, activation_drive_mounted_callback, callback_data);
-			return;
+	for (l = parameters->files; l != NULL; l = l->next) {
+		file = NAUTILUS_FILE (l->data);
+
+		/* We want the file for the activation URI since we care
+		 * about the attributes for that, not for the original file.
+		 */
+		actual_file = NULL;
+		uri = nautilus_file_get_activation_uri (file);
+		if (!(eel_str_has_prefix (uri, NAUTILUS_DESKTOP_COMMAND_SPECIFIER) ||
+		      eel_str_has_prefix (uri, NAUTILUS_COMMAND_SPECIFIER))) {
+			actual_file = nautilus_file_get (uri);
+		}
+		g_free (uri);
+		
+		if (actual_file != NULL) {
+			nautilus_file_unref (file);
+			l->data = actual_file;
 		}
-	}
-	
-	/* We want the file for the activation URI since we care
-	 * about the attributes for that, not for the original file.
-	 */
-	actual_file = NULL;
-	uri = nautilus_file_get_activation_uri (file);
-	if (!(eel_str_has_prefix (uri, NAUTILUS_DESKTOP_COMMAND_SPECIFIER) ||
-	      eel_str_has_prefix (uri, NAUTILUS_COMMAND_SPECIFIER))) {
-		actual_file = nautilus_file_get (uri);
-		nautilus_file_unref (file);
-	}
-	g_free (uri);
-	
-	if (actual_file == NULL) {
-		actual_file = file;
 	}
 	
 	/* get the parameters for the actual file */	
@@ -7576,14 +7713,11 @@ activate_activation_uri_ready_callback (
 		NAUTILUS_FILE_ATTRIBUTE_SLOW_MIME_TYPE |
 		NAUTILUS_FILE_ATTRIBUTE_ACTIVATION_URI;
 
-	parameters->file = actual_file;
 	parameters->callback = activate_callback;
-
-	nautilus_file_call_when_ready
-		(actual_file, attributes, activate_callback, parameters);
+	parameters->files_handle = nautilus_file_list_call_when_ready
+		(parameters->files, attributes, activate_callback, parameters);
 }
 
-
 /**
  * fm_directory_view_activate_file:
  * 
@@ -7600,21 +7734,55 @@ fm_directory_view_activate_file (FMDirec
 				 NautilusWindowOpenMode mode,
 				 NautilusWindowOpenFlags flags)
 {
+	GList *files;
+
+	g_return_if_fail (FM_IS_DIRECTORY_VIEW (view));
+	g_return_if_fail (NAUTILUS_IS_FILE (file));
+
+	files = g_list_prepend (NULL, file);
+	fm_directory_view_activate_files (view, files, mode, flags);
+	g_list_free (files);
+}
+
+
+/**
+ * fm_directory_view_activate_files:
+ * 
+ * Activate a list of files. Each one might launch with an application or
+ * with a component. This is normally called only by subclasses.
+ * @view: FMDirectoryView in question.
+ * @files: A GList of NautilusFiles to activate.
+ * 
+ **/
+void
+fm_directory_view_activate_files (FMDirectoryView *view, 
+				  GList *files,
+				  NautilusWindowOpenMode mode,
+				  NautilusWindowOpenFlags flags)
+{
+
+	GList *l;
 	ActivateParameters *parameters;
+	NautilusFile *file;
 	NautilusFileAttributes attributes;
 	char *file_name;
 	char *timed_wait_prompt;
+	int file_count;
 
 	g_return_if_fail (FM_IS_DIRECTORY_VIEW (view));
-	g_return_if_fail (NAUTILUS_IS_FILE (file));
+	g_return_if_fail (files != NULL);
+
+	file_count = g_list_length (files);
 
 	/* link target info might be stale, re-read it */
-	if (nautilus_file_is_symbolic_link (file)) {
-		nautilus_file_invalidate_attributes 
-			(file, NAUTILUS_FILE_ATTRIBUTE_ACTIVATION_URI);
-	}
+	for (l = files; l != NULL; l = l->next) {
+		file = NAUTILUS_FILE (l->data);
 
-	nautilus_file_ref (file);
+		if (nautilus_file_is_symbolic_link (file)) {
+			nautilus_file_invalidate_attributes 
+				(file, NAUTILUS_FILE_ATTRIBUTE_ACTIVATION_URI);
+		}
+	}
 
 	/* Might have to read some of the file to activate it. */
 	attributes = NAUTILUS_FILE_ATTRIBUTE_ACTIVATION_URI |
@@ -7622,17 +7790,24 @@ fm_directory_view_activate_file (FMDirec
 
 	parameters = g_new (ActivateParameters, 1);
 	parameters->view = view;
-	parameters->file = file;
+	parameters->files = nautilus_file_list_copy (files);
 	parameters->mode = mode;
 	parameters->flags = flags;
-	parameters->callback = activate_activation_uri_ready_callback;
-	parameters->mounted = FALSE;
-	parameters->mounting = FALSE;
+	parameters->callback = activate_activation_uris_ready_callback;
+	parameters->mount_success = FALSE;
+	parameters->pending_mounts = 0;
 	parameters->cancelled = FALSE;
 
-	file_name = nautilus_file_get_display_name (file);
-	timed_wait_prompt = g_strdup_printf (_("Opening \"%s\"."), file_name);
-	g_free (file_name);
+	if (file_count == 1) {
+		file_name = nautilus_file_get_display_name (files->data);
+		timed_wait_prompt = g_strdup_printf ("Opening \"%s\".", file_name);
+		g_free (file_name);
+	} else {
+		timed_wait_prompt = g_strdup_printf (ngettext ("Opening %d item.",
+							       "Opening %d items.",
+							       file_count),
+						     file_count);
+	}
 	
 	eel_timed_wait_start_with_duration
 		(DELAY_UNTIL_CANCEL_MSECS,
@@ -7645,56 +7820,8 @@ fm_directory_view_activate_file (FMDirec
 
 	g_object_weak_ref (G_OBJECT (view), activate_weak_notify, parameters);
 
-	nautilus_file_call_when_ready
-		(file, attributes, activate_activation_uri_ready_callback, parameters);
-}
-
-
-/**
- * fm_directory_view_activate_files:
- * 
- * Activate a list of files. Each one might launch with an application or
- * with a component. This is normally called only by subclasses.
- * @view: FMDirectoryView in question.
- * @files: A GList of NautilusFiles to activate.
- * 
- **/
-void
-fm_directory_view_activate_files (FMDirectoryView *view, 
-				  GList *files,
-				  NautilusWindowOpenMode mode,
-				  NautilusWindowOpenFlags flags)
-{
-	GList *node;
-	int file_count;
-	gboolean use_new_window;
-
-	g_return_if_fail (FM_IS_DIRECTORY_VIEW (view));
-
-	/* If there's a single file to activate, check user's preference whether
-	 * to open it in this window or a new window. If there is more than one
-	 * file to activate, open each one in a new window. Don't try to choose
-	 * one special one to replace the current window's contents; we tried this
-	 * but it proved mysterious in practice.
-	 */
-	file_count = g_list_length (files);
-	use_new_window = file_count > 1;
-
-	if (use_new_window && mode == NAUTILUS_WINDOW_OPEN_ACCORDING_TO_MODE) {
-#if !NEW_UI_COMPLETE
-		/* Match the current window type */
-		mode = NAUTILUS_WINDOW_OPEN_IN_SPATIAL;
-#endif
-	}
-	
-	if (!use_new_window || fm_directory_view_confirm_multiple_windows (view, file_count)) {
-		for (node = files; node != NULL; node = node->next) {  	
-			/* The ui should ask for navigation or object windows
-			 * depending on what the current one is */
-			fm_directory_view_activate_file
-				(view, node->data, mode, flags);
-		}
-	}
+	parameters->files_handle = nautilus_file_list_call_when_ready
+		(parameters->files, attributes, activate_activation_uris_ready_callback, parameters);
 }
 
 static void

Attachment: signature.asc
Description: This is a digitally signed message part



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