From: Matthias Clasen Date: Sat, 14 Jan 2023 17:22:51 +0000 (-0500) Subject: Add GtkUriLauncher X-Git-Tag: archive/raspbian/4.12.3+ds-1+rpi1~1^2^2^2~22^2~8^2~62^2~2 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=3080cb7acd52e62a15e9a42193dc74fad00050fa;p=gtk4.git Add GtkUriLauncher --- diff --git a/gtk/gtk.h b/gtk/gtk.h index e07a3f6605..ccb9c98fa3 100644 --- a/gtk/gtk.h +++ b/gtk/gtk.h @@ -286,6 +286,7 @@ #include #include #include +#include #include #include #include diff --git a/gtk/gtkurilauncher.c b/gtk/gtkurilauncher.c new file mode 100644 index 0000000000..e5bb51f697 --- /dev/null +++ b/gtk/gtkurilauncher.c @@ -0,0 +1,337 @@ +/* + * GTK - The GIMP Toolkit + * Copyright (C) 2022 Red Hat, Inc. + * All rights reserved. + * + * This Library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This Library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library. If not, see . + */ + +#include "config.h" + +#include "gtkurilauncher.h" + +#include "gtkdialogerror.h" +#include "gopenuriportal.h" +#include "deprecated/gtkshow.h" +#include + +/** + * GtkUriLauncher: + * + * A `GtkUriLauncher` object collects the arguments that are needed to open a uri + * with an application. + * + * Depending on system configuration, user preferences and available APIs, this + * may or may not show an app chooser dialog or launch the default application + * right away. + * + * The operation is started with the [method@Gtk.UriLauncher.launch] function. + * This API follows the GIO async pattern, and the result can be obtained by + * calling [method@Gtk.UriLauncher.launch_finish]. + * + * Since: 4.10 + */ + +/* {{{ GObject implementation */ + +struct _GtkUriLauncher +{ + GObject parent_instance; + + char *uri; +}; + +enum { + PROP_URI = 1, + + NUM_PROPERTIES +}; + +static GParamSpec *properties[NUM_PROPERTIES]; + +G_DEFINE_TYPE (GtkUriLauncher, gtk_uri_launcher, G_TYPE_OBJECT) + +static void +gtk_uri_launcher_init (GtkUriLauncher *self) +{ +} + +static void +gtk_uri_launcher_finalize (GObject *object) +{ + GtkUriLauncher *self = GTK_URI_LAUNCHER (object); + + g_free (self->uri); + + G_OBJECT_CLASS (gtk_uri_launcher_parent_class)->finalize (object); +} + +static void +gtk_uri_launcher_get_property (GObject *object, + unsigned int property_id, + GValue *value, + GParamSpec *pspec) +{ + GtkUriLauncher *self = GTK_URI_LAUNCHER (object); + + switch (property_id) + { + case PROP_URI: + g_value_set_string (value, self->uri); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gtk_uri_launcher_set_property (GObject *object, + unsigned int property_id, + const GValue *value, + GParamSpec *pspec) +{ + GtkUriLauncher *self = GTK_URI_LAUNCHER (object); + + switch (property_id) + { + case PROP_URI: + gtk_uri_launcher_set_uri (self, g_value_get_string (value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gtk_uri_launcher_class_init (GtkUriLauncherClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->finalize = gtk_uri_launcher_finalize; + object_class->get_property = gtk_uri_launcher_get_property; + object_class->set_property = gtk_uri_launcher_set_property; + + /** + * GtkUriLauncher:uri: (attributes org.gtk.Property.get=gtk_uri_launcher_get_uri org.gtk.Property.set=gtk_uri_launcher_set_uri) + * + * The uri to launch. + * + * Since: 4.10 + */ + properties[PROP_URI] = + g_param_spec_string ("uri", NULL, NULL, + NULL, + G_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY); + + g_object_class_install_properties (object_class, NUM_PROPERTIES, properties); +} + +/* }}} */ +/* {{{ API: Constructor */ + +/** + * gtk_uri_launcher_new: + * @uri: (nullable): the uri to open + * + * Creates a new `GtkUriLauncher` object. + * + * Returns: the new `GtkUriLauncher` + * + * Since: 4.10 + */ +GtkUriLauncher * +gtk_uri_launcher_new (const char *uri) +{ + return g_object_new (GTK_TYPE_URI_LAUNCHER, + "uri", uri, + NULL); +} + + /* }}} */ +/* {{{ API: Getters and setters */ + +/** + * gtk_uri_launcher_get_uri: + * @self: a `GtkUriLauncher` + * + * Gets the uri that will be opened. + * + * Returns: (transfer none) (nullable): the uri + * + * Since: 4.10 + */ +const char * +gtk_uri_launcher_get_uri (GtkUriLauncher *self) +{ + g_return_val_if_fail (GTK_IS_URI_LAUNCHER (self), NULL); + + return self->uri; +} + +/** + * gtk_uri_launcher_set_uri: + * @self: a `GtkUriLauncher` + * @uri: (nullable): the uri + * + * Sets the uri that will be opened. + * + * Since: 4.10 + */ +void +gtk_uri_launcher_set_uri (GtkUriLauncher *self, + const char *uri) +{ + g_return_if_fail (GTK_IS_URI_LAUNCHER (self)); + + if (g_strcmp0 (self->uri, uri) == 0) + return; + + g_free (self->uri); + self->uri = g_strdup (uri); + + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_URI]); +} + +/* }}} */ +/* {{{ Async implementation */ + +#ifndef G_OS_WIN32 +static void +open_done (GObject *source, + GAsyncResult *result, + gpointer data) +{ + GTask *task = G_TASK (data); + GError *error = NULL; + + if (!g_openuri_portal_open_finish (result, &error)) + g_task_return_error (task, error); + else + g_task_return_boolean (task, TRUE); + + g_object_unref (task); +} +#endif + +G_GNUC_BEGIN_IGNORE_DEPRECATIONS +static void +show_uri_done (GObject *source, + GAsyncResult *result, + gpointer data) +{ + GtkWindow *parent = GTK_WINDOW (source); + GTask *task = G_TASK (data); + GError *error = NULL; + + if (!gtk_show_uri_full_finish (parent, result, &error)) + { + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + g_task_return_new_error (task, GTK_DIALOG_ERROR, GTK_DIALOG_ERROR_CANCELLED, "Cancelled by user"); + else + g_task_return_new_error (task, GTK_DIALOG_ERROR, GTK_DIALOG_ERROR_FAILED, "%s", error->message); + g_error_free (error); + } + else + g_task_return_boolean (task, TRUE); + + g_object_unref (task); +} +G_GNUC_END_IGNORE_DEPRECATIONS + + /* }}} */ +/* {{{ Async API */ + +/** + * gtk_uri_launcher_launch: + * @self: a `GtkUriLauncher` + * @parent: (nullable): the parent `GtkWindow` + * @cancellable: (nullable): a `GCancellable` to cancel the operation + * @callback: (scope async): a callback to call when the operation is complete + * @user_data: (closure callback): data to pass to @callback + * + * Launch an application to open the uri. + * + * This may present an app chooser dialog to the user. + * + * The @callback will be called when the operation is completed. + * It should call [method@Gtk.UriLauncher.launch_finish] to obtain + * the result. + * + * Since: 4.10 + */ +void +gtk_uri_launcher_launch (GtkUriLauncher *self, + GtkWindow *parent, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + + g_return_if_fail (GTK_IS_URI_LAUNCHER (self)); + + task = g_task_new (self, cancellable, callback, user_data); + g_task_set_check_cancellable (task, FALSE); + g_task_set_source_tag (task, gtk_uri_launcher_launch); + + if (self->uri == NULL) + { + g_task_return_new_error (task, + GTK_DIALOG_ERROR, GTK_DIALOG_ERROR_FAILED, + "No uri to launch"); + return; + } + +#ifndef G_OS_WIN32 + if (g_openuri_portal_is_available ()) + g_openuri_portal_open_uri_async (self->uri, parent, cancellable, open_done, task); + else +#endif +G_GNUC_BEGIN_IGNORE_DEPRECATIONS + gtk_show_uri_full (parent, self->uri, GDK_CURRENT_TIME, cancellable, show_uri_done, task); +G_GNUC_END_IGNORE_DEPRECATIONS +} + +/** + * gtk_uri_launcher_launch_finish: + * @self: a `GtkUriLauncher` + * @result: a `GAsyncResult` + * @error: return location for a [enum@Gtk.DialogError] or [enum@Gio.Error] error + * + * Finishes the [method@Gtk.UriLauncher.launch] call and + * returns the result. + * + * Returns: `TRUE` if an application was launched, + * or `FALSE` and @error is set + * + * Since: 4.10 + */ +gboolean +gtk_uri_launcher_launch_finish (GtkUriLauncher *self, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (GTK_IS_URI_LAUNCHER (self), FALSE); + g_return_val_if_fail (g_task_is_valid (result, self), FALSE); + g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == gtk_uri_launcher_launch, FALSE); + + return g_task_propagate_boolean (G_TASK (result), error); +} + +/* }}} */ +/* vim:set foldmethod=marker expandtab: */ diff --git a/gtk/gtkurilauncher.h b/gtk/gtkurilauncher.h new file mode 100644 index 0000000000..1909ac1327 --- /dev/null +++ b/gtk/gtkurilauncher.h @@ -0,0 +1,57 @@ +/* GTK - The GIMP Toolkit + * + * Copyright (C) 2022 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#pragma once + +#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only can be included directly." +#endif + +#include +#include + +G_BEGIN_DECLS + +#define GTK_TYPE_URI_LAUNCHER (gtk_uri_launcher_get_type ()) + +GDK_AVAILABLE_IN_4_10 +G_DECLARE_FINAL_TYPE (GtkUriLauncher, gtk_uri_launcher, GTK, URI_LAUNCHER, GObject) + +GDK_AVAILABLE_IN_4_10 +GtkUriLauncher * gtk_uri_launcher_new (const char *uri); + +GDK_AVAILABLE_IN_4_10 +const char * gtk_uri_launcher_get_uri (GtkUriLauncher *self); +GDK_AVAILABLE_IN_4_10 +void gtk_uri_launcher_set_uri (GtkUriLauncher *self, + const char *uri); + +GDK_AVAILABLE_IN_4_10 +void gtk_uri_launcher_launch (GtkUriLauncher *self, + GtkWindow *parent, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + +GDK_AVAILABLE_IN_4_10 +gboolean gtk_uri_launcher_launch_finish (GtkUriLauncher *self, + GAsyncResult *result, + GError **error); + + +G_END_DECLS diff --git a/gtk/meson.build b/gtk/meson.build index 7ac245419a..13d2404630 100644 --- a/gtk/meson.build +++ b/gtk/meson.build @@ -390,6 +390,7 @@ gtk_public_sources = files([ 'gtktreeexpander.c', 'gtktreelistmodel.c', 'gtktreelistrowsorter.c', + 'gtkurilauncher.c', 'gtkversion.c', 'gtkvideo.c', 'gtkviewport.c', @@ -615,6 +616,7 @@ gtk_public_headers = files([ 'gtktreelistmodel.h', 'gtktreelistrowsorter.h', 'gtktypes.h', + 'gtkurilauncher.h', 'gtkvideo.h', 'gtkviewport.h', 'gtkvolumebutton.h',