diff options
Diffstat (limited to 'src/nautilus-program-choosing.c')
-rw-r--r-- | src/nautilus-program-choosing.c | 277 |
1 files changed, 257 insertions, 20 deletions
diff --git a/src/nautilus-program-choosing.c b/src/nautilus-program-choosing.c index 92c6ddcf7..bb3c5c393 100644 --- a/src/nautilus-program-choosing.c +++ b/src/nautilus-program-choosing.c @@ -86,6 +86,32 @@ nautilus_launch_application (GAppInfo *application, g_list_free_full (uris, g_free); } +static GdkAppLaunchContext * +get_launch_context (GtkWindow *parent_window) +{ + GdkDisplay *display; + GdkAppLaunchContext *launch_context; + + if (parent_window != NULL) + { + display = gtk_widget_get_display (GTK_WIDGET (parent_window)); + } + else + { + display = gdk_display_get_default (); + } + + launch_context = gdk_display_get_app_launch_context (display); + + if (parent_window != NULL) + { + gdk_app_launch_context_set_screen (launch_context, + gtk_window_get_screen (parent_window)); + } + + return launch_context; +} + void nautilus_launch_application_by_uri (GAppInfo *application, GList *uris, @@ -97,8 +123,7 @@ nautilus_launch_application_by_uri (GAppInfo *application, NautilusFile *file; gboolean result; GError *error; - GdkDisplay *display; - GdkAppLaunchContext *launch_context; + g_autoptr (GdkAppLaunchContext) launch_context = NULL; NautilusIconInfo *icon; int count, total; @@ -121,22 +146,7 @@ nautilus_launch_application_by_uri (GAppInfo *application, } locations = g_list_reverse (locations); - if (parent_window != NULL) - { - display = gtk_widget_get_display (GTK_WIDGET (parent_window)); - } - else - { - display = gdk_display_get_default (); - } - - launch_context = gdk_display_get_app_launch_context (display); - - if (parent_window != NULL) - { - gdk_app_launch_context_set_screen (launch_context, - gtk_window_get_screen (parent_window)); - } + launch_context = get_launch_context (parent_window); file = nautilus_file_get_by_uri (uris->data); icon = nautilus_file_get_icon (file, @@ -172,8 +182,6 @@ nautilus_launch_application_by_uri (GAppInfo *application, &error); } - g_object_unref (launch_context); - if (result) { for (l = uris; l != NULL; l = l->next) @@ -430,3 +438,232 @@ nautilus_launch_desktop_file (GdkScreen *screen, g_object_unref (context); g_object_unref (app_info); } + +/* HAX + * + * TODO: remove everything below once it’s doable from GTK+. + */ + +#ifdef GDK_WINDOWING_WAYLAND +#include <gdk/gdkwayland.h> +#endif + +typedef void (*GtkWindowHandleExported) (GtkWindow *window, + const char *handle, + gpointer user_data); + +#ifdef GDK_WINDOWING_WAYLAND +typedef struct +{ + GtkWindow *window; + GtkWindowHandleExported callback; + gpointer user_data; +} WaylandWindowHandleExportedData; + +static void +wayland_window_handle_exported (GdkWindow *window, + const char *wayland_handle_str, + gpointer user_data) +{ + WaylandWindowHandleExportedData *data = user_data; + char *handle_str; + + handle_str = g_strdup_printf ("wayland:%s", wayland_handle_str); + data->callback (data->window, handle_str, data->user_data); + g_free (handle_str); + + g_free (data); +} +#endif + +static gboolean +window_export_handle (GtkWindow *window, + GtkWindowHandleExported callback, + gpointer user_data) +{ + +#ifdef GDK_WINDOWING_X11 + if (GDK_IS_X11_DISPLAY (gtk_widget_get_display (GTK_WIDGET (window)))) + { + GdkWindow *gdk_window = gtk_widget_get_window (GTK_WIDGET (window)); + char *handle_str; + guint32 xid = (guint32) gdk_x11_window_get_xid (gdk_window); + + handle_str = g_strdup_printf ("x11:%x", xid); + callback (window, handle_str, user_data); + + return TRUE; + } +#endif +#ifdef GDK_WINDOWING_WAYLAND + if (GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (GTK_WIDGET (window)))) + { + GdkWindow *gdk_window = gtk_widget_get_window (GTK_WIDGET (window)); + WaylandWindowHandleExportedData *data; + + data = g_new0 (WaylandWindowHandleExportedData, 1); + data->window = window; + data->callback = callback; + data->user_data = user_data; + + if (!gdk_wayland_window_export_handle (gdk_window, + wayland_window_handle_exported, + data, + g_free)) + { + g_free (data); + return FALSE; + } + else + { + return TRUE; + } + } +#endif + + g_warning ("Couldn't export handle, unsupported windowing system"); + + return FALSE; +} + +void +gtk_window_unexport_handle (GtkWindow *window) +{ +#ifdef GDK_WINDOWING_WAYLAND + if (GDK_IS_WAYLAND_DISPLAY (gtk_widget_get_display (GTK_WIDGET (window)))) + { + GdkWindow *gdk_window = gtk_widget_get_window (GTK_WIDGET (window)); + + gdk_wayland_window_unexport_handle (gdk_window); + } +#endif +} + +static void +on_launch_default_for_uri (GObject *source, + GAsyncResult *result, + gpointer data) +{ + GTask *task; + GtkWindow *window; + gboolean success; + GError *error = NULL; + + task = data; + window = g_task_get_source_object (task); + + success = g_app_info_launch_default_for_uri_finish (result, &error); + + if (window) + { + gtk_window_unexport_handle (window); + } + + if (success) + { + g_task_return_boolean (task, success); + } + else + { + g_task_return_error (task, error); + } + + /* Reffed in the call to window_export_handle */ + g_object_unref (task); +} + +static void +on_window_handle_export (GtkWindow *window, + const char *handle_str, + gpointer user_data) +{ + GTask *task = user_data; + GAppLaunchContext *context = g_task_get_task_data (task); + const char *uri; + + uri = g_object_get_data (G_OBJECT (context), "uri"); + + g_app_launch_context_setenv (context, "PARENT_WINDOW_ID", handle_str); + + g_app_info_launch_default_for_uri_async (uri, + context, + g_task_get_cancellable (task), + on_launch_default_for_uri, + task); +} + +static void +launch_default_for_uri_thread_func (GTask *task, + gpointer source_object, + gpointer task_data, + GCancellable *cancellable) +{ + GAppLaunchContext *launch_context; + const char *uri; + gboolean success; + GError *error = NULL; + + launch_context = task_data; + uri = g_object_get_data (G_OBJECT (launch_context), "uri"); + success = g_app_info_launch_default_for_uri (uri, launch_context, &error); + + if (success) + { + g_task_return_boolean (task, success); + } + else + { + g_task_return_error (task, error); + } +} + +void +nautilus_launch_default_for_uri_async (const char *uri, + GtkWindow *parent_window, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer callback_data) +{ + g_autoptr (GdkAppLaunchContext) launch_context = NULL; + g_autoptr (GTask) task = NULL; + + g_return_if_fail (uri != NULL); + + launch_context = get_launch_context (parent_window); + task = g_task_new (parent_window, cancellable, callback, callback_data); + + gdk_app_launch_context_set_timestamp (launch_context, GDK_CURRENT_TIME); + + g_object_set_data_full (G_OBJECT (launch_context), + "uri", g_strdup (uri), g_free); + g_task_set_task_data (task, + g_object_ref (launch_context), g_object_unref); + + if (parent_window != NULL) + { + gboolean handle_exported; + + handle_exported = window_export_handle (parent_window, + on_window_handle_export, + g_object_ref (task)); + + if (handle_exported) + { + /* Launching will now be handled from the callback */ + return; + } + } + + g_task_run_in_thread (task, launch_default_for_uri_thread_func); +} + +gboolean +nautilus_launch_default_for_uri_finish (GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE); + + return g_task_propagate_boolean (G_TASK (result), error); +} + +/* END OF HAX */ |