1 /*
2 * Copyright © 2011 Kristian Høgsberg
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
11 *
12 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial
14 * portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 */
25
26 #define EXECUTIVE_MODE_ENABLED
27 #define E_COMP_WL
28 #include "e.h"
29
30 #if defined(__clang__)
31 # pragma clang diagnostic ignored "-Wunused-parameter"
32 #elif (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4
33 # pragma GCC diagnostic ignored "-Wunused-parameter"
34 #endif
35
36 #define ALL_ACTIONS (WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | \
37 WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | \
38 WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
39
40 static void
_mime_types_free(E_Comp_Wl_Data_Source * source)41 _mime_types_free(E_Comp_Wl_Data_Source *source)
42 {
43 if (!source->mime_types) return;
44 while (eina_array_count(source->mime_types))
45 eina_stringshare_del(eina_array_pop(source->mime_types));
46 eina_array_free(source->mime_types);
47 }
48
49 static void
_e_comp_wl_data_offer_cb_accept(struct wl_client * client EINA_UNUSED,struct wl_resource * resource,uint32_t serial,const char * mime_type)50 _e_comp_wl_data_offer_cb_accept(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t serial, const char *mime_type)
51 {
52 E_Comp_Wl_Data_Offer *offer;
53
54 DBG("Data Offer Accept");
55 if (!(offer = wl_resource_get_user_data(resource)))
56 return;
57
58 /* Protect against untimely calls from older data offers */
59 if ((!offer->source) || (offer != offer->source->offer))
60 return;
61
62 offer->source->target(offer->source, serial, mime_type);
63 offer->source->accepted = !!mime_type;
64 }
65
66 static void
_e_comp_wl_data_offer_cb_receive(struct wl_client * client EINA_UNUSED,struct wl_resource * resource,const char * mime_type,int32_t fd)67 _e_comp_wl_data_offer_cb_receive(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, const char *mime_type, int32_t fd)
68 {
69 E_Comp_Wl_Data_Offer *offer;
70
71 DBG("Data Offer Receive");
72
73 if (!(offer = wl_resource_get_user_data(resource)))
74 return;
75
76 if (offer->source)
77 offer->source->send(offer->source, mime_type, fd);
78 else
79 close(fd);
80 }
81
82 /* called by wl_data_offer_destroy */
83 static void
_e_comp_wl_data_offer_cb_destroy(struct wl_client * client EINA_UNUSED,struct wl_resource * resource)84 _e_comp_wl_data_offer_cb_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
85 {
86 DBG("Data Offer Destroy");
87 wl_resource_destroy(resource);
88 }
89
90 static void
data_source_notify_finish(E_Comp_Wl_Data_Source * source)91 data_source_notify_finish(E_Comp_Wl_Data_Source *source)
92 {
93 if (!source->actions_set)
94 return;
95
96 if (source->offer->in_ask &&
97 wl_resource_get_version(source->resource) >=
98 WL_DATA_SOURCE_ACTION_SINCE_VERSION)
99 {
100 wl_data_source_send_action(source->resource,
101 source->current_dnd_action);
102 }
103
104 if (wl_resource_get_version(source->resource) >=
105 WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION)
106 {
107 wl_data_source_send_dnd_finished(source->resource);
108 }
109
110 source->offer = NULL;
111 }
112
113 static uint32_t
data_offer_choose_action(E_Comp_Wl_Data_Offer * offer)114 data_offer_choose_action(E_Comp_Wl_Data_Offer *offer)
115 {
116 uint32_t available_actions, preferred_action = 0;
117 uint32_t source_actions, offer_actions;
118
119 if (wl_resource_get_version(offer->resource) >=
120 WL_DATA_OFFER_ACTION_SINCE_VERSION)
121 {
122 offer_actions = offer->dnd_actions;
123 preferred_action = offer->preferred_dnd_action;
124 }
125 else
126 {
127 offer_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
128 }
129
130 if (wl_resource_get_version(offer->source->resource) >=
131 WL_DATA_SOURCE_ACTION_SINCE_VERSION)
132 source_actions = offer->source->dnd_actions;
133 else
134 source_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
135
136 available_actions = offer_actions & source_actions;
137
138 if (!available_actions)
139 return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
140
141 if ( //offer->source->seat &&
142 offer->source->compositor_action & available_actions)
143 return offer->source->compositor_action;
144
145 /* If the dest side has a preferred DnD action, use it */
146 if ((preferred_action & available_actions) != 0)
147 return preferred_action;
148
149 /* Use the first found action, in bit order */
150 return 1 << (ffs(available_actions) - 1);
151 }
152
153 static void
data_offer_update_action(E_Comp_Wl_Data_Offer * offer)154 data_offer_update_action(E_Comp_Wl_Data_Offer *offer)
155 {
156 uint32_t action;
157
158 if (!offer->source)
159 return;
160
161 action = data_offer_choose_action(offer);
162
163 if (offer->source->current_dnd_action == action)
164 return;
165
166 offer->source->current_dnd_action = action;
167
168 if (offer->in_ask)
169 return;
170
171 if (wl_resource_get_version(offer->source->resource) >=
172 WL_DATA_SOURCE_ACTION_SINCE_VERSION)
173 wl_data_source_send_action(offer->source->resource, action);
174
175 if (wl_resource_get_version(offer->resource) >=
176 WL_DATA_OFFER_ACTION_SINCE_VERSION)
177 wl_data_offer_send_action(offer->resource, action);
178 }
179
180 static void
data_offer_set_actions(struct wl_client * client,struct wl_resource * resource,uint32_t dnd_actions,uint32_t preferred_action)181 data_offer_set_actions(struct wl_client *client,
182 struct wl_resource *resource,
183 uint32_t dnd_actions, uint32_t preferred_action)
184 {
185 E_Comp_Wl_Data_Offer *offer = wl_resource_get_user_data(resource);
186
187 if (dnd_actions & ~ALL_ACTIONS)
188 {
189 wl_resource_post_error(offer->resource,
190 WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK,
191 "invalid action mask %x", dnd_actions);
192 return;
193 }
194
195 if (preferred_action &&
196 (!(preferred_action & dnd_actions) ||
197 __builtin_popcount(preferred_action) > 1))
198 {
199 wl_resource_post_error(offer->resource,
200 WL_DATA_OFFER_ERROR_INVALID_ACTION,
201 "invalid action %x", preferred_action);
202 return;
203 }
204
205 offer->dnd_actions = dnd_actions;
206 offer->preferred_dnd_action = preferred_action;
207 data_offer_update_action(offer);
208 }
209
210 static void
data_offer_finish(struct wl_client * client,struct wl_resource * resource)211 data_offer_finish(struct wl_client *client, struct wl_resource *resource)
212 {
213 E_Comp_Wl_Data_Offer *offer = wl_resource_get_user_data(resource);
214
215 if (!offer->source || offer->source->offer != offer)
216 return;
217
218 /* Disallow finish while we have a grab driving drag-and-drop, or
219 * if the negotiation is not at the right stage
220 */
221 if ( //offer->source->seat ||
222 !offer->source->accepted)
223 {
224 wl_resource_post_error(offer->resource,
225 WL_DATA_OFFER_ERROR_INVALID_FINISH,
226 "premature finish request");
227 return;
228 }
229
230 switch (offer->source->current_dnd_action)
231 {
232 case WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE:
233 case WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK:
234 wl_resource_post_error(offer->resource,
235 WL_DATA_OFFER_ERROR_INVALID_OFFER,
236 "offer finished with an invalid action");
237 return;
238
239 default:
240 break;
241 }
242
243 data_source_notify_finish(offer->source);
244 }
245
246 /* called by wl_resource_destroy */
247 static void
_e_comp_wl_data_offer_cb_resource_destroy(struct wl_resource * resource)248 _e_comp_wl_data_offer_cb_resource_destroy(struct wl_resource *resource)
249 {
250 E_Comp_Wl_Data_Offer *offer = wl_resource_get_user_data(resource);
251
252 if (!offer->source)
253 goto out;
254
255 wl_list_remove(&offer->source_destroy_listener.link);
256
257 if (offer->source->offer != offer)
258 goto out;
259
260 /* If the drag destination has version < 3, wl_data_offer.finish
261 * won't be called, so do this here as a safety net, because
262 * we still want the version >=3 drag source to be happy.
263 */
264 if (wl_resource_get_version(offer->resource) <
265 WL_DATA_OFFER_ACTION_SINCE_VERSION)
266 {
267 data_source_notify_finish(offer->source);
268 }
269 else if (offer->source->resource &&
270 wl_resource_get_version(offer->source->resource) >=
271 WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION)
272 {
273 wl_data_source_send_cancelled(offer->source->resource);
274 }
275
276 offer->source->offer = NULL;
277 out:
278 free(offer);
279 }
280
281 /* called by emission of source->destroy_signal */
282 static void
_e_comp_wl_data_offer_cb_source_destroy(struct wl_listener * listener,void * data EINA_UNUSED)283 _e_comp_wl_data_offer_cb_source_destroy(struct wl_listener *listener, void *data EINA_UNUSED)
284 {
285 E_Comp_Wl_Data_Offer *offer;
286
287 DBG("Data Offer Source Destroy");
288 if (!listener) return;
289 offer = container_of(listener, E_Comp_Wl_Data_Offer,
290 source_destroy_listener);
291
292 offer->source = NULL;
293 }
294
295 static const struct wl_data_offer_interface _e_data_offer_interface =
296 {
297 _e_comp_wl_data_offer_cb_accept,
298 _e_comp_wl_data_offer_cb_receive,
299 _e_comp_wl_data_offer_cb_destroy,
300 data_offer_finish,
301 data_offer_set_actions,
302 };
303
304 static void
_e_comp_wl_data_source_cb_offer(struct wl_client * client EINA_UNUSED,struct wl_resource * resource,const char * mime_type)305 _e_comp_wl_data_source_cb_offer(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, const char *mime_type)
306 {
307 E_Comp_Wl_Data_Source *source;
308
309 DBG("Data Source Offer");
310 if (!(source = wl_resource_get_user_data(resource)))
311 return;
312
313 if (!source->mime_types)
314 source->mime_types = eina_array_new(1);
315 eina_array_push(source->mime_types, eina_stringshare_add(mime_type));
316 }
317
318 /* called by wl_data_source_destroy */
319 static void
_e_comp_wl_data_source_cb_destroy(struct wl_client * client EINA_UNUSED,struct wl_resource * resource)320 _e_comp_wl_data_source_cb_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
321 {
322 DBG("Data Source Destroy");
323 wl_resource_destroy(resource);
324 }
325
326 static void
data_source_set_actions(struct wl_client * client,struct wl_resource * resource,uint32_t dnd_actions)327 data_source_set_actions(struct wl_client *client,
328 struct wl_resource *resource,
329 uint32_t dnd_actions)
330 {
331 E_Comp_Wl_Data_Source *source =
332 wl_resource_get_user_data(resource);
333
334 if (source->actions_set)
335 {
336 wl_resource_post_error(source->resource,
337 WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
338 "cannot set actions more than once");
339 return;
340 }
341
342 if (dnd_actions & ~ALL_ACTIONS)
343 {
344 wl_resource_post_error(source->resource,
345 WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
346 "invalid action mask %x", dnd_actions);
347 return;
348 }
349 /* FIXME
350 if (source->seat) {
351 wl_resource_post_error(source->resource,
352 WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
353 "invalid action change after "
354 "wl_data_device.start_drag");
355 return;
356 }
357 */
358 source->dnd_actions = dnd_actions;
359 source->actions_set = 1;
360 }
361
362 /* called by wl_resource_destroy */
363 static void
_e_comp_wl_data_source_cb_resource_destroy(struct wl_resource * resource)364 _e_comp_wl_data_source_cb_resource_destroy(struct wl_resource *resource)
365 {
366 E_Comp_Wl_Data_Source *source;
367
368 if (!(source = wl_resource_get_user_data(resource)))
369 return;
370
371 wl_signal_emit(&source->destroy_signal, source);
372
373 _mime_types_free(source);
374
375 if (e_comp_wl->drag_source == source)
376 {
377 //free the drag here
378 e_object_del(E_OBJECT(e_comp_wl->drag));
379 e_comp_wl->drag = NULL;
380 }
381
382 free(source);
383 }
384
385 static void
_e_comp_wl_data_source_target_send(E_Comp_Wl_Data_Source * source,uint32_t serial EINA_UNUSED,const char * mime_type)386 _e_comp_wl_data_source_target_send(E_Comp_Wl_Data_Source *source, uint32_t serial EINA_UNUSED, const char *mime_type)
387 {
388 DBG("Data Source Target Send");
389 wl_data_source_send_target(source->resource, mime_type);
390 }
391
392 static void
_e_comp_wl_data_source_send_send(E_Comp_Wl_Data_Source * source,const char * mime_type,int32_t fd)393 _e_comp_wl_data_source_send_send(E_Comp_Wl_Data_Source *source, const char *mime_type, int32_t fd)
394 {
395 DBG("Data Source Source Send");
396 wl_data_source_send_send(source->resource, mime_type, fd);
397 close(fd);
398 }
399
400 static void
_e_comp_wl_data_source_cancelled_send(E_Comp_Wl_Data_Source * source)401 _e_comp_wl_data_source_cancelled_send(E_Comp_Wl_Data_Source *source)
402 {
403 DBG("Data Source Cancelled Send");
404 wl_data_source_send_cancelled(source->resource);
405 }
406
407 static const struct wl_data_source_interface _e_data_source_interface =
408 {
409 _e_comp_wl_data_source_cb_offer,
410 _e_comp_wl_data_source_cb_destroy,
411 data_source_set_actions,
412 };
413
414 static void
_e_comp_wl_data_device_destroy_selection_data_source(struct wl_listener * listener EINA_UNUSED,void * data)415 _e_comp_wl_data_device_destroy_selection_data_source(struct wl_listener *listener EINA_UNUSED, void *data)
416 {
417 E_Comp_Wl_Data_Source *source;
418 struct wl_resource *data_device_res = NULL, *focus = NULL;
419
420 DBG("Data Device Destroy Selection Source");
421 if (!(source = (E_Comp_Wl_Data_Source *)data))
422 return;
423
424 e_comp_wl->selection.data_source = NULL;
425
426 if (e_comp_wl->kbd.enabled)
427 focus = e_comp_wl->kbd.focus;
428
429 if (focus)
430 {
431 if (source->resource)
432 data_device_res =
433 e_comp_wl_data_find_for_client(wl_resource_get_client(source->resource));
434
435 if (data_device_res)
436 wl_data_device_send_selection(data_device_res, NULL);
437 }
438
439 wl_signal_emit(&e_comp_wl->selection.signal, e_comp->wl_comp_data);
440 }
441
442 static struct wl_resource *
_e_comp_wl_data_device_data_offer_create(E_Comp_Wl_Data_Source * source,struct wl_resource * data_device)443 _e_comp_wl_data_device_data_offer_create(E_Comp_Wl_Data_Source *source, struct wl_resource *data_device)
444 {
445 E_Comp_Wl_Data_Offer *offer;
446 Eina_Iterator *it;
447 char *t;
448
449 DBG("Data Offer Create");
450
451 offer = E_NEW(E_Comp_Wl_Data_Offer, 1);
452 if (!offer) return NULL;
453
454 offer->resource =
455 wl_resource_create(wl_resource_get_client(data_device),
456 &wl_data_offer_interface, wl_resource_get_version(data_device), 0);
457 if (!offer->resource)
458 {
459 free(offer);
460 return NULL;
461 }
462
463 wl_resource_set_implementation(offer->resource,
464 &_e_data_offer_interface, offer,
465 _e_comp_wl_data_offer_cb_resource_destroy);
466 offer->source = source;
467 source->offer = offer;
468 offer->source_destroy_listener.notify =
469 _e_comp_wl_data_offer_cb_source_destroy;
470 wl_signal_add(&source->destroy_signal, &offer->source_destroy_listener);
471
472 wl_data_device_send_data_offer(data_device, offer->resource);
473
474 it = eina_array_iterator_new(source->mime_types);
475 EINA_ITERATOR_FOREACH(it, t)
476 wl_data_offer_send_offer(offer->resource, t);
477 eina_iterator_free(it);
478
479 return offer->resource;
480 }
481
482 static void
_e_comp_wl_data_device_selection_set(void * data EINA_UNUSED,E_Comp_Wl_Data_Source * source,uint32_t serial)483 _e_comp_wl_data_device_selection_set(void *data EINA_UNUSED, E_Comp_Wl_Data_Source *source, uint32_t serial)
484 {
485 E_Comp_Wl_Data_Source *sel_source;
486 struct wl_resource *offer_res, *data_device_res, *focus = NULL;
487
488 sel_source = (E_Comp_Wl_Data_Source *)e_comp_wl->selection.data_source;
489 if (sel_source && (e_comp_wl->selection.serial - serial < UINT32_MAX / 2))
490 {
491 if ((source) && (!serial))
492 {
493 /* drm canvas will always have serial 0 */
494 pid_t pid;
495
496 wl_client_get_credentials(wl_resource_get_client(source->resource), &pid, NULL, NULL);
497 if (pid != getpid()) return;
498 }
499 else return;
500 }
501
502 if (sel_source)
503 {
504 if (!e_comp_wl->clipboard.xwl_owner)
505 wl_list_remove(&e_comp_wl->selection.data_source_listener.link);
506 if (sel_source->cancelled)
507 sel_source->cancelled(sel_source);
508 e_comp_wl->selection.data_source = NULL;
509 }
510
511 e_comp_wl->selection.data_source = sel_source = source;
512 e_comp_wl->clipboard.xwl_owner = 0;
513 e_comp_wl->selection.serial = serial;
514 if (source) source->serial = serial;
515
516 if (e_comp_wl->kbd.enabled)
517 focus = e_comp_wl->kbd.focus;
518
519 if (focus)
520 {
521 data_device_res =
522 e_comp_wl_data_find_for_client(wl_resource_get_client(focus));
523 if ((data_device_res) && (source))
524 {
525 offer_res =
526 _e_comp_wl_data_device_data_offer_create(source,
527 data_device_res);
528 wl_data_device_send_selection(data_device_res, offer_res);
529 }
530 else if (data_device_res)
531 wl_data_device_send_selection(data_device_res, NULL);
532 }
533
534 wl_signal_emit(&e_comp_wl->selection.signal, e_comp->wl_comp_data);
535
536 if (source)
537 {
538 e_comp_wl->selection.data_source_listener.notify =
539 _e_comp_wl_data_device_destroy_selection_data_source;
540 wl_signal_add(&source->destroy_signal,
541 &e_comp_wl->selection.data_source_listener);
542 }
543 }
544
545 static void
_e_comp_wl_data_device_drag_finished(E_Drag * drag,int dropped)546 _e_comp_wl_data_device_drag_finished(E_Drag *drag, int dropped)
547 {
548 struct wl_resource *res = NULL;
549 Evas_Object *o, *z;
550 E_Comp_Wl_Data_Source *data_source = e_comp_wl->drag_source;
551
552 o = edje_object_part_swallow_get(drag->comp_object, "e.swallow.content");
553 if (eina_streq(evas_object_type_get(o), "e_comp_object"))
554 edje_object_part_unswallow(drag->comp_object, o);
555 else
556 {
557 z = o;
558 o = e_zoomap_child_get(z);
559 e_zoomap_child_set(z, NULL);
560 }
561 evas_object_hide(o);
562 evas_object_pass_events_set(o, 1);
563 if (e_comp_wl->drag != drag) return;
564 e_comp_wl->drag = NULL;
565 e_comp_wl->drag_client = NULL;
566 e_screensaver_inhibit_toggle(0);
567 if (dropped) return;
568 #ifndef HAVE_WAYLAND_ONLY
569 if (e_comp_wl->selection.target && e_client_has_xwindow(e_comp_wl->selection.target))
570 {
571 ecore_x_client_message32_send(e_client_util_win_get(e_comp_wl->selection.target),
572 ECORE_X_ATOM_XDND_DROP,
573 ECORE_X_EVENT_MASK_NONE,
574 e_comp->cm_selection, 0,
575 ecore_x_current_time_get(), 0, 0);
576 return;
577 }
578 #endif
579
580 if (e_comp_wl->selection.target)
581 res = e_comp_wl_data_find_for_client(wl_resource_get_client(e_comp_wl->selection.target->comp_data->surface));
582 if (res && data_source->accepted && data_source->current_dnd_action)
583 {
584 wl_data_device_send_drop(res);
585 if (wl_resource_get_version(data_source->resource) >=
586 WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION)
587 wl_data_source_send_dnd_drop_performed(data_source->resource);
588
589 data_source->offer->in_ask = data_source->current_dnd_action ==
590 WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
591 }
592 else if (wl_resource_get_version(data_source->resource) >=
593 WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION)
594 wl_data_source_send_cancelled(data_source->resource);
595 if (res) wl_data_device_send_leave(res);
596 #ifndef HAVE_WAYLAND_ONLY
597 if (e_comp_util_has_xwayland())
598 {
599 ecore_x_selection_owner_set(0, ECORE_X_ATOM_SELECTION_XDND,
600 ecore_x_current_time_get());
601 ecore_x_window_hide(e_comp->cm_selection);
602 }
603 #endif
604 e_comp_wl->selection.target = NULL;
605 e_comp_wl->drag_source = NULL;
606 }
607
608 static void
_e_comp_wl_data_device_drag_key(E_Drag * drag EINA_UNUSED,Ecore_Event_Key * ev)609 _e_comp_wl_data_device_drag_key(E_Drag *drag EINA_UNUSED, Ecore_Event_Key *ev)
610 {
611 uint32_t compositor_action = 0;
612 const Evas_Modifier *m;
613 E_Comp_Wl_Data_Source *drag_source = e_comp_wl->drag_source;
614
615 m = evas_key_modifier_get(e_comp->evas);
616 if (evas_key_modifier_is_set(m, "Shift"))
617 compositor_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
618 else if (evas_key_modifier_is_set(m, "Control"))
619 compositor_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
620 if (drag_source->compositor_action == compositor_action) return;
621 drag_source->compositor_action = compositor_action;
622 if (drag_source->offer)
623 data_offer_update_action(drag_source->offer);
624 }
625
626 static void
_e_comp_wl_data_device_cb_drag_start(struct wl_client * client,struct wl_resource * resource EINA_UNUSED,struct wl_resource * source_resource,struct wl_resource * origin_resource,struct wl_resource * icon_resource,uint32_t serial)627 _e_comp_wl_data_device_cb_drag_start(struct wl_client *client, struct wl_resource *resource EINA_UNUSED, struct wl_resource *source_resource, struct wl_resource *origin_resource, struct wl_resource *icon_resource, uint32_t serial)
628 {
629 E_Comp_Wl_Data_Source *source;
630 Eina_List *l;
631 struct wl_resource *res;
632 E_Client *ec = NULL;
633 int x, y;
634
635 DBG("Data Device Drag Start");
636
637 if ((e_comp_wl->kbd.focus) && (e_comp_wl->kbd.focus != origin_resource))
638 return;
639
640 if (!(source = wl_resource_get_user_data(source_resource))) return;
641 e_comp_wl->drag_source = source;
642
643 if (icon_resource)
644 {
645 DBG("\tHave Icon Resource: %p", icon_resource);
646 ec = wl_resource_get_user_data(icon_resource);
647 if (!ec->re_manage)
648 {
649 ec->re_manage = 1;
650
651 ec->lock_focus_out = ec->override = 1;
652 ec->icccm.title = eina_stringshare_add("noshadow");
653 ec->layer = E_LAYER_CLIENT_DRAG;
654 evas_object_layer_set(ec->frame, E_LAYER_CLIENT_DRAG);
655 e_client_focus_stack_set(eina_list_remove(e_client_focus_stack_get(), ec));
656 EC_CHANGED(ec);
657 e_comp_wl->drag_client = ec;
658 }
659 if (ec->comp_data->pending.input)
660 eina_tiler_clear(ec->comp_data->pending.input);
661 else
662 {
663 ec->comp_data->pending.input = eina_tiler_new(65535, 65535);
664 eina_tiler_tile_size_set(ec->comp_data->pending.input, 1, 1);
665 }
666 }
667
668 EINA_LIST_FOREACH(e_comp_wl->ptr.resources, l, res)
669 {
670 if (!e_comp_wl_input_pointer_check(res)) continue;
671 if (wl_resource_get_client(res) != client) continue;
672 wl_pointer_send_leave(res, serial, e_comp_wl->kbd.focus);
673 }
674
675 evas_pointer_canvas_xy_get(e_comp->evas, &x, &y);
676 e_comp_wl->drag = e_drag_new(x, y, NULL, 0, NULL, 0, NULL,
677 _e_comp_wl_data_device_drag_finished);
678 e_drag_key_down_cb_set(e_comp_wl->drag, _e_comp_wl_data_device_drag_key);
679 e_drag_key_up_cb_set(e_comp_wl->drag, _e_comp_wl_data_device_drag_key);
680 e_comp_wl->drag->button_mask =
681 evas_pointer_button_down_mask_get(e_comp->evas);
682 if (ec)
683 e_drag_object_set(e_comp_wl->drag, ec->frame);
684 e_drag_start(e_comp_wl->drag, x, y);
685 #ifndef HAVE_WAYLAND_ONLY
686 if (e_comp_util_has_xwayland())
687 {
688 ecore_x_window_show(e_comp->cm_selection);
689 ecore_x_selection_owner_set(e_comp->cm_selection,
690 ECORE_X_ATOM_SELECTION_XDND,
691 ecore_x_current_time_get());
692 }
693 #endif
694 if (e_comp_wl->ptr.ec)
695 e_comp_wl_data_device_send_enter(e_comp_wl->ptr.ec);
696 e_screensaver_inhibit_toggle(1);
697 e_comp_canvas_feed_mouse_up(0);
698 }
699
700 static void
_e_comp_wl_data_device_cb_selection_set(struct wl_client * client EINA_UNUSED,struct wl_resource * resource EINA_UNUSED,struct wl_resource * source_resource,uint32_t serial)701 _e_comp_wl_data_device_cb_selection_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource EINA_UNUSED, struct wl_resource *source_resource, uint32_t serial)
702 {
703 E_Comp_Wl_Data_Source *source;
704
705 DBG("Data Device Selection Set");
706 if (!source_resource) return;
707 if (!(source = wl_resource_get_user_data(source_resource))) return;
708 if (source->actions_set)
709 {
710 wl_resource_post_error(source_resource,
711 WL_DATA_SOURCE_ERROR_INVALID_SOURCE,
712 "cannot set drag-and-drop source as selection");
713 return;
714 }
715
716 _e_comp_wl_data_device_selection_set(e_comp->wl_comp_data, source, serial);
717 }
718
719 static void
_e_comp_wl_data_device_cb_release(struct wl_client * client EINA_UNUSED,struct wl_resource * resource)720 _e_comp_wl_data_device_cb_release(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
721 {
722 DBG("Data Device Release");
723 wl_resource_destroy(resource);
724 }
725
726 static const struct wl_data_device_interface _e_data_device_interface =
727 {
728 _e_comp_wl_data_device_cb_drag_start,
729 _e_comp_wl_data_device_cb_selection_set,
730 _e_comp_wl_data_device_cb_release
731 };
732
733 static void
_e_comp_wl_data_device_cb_unbind(struct wl_resource * resource)734 _e_comp_wl_data_device_cb_unbind(struct wl_resource *resource)
735 {
736 struct wl_client *wc = wl_resource_get_client(resource);
737 eina_hash_del_by_key(e_comp_wl->mgr.data_resources, &wc);
738 }
739
740 static void
_e_comp_wl_data_manager_cb_device_get(struct wl_client * client,struct wl_resource * manager_resource,uint32_t id,struct wl_resource * seat_resource EINA_UNUSED)741 _e_comp_wl_data_manager_cb_device_get(struct wl_client *client, struct wl_resource *manager_resource, uint32_t id, struct wl_resource *seat_resource EINA_UNUSED)
742 {
743 struct wl_resource *res;
744
745 DBG("Data Manager Device Get");
746
747 /* try to create the data device resource */
748 res = wl_resource_create(client, &wl_data_device_interface, wl_resource_get_version(manager_resource), id);
749 if (!res)
750 {
751 ERR("Could not create data device resource");
752 wl_resource_post_no_memory(manager_resource);
753 return;
754 }
755
756 eina_hash_add(e_comp_wl->mgr.data_resources, &client, res);
757 wl_resource_set_implementation(res, &_e_data_device_interface,
758 e_comp->wl_comp_data,
759 _e_comp_wl_data_device_cb_unbind);
760 }
761
762 static const struct wl_data_device_manager_interface _e_manager_interface =
763 {
764 (void *)e_comp_wl_data_manager_source_create,
765 _e_comp_wl_data_manager_cb_device_get
766 };
767
768 /* static void */
769 /* _e_comp_wl_data_cb_unbind_manager(struct wl_resource *resource) */
770 /* { */
771 /* E_Comp_Data *e_comp->wl_comp_data; */
772
773 /* DBG("Comp_Wl_Data: Unbind Manager"); */
774
775 /* if (!(e_comp->wl_comp_data = wl_resource_get_user_data(resource))) return; */
776
777 /* e_comp_wl->mgr.resource = NULL; */
778 /* } */
779
780 static void
_e_comp_wl_data_cb_bind_manager(struct wl_client * client,void * data EINA_UNUSED,uint32_t version EINA_UNUSED,uint32_t id)781 _e_comp_wl_data_cb_bind_manager(struct wl_client *client, void *data EINA_UNUSED, uint32_t version EINA_UNUSED, uint32_t id)
782 {
783 struct wl_resource *res;
784 pid_t pid;
785
786 /* try to create data manager resource */
787 res = wl_resource_create(client, &wl_data_device_manager_interface, 3, id);
788 if (!res)
789 {
790 ERR("Could not create data device manager");
791 wl_client_post_no_memory(client);
792 return;
793 }
794 wl_client_get_credentials(client, &pid, NULL, NULL);
795 if (pid == getpid())
796 e_comp_wl->mgr.resource = res;
797
798 wl_resource_set_implementation(res, &_e_manager_interface,
799 e_comp->wl_comp_data, NULL);
800 }
801
802 static Eina_Bool
_e_comp_wl_clipboard_offer_load(void * data,Ecore_Fd_Handler * handler)803 _e_comp_wl_clipboard_offer_load(void *data, Ecore_Fd_Handler *handler)
804 {
805 E_Comp_Wl_Clipboard_Offer *offer;
806 char *p;
807 size_t size;
808 int len;
809 int fd;
810
811 if (!(offer = (E_Comp_Wl_Clipboard_Offer *)data))
812 return ECORE_CALLBACK_CANCEL;
813
814 fd = ecore_main_fd_handler_fd_get(handler);
815
816 size = offer->source->contents.size;
817 p = (char *)offer->source->contents.data;
818 len = write(fd, p + offer->offset, size - offer->offset);
819 if (len > 0) offer->offset += len;
820
821 if ((offer->offset == size) || (len <= 0))
822 {
823 close(fd);
824 ecore_main_fd_handler_del(handler);
825 e_comp_wl_clipboard_source_unref(offer->source);
826 free(offer);
827 }
828
829 return ECORE_CALLBACK_RENEW;
830 }
831
832 static void
_e_comp_wl_clipboard_offer_create(E_Comp_Wl_Clipboard_Source * source,int fd)833 _e_comp_wl_clipboard_offer_create(E_Comp_Wl_Clipboard_Source *source, int fd)
834 {
835 E_Comp_Wl_Clipboard_Offer *offer;
836
837 offer = E_NEW(E_Comp_Wl_Clipboard_Offer, 1);
838
839 offer->offset = 0;
840 offer->source = source;
841 source->ref++;
842 offer->fd_handler =
843 ecore_main_fd_handler_add(fd, ECORE_FD_WRITE,
844 _e_comp_wl_clipboard_offer_load, offer,
845 NULL, NULL);
846 }
847
848 static Eina_Bool
_e_comp_wl_clipboard_source_save(void * data EINA_UNUSED,Ecore_Fd_Handler * handler)849 _e_comp_wl_clipboard_source_save(void *data EINA_UNUSED, Ecore_Fd_Handler *handler)
850 {
851 E_Comp_Wl_Clipboard_Source *source;
852 char *p;
853 int len, size;
854
855 if (!(source = (E_Comp_Wl_Clipboard_Source *)e_comp_wl->clipboard.source))
856 return ECORE_CALLBACK_CANCEL;
857
858 /* extend contents buffer */
859 if ((source->contents.alloc - source->contents.size) < CLIPBOARD_CHUNK)
860 {
861 wl_array_add(&source->contents, CLIPBOARD_CHUNK);
862 source->contents.size -= CLIPBOARD_CHUNK;
863 }
864
865 p = (char *)source->contents.data + source->contents.size;
866 size = source->contents.alloc - source->contents.size;
867 len = read(source->fd, p, size);
868
869 if (len == 0)
870 {
871 ecore_main_fd_handler_del(handler);
872 close(source->fd);
873 source->fd_handler = NULL;
874 }
875 else if (len < 0)
876 {
877 e_comp_wl_clipboard_source_unref(source);
878 e_comp_wl->clipboard.source = NULL;
879 }
880 else
881 {
882 source->contents.size += len;
883 }
884
885 return ECORE_CALLBACK_RENEW;
886 }
887
888 static void
_e_comp_wl_clipboard_source_target_send(E_Comp_Wl_Data_Source * source EINA_UNUSED,uint32_t serial EINA_UNUSED,const char * mime_type EINA_UNUSED)889 _e_comp_wl_clipboard_source_target_send(E_Comp_Wl_Data_Source *source EINA_UNUSED, uint32_t serial EINA_UNUSED, const char *mime_type EINA_UNUSED)
890 {
891 }
892
893 static void
_e_comp_wl_clipboard_source_send_send(E_Comp_Wl_Data_Source * source,const char * mime_type,int fd)894 _e_comp_wl_clipboard_source_send_send(E_Comp_Wl_Data_Source *source, const char *mime_type, int fd)
895 {
896 E_Comp_Wl_Clipboard_Source *clip_source;
897 char *t;
898
899 clip_source = container_of(source, E_Comp_Wl_Clipboard_Source, data_source);
900 if (!clip_source) return;
901
902 t = eina_array_data_get(source->mime_types, 0);
903 if (!strcmp(mime_type, t))
904 _e_comp_wl_clipboard_offer_create(clip_source, fd);
905 else
906 close(fd);
907 }
908
909 static void
_e_comp_wl_clipboard_source_cancelled_send(E_Comp_Wl_Data_Source * source EINA_UNUSED)910 _e_comp_wl_clipboard_source_cancelled_send(E_Comp_Wl_Data_Source *source EINA_UNUSED)
911 {
912 }
913
914 static void
_e_comp_wl_clipboard_selection_set(struct wl_listener * listener EINA_UNUSED,void * data EINA_UNUSED)915 _e_comp_wl_clipboard_selection_set(struct wl_listener *listener EINA_UNUSED, void *data EINA_UNUSED)
916 {
917 E_Comp_Wl_Data_Source *sel_source;
918 E_Comp_Wl_Clipboard_Source *clip_source;
919 int p[2];
920 char *mime_type;
921
922 sel_source = (E_Comp_Wl_Data_Source *)e_comp_wl->selection.data_source;
923 clip_source = (E_Comp_Wl_Clipboard_Source *)e_comp_wl->clipboard.source;
924
925 if (!sel_source)
926 {
927 if (clip_source)
928 _e_comp_wl_data_device_selection_set(e_comp->wl_comp_data,
929 &clip_source->data_source,
930 clip_source->serial);
931 return;
932 }
933 else if (sel_source->target == _e_comp_wl_clipboard_source_target_send)
934 return;
935
936 if (clip_source)
937 e_comp_wl_clipboard_source_unref(clip_source);
938
939 e_comp_wl->clipboard.source = NULL;
940 mime_type = eina_array_data_get(sel_source->mime_types, 0);
941
942 if (pipe2(p, O_CLOEXEC) == -1)
943 return;
944
945 sel_source->send(sel_source, mime_type, p[1]);
946
947 e_comp_wl->clipboard.source =
948 e_comp_wl_clipboard_source_create(mime_type,
949 e_comp_wl->selection.serial, p[0]);
950
951 if (!e_comp_wl->clipboard.source)
952 close(p[0]);
953 }
954
955 static void
_e_comp_wl_clipboard_create(void)956 _e_comp_wl_clipboard_create(void)
957 {
958 e_comp_wl->clipboard.listener.notify = _e_comp_wl_clipboard_selection_set;
959 wl_signal_add(&e_comp_wl->selection.signal, &e_comp_wl->clipboard.listener);
960 }
961
962 E_API void
e_comp_wl_data_device_send_enter(E_Client * ec)963 e_comp_wl_data_device_send_enter(E_Client *ec)
964 {
965 struct wl_resource *data_device_res, *offer_res;
966 uint32_t serial;
967 int x, y;
968
969 if (e_client_has_xwindow(ec) &&
970 e_client_has_xwindow(e_comp_wl->drag_client))
971 return;
972 if (e_comp_wl->drag && (e_comp_wl->drag->object == ec->frame)) return;
973 if (!e_client_has_xwindow(ec))
974 {
975 E_Comp_Wl_Data_Source *drag_source = e_comp_wl->drag_source;
976 data_device_res =
977 e_comp_wl_data_find_for_client(wl_resource_get_client(ec->comp_data->surface));
978 if (!data_device_res) return;
979 offer_res = e_comp_wl_data_device_send_offer(ec);
980 if (e_comp_wl->drag_source && (!offer_res)) return;
981 if (e_client_has_xwindow(e_comp_wl->drag_client))
982 {
983 drag_source->offer->dnd_actions = drag_source->dnd_actions;
984 drag_source->offer->preferred_dnd_action = drag_source->current_dnd_action;
985 }
986 data_offer_update_action(drag_source->offer);
987 if (offer_res)
988 {
989 if (wl_resource_get_version(offer_res) >= WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION)
990 wl_data_offer_send_source_actions(offer_res, drag_source->dnd_actions);
991 }
992 }
993 e_comp_wl->selection.target = ec;
994
995 #ifndef HAVE_WAYLAND_ONLY
996 if (e_client_has_xwindow(ec))
997 {
998 int d1 = 0x5UL, d2, d3, d4;
999 E_Comp_Wl_Data_Source *source;
1000
1001 d2 = d3 = d4 = 0;
1002 source = e_comp_wl->drag_source;
1003
1004 if ((source->mime_types) && (eina_array_count(source->mime_types) > 3))
1005 {
1006 const char *type, *types[eina_array_count(source->mime_types)];
1007 int i = 0;
1008 Eina_Iterator *it;
1009
1010 d1 |= 0x1UL;
1011 it = eina_array_iterator_new(source->mime_types);
1012 EINA_ITERATOR_FOREACH(it, type)
1013 types[i++] = type;
1014 eina_iterator_free(it);
1015 ecore_x_dnd_types_set(e_comp->cm_selection, types, i);
1016 }
1017 else if (source->mime_types)
1018 {
1019 if (eina_array_count(source->mime_types))
1020 d2 = ecore_x_atom_get(eina_array_data_get(source->mime_types, 0));
1021 if (eina_array_count(source->mime_types) > 1)
1022 d3 = ecore_x_atom_get(eina_array_data_get(source->mime_types, 1));
1023 if (eina_array_count(source->mime_types) > 2)
1024 d4 = ecore_x_atom_get(eina_array_data_get(source->mime_types, 2));
1025 }
1026
1027 ecore_x_client_message32_send(e_client_util_win_get(ec),
1028 ECORE_X_ATOM_XDND_ENTER,
1029 ECORE_X_EVENT_MASK_NONE,
1030 e_comp->cm_selection, d1, d2, d3, d4);
1031
1032 return;
1033 }
1034 #endif
1035 x = e_comp_wl->ptr.x - e_comp_wl->selection.target->client.x;
1036 y = e_comp_wl->ptr.y - e_comp_wl->selection.target->client.y;
1037 serial = wl_display_next_serial(e_comp_wl->wl.disp);
1038 wl_data_device_send_enter(data_device_res, serial, ec->comp_data->surface,
1039 wl_fixed_from_int(x), wl_fixed_from_int(y),
1040 offer_res);
1041 }
1042
1043 E_API void
e_comp_wl_data_device_send_leave(E_Client * ec)1044 e_comp_wl_data_device_send_leave(E_Client *ec)
1045 {
1046 struct wl_resource *res;
1047
1048 if (e_client_has_xwindow(ec) &&
1049 e_client_has_xwindow(e_comp_wl->drag_client))
1050 return;
1051 if (e_comp_wl->drag && (e_comp_wl->drag->object == ec->frame)) return;
1052 if (e_comp_wl->selection.target == ec)
1053 e_comp_wl->selection.target = NULL;
1054 #ifndef HAVE_WAYLAND_ONLY
1055 if (e_client_has_xwindow(ec))
1056 {
1057 ecore_x_client_message32_send(e_client_util_win_get(ec),
1058 ECORE_X_ATOM_XDND_LEAVE,
1059 ECORE_X_EVENT_MASK_NONE,
1060 e_comp->cm_selection, 0, 0, 0, 0);
1061 return;
1062 }
1063 #endif
1064 {
1065 E_Comp_Wl_Data_Source *drag_source = e_comp_wl->drag_source;
1066 if (drag_source &&
1067 drag_source->offer)
1068 {
1069 E_Comp_Wl_Data_Offer *offer;
1070 /* Unlink the offer from the source */
1071 offer = drag_source->offer;
1072 offer->source = NULL;
1073 drag_source->offer = NULL;
1074 drag_source->accepted = 0;
1075 wl_list_remove(&offer->source_destroy_listener.link);
1076 }
1077 }
1078 res = e_comp_wl_data_find_for_client(wl_resource_get_client(ec->comp_data->surface));
1079 if (res)
1080 wl_data_device_send_leave(res);
1081 }
1082
1083 EINTERN void *
e_comp_wl_data_device_send_offer(E_Client * ec)1084 e_comp_wl_data_device_send_offer(E_Client *ec)
1085 {
1086 struct wl_resource *data_device_res, *offer_res = NULL;
1087 E_Comp_Wl_Data_Source *source;
1088
1089 data_device_res =
1090 e_comp_wl_data_find_for_client(wl_resource_get_client(ec->comp_data->surface));
1091 if (!data_device_res) return NULL;
1092 source = e_comp_wl->drag_source;
1093 if (source)
1094 {
1095 offer_res =
1096 _e_comp_wl_data_device_data_offer_create(source, data_device_res);
1097 }
1098
1099 return offer_res;
1100 }
1101
1102 E_API void
e_comp_wl_data_device_keyboard_focus_set(void)1103 e_comp_wl_data_device_keyboard_focus_set(void)
1104 {
1105 struct wl_resource *data_device_res, *offer_res = NULL, *focus;
1106 E_Comp_Wl_Data_Source *source;
1107 E_Client *focused;
1108
1109 if (!e_comp_wl->kbd.enabled)
1110 {
1111 ERR("Keyboard not enabled");
1112 return;
1113 }
1114
1115 if (!(focus = e_comp_wl->kbd.focus))
1116 {
1117 ERR("No focused resource");
1118 return;
1119 }
1120 focused = wl_resource_get_user_data(focus);
1121 source = (E_Comp_Wl_Data_Source *)e_comp_wl->selection.data_source;
1122
1123 #ifndef HAVE_WAYLAND_ONLY
1124 do
1125 {
1126 if (!e_comp_util_has_xwayland()) break;
1127 if (e_comp_wl->clipboard.xwl_owner)
1128 {
1129 if (e_client_has_xwindow(focused)) return;
1130 break;
1131 }
1132 else if (source && e_client_has_xwindow(focused))
1133 {
1134 /* wl -> x11 */
1135 ecore_x_selection_owner_set(e_comp->cm_selection,
1136 ECORE_X_ATOM_SELECTION_CLIPBOARD,
1137 ecore_x_current_time_get());
1138 return;
1139 }
1140 } while (0);
1141 #endif
1142 data_device_res =
1143 e_comp_wl_data_find_for_client(wl_resource_get_client(focus));
1144 if (!data_device_res) return;
1145
1146 if (source)
1147 {
1148 offer_res =
1149 _e_comp_wl_data_device_data_offer_create(source, data_device_res);
1150 }
1151
1152 wl_data_device_send_selection(data_device_res, offer_res);
1153 }
1154
1155 EINTERN Eina_Bool
e_comp_wl_data_manager_init(void)1156 e_comp_wl_data_manager_init(void)
1157 {
1158 /* try to create global data manager */
1159 e_comp_wl->mgr.global =
1160 wl_global_create(e_comp_wl->wl.disp, &wl_data_device_manager_interface, 3,
1161 NULL, _e_comp_wl_data_cb_bind_manager);
1162 if (!e_comp_wl->mgr.global)
1163 {
1164 ERR("Could not create global for data device manager");
1165 return EINA_FALSE;
1166 }
1167
1168 wl_signal_init(&e_comp_wl->selection.signal);
1169
1170 /* create clipboard */
1171 _e_comp_wl_clipboard_create();
1172 e_comp_wl->mgr.data_resources = eina_hash_pointer_new(NULL);
1173
1174 return EINA_TRUE;
1175 }
1176
1177 EINTERN void
e_comp_wl_data_manager_shutdown(void)1178 e_comp_wl_data_manager_shutdown(void)
1179 {
1180 /* destroy the global manager resource */
1181 /* if (e_comp_wl->mgr.global) wl_global_destroy(e_comp_wl->mgr.global); */
1182
1183 wl_list_remove(&e_comp_wl->clipboard.listener.link);
1184 E_FREE_FUNC(e_comp_wl->mgr.data_resources, eina_hash_free);
1185 }
1186
1187 E_API struct wl_resource *
e_comp_wl_data_find_for_client(struct wl_client * client)1188 e_comp_wl_data_find_for_client(struct wl_client *client)
1189 {
1190 return eina_hash_find(e_comp_wl->mgr.data_resources, &client);
1191 }
1192
1193 E_API E_Comp_Wl_Data_Source *
e_comp_wl_data_manager_source_create(struct wl_client * client,struct wl_resource * resource,uint32_t id)1194 e_comp_wl_data_manager_source_create(struct wl_client *client, struct wl_resource *resource, uint32_t id)
1195 {
1196 E_Comp_Wl_Data_Source *source;
1197
1198 DBG("Data Manager Source Create");
1199
1200 source = E_NEW(E_Comp_Wl_Data_Source, 1);
1201 if (!source)
1202 {
1203 wl_resource_post_no_memory(resource);
1204 return NULL;
1205 }
1206
1207 wl_signal_init(&source->destroy_signal);
1208 source->target = _e_comp_wl_data_source_target_send;
1209 source->send = _e_comp_wl_data_source_send_send;
1210 source->cancelled = _e_comp_wl_data_source_cancelled_send;
1211
1212 source->resource =
1213 wl_resource_create(client, &wl_data_source_interface, wl_resource_get_version(resource), id);
1214 if (!source->resource)
1215 {
1216 ERR("Could not create data source resource");
1217 free(source);
1218 wl_resource_post_no_memory(resource);
1219 return NULL;
1220 }
1221
1222 wl_resource_set_implementation(source->resource,
1223 &_e_data_source_interface, source,
1224 _e_comp_wl_data_source_cb_resource_destroy);
1225 return source;
1226 }
1227
1228 E_API E_Comp_Wl_Clipboard_Source *
e_comp_wl_clipboard_source_create(const char * mime_type,uint32_t serial,int fd)1229 e_comp_wl_clipboard_source_create(const char *mime_type, uint32_t serial, int fd)
1230 {
1231 E_Comp_Wl_Clipboard_Source *source;
1232
1233 source = E_NEW(E_Comp_Wl_Clipboard_Source, 1);
1234 if (!source) return NULL;
1235
1236 source->data_source.resource = NULL;
1237 source->data_source.target = _e_comp_wl_clipboard_source_target_send;
1238 source->data_source.send = _e_comp_wl_clipboard_source_send_send;
1239 source->data_source.cancelled = _e_comp_wl_clipboard_source_cancelled_send;
1240
1241 wl_array_init(&source->contents);
1242 wl_signal_init(&source->data_source.destroy_signal);
1243
1244 source->ref = 1;
1245 source->serial = serial;
1246
1247 if (mime_type)
1248 {
1249 if (!source->data_source.mime_types)
1250 source->data_source.mime_types = eina_array_new(1);
1251 eina_array_push(source->data_source.mime_types,
1252 eina_stringshare_add(mime_type));
1253 }
1254
1255 if (fd > 0)
1256 {
1257 source->fd_handler =
1258 ecore_main_fd_handler_file_add(fd, ECORE_FD_READ | ECORE_FD_ERROR,
1259 _e_comp_wl_clipboard_source_save,
1260 e_comp->wl_comp_data, NULL, NULL);
1261 if (!source->fd_handler)
1262 {
1263 _mime_types_free(&source->data_source);
1264 free(source);
1265 return NULL;
1266 }
1267 }
1268
1269 source->fd = fd;
1270
1271 return source;
1272 }
1273
1274 E_API void
e_comp_wl_clipboard_source_unref(E_Comp_Wl_Clipboard_Source * source)1275 e_comp_wl_clipboard_source_unref(E_Comp_Wl_Clipboard_Source *source)
1276 {
1277 EINA_SAFETY_ON_NULL_RETURN(source);
1278 source->ref--;
1279 if (source->ref > 0) return;
1280
1281 if (source->fd_handler)
1282 {
1283 ecore_main_fd_handler_del(source->fd_handler);
1284 close(source->fd);
1285 }
1286
1287 _mime_types_free(&source->data_source);
1288 if (source == e_comp_wl->clipboard.source)
1289 e_comp_wl->clipboard.source = NULL;
1290 if (&source->data_source == e_comp_wl->selection.data_source)
1291 e_comp_wl->selection.data_source = NULL;
1292
1293 wl_signal_emit(&source->data_source.destroy_signal, &source->data_source);
1294 wl_array_release(&source->contents);
1295 free(source);
1296 }
1297
1298