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