Merge branch 'export-handles-properly' into 'main'

Add testfilelauncher

See merge request GNOME/gtk!5968
This commit is contained in:
Matthias Clasen 2023-05-15 10:12:29 +00:00
commit d517b25ea3
15 changed files with 242 additions and 52 deletions

View File

@ -135,7 +135,8 @@ gdk_toplevel_default_export_handle_finish (GdkToplevel *toplevel,
} }
static void 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` * @result: the `GAsyncResult`
* @error: return location for an error * @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 the resulting handle.
* *
* Returns: (nullable) (transfer full): the exported handle, * Returns: (nullable) (transfer full): the exported handle,
@ -810,6 +811,7 @@ gdk_toplevel_export_handle_finish (GdkToplevel *toplevel,
/*< private > /*< private >
* gdk_toplevel_unexport_handle: * gdk_toplevel_unexport_handle:
* @toplevel: a `GdkToplevel` * @toplevel: a `GdkToplevel`
* @handle: the handle to unexport
* *
* Destroys the handle that was obtained with [method@Gdk.Toplevel.export_handle]. * 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 * Since: 4.10
*/ */
void 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);
} }

View File

@ -49,7 +49,8 @@ struct _GdkToplevelInterface
GAsyncResult *result, GAsyncResult *result,
GError **error); GError **error);
void (* unexport_handle) (GdkToplevel *toplevel); void (* unexport_handle) (GdkToplevel *toplevel,
const char *handle);
}; };
typedef enum typedef enum
@ -82,7 +83,8 @@ char *gdk_toplevel_export_handle_finish (GdkToplevel *toplevel,
GAsyncResult *result, GAsyncResult *result,
GError **error); GError **error);
void gdk_toplevel_unexport_handle (GdkToplevel *toplevel); void gdk_toplevel_unexport_handle (GdkToplevel *toplevel,
const char *handle);
G_END_DECLS G_END_DECLS

View File

@ -1148,7 +1148,10 @@ gdk_wayland_surface_destroy (GdkSurface *surface,
gdk_wayland_surface_hide_surface (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); frame_clock = gdk_surface_get_frame_clock (surface);
g_signal_handlers_disconnect_by_func (frame_clock, on_frame_clock_before_paint, surface); g_signal_handlers_disconnect_by_func (frame_clock, on_frame_clock_before_paint, surface);

View File

@ -39,3 +39,4 @@ void gdk_wayland_toplevel_announce_ssd (GdkToplevel *toplevel);
gboolean gdk_wayland_toplevel_inhibit_idle (GdkToplevel *toplevel); gboolean gdk_wayland_toplevel_inhibit_idle (GdkToplevel *toplevel);
void gdk_wayland_toplevel_uninhibit_idle (GdkToplevel *toplevel); void gdk_wayland_toplevel_uninhibit_idle (GdkToplevel *toplevel);
void gdk_wayland_toplevel_destroy (GdkToplevel *toplevel);

View File

@ -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_toplevel_sync_parent_of_imported (GdkWaylandToplevel *toplevel);
static void gdk_wayland_surface_create_xdg_toplevel (GdkWaylandToplevel *toplevel); static void gdk_wayland_surface_create_xdg_toplevel (GdkWaylandToplevel *toplevel);
static void gdk_wayland_toplevel_sync_title (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); static void unset_transient_for_exported (GdkWaylandToplevel *toplevel);
/* {{{ GdkWaylandToplevel definition */ /* {{{ GdkWaylandToplevel definition */
typedef struct {
struct zxdg_exported_v1 *xdg_exported;
struct zxdg_exported_v2 *xdg_exported_v2;
char *handle;
} GdkWaylandExported;
/** /**
* GdkWaylandToplevel: * GdkWaylandToplevel:
* *
@ -83,8 +88,7 @@ struct _GdkWaylandToplevel
GdkWaylandToplevel *transient_for; GdkWaylandToplevel *transient_for;
struct org_kde_kwin_server_decoration *server_decoration; struct org_kde_kwin_server_decoration *server_decoration;
struct zxdg_exported_v1 *xdg_exported; GList *exported;
struct zxdg_exported_v2 *xdg_exported_v2;
struct { struct {
int width; int width;
@ -102,12 +106,6 @@ struct _GdkWaylandToplevel
gboolean size_is_fixed; gboolean size_is_fixed;
} next_layout; } next_layout;
struct {
GdkWaylandToplevelExported callback;
gpointer user_data;
GDestroyNotify destroy_func;
} exported;
struct { struct {
gboolean was_set; gboolean was_set;
@ -1280,9 +1278,6 @@ gdk_wayland_toplevel_finalize (GObject *object)
display_wayland->toplevels = g_list_remove (display_wayland->toplevels, self); 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.application_id);
g_free (self->application.app_menu_path); g_free (self->application.app_menu_path);
g_free (self->application.menubar_path); g_free (self->application.menubar_path);
@ -1747,8 +1742,12 @@ xdg_exported_handle_v1 (void *data,
struct zxdg_exported_v1 *zxdg_exported_v1, struct zxdg_exported_v1 *zxdg_exported_v1,
const char *handle) const char *handle)
{ {
g_task_return_pointer (G_TASK (data), g_strdup (handle), g_free); GTask *task = G_TASK (data);
g_object_unref (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 = { 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, struct zxdg_exported_v2 *zxdg_exported_v2,
const char *handle) const char *handle)
{ {
g_task_return_pointer (G_TASK (data), g_strdup (handle), g_free); GTask *task = G_TASK (data);
g_object_unref (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 = { 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) 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, zxdg_exporter_v2_export_toplevel (display_wayland->xdg_exporter_v2,
gdk_wayland_surface_get_wl_surface (surface)); 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); &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) 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, zxdg_exporter_v1_export (display_wayland->xdg_exporter,
gdk_wayland_surface_get_wl_surface (surface)); 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); &xdg_exported_listener_v1, task);
wayland_toplevel->exported = g_list_prepend (wayland_toplevel->exported, exported);
g_task_set_task_data (task, exported, NULL);
} }
else else
{ {
@ -1815,15 +1826,36 @@ gdk_wayland_toplevel_real_export_handle_finish (GdkToplevel *toplevel,
} }
static void 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); GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
g_return_if_fail (GDK_IS_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);
g_clear_pointer (&wayland_toplevel->xdg_exported_v2, zxdg_exported_v2_destroy); for (GList *l = wayland_toplevel->exported; l; l = l->next)
g_clear_pointer (&wayland_toplevel->xdg_exported, zxdg_exported_v1_destroy); {
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_warn_if_reached ();
} }
static gboolean static gboolean
@ -2255,6 +2287,32 @@ gdk_wayland_toplevel_set_dbus_properties (GdkToplevel *toplevel,
maybe_set_gtk_surface_dbus_properties (wayland_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 */ /* {{{ Toplevel API */
@ -2397,12 +2455,6 @@ gdk_wayland_toplevel_uninhibit_idle (GdkToplevel *toplevel)
* marking surfaces as transient for out-of-process surfaces. * 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 { typedef struct {
GdkWaylandToplevelExported callback; GdkWaylandToplevelExported callback;
gpointer user_data; gpointer user_data;
@ -2450,6 +2502,12 @@ export_handle_done (GObject *source,
* from another surface as transient for this one, see * from another surface as transient for this one, see
* [method@GdkWayland.WaylandToplevel.set_transient_for_exported]. * [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, * Note that this API depends on an unstable Wayland protocol,
* and thus may require changes in the future. * 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 * It is an error to call this function on a surface that
* does not have a handle. * 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, * Note that this API depends on an unstable Wayland protocol,
* and thus may require changes in the future. * and thus may require changes in the future.
*
* Deprecated: 4.12: Use [method@GdkWayland.WaylandToplevel.drop_exported_handle]
* instead, this function does nothing
*/ */
void void
gdk_wayland_toplevel_unexport_handle (GdkToplevel *toplevel) gdk_wayland_toplevel_unexport_handle (GdkToplevel *toplevel)
{ {
g_return_if_fail (GDK_IS_WAYLAND_TOPLEVEL (toplevel)); GdkWaylandToplevel *wayland_toplevel = GDK_WAYLAND_TOPLEVEL (toplevel);
gdk_toplevel_unexport_handle (toplevel); if (wayland_toplevel->exported != NULL &&
wayland_toplevel->exported->next == NULL)
{
GdkWaylandExported *exported = wayland_toplevel->exported->data;
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 static void

View File

@ -52,9 +52,13 @@ gboolean gdk_wayland_toplevel_export_handle (GdkToplevel
gpointer user_data, gpointer user_data,
GDestroyNotify destroy_func); 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); 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 GDK_AVAILABLE_IN_ALL
gboolean gdk_wayland_toplevel_set_transient_for_exported (GdkToplevel *toplevel, gboolean gdk_wayland_toplevel_set_transient_for_exported (GdkToplevel *toplevel,
const char *parent_handle_str); const char *parent_handle_str);

View File

@ -5318,7 +5318,8 @@ gdk_x11_toplevel_export_handle_finish (GdkToplevel *toplevel,
} }
static void static void
gdk_x11_toplevel_unexport_handle (GdkToplevel *toplevel) gdk_x11_toplevel_unexport_handle (GdkToplevel *toplevel,
const char *handle)
{ {
} }

View File

@ -31,6 +31,7 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
typedef struct { typedef struct {
GtkWindow *parent; GtkWindow *parent;
char *handle;
GAppLaunchContext *context; GAppLaunchContext *context;
char *uri; char *uri;
GTask *task; GTask *task;
@ -39,9 +40,10 @@ typedef struct {
static void static void
gtk_show_uri_data_free (GtkShowUriData *data) gtk_show_uri_data_free (GtkShowUriData *data)
{ {
if (data->parent) if (data->parent && data->handle)
gtk_window_unexport_handle (data->parent); gtk_window_unexport_handle (data->parent, data->handle);
g_clear_object (&data->parent); g_clear_object (&data->parent);
g_free (data->handle);
g_clear_object (&data->context); g_clear_object (&data->context);
g_free (data->uri); g_free (data->uri);
g_clear_object (&data->task); g_clear_object (&data->task);
@ -72,7 +74,10 @@ window_handle_exported (GtkWindow *window,
GtkShowUriData *data = user_data; GtkShowUriData *data = user_data;
if (handle) 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, g_app_info_launch_default_for_uri_async (data->uri,
data->context, data->context,

View File

@ -52,6 +52,7 @@ typedef struct {
const char *method_name; const char *method_name;
char *exported_handle;
GtkWindow *exported_window; GtkWindow *exported_window;
PortalErrorHandler error_handler; PortalErrorHandler error_handler;
} FilechooserPortalData; } FilechooserPortalData;
@ -79,7 +80,11 @@ filechooser_portal_data_clear (FilechooserPortalData *data)
if (data->exported_window) 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); g_clear_object (&data->exported_window);
} }
@ -460,6 +465,7 @@ window_handle_exported (GtkWindow *window,
gtk_grab_add (GTK_WIDGET (data->grab_widget)); gtk_grab_add (GTK_WIDGET (data->grab_widget));
} }
data->exported_handle = g_strdup (handle_str);
show_portal_file_chooser (self, handle_str); show_portal_file_chooser (self, handle_str);
} }

View File

@ -108,6 +108,7 @@ enum {
typedef struct { typedef struct {
GtkWindow *parent; GtkWindow *parent;
char *parent_handle;
GFile *file; GFile *file;
char *uri; char *uri;
gboolean open_folder; gboolean open_folder;
@ -128,8 +129,9 @@ open_uri_data_free (OpenUriData *data)
g_clear_object (&data->connection); g_clear_object (&data->connection);
if (data->cancel_handler) if (data->cancel_handler)
g_signal_handler_disconnect (data->cancellable, data->cancel_handler); g_signal_handler_disconnect (data->cancellable, data->cancel_handler);
if (data->parent) if (data->parent && data->parent_handle)
gtk_window_unexport_handle (data->parent); gtk_window_unexport_handle (data->parent, data->parent_handle);
g_free (data->parent_handle);
g_clear_object (&data->parent); g_clear_object (&data->parent);
g_clear_object (&data->file); g_clear_object (&data->file);
g_free (data->uri); g_free (data->uri);
@ -426,6 +428,8 @@ window_handle_exported (GtkWindow *window,
GAppLaunchContext *context; GAppLaunchContext *context;
char *activation_token = NULL; char *activation_token = NULL;
data->parent_handle = g_strdup (handle);
if (window) if (window)
display = gtk_widget_get_display (GTK_WIDGET (window)); display = gtk_widget_get_display (GTK_WIDGET (window));
else else

View File

@ -48,6 +48,7 @@ typedef struct {
GtkPrintOperationResult result; GtkPrintOperationResult result;
GtkPrintOperationPrintFunc print_cb; GtkPrintOperationPrintFunc print_cb;
GtkWindow *parent; GtkWindow *parent;
char *handle;
GMainLoop *loop; GMainLoop *loop;
guint32 token; guint32 token;
GDestroyNotify destroy; GDestroyNotify destroy;
@ -62,8 +63,9 @@ portal_data_free (gpointer data)
{ {
PortalData *portal = data; PortalData *portal = data;
if (portal->parent) if (portal->parent && portal->handle)
gtk_window_unexport_handle (portal->parent); gtk_window_unexport_handle (portal->parent, portal->handle);
g_free (portal->handle);
g_object_unref (portal->op); g_object_unref (portal->op);
g_object_unref (portal->proxy); g_object_unref (portal->proxy);
if (portal->loop) if (portal->loop)
@ -547,6 +549,8 @@ window_handle_exported (GtkWindow *window,
{ {
PortalData *portal = user_data; PortalData *portal = user_data;
portal->handle = g_strdup (handle_str);
g_dbus_proxy_call (portal->proxy, g_dbus_proxy_call (portal->proxy,
"PreparePrint", "PreparePrint",
g_variant_new ("(ss@a{sv}@a{sv}@a{sv})", g_variant_new ("(ss@a{sv}@a{sv}@a{sv})",

View File

@ -6291,6 +6291,17 @@ prefix_handle (GdkDisplay *display,
return NULL; 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 static void
export_handle_done (GObject *source, export_handle_done (GObject *source,
GAsyncResult *result, GAsyncResult *result,
@ -6336,11 +6347,12 @@ gtk_window_export_handle (GtkWindow *window,
} }
void void
gtk_window_unexport_handle (GtkWindow *window) gtk_window_unexport_handle (GtkWindow *window,
const char *handle)
{ {
GtkWindowPrivate *priv = gtk_window_get_instance_private (window); 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 * static GtkPointerFocus *

View File

@ -79,7 +79,8 @@ typedef void (*GtkWindowHandleExported) (GtkWindow *window,
gboolean gtk_window_export_handle (GtkWindow *window, gboolean gtk_window_export_handle (GtkWindow *window,
GtkWindowHandleExported callback, GtkWindowHandleExported callback,
gpointer user_data); 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, GtkWidget * gtk_window_lookup_pointer_focus_widget (GtkWindow *window,
GdkDevice *device, GdkDevice *device,

View File

@ -1,5 +1,6 @@
gtk_tests = [ gtk_tests = [
# testname, optional extra sources # testname, optional extra sources
['testfilelauncher'],
['input'], ['input'],
['testpopup'], ['testpopup'],
['testupload'], ['testupload'],

47
tests/testfilelauncher.c Normal file
View File

@ -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;
}