1/*
2 * GTK - The GIMP Toolkit
3 * Copyright (C) 2008 Jaap Haitsma <jaap@haitsma.org>
4 *
5 * All rights reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include "config.h"
22
23#include <gdk/gdk.h>
24
25#include "gtkshow.h"
26#include "gtkwindowprivate.h"
27#include "gtkmessagedialog.h"
28#include "gtkintl.h"
29
30typedef struct {
31 GtkWindow *parent;
32 GAppLaunchContext *context;
33 char *uri;
34 GTask *task;
35} GtkShowUriData;
36
37static void
38gtk_show_uri_data_free (GtkShowUriData *data)
39{
40 if (data->parent)
41 gtk_window_unexport_handle (window: data->parent);
42 g_clear_object (&data->parent);
43 g_clear_object (&data->context);
44 g_free (mem: data->uri);
45 g_clear_object (&data->task);
46 g_free (mem: data);
47}
48
49static void
50launch_uri_done (GObject *source,
51 GAsyncResult *result,
52 gpointer user_data)
53{
54 GtkShowUriData *data = user_data;
55 GError *error = NULL;
56
57 if (g_app_info_launch_default_for_uri_finish (result, error: &error))
58 g_task_return_boolean (task: data->task, TRUE);
59 else
60 g_task_return_error (task: data->task, error);
61
62 gtk_show_uri_data_free (data);
63}
64
65static void
66window_handle_exported (GtkWindow *window,
67 const char *handle,
68 gpointer user_data)
69{
70 GtkShowUriData *data = user_data;
71
72 if (handle)
73 g_app_launch_context_setenv (context: data->context, variable: "PARENT_WINDOW_ID", value: handle);
74
75 g_app_info_launch_default_for_uri_async (uri: data->uri,
76 context: data->context,
77 cancellable: g_task_get_cancellable (task: data->task),
78 callback: launch_uri_done,
79 user_data: data);
80}
81
82/**
83 * gtk_show_uri_full:
84 * @parent: (nullable): parent window
85 * @uri: the uri to show
86 * @timestamp: timestamp from the event that triggered this call, or %GDK_CURRENT_TIME
87 * @cancellable: (nullable): a `GCancellable` to cancel the launch
88 * @callback: (scope async): a callback to call when the action is complete
89 * @user_data: (closure callback): data to pass to @callback
90 *
91 * This function launches the default application for showing
92 * a given uri.
93 *
94 * The @callback will be called when the launch is completed.
95 * It should call gtk_show_uri_full_finish() to obtain the result.
96 *
97 * This is the recommended call to be used as it passes information
98 * necessary for sandbox helpers to parent their dialogs properly.
99 */
100void
101gtk_show_uri_full (GtkWindow *parent,
102 const char *uri,
103 guint32 timestamp,
104 GCancellable *cancellable,
105 GAsyncReadyCallback callback,
106 gpointer user_data)
107{
108 GtkShowUriData *data;
109 GdkAppLaunchContext *context;
110 GdkDisplay *display;
111
112 g_return_if_fail (parent == NULL || GTK_IS_WINDOW (parent));
113 g_return_if_fail (uri != NULL);
114
115 if (parent)
116 display = gtk_widget_get_display (GTK_WIDGET (parent));
117 else
118 display = gdk_display_get_default ();
119
120 context = gdk_display_get_app_launch_context (display);
121 gdk_app_launch_context_set_timestamp (context, timestamp);
122
123 data = g_new0 (GtkShowUriData, 1);
124 data->parent = parent ? g_object_ref (parent) : NULL;
125 data->context = G_APP_LAUNCH_CONTEXT (context);
126 data->uri = g_strdup (str: uri);
127 data->task = g_task_new (source_object: parent, cancellable, callback, callback_data: user_data);
128 g_task_set_source_tag (data->task, gtk_show_uri);
129
130 if (!parent || !gtk_window_export_handle (window: parent, callback: window_handle_exported, user_data: data))
131 window_handle_exported (window: parent, NULL, user_data: data);
132}
133
134/**
135 * gtk_show_uri_full_finish:
136 * @parent: the `GtkWindow` passed to gtk_show_uri()
137 * @result: `GAsyncResult` that was passed to @callback
138 * @error: return location for an error
139 *
140 * Finishes the gtk_show_uri() call and returns the result
141 * of the operation.
142 *
143 * Returns: %TRUE if the URI was shown successfully.
144 * Otherwise, %FALSE is returned and @error is set
145 */
146gboolean
147gtk_show_uri_full_finish (GtkWindow *parent,
148 GAsyncResult *result,
149 GError **error)
150{
151 g_return_val_if_fail (parent == NULL || GTK_IS_WINDOW (parent), FALSE);
152 g_return_val_if_fail (g_task_is_valid (result, parent), FALSE);
153 g_return_val_if_fail (g_task_get_source_tag (G_TASK (result)) == gtk_show_uri, FALSE);
154
155 return g_task_propagate_boolean (G_TASK (result), error);
156}
157
158static void
159show_uri_done (GObject *object,
160 GAsyncResult *result,
161 gpointer data)
162{
163 GtkWindow *parent = GTK_WINDOW (object);
164 GError *error = NULL;
165
166 if (!gtk_show_uri_full_finish (parent, result, error: &error))
167 {
168 GtkWidget *dialog;
169
170 dialog = gtk_message_dialog_new (parent,
171 flags: GTK_DIALOG_DESTROY_WITH_PARENT |
172 GTK_DIALOG_MODAL,
173 type: GTK_MESSAGE_ERROR,
174 buttons: GTK_BUTTONS_CLOSE,
175 message_format: "%s", _("Could not show link"));
176 gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
177 message_format: "%s", error->message);
178
179 g_signal_connect (dialog, "response",
180 G_CALLBACK (gtk_window_destroy), NULL);
181
182 gtk_window_present (GTK_WINDOW (dialog));
183
184 g_error_free (error);
185 }
186}
187
188/**
189 * gtk_show_uri:
190 * @parent: (nullable): parent window
191 * @uri: the uri to show
192 * @timestamp: timestamp from the event that triggered this call, or %GDK_CURRENT_TIME
193 *
194 * This function launches the default application for showing
195 * a given uri, or shows an error dialog if that fails.
196 */
197void
198gtk_show_uri (GtkWindow *parent,
199 const char *uri,
200 guint32 timestamp)
201{
202 gtk_show_uri_full (parent, uri, timestamp, NULL, callback: show_uri_done, NULL);
203}
204

source code of gtk/gtk/gtkshow.c