1 /*
2 * Copyright © 2011 Kristian Høgsberg
3 * 2020 Red Hat Inc.
4 *
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that copyright
8 * notice and this permission notice appear in supporting documentation, and
9 * that the name of the copyright holders not be used in advertising or
10 * publicity pertaining to distribution of the software without specific,
11 * written prior permission. The copyright holders make no representations
12 * about the suitability of this software for any purpose. It is provided "as
13 * is" without express or implied warranty.
14 *
15 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
17 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
18 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
19 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
20 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
21 * OF THIS SOFTWARE.
22 */
23
24 #include "config.h"
25
26 #include <unistd.h>
27
28 #include "wayland/meta-wayland-data-source.h"
29 #include "wayland/meta-wayland-private.h"
30
31 #define ALL_ACTIONS (WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | \
32 WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | \
33 WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
34
35 typedef struct _MetaWaylandDataSourcePrivate
36 {
37 struct wl_resource *resource;
38 MetaWaylandDataOffer *offer;
39 struct wl_array mime_types;
40 gboolean has_target;
41 uint32_t dnd_actions;
42 enum wl_data_device_manager_dnd_action user_dnd_action;
43 enum wl_data_device_manager_dnd_action current_dnd_action;
44 MetaWaylandSeat *seat;
45 guint actions_set : 1;
46 guint in_ask : 1;
47 guint drop_performed : 1;
48 } MetaWaylandDataSourcePrivate;
49
50 G_DEFINE_TYPE_WITH_PRIVATE (MetaWaylandDataSource, meta_wayland_data_source,
51 G_TYPE_OBJECT);
52
53 static void
meta_wayland_data_source_real_send(MetaWaylandDataSource * source,const gchar * mime_type,gint fd)54 meta_wayland_data_source_real_send (MetaWaylandDataSource *source,
55 const gchar *mime_type,
56 gint fd)
57 {
58 MetaWaylandDataSourcePrivate *priv =
59 meta_wayland_data_source_get_instance_private (source);
60
61 wl_data_source_send_send (priv->resource, mime_type, fd);
62 close (fd);
63 }
64
65 static void
meta_wayland_data_source_real_target(MetaWaylandDataSource * source,const gchar * mime_type)66 meta_wayland_data_source_real_target (MetaWaylandDataSource *source,
67 const gchar *mime_type)
68 {
69 MetaWaylandDataSourcePrivate *priv =
70 meta_wayland_data_source_get_instance_private (source);
71
72 wl_data_source_send_target (priv->resource, mime_type);
73 }
74
75 static void
meta_wayland_data_source_real_cancel(MetaWaylandDataSource * source)76 meta_wayland_data_source_real_cancel (MetaWaylandDataSource *source)
77 {
78 MetaWaylandDataSourcePrivate *priv =
79 meta_wayland_data_source_get_instance_private (source);
80
81 if (!priv->resource)
82 return;
83
84 wl_data_source_send_cancelled (priv->resource);
85 }
86
87 static void
meta_wayland_data_source_real_action(MetaWaylandDataSource * source,enum wl_data_device_manager_dnd_action action)88 meta_wayland_data_source_real_action (MetaWaylandDataSource *source,
89 enum wl_data_device_manager_dnd_action action)
90 {
91 MetaWaylandDataSourcePrivate *priv =
92 meta_wayland_data_source_get_instance_private (source);
93
94 if (wl_resource_get_version (priv->resource) >=
95 WL_DATA_SOURCE_ACTION_SINCE_VERSION)
96 wl_data_source_send_action (priv->resource, action);
97 }
98
99 static void
meta_wayland_data_source_real_drop_performed(MetaWaylandDataSource * source)100 meta_wayland_data_source_real_drop_performed (MetaWaylandDataSource *source)
101 {
102 MetaWaylandDataSourcePrivate *priv =
103 meta_wayland_data_source_get_instance_private (source);
104
105 if (wl_resource_get_version (priv->resource) >=
106 WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION)
107 {
108 priv->drop_performed = TRUE;
109 wl_data_source_send_dnd_drop_performed (priv->resource);
110 }
111 }
112
113 static void
meta_wayland_data_source_real_drag_finished(MetaWaylandDataSource * source)114 meta_wayland_data_source_real_drag_finished (MetaWaylandDataSource *source)
115 {
116 MetaWaylandDataSourcePrivate *priv =
117 meta_wayland_data_source_get_instance_private (source);
118 enum wl_data_device_manager_dnd_action action;
119
120 if (meta_wayland_data_source_get_in_ask (source))
121 {
122 action = meta_wayland_data_source_get_current_action (source);
123 meta_wayland_data_source_real_action (source, action);
124 }
125
126 if (wl_resource_get_version (priv->resource) >=
127 WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION)
128 wl_data_source_send_dnd_finished (priv->resource);
129 }
130
131 static void
meta_wayland_data_source_finalize(GObject * object)132 meta_wayland_data_source_finalize (GObject *object)
133 {
134 MetaWaylandDataSource *source = META_WAYLAND_DATA_SOURCE (object);
135 MetaWaylandDataSourcePrivate *priv =
136 meta_wayland_data_source_get_instance_private (source);
137 char **pos;
138
139 wl_array_for_each (pos, &priv->mime_types)
140 g_free (*pos);
141 wl_array_release (&priv->mime_types);
142
143 G_OBJECT_CLASS (meta_wayland_data_source_parent_class)->finalize (object);
144 }
145
146 static void
meta_wayland_data_source_init(MetaWaylandDataSource * source)147 meta_wayland_data_source_init (MetaWaylandDataSource *source)
148 {
149 MetaWaylandDataSourcePrivate *priv =
150 meta_wayland_data_source_get_instance_private (source);
151
152 wl_array_init (&priv->mime_types);
153 priv->current_dnd_action = -1;
154 priv->drop_performed = FALSE;
155 }
156
157 static void
meta_wayland_data_source_class_init(MetaWaylandDataSourceClass * klass)158 meta_wayland_data_source_class_init (MetaWaylandDataSourceClass *klass)
159 {
160 GObjectClass *object_class = G_OBJECT_CLASS (klass);
161
162 object_class->finalize = meta_wayland_data_source_finalize;
163
164 klass->send = meta_wayland_data_source_real_send;
165 klass->target = meta_wayland_data_source_real_target;
166 klass->cancel = meta_wayland_data_source_real_cancel;
167 klass->action = meta_wayland_data_source_real_action;
168 klass->drop_performed = meta_wayland_data_source_real_drop_performed;
169 klass->drag_finished = meta_wayland_data_source_real_drag_finished;
170 }
171
172
173 static void
data_source_offer(struct wl_client * client,struct wl_resource * resource,const char * type)174 data_source_offer (struct wl_client *client,
175 struct wl_resource *resource, const char *type)
176 {
177 MetaWaylandDataSource *source = wl_resource_get_user_data (resource);
178
179 if (!meta_wayland_data_source_add_mime_type (source, type))
180 wl_resource_post_no_memory (resource);
181 }
182
183 static void
data_source_destroy(struct wl_client * client,struct wl_resource * resource)184 data_source_destroy (struct wl_client *client,
185 struct wl_resource *resource)
186 {
187 wl_resource_destroy (resource);
188 }
189
190 static void
data_source_set_actions(struct wl_client * client,struct wl_resource * resource,uint32_t dnd_actions)191 data_source_set_actions (struct wl_client *client,
192 struct wl_resource *resource,
193 uint32_t dnd_actions)
194 {
195 MetaWaylandDataSource *source = wl_resource_get_user_data (resource);
196 MetaWaylandDataSourcePrivate *priv =
197 meta_wayland_data_source_get_instance_private (source);
198
199 if (priv->actions_set)
200 {
201 wl_resource_post_error (priv->resource,
202 WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
203 "cannot set actions more than once");
204 return;
205 }
206
207 if (dnd_actions & ~(ALL_ACTIONS))
208 {
209 wl_resource_post_error (priv->resource,
210 WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
211 "invalid actions mask %x", dnd_actions);
212 return;
213 }
214
215 if (meta_wayland_data_source_get_seat (source))
216 {
217 wl_resource_post_error (priv->resource,
218 WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
219 "invalid action change after "
220 "wl_data_device.start_drag");
221 return;
222 }
223
224 meta_wayland_data_source_set_actions (source, dnd_actions);
225 }
226
227 static struct wl_data_source_interface data_source_interface = {
228 data_source_offer,
229 data_source_destroy,
230 data_source_set_actions
231 };
232
233 static void
destroy_data_source(struct wl_resource * resource)234 destroy_data_source (struct wl_resource *resource)
235 {
236 MetaWaylandDataSource *source = wl_resource_get_user_data (resource);
237
238 meta_wayland_data_source_set_resource (source, NULL);
239 g_object_unref (source);
240 }
241
242 MetaWaylandDataSource *
meta_wayland_data_source_new(struct wl_resource * resource)243 meta_wayland_data_source_new (struct wl_resource *resource)
244 {
245 MetaWaylandDataSource *source =
246 g_object_new (META_TYPE_WAYLAND_DATA_SOURCE, NULL);
247 MetaWaylandDataSourcePrivate *priv =
248 meta_wayland_data_source_get_instance_private (source);
249
250 meta_wayland_data_source_set_resource (source, resource);
251 wl_resource_set_implementation (resource, &data_source_interface,
252 source, destroy_data_source);
253
254 if (wl_resource_get_version (resource) < WL_DATA_SOURCE_ACTION_SINCE_VERSION)
255 {
256 priv->dnd_actions = priv->user_dnd_action =
257 WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
258 }
259
260 return source;
261 }
262
263 struct wl_resource *
meta_wayland_data_source_get_resource(MetaWaylandDataSource * source)264 meta_wayland_data_source_get_resource (MetaWaylandDataSource *source)
265 {
266 MetaWaylandDataSourcePrivate *priv =
267 meta_wayland_data_source_get_instance_private (source);
268
269 return priv->resource;
270 }
271
272 void
meta_wayland_data_source_set_resource(MetaWaylandDataSource * source,struct wl_resource * resource)273 meta_wayland_data_source_set_resource (MetaWaylandDataSource *source,
274 struct wl_resource *resource)
275 {
276 MetaWaylandDataSourcePrivate *priv =
277 meta_wayland_data_source_get_instance_private (source);
278
279 priv->resource = resource;
280 }
281
282 gboolean
meta_wayland_data_source_get_in_ask(MetaWaylandDataSource * source)283 meta_wayland_data_source_get_in_ask (MetaWaylandDataSource *source)
284 {
285 MetaWaylandDataSourcePrivate *priv =
286 meta_wayland_data_source_get_instance_private (source);
287
288 return priv->in_ask;
289 }
290
291 void
meta_wayland_data_source_update_in_ask(MetaWaylandDataSource * source)292 meta_wayland_data_source_update_in_ask (MetaWaylandDataSource *source)
293 {
294 MetaWaylandDataSourcePrivate *priv =
295 meta_wayland_data_source_get_instance_private (source);
296
297 priv->in_ask =
298 priv->current_dnd_action == WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
299 }
300
301 void
meta_wayland_data_source_target(MetaWaylandDataSource * source,const char * mime_type)302 meta_wayland_data_source_target (MetaWaylandDataSource *source,
303 const char *mime_type)
304 {
305 if (META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->target)
306 META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->target (source, mime_type);
307 }
308
309 void
meta_wayland_data_source_send(MetaWaylandDataSource * source,const char * mime_type,int fd)310 meta_wayland_data_source_send (MetaWaylandDataSource *source,
311 const char *mime_type,
312 int fd)
313 {
314 META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->send (source, mime_type, fd);
315 }
316
317 gboolean
meta_wayland_data_source_has_target(MetaWaylandDataSource * source)318 meta_wayland_data_source_has_target (MetaWaylandDataSource *source)
319 {
320 MetaWaylandDataSourcePrivate *priv =
321 meta_wayland_data_source_get_instance_private (source);
322
323 return priv->has_target;
324 }
325
326 void
meta_wayland_data_source_set_seat(MetaWaylandDataSource * source,MetaWaylandSeat * seat)327 meta_wayland_data_source_set_seat (MetaWaylandDataSource *source,
328 MetaWaylandSeat *seat)
329 {
330 MetaWaylandDataSourcePrivate *priv =
331 meta_wayland_data_source_get_instance_private (source);
332
333 priv->seat = seat;
334 }
335
336 MetaWaylandSeat *
meta_wayland_data_source_get_seat(MetaWaylandDataSource * source)337 meta_wayland_data_source_get_seat (MetaWaylandDataSource *source)
338 {
339 MetaWaylandDataSourcePrivate *priv =
340 meta_wayland_data_source_get_instance_private (source);
341
342 return priv->seat;
343 }
344
345 void
meta_wayland_data_source_set_has_target(MetaWaylandDataSource * source,gboolean has_target)346 meta_wayland_data_source_set_has_target (MetaWaylandDataSource *source,
347 gboolean has_target)
348 {
349 MetaWaylandDataSourcePrivate *priv =
350 meta_wayland_data_source_get_instance_private (source);
351
352 priv->has_target = has_target;
353 }
354
355 struct wl_array *
meta_wayland_data_source_get_mime_types(MetaWaylandDataSource * source)356 meta_wayland_data_source_get_mime_types (MetaWaylandDataSource *source)
357 {
358 MetaWaylandDataSourcePrivate *priv =
359 meta_wayland_data_source_get_instance_private ((MetaWaylandDataSource *)source);
360
361 return &priv->mime_types;
362 }
363
364 void
meta_wayland_data_source_cancel(MetaWaylandDataSource * source)365 meta_wayland_data_source_cancel (MetaWaylandDataSource *source)
366 {
367 META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->cancel (source);
368 }
369
370 gboolean
meta_wayland_data_source_get_actions(MetaWaylandDataSource * source,uint32_t * dnd_actions)371 meta_wayland_data_source_get_actions (MetaWaylandDataSource *source,
372 uint32_t *dnd_actions)
373 {
374 MetaWaylandDataSourcePrivate *priv =
375 meta_wayland_data_source_get_instance_private (source);
376
377 if (dnd_actions)
378 *dnd_actions = priv->dnd_actions;
379
380 return priv->actions_set;
381 }
382
383 enum wl_data_device_manager_dnd_action
meta_wayland_data_source_get_user_action(MetaWaylandDataSource * source)384 meta_wayland_data_source_get_user_action (MetaWaylandDataSource *source)
385 {
386 MetaWaylandDataSourcePrivate *priv =
387 meta_wayland_data_source_get_instance_private (source);
388
389 if (!priv->seat)
390 return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
391
392 return priv->user_dnd_action;
393 }
394
395 enum wl_data_device_manager_dnd_action
meta_wayland_data_source_get_current_action(MetaWaylandDataSource * source)396 meta_wayland_data_source_get_current_action (MetaWaylandDataSource *source)
397 {
398 MetaWaylandDataSourcePrivate *priv =
399 meta_wayland_data_source_get_instance_private (source);
400
401 return priv->current_dnd_action;
402 }
403
404 void
meta_wayland_data_source_set_current_offer(MetaWaylandDataSource * source,MetaWaylandDataOffer * offer)405 meta_wayland_data_source_set_current_offer (MetaWaylandDataSource *source,
406 MetaWaylandDataOffer *offer)
407 {
408 MetaWaylandDataSourcePrivate *priv =
409 meta_wayland_data_source_get_instance_private (source);
410
411 priv->offer = offer;
412 }
413
414 MetaWaylandDataOffer *
meta_wayland_data_source_get_current_offer(MetaWaylandDataSource * source)415 meta_wayland_data_source_get_current_offer (MetaWaylandDataSource *source)
416 {
417 MetaWaylandDataSourcePrivate *priv =
418 meta_wayland_data_source_get_instance_private (source);
419
420 return priv->offer;
421 }
422
423 void
meta_wayland_data_source_set_current_action(MetaWaylandDataSource * source,enum wl_data_device_manager_dnd_action action)424 meta_wayland_data_source_set_current_action (MetaWaylandDataSource *source,
425 enum wl_data_device_manager_dnd_action action)
426 {
427 MetaWaylandDataSourcePrivate *priv =
428 meta_wayland_data_source_get_instance_private (source);
429
430 if (priv->current_dnd_action == action)
431 return;
432
433 priv->current_dnd_action = action;
434
435 if (!meta_wayland_data_source_get_in_ask (source))
436 META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->action (source, action);
437 }
438
439 void
meta_wayland_data_source_set_actions(MetaWaylandDataSource * source,uint32_t dnd_actions)440 meta_wayland_data_source_set_actions (MetaWaylandDataSource *source,
441 uint32_t dnd_actions)
442 {
443 MetaWaylandDataSourcePrivate *priv =
444 meta_wayland_data_source_get_instance_private (source);
445
446 priv->dnd_actions = dnd_actions;
447 priv->actions_set = TRUE;
448 }
449
450 void
meta_wayland_data_source_set_user_action(MetaWaylandDataSource * source,uint32_t action)451 meta_wayland_data_source_set_user_action (MetaWaylandDataSource *source,
452 uint32_t action)
453 {
454 MetaWaylandDataSourcePrivate *priv =
455 meta_wayland_data_source_get_instance_private (source);
456 MetaWaylandDataOffer *offer;
457
458 if (priv->user_dnd_action == action)
459 return;
460
461 priv->user_dnd_action = action;
462 offer = meta_wayland_data_source_get_current_offer (source);
463
464 if (offer)
465 meta_wayland_data_offer_update_action (offer);
466 }
467
468 gboolean
meta_wayland_data_source_get_drop_performed(MetaWaylandDataSource * source)469 meta_wayland_data_source_get_drop_performed (MetaWaylandDataSource *source)
470 {
471 MetaWaylandDataSourcePrivate *priv =
472 meta_wayland_data_source_get_instance_private (source);
473
474 return priv->drop_performed;
475 }
476
477 void
meta_wayland_data_source_notify_drop_performed(MetaWaylandDataSource * source)478 meta_wayland_data_source_notify_drop_performed (MetaWaylandDataSource *source)
479 {
480 META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->drop_performed (source);
481 }
482
483 void
meta_wayland_data_source_notify_finish(MetaWaylandDataSource * source)484 meta_wayland_data_source_notify_finish (MetaWaylandDataSource *source)
485 {
486 META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->drag_finished (source);
487 }
488
489 gboolean
meta_wayland_data_source_add_mime_type(MetaWaylandDataSource * source,const char * mime_type)490 meta_wayland_data_source_add_mime_type (MetaWaylandDataSource *source,
491 const char *mime_type)
492 {
493 MetaWaylandDataSourcePrivate *priv =
494 meta_wayland_data_source_get_instance_private (source);
495 char **pos;
496
497 pos = wl_array_add (&priv->mime_types, sizeof (*pos));
498
499 if (pos)
500 {
501 *pos = g_strdup (mime_type);
502 return *pos != NULL;
503 }
504
505 return FALSE;
506 }
507
508 gboolean
meta_wayland_data_source_has_mime_type(MetaWaylandDataSource * source,const char * mime_type)509 meta_wayland_data_source_has_mime_type (MetaWaylandDataSource *source,
510 const char *mime_type)
511 {
512 MetaWaylandDataSourcePrivate *priv =
513 meta_wayland_data_source_get_instance_private (source);
514 char **p;
515
516 wl_array_for_each (p, &priv->mime_types)
517 {
518 if (g_strcmp0 (mime_type, *p) == 0)
519 return TRUE;
520 }
521
522 return FALSE;
523 }
524