summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2023-05-15 10:12:29 +0000
committerMatthias Clasen <mclasen@redhat.com>2023-05-15 10:12:29 +0000
commitd517b25ea3eed3bafbd6e76ab1a2622c82ac7488 (patch)
treefcd7c13ba0edf188c6a7314edec52d4f4b4d8900
parent18b8baaf25e9bcb7d0d7ec480f8d673ad7d31309 (diff)
parent37345670c8c932e2338376fc8b1e47d8bb8bf40e (diff)
downloadgtk+-d517b25ea3eed3bafbd6e76ab1a2622c82ac7488.tar.gz
Merge branch 'export-handles-properly' into 'main'
Add testfilelauncher See merge request GNOME/gtk!5968
-rw-r--r--gdk/gdktoplevel.c11
-rw-r--r--gdk/gdktoplevelprivate.h6
-rw-r--r--gdk/wayland/gdksurface-wayland.c5
-rw-r--r--gdk/wayland/gdktoplevel-wayland-private.h1
-rw-r--r--gdk/wayland/gdktoplevel-wayland.c160
-rw-r--r--gdk/wayland/gdkwaylandtoplevel.h6
-rw-r--r--gdk/x11/gdksurface-x11.c3
-rw-r--r--gtk/deprecated/gtkshow.c11
-rw-r--r--gtk/gtkfilechoosernativeportal.c8
-rw-r--r--gtk/gtkopenuriportal.c8
-rw-r--r--gtk/gtkprintoperation-portal.c8
-rw-r--r--gtk/gtkwindow.c16
-rw-r--r--gtk/gtkwindowprivate.h3
-rw-r--r--tests/meson.build1
-rw-r--r--tests/testfilelauncher.c47
15 files changed, 242 insertions, 52 deletions
diff --git a/gdk/gdktoplevel.c b/gdk/gdktoplevel.c
index 5a5c9e4d0f..6a1667768a 100644
--- a/gdk/gdktoplevel.c
+++ b/gdk/gdktoplevel.c
@@ -135,7 +135,8 @@ gdk_toplevel_default_export_handle_finish (GdkToplevel *toplevel,
}
static void
-gdk_toplevel_default_unexport_handle (GdkToplevel *toplevel)
+gdk_toplevel_default_unexport_handle (GdkToplevel *toplevel,
+ const char *handle)
{
}
@@ -791,7 +792,7 @@ gdk_toplevel_export_handle (GdkToplevel *toplevel,
* @result: the `GAsyncResult`
* @error: return location for an error
*
- * Finishes the [method@Gdk.Toplevel.export_handle] cal and
+ * Finishes the [method@Gdk.Toplevel.export_handle] call and
* returns the resulting handle.
*
* Returns: (nullable) (transfer full): the exported handle,
@@ -810,6 +811,7 @@ gdk_toplevel_export_handle_finish (GdkToplevel *toplevel,
/*< private >
* gdk_toplevel_unexport_handle:
* @toplevel: a `GdkToplevel`
+ * @handle: the handle to unexport
*
* Destroys the handle that was obtained with [method@Gdk.Toplevel.export_handle].
*
@@ -819,7 +821,8 @@ gdk_toplevel_export_handle_finish (GdkToplevel *toplevel,
* Since: 4.10
*/
void
-gdk_toplevel_unexport_handle (GdkToplevel *toplevel)
+gdk_toplevel_unexport_handle (GdkToplevel *toplevel,
+ const char *handle)
{
- GDK_TOPLEVEL_GET_IFACE (toplevel)->unexport_handle (toplevel);
+ GDK_TOPLEVEL_GET_IFACE (toplevel)->unexport_handle (toplevel, handle);
}
diff --git a/gdk/gdktoplevelprivate.h b/gdk/gdktoplevelprivate.h
index 8f0f8d6f8e..6fb6d40835 100644
--- a/gdk/gdktoplevelprivate.h
+++ b/gdk/gdktoplevelprivate.h
@@ -49,7 +49,8 @@ struct _GdkToplevelInterface
GAsyncResult *result,
GError **error);
- void (* unexport_handle) (GdkToplevel *toplevel);
+ void (* unexport_handle) (GdkToplevel *toplevel,
+ const char *handle);
};
typedef enum
@@ -82,7 +83,8 @@ char *gdk_toplevel_export_handle_finish (GdkToplevel *toplevel,
GAsyncResult *result,
GError **error);
-void gdk_toplevel_unexport_handle (GdkToplevel *toplevel);
+void gdk_toplevel_unexport_handle (GdkToplevel *toplevel,
+ const char *handle);
G_END_DECLS
diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c
index 5663a42d38..9d92737f83 100644
--- a/gdk/wayland/gdksurface-wayland.c
+++ b/gdk/wayland/gdksurface-wayland.c
@@ -1148,7 +1148,10 @@ gdk_wayland_surface_destroy (GdkSurface *surface,
gdk_wayland_surface_hide_surface (surface);
- gdk_wayland_surface_destroy_wl_surface (GDK_WAYLAND_SURFACE(surface));
+ if (GDK_IS_TOPLEVEL (surface))
+ gdk_wayland_toplevel_destroy (GDK_TOPLEVEL (surface));
+
+ gdk_wayland_surface_destroy_wl_surface (GDK_WAYLAND_SURFACE (surface));
frame_clock = gdk_surface_get_frame_clock (surface);
g_signal_handlers_disconnect_by_func (frame_clock, on_frame_clock_before_paint, surface);
diff --git a/gdk/wayland/gdktoplevel-wayland-private.h b/gdk/wayland/gdktoplevel-wayland-private.h
index 9b06101371..bd0836c0a0 100644
--- a/gdk/wayland/gdktoplevel-wayland-private.h
+++ b/gdk/wayland/gdktoplevel-wayland-private.h
@@ -39,3 +39,4 @@ void gdk_wayland_toplevel_announce_ssd (GdkToplevel *toplevel);
gboolean gdk_wayland_toplevel_inhibit_idle (GdkToplevel *toplevel);
void gdk_wayland_toplevel_uninhibit_idle (GdkToplevel *toplevel);
+void gdk_wayland_toplevel_destroy (GdkToplevel *toplevel);
diff --git a/gdk/wayland/gdktoplevel-wayland.c b/gdk/wayland/gdktoplevel-wayland.c
index 022e341dd7..efe9ef86ce 100644
--- a/gdk/wayland/gdktoplevel-wayland.c
+++ b/gdk/wayland/gdktoplevel-wayland.c
@@ -54,11 +54,16 @@ static void gdk_wayland_toplevel_sync_parent (GdkWaylandToplevel *to
static void gdk_wayland_toplevel_sync_parent_of_imported (GdkWaylandToplevel *toplevel);
static void gdk_wayland_surface_create_xdg_toplevel (GdkWaylandToplevel *toplevel);
static void gdk_wayland_toplevel_sync_title (GdkWaylandToplevel *toplevel);
-static gboolean gdk_wayland_toplevel_is_exported (GdkWaylandToplevel *toplevel);
static void unset_transient_for_exported (GdkWaylandToplevel *toplevel);
/* {{{ GdkWaylandToplevel definition */
+typedef struct {
+ struct zxdg_exported_v1 *xdg_exported;
+ struct zxdg_exported_v2 *xdg_exported_v2;
+ char *handle;
+} GdkWaylandExported;
+
/**
* GdkWaylandToplevel:
*
@@ -83,8 +88,7 @@ struct _GdkWaylandToplevel
GdkWaylandToplevel *transient_for;
struct org_kde_kwin_server_decoration *server_decoration;
- struct zxdg_exported_v1 *xdg_exported;
- struct zxdg_exported_v2 *xdg_exported_v2;
+ GList *exported;
struct {
int width;
@@ -103,12 +107,6 @@ struct _GdkWaylandToplevel
} next_layout;
struct {
- GdkWaylandToplevelExported callback;
- gpointer user_data;
- GDestroyNotify destroy_func;
- } exported;
-
- struct {
gboolean was_set;
char *application_id;
@@ -1280,9 +1278,6 @@ gdk_wayland_toplevel_finalize (GObject *object)
display_wayland->toplevels = g_list_remove (display_wayland->toplevels, self);
- if (gdk_wayland_toplevel_is_exported (self))
- gdk_wayland_toplevel_unexport_handle (GDK_TOPLEVEL (self));
-
g_free (self->application.application_id);
g_free (self->application.app_menu_path);
g_free (self->application.menubar_path);
@@ -1747,8 +1742,12 @@ xdg_exported_handle_v1 (void *data,
struct zxdg_exported_v1 *zxdg_exported_v1,
const char *handle)
{
- g_task_return_pointer (G_TASK (data), g_strdup (handle), g_free);
- g_object_unref (data);
+ GTask *task = G_TASK (data);
+ GdkWaylandExported *exported = (GdkWaylandExported *)g_task_get_task_data (task);
+
+ exported->handle = g_strdup (handle);
+ g_task_return_pointer (task, g_strdup (handle), g_free);
+ g_object_unref (task);
}
static const struct zxdg_exported_v1_listener xdg_exported_listener_v1 = {
@@ -1760,8 +1759,12 @@ xdg_exported_handle_v2 (void *data,
struct zxdg_exported_v2 *zxdg_exported_v2,
const char *handle)
{
- g_task_return_pointer (G_TASK (data), g_strdup (handle), g_free);
- g_object_unref (data);
+ GTask *task = G_TASK (data);
+ GdkWaylandExported *exported = (GdkWaylandExported *)g_task_get_task_data (task);
+
+ exported->handle = g_strdup (handle);
+ g_task_return_pointer (task, g_strdup (handle), g_free);
+ g_object_unref (task);
}
static const struct zxdg_exported_v2_listener xdg_exported_listener_v2 = {
@@ -1784,19 +1787,27 @@ gdk_wayland_toplevel_real_export_handle (GdkToplevel *toplevel,
if (display_wayland->xdg_exporter_v2)
{
- wayland_toplevel->xdg_exported_v2 =
+ GdkWaylandExported *exported = g_new0 (GdkWaylandExported, 1);
+ exported->xdg_exported_v2 =
zxdg_exporter_v2_export_toplevel (display_wayland->xdg_exporter_v2,
gdk_wayland_surface_get_wl_surface (surface));
- zxdg_exported_v2_add_listener (wayland_toplevel->xdg_exported_v2,
+ zxdg_exported_v2_add_listener (exported->xdg_exported_v2,
&xdg_exported_listener_v2, task);
+
+ wayland_toplevel->exported = g_list_prepend (wayland_toplevel->exported, exported);
+ g_task_set_task_data (task, exported, NULL);
}
else if (display_wayland->xdg_exporter)
{
- wayland_toplevel->xdg_exported =
+ GdkWaylandExported *exported = g_new0 (GdkWaylandExported, 1);
+ exported->xdg_exported =
zxdg_exporter_v1_export (display_wayland->xdg_exporter,
gdk_wayland_surface_get_wl_surface (surface));
- zxdg_exported_v1_add_listener (wayland_toplevel->xdg_exported,
+ zxdg_exported_v1_add_listener (exported->xdg_exported,
&xdg_exported_listener_v1, task);
+
+ wayland_toplevel->exported = g_list_prepend (wayland_toplevel->exported, exported);
+ g_task_set_task_data (task, exported, NULL);
}
else
{
@@ -1815,15 +1826,36 @@ gdk_wayland_toplevel_real_export_handle_finish (GdkToplevel *toplevel,
}
static void
-gdk_wayland_toplevel_real_unexport_handle (GdkToplevel *toplevel)
+destroy_exported (GdkWaylandExported *exported)
+{
+ g_clear_pointer (&exported->handle, g_free);
+ g_clear_pointer (&exported->xdg_exported_v2, zxdg_exported_v2_destroy);
+ g_clear_pointer (&exported->xdg_exported, zxdg_exported_v1_destroy);
+ g_free (exported);
+}
+
+static void
+gdk_wayland_toplevel_real_unexport_handle (GdkToplevel *toplevel,
+ const char *handle)
{
GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel));
- g_return_if_fail (wayland_toplevel->xdg_exported_v2 || wayland_toplevel->xdg_exported);
+ g_return_if_fail (handle != NULL);
+
+ for (GList *l = wayland_toplevel->exported; l; l = l->next)
+ {
+ GdkWaylandExported *exported = l->data;
+
+ if (exported->handle && strcmp (exported->handle, handle) == 0)
+ {
+ wayland_toplevel->exported = g_list_delete_link (wayland_toplevel->exported, l);
+ destroy_exported (exported);
+ return;
+ }
+ }
- g_clear_pointer (&wayland_toplevel->xdg_exported_v2, zxdg_exported_v2_destroy);
- g_clear_pointer (&wayland_toplevel->xdg_exported, zxdg_exported_v1_destroy);
+ g_warn_if_reached ();
}
static gboolean
@@ -2255,6 +2287,32 @@ gdk_wayland_toplevel_set_dbus_properties (GdkToplevel *toplevel,
maybe_set_gtk_surface_dbus_properties (wayland_toplevel);
}
+void
+gdk_wayland_toplevel_destroy (GdkToplevel *toplevel)
+{
+ GdkWaylandToplevel *self = GDK_WAYLAND_TOPLEVEL (toplevel);
+
+ while (self->exported)
+ {
+ GdkWaylandExported *exported = self->exported->data;
+ self->exported = g_list_delete_link (self->exported, self->exported);
+ if (exported->handle == NULL)
+ {
+ GTask *task;
+
+ if (exported->xdg_exported_v2)
+ task = G_TASK (wl_proxy_get_user_data ((struct wl_proxy *) exported->xdg_exported_v2));
+ else
+ task = G_TASK (wl_proxy_get_user_data ((struct wl_proxy *) exported->xdg_exported));
+
+ g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, "Surface was destroyed");
+ g_object_unref (task);
+ }
+
+ destroy_exported (exported);
+ }
+}
+
/* }}} */
/* {{{ Toplevel API */
@@ -2397,12 +2455,6 @@ gdk_wayland_toplevel_uninhibit_idle (GdkToplevel *toplevel)
* marking surfaces as transient for out-of-process surfaces.
*/
-static gboolean
-gdk_wayland_toplevel_is_exported (GdkWaylandToplevel *toplevel)
-{
- return toplevel->xdg_exported != NULL || toplevel->xdg_exported_v2 != NULL;
-}
-
typedef struct {
GdkWaylandToplevelExported callback;
gpointer user_data;
@@ -2450,6 +2502,12 @@ export_handle_done (GObject *source,
* from another surface as transient for this one, see
* [method@GdkWayland.WaylandToplevel.set_transient_for_exported].
*
+ * Before 4.12, this API could not safely be used multiple times,
+ * since there was no reference counting for handles. Starting with
+ * 4.12, every call to this function obtains a new handle, and every
+ * call to [method@GdkWayland.WaylandToplevel.drop_exported_handle] drops
+ * just the handle that it is given.
+ *
* Note that this API depends on an unstable Wayland protocol,
* and thus may require changes in the future.
*
@@ -2486,15 +2544,53 @@ gdk_wayland_toplevel_export_handle (GdkToplevel *toplevel,
* It is an error to call this function on a surface that
* does not have a handle.
*
+ * Since 4.12, this function does nothing. Use
+ * [method@GdkWayland.WaylandToplevel.drop_exported_handle] instead to drop a
+ * handle that was obtained with [method@GdkWayland.WaylandToplevel.export_handle].
+ *
* Note that this API depends on an unstable Wayland protocol,
* and thus may require changes in the future.
+ *
+ * Deprecated: 4.12: Use [method@GdkWayland.WaylandToplevel.drop_exported_handle]
+ * instead, this function does nothing
*/
void
gdk_wayland_toplevel_unexport_handle (GdkToplevel *toplevel)
{
- g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel));
+ GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
+
+ if (wayland_toplevel->exported != NULL &&
+ wayland_toplevel->exported->next == NULL)
+ {
+ GdkWaylandExported *exported = wayland_toplevel->exported->data;
- gdk_toplevel_unexport_handle (toplevel);
+ if (exported->handle)
+ {
+ gdk_toplevel_unexport_handle (toplevel, exported->handle);
+ return;
+ }
+ }
+
+ g_warning ("Use gdk_wayland_toplevel_drop_exported_handle()");
+}
+
+/**
+ * gdk_wayland_toplevel_drop_exported_handle:
+ * @toplevel: (type GdkWaylandToplevel): the `GdkToplevel` that was exported
+ * @handle: the handle to drop
+ *
+ * Destroy a handle that was obtained with gdk_wayland_toplevel_export_handle().
+ *
+ * Note that this API depends on an unstable Wayland protocol,
+ * and thus may require changes in the future.
+ *
+ * Since: 4.12
+ */
+void
+gdk_wayland_toplevel_drop_exported_handle (GdkToplevel *toplevel,
+ const char *handle)
+{
+ gdk_toplevel_unexport_handle (toplevel, handle);
}
static void
diff --git a/gdk/wayland/gdkwaylandtoplevel.h b/gdk/wayland/gdkwaylandtoplevel.h
index 36410b3054..0240f9d19f 100644
--- a/gdk/wayland/gdkwaylandtoplevel.h
+++ b/gdk/wayland/gdkwaylandtoplevel.h
@@ -52,9 +52,13 @@ gboolean gdk_wayland_toplevel_export_handle (GdkToplevel
gpointer user_data,
GDestroyNotify destroy_func);
-GDK_AVAILABLE_IN_ALL
+GDK_DEPRECATED_IN_4_12_FOR(gdk_wayland_toplevel_drop_exported_handle)
void gdk_wayland_toplevel_unexport_handle (GdkToplevel *toplevel);
+GDK_AVAILABLE_IN_4_12
+void gdk_wayland_toplevel_drop_exported_handle (GdkToplevel *toplevel,
+ const char *handle);
+
GDK_AVAILABLE_IN_ALL
gboolean gdk_wayland_toplevel_set_transient_for_exported (GdkToplevel *toplevel,
const char *parent_handle_str);
diff --git a/gdk/x11/gdksurface-x11.c b/gdk/x11/gdksurface-x11.c
index db8a8770ed..468ee941b6 100644
--- a/gdk/x11/gdksurface-x11.c
+++ b/gdk/x11/gdksurface-x11.c
@@ -5318,7 +5318,8 @@ gdk_x11_toplevel_export_handle_finish (GdkToplevel *toplevel,
}
static void
-gdk_x11_toplevel_unexport_handle (GdkToplevel *toplevel)
+gdk_x11_toplevel_unexport_handle (GdkToplevel *toplevel,
+ const char *handle)
{
}
diff --git a/gtk/deprecated/gtkshow.c b/gtk/deprecated/gtkshow.c
index cd37905cf0..3c3b9616cd 100644
--- a/gtk/deprecated/gtkshow.c
+++ b/gtk/deprecated/gtkshow.c
@@ -31,6 +31,7 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
typedef struct {
GtkWindow *parent;
+ char *handle;
GAppLaunchContext *context;
char *uri;
GTask *task;
@@ -39,9 +40,10 @@ typedef struct {
static void
gtk_show_uri_data_free (GtkShowUriData *data)
{
- if (data->parent)
- gtk_window_unexport_handle (data->parent);
+ if (data->parent && data->handle)
+ gtk_window_unexport_handle (data->parent, data->handle);
g_clear_object (&data->parent);
+ g_free (data->handle);
g_clear_object (&data->context);
g_free (data->uri);
g_clear_object (&data->task);
@@ -72,7 +74,10 @@ window_handle_exported (GtkWindow *window,
GtkShowUriData *data = user_data;
if (handle)
- g_app_launch_context_setenv (data->context, "PARENT_WINDOW_ID", handle);
+ {
+ g_app_launch_context_setenv (data->context, "PARENT_WINDOW_ID", handle);
+ data->handle = g_strdup (handle);
+ }
g_app_info_launch_default_for_uri_async (data->uri,
data->context,
diff --git a/gtk/gtkfilechoosernativeportal.c b/gtk/gtkfilechoosernativeportal.c
index 3d73fa6db9..4bb312d8fb 100644
--- a/gtk/gtkfilechoosernativeportal.c
+++ b/gtk/gtkfilechoosernativeportal.c
@@ -52,6 +52,7 @@ typedef struct {
const char *method_name;
+ char *exported_handle;
GtkWindow *exported_window;
PortalErrorHandler error_handler;
} FilechooserPortalData;
@@ -79,7 +80,11 @@ filechooser_portal_data_clear (FilechooserPortalData *data)
if (data->exported_window)
{
- gtk_window_unexport_handle (data->exported_window);
+ if (data->exported_handle)
+ {
+ gtk_window_unexport_handle (data->exported_window, data->exported_handle);
+ g_clear_pointer (&data->exported_handle, g_free);
+ }
g_clear_object (&data->exported_window);
}
@@ -460,6 +465,7 @@ window_handle_exported (GtkWindow *window,
gtk_grab_add (GTK_WIDGET (data->grab_widget));
}
+ data->exported_handle = g_strdup (handle_str);
show_portal_file_chooser (self, handle_str);
}
diff --git a/gtk/gtkopenuriportal.c b/gtk/gtkopenuriportal.c
index 1bec7a1cb0..67778affda 100644
--- a/gtk/gtkopenuriportal.c
+++ b/gtk/gtkopenuriportal.c
@@ -108,6 +108,7 @@ enum {
typedef struct {
GtkWindow *parent;
+ char *parent_handle;
GFile *file;
char *uri;
gboolean open_folder;
@@ -128,8 +129,9 @@ open_uri_data_free (OpenUriData *data)
g_clear_object (&data->connection);
if (data->cancel_handler)
g_signal_handler_disconnect (data->cancellable, data->cancel_handler);
- if (data->parent)
- gtk_window_unexport_handle (data->parent);
+ if (data->parent && data->parent_handle)
+ gtk_window_unexport_handle (data->parent, data->parent_handle);
+ g_free (data->parent_handle);
g_clear_object (&data->parent);
g_clear_object (&data->file);
g_free (data->uri);
@@ -426,6 +428,8 @@ window_handle_exported (GtkWindow *window,
GAppLaunchContext *context;
char *activation_token = NULL;
+ data->parent_handle = g_strdup (handle);
+
if (window)
display = gtk_widget_get_display (GTK_WIDGET (window));
else
diff --git a/gtk/gtkprintoperation-portal.c b/gtk/gtkprintoperation-portal.c
index 61e4071df4..d39ad1645c 100644
--- a/gtk/gtkprintoperation-portal.c
+++ b/gtk/gtkprintoperation-portal.c
@@ -48,6 +48,7 @@ typedef struct {
GtkPrintOperationResult result;
GtkPrintOperationPrintFunc print_cb;
GtkWindow *parent;
+ char *handle;
GMainLoop *loop;
guint32 token;
GDestroyNotify destroy;
@@ -62,8 +63,9 @@ portal_data_free (gpointer data)
{
PortalData *portal = data;
- if (portal->parent)
- gtk_window_unexport_handle (portal->parent);
+ if (portal->parent && portal->handle)
+ gtk_window_unexport_handle (portal->parent, portal->handle);
+ g_free (portal->handle);
g_object_unref (portal->op);
g_object_unref (portal->proxy);
if (portal->loop)
@@ -547,6 +549,8 @@ window_handle_exported (GtkWindow *window,
{
PortalData *portal = user_data;
+ portal->handle = g_strdup (handle_str);
+
g_dbus_proxy_call (portal->proxy,
"PreparePrint",
g_variant_new ("(ss@a{sv}@a{sv}@a{sv})",
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index 42f1765cd0..4b67f2793b 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -6291,6 +6291,17 @@ prefix_handle (GdkDisplay *display,
return NULL;
}
+static const char *
+unprefix_handle (const char *handle)
+{
+ if (g_str_has_prefix (handle, "wayland:"))
+ return handle + strlen ("wayland:");
+ else if (g_str_has_prefix (handle, "x11:"))
+ return handle + strlen ("x1!:");
+ else
+ return handle;
+}
+
static void
export_handle_done (GObject *source,
GAsyncResult *result,
@@ -6336,11 +6347,12 @@ gtk_window_export_handle (GtkWindow *window,
}
void
-gtk_window_unexport_handle (GtkWindow *window)
+gtk_window_unexport_handle (GtkWindow *window,
+ const char *handle)
{
GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
- gdk_toplevel_unexport_handle (GDK_TOPLEVEL (priv->surface));
+ gdk_toplevel_unexport_handle (GDK_TOPLEVEL (priv->surface), unprefix_handle (handle));
}
static GtkPointerFocus *
diff --git a/gtk/gtkwindowprivate.h b/gtk/gtkwindowprivate.h
index d17ce474da..96d9dd110b 100644
--- a/gtk/gtkwindowprivate.h
+++ b/gtk/gtkwindowprivate.h
@@ -79,7 +79,8 @@ typedef void (*GtkWindowHandleExported) (GtkWindow *window,
gboolean gtk_window_export_handle (GtkWindow *window,
GtkWindowHandleExported callback,
gpointer user_data);
-void gtk_window_unexport_handle (GtkWindow *window);
+void gtk_window_unexport_handle (GtkWindow *window,
+ const char *handle);
GtkWidget * gtk_window_lookup_pointer_focus_widget (GtkWindow *window,
GdkDevice *device,
diff --git a/tests/meson.build b/tests/meson.build
index c2d08c26de..c9c6e6a4cd 100644
--- a/tests/meson.build
+++ b/tests/meson.build
@@ -1,5 +1,6 @@
gtk_tests = [
# testname, optional extra sources
+ ['testfilelauncher'],
['input'],
['testpopup'],
['testupload'],
diff --git a/tests/testfilelauncher.c b/tests/testfilelauncher.c
new file mode 100644
index 0000000000..3a44037d51
--- /dev/null
+++ b/tests/testfilelauncher.c
@@ -0,0 +1,47 @@
+#include <gtk/gtk.h>
+
+static void
+launched_cb (GObject *source,
+ GAsyncResult *result,
+ gpointer data)
+{
+ GtkFileLauncher *launcher = GTK_FILE_LAUNCHER (source);
+ GError *error = NULL;
+
+ if (!gtk_file_launcher_launch_finish (launcher, result, &error))
+ {
+ g_print ("Launching failed: %s\n", error->message);
+ g_error_free (error);
+ }
+}
+
+int
+main (int argc, char *argv[])
+{
+ GtkWidget *window;
+ GtkFileLauncher *launcher;
+
+ gtk_init ();
+
+ window = gtk_window_new ();
+
+ launcher = gtk_file_launcher_new (NULL);
+
+ gtk_window_present (GTK_WINDOW (window));
+
+ for (int i = 1; i < argc; i++)
+ {
+ GFile *file = g_file_new_for_commandline_arg (argv[i]);
+
+ g_print ("launching %s\n", argv[i]);
+
+ gtk_file_launcher_set_file (launcher, file);
+ gtk_file_launcher_launch (launcher, GTK_WINDOW (window), NULL, launched_cb, NULL);
+ g_object_unref (file);
+ }
+
+ while (g_list_model_get_n_items (gtk_window_get_toplevels ()) > 0)
+ g_main_context_iteration (NULL, FALSE);
+
+ return 0;
+}