1 /*
2 * Copyright (C) 2020 Red Hat
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17 * 02111-1307, USA.
18 *
19 * Author: Carlos Garnacho <carlosg@gnome.org>
20 */
21
22 #include "config.h"
23
24 #include "wayland/meta-wayland-activation.h"
25
26 #include <glib.h>
27 #include <wayland-server.h>
28
29 #include "wayland/meta-wayland-private.h"
30 #include "wayland/meta-wayland-versions.h"
31
32 #include "xdg-activation-v1-server-protocol.h"
33
34 typedef struct _MetaXdgActivationToken MetaXdgActivationToken;
35
36 struct _MetaWaylandActivation
37 {
38 MetaWaylandCompositor *compositor;
39 struct wl_list resource_list;
40 struct wl_list token_list;
41 GHashTable *tokens;
42 };
43
44 struct _MetaXdgActivationToken
45 {
46 MetaWaylandSurface *surface;
47 MetaWaylandSeat *seat;
48 MetaWaylandActivation *activation;
49 MetaStartupSequence *sequence;
50 char *app_id;
51 char *token;
52 uint32_t serial;
53 gulong sequence_complete_id;
54 gboolean committed;
55 };
56
57 static void
unbind_resource(struct wl_resource * resource)58 unbind_resource (struct wl_resource *resource)
59 {
60 wl_list_remove (wl_resource_get_link (resource));
61 }
62
63 static void
token_set_serial(struct wl_client * client,struct wl_resource * resource,uint32_t serial,struct wl_resource * seat_resource)64 token_set_serial (struct wl_client *client,
65 struct wl_resource *resource,
66 uint32_t serial,
67 struct wl_resource *seat_resource)
68 {
69 MetaXdgActivationToken *token = wl_resource_get_user_data (resource);
70 MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
71
72 token->serial = serial;
73 token->seat = seat;
74 }
75
76 static void
token_set_app_id(struct wl_client * client,struct wl_resource * resource,const char * app_id)77 token_set_app_id (struct wl_client *client,
78 struct wl_resource *resource,
79 const char *app_id)
80 {
81 MetaXdgActivationToken *token = wl_resource_get_user_data (resource);
82
83 g_clear_pointer (&token->app_id, g_free);
84 token->app_id = g_strdup (app_id);
85 }
86
87 static void
token_set_surface(struct wl_client * client,struct wl_resource * resource,struct wl_resource * surface_resource)88 token_set_surface (struct wl_client *client,
89 struct wl_resource *resource,
90 struct wl_resource *surface_resource)
91 {
92 MetaXdgActivationToken *token = wl_resource_get_user_data (resource);
93 MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
94
95 token->surface = surface;
96 }
97
98 static void
sequence_complete_cb(MetaStartupSequence * sequence,MetaXdgActivationToken * token)99 sequence_complete_cb (MetaStartupSequence *sequence,
100 MetaXdgActivationToken *token)
101 {
102 MetaWaylandActivation *activation = token->activation;
103 MetaDisplay *display = meta_get_display ();
104
105 meta_startup_notification_remove_sequence (display->startup_notification,
106 sequence);
107 g_hash_table_remove (activation->tokens, token->token);
108 }
109
110 static char *
create_startup_token(MetaWaylandActivation * activation,MetaDisplay * display)111 create_startup_token (MetaWaylandActivation *activation,
112 MetaDisplay *display)
113 {
114 g_autofree char *uuid = NULL, *token = NULL;
115
116 do
117 {
118 g_clear_pointer (&uuid, g_free);
119 g_clear_pointer (&token, g_free);
120 uuid = g_uuid_string_random ();
121 token = g_strdup_printf ("%s_TIME%d", uuid,
122 meta_display_get_current_time (display));
123 }
124 while (g_hash_table_contains (activation->tokens, token));
125
126 return g_steal_pointer (&token);
127 }
128
129 static void
token_commit(struct wl_client * client,struct wl_resource * resource)130 token_commit (struct wl_client *client,
131 struct wl_resource *resource)
132 {
133 MetaXdgActivationToken *token = wl_resource_get_user_data (resource);
134 MetaWaylandActivation *activation = token->activation;
135 MetaDisplay *display = meta_get_display ();
136 uint32_t timestamp;
137
138 if (token->committed)
139 {
140 wl_resource_post_error (resource,
141 XDG_ACTIVATION_TOKEN_V1_ERROR_ALREADY_USED,
142 "Activation token was already used");
143 return;
144 }
145
146 timestamp = meta_display_get_current_time_roundtrip (display);
147
148 token->committed = TRUE;
149 token->token = create_startup_token (activation, display);
150 token->sequence = g_object_new (META_TYPE_STARTUP_SEQUENCE,
151 "id", token->token,
152 "application-id", token->app_id,
153 "timestamp", timestamp,
154 NULL);
155
156 token->sequence_complete_id =
157 g_signal_connect (token->sequence,
158 "complete",
159 G_CALLBACK (sequence_complete_cb),
160 token);
161
162 meta_startup_notification_add_sequence (display->startup_notification,
163 token->sequence);
164
165 xdg_activation_token_v1_send_done (resource, token->token);
166 g_hash_table_insert (activation->tokens, token->token, token);
167 }
168
169 static void
token_destroy(struct wl_client * client,struct wl_resource * resource)170 token_destroy (struct wl_client *client,
171 struct wl_resource *resource)
172 {
173 wl_resource_destroy (resource);
174 }
175
176 static const struct xdg_activation_token_v1_interface token_interface = {
177 token_set_serial,
178 token_set_app_id,
179 token_set_surface,
180 token_commit,
181 token_destroy,
182 };
183
184 static void
meta_xdg_activation_token_free(MetaXdgActivationToken * token)185 meta_xdg_activation_token_free (MetaXdgActivationToken *token)
186 {
187 if (token->sequence)
188 {
189 g_clear_signal_handler (&token->sequence_complete_id,
190 token->sequence);
191 g_clear_object (&token->sequence);
192 }
193
194 g_free (token->app_id);
195 g_free (token->token);
196 g_free (token);
197 }
198
199 static void
meta_wayland_activation_token_create_new_resource(MetaWaylandActivation * activation,struct wl_client * client,struct wl_resource * activation_resource,uint32_t id)200 meta_wayland_activation_token_create_new_resource (MetaWaylandActivation *activation,
201 struct wl_client *client,
202 struct wl_resource *activation_resource,
203 uint32_t id)
204 {
205 MetaXdgActivationToken *token;
206 struct wl_resource *token_resource;
207
208 token = g_new0 (MetaXdgActivationToken, 1);
209 token->activation = activation;
210
211 token_resource =
212 wl_resource_create (client, &xdg_activation_token_v1_interface,
213 wl_resource_get_version (activation_resource),
214 id);
215 wl_resource_set_implementation (token_resource, &token_interface,
216 token, unbind_resource);
217 wl_resource_set_user_data (token_resource, token);
218 wl_list_insert (&activation->token_list,
219 wl_resource_get_link (token_resource));
220 }
221
222 static void
activation_destroy(struct wl_client * client,struct wl_resource * resource)223 activation_destroy (struct wl_client *client,
224 struct wl_resource *resource)
225 {
226 wl_resource_destroy (resource);
227 }
228
229 static void
activation_get_activation_token(struct wl_client * client,struct wl_resource * resource,uint32_t id)230 activation_get_activation_token (struct wl_client *client,
231 struct wl_resource *resource,
232 uint32_t id)
233 {
234 MetaWaylandActivation *activation = wl_resource_get_user_data (resource);
235
236 meta_wayland_activation_token_create_new_resource (activation,
237 client,
238 resource,
239 id);
240 }
241
242 static void
activation_activate(struct wl_client * client,struct wl_resource * resource,const char * token_str,struct wl_resource * surface_resource)243 activation_activate (struct wl_client *client,
244 struct wl_resource *resource,
245 const char *token_str,
246 struct wl_resource *surface_resource)
247 {
248 MetaWaylandActivation *activation = wl_resource_get_user_data (resource);
249 MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource);
250 MetaXdgActivationToken *token;
251 MetaWindow *window;
252
253 window = meta_wayland_surface_get_window (surface);
254 if (!window)
255 return;
256
257 token = g_hash_table_lookup (activation->tokens, token_str);
258 if (!token)
259 return;
260
261 if (meta_wayland_seat_get_grab_info (token->seat,
262 token->surface,
263 token->serial,
264 FALSE, NULL, NULL))
265 {
266 uint32_t timestamp;
267 int32_t workspace_idx;
268
269 workspace_idx = meta_startup_sequence_get_workspace (token->sequence);
270 timestamp = meta_startup_sequence_get_timestamp (token->sequence);
271
272 if (workspace_idx >= 0)
273 meta_window_change_workspace_by_index (window, workspace_idx, TRUE);
274
275 meta_window_activate_full (window, timestamp,
276 META_CLIENT_TYPE_APPLICATION, NULL);
277 }
278 else
279 {
280 meta_window_set_demands_attention (window);
281 }
282
283 meta_startup_sequence_complete (token->sequence);
284 }
285
286 static const struct xdg_activation_v1_interface activation_interface = {
287 activation_destroy,
288 activation_get_activation_token,
289 activation_activate,
290 };
291
292 static void
bind_activation(struct wl_client * client,void * data,uint32_t version,uint32_t id)293 bind_activation (struct wl_client *client,
294 void *data,
295 uint32_t version,
296 uint32_t id)
297 {
298 MetaWaylandCompositor *compositor = data;
299 MetaWaylandActivation *activation = compositor->activation;
300 struct wl_resource *resource;
301
302 resource = wl_resource_create (client, &xdg_activation_v1_interface,
303 MIN (version, META_XDG_ACTIVATION_V1_VERSION),
304 id);
305 wl_resource_set_implementation (resource, &activation_interface,
306 activation, unbind_resource);
307 wl_resource_set_user_data (resource, activation);
308 wl_list_insert (&activation->resource_list,
309 wl_resource_get_link (resource));
310 }
311
312 void
meta_wayland_activation_init(MetaWaylandCompositor * compositor)313 meta_wayland_activation_init (MetaWaylandCompositor *compositor)
314 {
315 MetaWaylandActivation *activation;
316
317 activation = g_new0 (MetaWaylandActivation, 1);
318 activation->compositor = compositor;
319 wl_list_init (&activation->resource_list);
320 wl_list_init (&activation->token_list);
321
322 activation->tokens =
323 g_hash_table_new_full (g_str_hash, g_str_equal,
324 NULL,
325 (GDestroyNotify) meta_xdg_activation_token_free);
326
327 wl_global_create (compositor->wayland_display,
328 &xdg_activation_v1_interface,
329 META_XDG_ACTIVATION_V1_VERSION,
330 compositor, bind_activation);
331
332 compositor->activation = activation;
333 }
334