Merge branch 'amolenaar/macos-launch-uris-async' into 'main'

Draft: macos: Implement GAppInfo launch_uris_async interface

Closes #3403

See merge request GNOME/glib!4129
This commit is contained in:
Arjan Molenaar 2024-07-15 19:23:53 +00:00
commit 3cbac9d277

View File

@ -27,6 +27,7 @@
#include "gfile.h"
#include "gfileicon.h"
#include "gioerror.h"
#include "gtask.h"
#import <CoreFoundation/CoreFoundation.h>
#import <Foundation/Foundation.h>
@ -270,30 +271,19 @@ create_url_list_from_glist (GList *uris,
return (CFArrayRef)array;
}
static LSLaunchURLSpec *
create_urlspec_for_appinfo (GOsxAppInfo *info,
GList *uris,
gboolean are_files)
static void
fill_urlspec_for_appinfo (LSLaunchURLSpec *urlspec,
GOsxAppInfo *info,
GList *uris,
gboolean are_files)
{
LSLaunchURLSpec *urlspec = NULL;
const gchar *app_cstr;
g_return_val_if_fail (G_IS_OSX_APP_INFO (info), NULL);
urlspec = g_new0 (LSLaunchURLSpec, 1);
app_cstr = g_osx_app_info_get_filename (info);
g_assert (app_cstr != NULL);
/* Strip file:// from app url but ensure filesystem url */
urlspec->appURL = create_url_from_cstr (app_cstr + strlen ("file://"), TRUE);
urlspec->appURL = CFBridgingRetain ([NSURL fileURLWithPath: [info->bundle bundlePath]]);
urlspec->launchFlags = kLSLaunchDefaults;
urlspec->itemURLs = create_url_list_from_glist (uris, are_files);
return urlspec;
}
static void
free_urlspec (LSLaunchURLSpec *urlspec)
clear_urlspec (LSLaunchURLSpec *urlspec)
{
if (urlspec->itemURLs)
{
@ -301,7 +291,6 @@ free_urlspec (LSLaunchURLSpec *urlspec)
CFRelease (urlspec->itemURLs);
}
CFRelease (urlspec->appURL);
g_free (urlspec);
}
static NSBundle *
@ -457,20 +446,21 @@ g_osx_app_info_get_icon (GAppInfo *appinfo)
static gboolean
g_osx_app_info_launch_internal (GAppInfo *appinfo,
GList *uris,
gboolean are_files,
GError **error)
GList *uris,
gboolean are_files,
GError **error)
{
GOsxAppInfo *info = G_OSX_APP_INFO (appinfo);
LSLaunchURLSpec *urlspec;
LSLaunchURLSpec urlspec;
gint ret, success = TRUE;
g_return_val_if_fail (G_IS_OSX_APP_INFO (appinfo), FALSE);
g_return_val_if_fail (uris == NULL, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
urlspec = create_urlspec_for_appinfo (info, uris, are_files);
fill_urlspec_for_appinfo (&urlspec, info, uris, are_files);
if ((ret = LSOpenFromURLSpec (urlspec, NULL)))
if ((ret = LSOpenFromURLSpec (&urlspec, NULL)))
{
/* TODO: Better error codes */
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
@ -478,7 +468,7 @@ g_osx_app_info_launch_internal (GAppInfo *appinfo,
success = FALSE;
}
free_urlspec (urlspec);
clear_urlspec (&urlspec);
return success;
}
@ -512,6 +502,72 @@ g_osx_app_info_launch_uris (GAppInfo *appinfo,
return g_osx_app_info_launch_internal (appinfo, uris, FALSE, error);
}
typedef struct
{
GList *uris; /* (element-type utf8) (owned) (nullable) */
GAppLaunchContext *context; /* (owned) (nullable) */
} LaunchUrisData;
static void
launch_uris_data_free (LaunchUrisData *data)
{
g_clear_object (&data->context);
g_list_free_full (data->uris, g_free);
g_free (data);
}
static void
launch_uris_async_thread (GTask *task,
gpointer source_object,
gpointer task_data,
GCancellable *cancellable)
{
GAppInfo *appinfo = G_APP_INFO (source_object);
LaunchUrisData *data = task_data;
GError *local_error = NULL;
gboolean succeeded;
succeeded = g_osx_app_info_launch_internal (appinfo, data->uris, FALSE, &local_error);
if (local_error != NULL)
g_task_return_error (task, g_steal_pointer (&local_error));
else
g_task_return_boolean (task, succeeded);
}
static void
g_osx_app_info_launch_uris_async (GAppInfo *appinfo,
GList *uris,
GAppLaunchContext *context,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
GTask *task;
LaunchUrisData *data;
task = g_task_new (appinfo, cancellable, callback, user_data);
g_task_set_source_tag (task, g_osx_app_info_launch_uris_async);
data = g_new0 (LaunchUrisData, 1);
data->uris = g_list_copy_deep (uris, (GCopyFunc) g_strdup, NULL);
g_set_object (&data->context, context);
g_task_set_task_data (task, g_steal_pointer (&data), (GDestroyNotify) launch_uris_data_free);
g_task_run_in_thread (task, launch_uris_async_thread);
g_object_unref (task);
}
static gboolean
g_osx_app_info_launch_uris_finish (GAppInfo *appinfo,
GAsyncResult *result,
GError **error)
{
g_return_val_if_fail (g_task_is_valid (result, appinfo), FALSE);
return g_task_propagate_boolean (G_TASK (result), error);
}
static gboolean
g_osx_app_info_should_show (GAppInfo *appinfo)
{
@ -569,7 +625,8 @@ g_osx_app_info_iface_init (GAppInfoIface *iface)
iface->launch = g_osx_app_info_launch;
iface->launch_uris = g_osx_app_info_launch_uris;
iface->launch_uris_async = g_osx_app_info_launch_uris_async;
iface->launch_uris_finish = g_osx_app_info_launch_uris_finish;
iface->supports_uris = g_osx_app_info_supports_uris;
iface->supports_files = g_osx_app_info_supports_files;
iface->should_show = g_osx_app_info_should_show;