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 | |
30 | typedef struct { |
31 | GtkWindow *parent; |
32 | GAppLaunchContext *context; |
33 | char *uri; |
34 | GTask *task; |
35 | } GtkShowUriData; |
36 | |
37 | static void |
38 | gtk_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 | |
49 | static void |
50 | launch_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 | |
65 | static void |
66 | window_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 | */ |
100 | void |
101 | gtk_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 | */ |
146 | gboolean |
147 | gtk_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 | |
158 | static void |
159 | show_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 | */ |
197 | void |
198 | gtk_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 | |