1 /*
2  * Copyright © 2011 Kristian Høgsberg
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that copyright
7  * notice and this permission notice appear in supporting documentation, and
8  * that the name of the copyright holders not be used in advertising or
9  * publicity pertaining to distribution of the software without specific,
10  * written prior permission.  The copyright holders make no representations
11  * about the suitability of this software for any purpose.  It is provided "as
12  * is" without express or implied warranty.
13  *
14  * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16  * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20  * OF THIS SOFTWARE.
21  */
22 
23 /* The file is based on src/data-device.c from Weston */
24 
25 #include "config.h"
26 
27 #include "wayland/meta-wayland-data-device-primary-legacy.h"
28 
29 #include "compositor/meta-dnd-actor-private.h"
30 #include "meta/meta-selection-source-memory.h"
31 #include "wayland/meta-selection-source-wayland-private.h"
32 #include "wayland/meta-wayland-data-offer-primary-legacy.h"
33 #include "wayland/meta-wayland-data-source-primary-legacy.h"
34 #include "wayland/meta-wayland-dnd-surface.h"
35 #include "wayland/meta-wayland-pointer.h"
36 #include "wayland/meta-wayland-private.h"
37 #include "wayland/meta-wayland-seat.h"
38 
39 #include "gtk-primary-selection-server-protocol.h"
40 
41 static struct wl_resource * create_and_send_primary_offer (MetaWaylandDataDevicePrimaryLegacy *data_device,
42                                                            struct wl_resource                 *target);
43 
44 static void
move_resources(struct wl_list * destination,struct wl_list * source)45 move_resources (struct wl_list *destination,
46                 struct wl_list *source)
47 {
48   wl_list_insert_list (destination, source);
49   wl_list_init (source);
50 }
51 
52 static void
move_resources_for_client(struct wl_list * destination,struct wl_list * source,struct wl_client * client)53 move_resources_for_client (struct wl_list   *destination,
54 			   struct wl_list   *source,
55 			   struct wl_client *client)
56 {
57   struct wl_resource *resource, *tmp;
58   wl_resource_for_each_safe (resource, tmp, source)
59     {
60       if (wl_resource_get_client (resource) == client)
61         {
62           wl_list_remove (wl_resource_get_link (resource));
63           wl_list_insert (destination, wl_resource_get_link (resource));
64         }
65     }
66 }
67 
68 static void
unbind_resource(struct wl_resource * resource)69 unbind_resource (struct wl_resource *resource)
70 {
71   wl_list_remove (wl_resource_get_link (resource));
72 }
73 
74 static void
default_destructor(struct wl_client * client,struct wl_resource * resource)75 default_destructor (struct wl_client   *client,
76                     struct wl_resource *resource)
77 {
78   wl_resource_destroy (resource);
79 }
80 
81 static void
set_selection_source(MetaWaylandDataDevicePrimaryLegacy * data_device,MetaSelectionSource * selection_source)82 set_selection_source (MetaWaylandDataDevicePrimaryLegacy *data_device,
83                       MetaSelectionSource                *selection_source)
84 
85 {
86   MetaDisplay *display = meta_get_display ();
87 
88   meta_selection_set_owner (meta_display_get_selection (display),
89                             META_SELECTION_PRIMARY,
90                             selection_source);
91   g_set_object (&data_device->owner, selection_source);
92 }
93 
94 static void
unset_selection_source(MetaWaylandDataDevicePrimaryLegacy * data_device)95 unset_selection_source (MetaWaylandDataDevicePrimaryLegacy *data_device)
96 {
97   MetaDisplay *display = meta_get_display ();
98 
99   if (!data_device->owner)
100     return;
101 
102   meta_selection_unset_owner (meta_display_get_selection (display),
103                               META_SELECTION_PRIMARY,
104                               data_device->owner);
105   g_clear_object (&data_device->owner);
106 }
107 
108 static void
primary_source_destroyed(gpointer data,GObject * object_was_here)109 primary_source_destroyed (gpointer  data,
110                           GObject  *object_was_here)
111 {
112   MetaWaylandDataDevicePrimaryLegacy *data_device = data;
113 
114   data_device->data_source = NULL;
115   unset_selection_source (data_device);
116 }
117 
118 static void
meta_wayland_data_device_primary_legacy_set_selection(MetaWaylandDataDevicePrimaryLegacy * data_device,MetaWaylandDataSource * source,uint32_t serial)119 meta_wayland_data_device_primary_legacy_set_selection (MetaWaylandDataDevicePrimaryLegacy *data_device,
120                                                        MetaWaylandDataSource              *source,
121                                                        uint32_t                            serial)
122 {
123   MetaWaylandSeat *seat = wl_container_of (data_device, seat, primary_legacy_data_device);
124   MetaSelectionSource *selection_source;
125 
126   g_assert (!source || META_IS_WAYLAND_DATA_SOURCE_PRIMARY_LEGACY (source));
127 
128   if (data_device->data_source &&
129       data_device->serial - serial < UINT32_MAX / 2)
130     return;
131 
132   if (data_device->data_source)
133     {
134       g_object_weak_unref (G_OBJECT (data_device->data_source),
135                            primary_source_destroyed,
136                            data_device);
137     }
138 
139   data_device->data_source = source;
140   data_device->serial = serial;
141 
142   if (source)
143     {
144       meta_wayland_data_source_set_seat (source, seat);
145       g_object_weak_ref (G_OBJECT (source),
146                          primary_source_destroyed,
147                          data_device);
148 
149       selection_source = meta_selection_source_wayland_new (source);
150     }
151   else
152     {
153       selection_source = g_object_new (META_TYPE_SELECTION_SOURCE_MEMORY, NULL);
154     }
155 
156   set_selection_source (data_device, selection_source);
157   g_object_unref (selection_source);
158 }
159 
160 static void
primary_device_set_selection(struct wl_client * client,struct wl_resource * resource,struct wl_resource * source_resource,uint32_t serial)161 primary_device_set_selection (struct wl_client   *client,
162                               struct wl_resource *resource,
163                               struct wl_resource *source_resource,
164                               uint32_t            serial)
165 {
166   MetaWaylandDataDevicePrimaryLegacy *data_device = wl_resource_get_user_data (resource);
167   MetaWaylandSeat *seat = wl_container_of (data_device, seat, primary_legacy_data_device);
168   MetaWaylandDataSource *source = NULL;
169 
170   if (source_resource)
171     source = wl_resource_get_user_data (source_resource);
172 
173   if (wl_resource_get_client (resource) !=
174       meta_wayland_keyboard_get_focus_client (seat->keyboard))
175     {
176       if (source)
177         meta_wayland_data_source_cancel (source);
178       return;
179     }
180 
181   meta_wayland_data_device_primary_legacy_set_selection (data_device, source, serial);
182 }
183 
184 static const struct gtk_primary_selection_device_interface primary_device_interface = {
185   primary_device_set_selection,
186   default_destructor,
187 };
188 
189 static void
owner_changed_cb(MetaSelection * selection,MetaSelectionType selection_type,MetaSelectionSource * new_owner,MetaWaylandDataDevicePrimaryLegacy * data_device)190 owner_changed_cb (MetaSelection                      *selection,
191                   MetaSelectionType                   selection_type,
192                   MetaSelectionSource                *new_owner,
193                   MetaWaylandDataDevicePrimaryLegacy *data_device)
194 {
195   MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
196   MetaWaylandSeat *seat = compositor->seat;
197   struct wl_resource *data_device_resource;
198   struct wl_client *focus_client;
199 
200   focus_client = meta_wayland_keyboard_get_focus_client (seat->keyboard);
201   if (!focus_client)
202     return;
203 
204   if (selection_type == META_SELECTION_PRIMARY)
205     {
206       wl_resource_for_each (data_device_resource, &data_device->focus_resource_list)
207         {
208           struct wl_resource *offer = NULL;
209 
210           if (new_owner)
211             {
212               offer = create_and_send_primary_offer (data_device,
213                                                      data_device_resource);
214             }
215 
216           gtk_primary_selection_device_send_selection (data_device_resource,
217                                                        offer);
218         }
219     }
220 }
221 
222 static void
ensure_owners_changed_handler_connected(MetaWaylandDataDevicePrimaryLegacy * data_device)223 ensure_owners_changed_handler_connected (MetaWaylandDataDevicePrimaryLegacy *data_device)
224 {
225   if (data_device->selection_owner_signal_id != 0)
226     return;
227 
228   data_device->selection_owner_signal_id =
229     g_signal_connect (meta_display_get_selection (meta_get_display ()),
230                       "owner-changed",
231                       G_CALLBACK (owner_changed_cb), data_device);
232 }
233 
234 static void
primary_device_manager_create_source(struct wl_client * client,struct wl_resource * manager_resource,guint32 id)235 primary_device_manager_create_source (struct wl_client   *client,
236                                       struct wl_resource *manager_resource,
237                                       guint32             id)
238 {
239   struct wl_resource *source_resource;
240 
241   source_resource =
242     wl_resource_create (client, &gtk_primary_selection_source_interface,
243                         wl_resource_get_version (manager_resource),
244                         id);
245   meta_wayland_data_source_primary_legacy_new (source_resource);
246 }
247 
248 static void
primary_device_manager_get_device(struct wl_client * client,struct wl_resource * manager_resource,guint32 id,struct wl_resource * seat_resource)249 primary_device_manager_get_device (struct wl_client   *client,
250                                    struct wl_resource *manager_resource,
251                                    guint32             id,
252                                    struct wl_resource *seat_resource)
253 {
254   MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource);
255   struct wl_resource *cr;
256 
257   cr = wl_resource_create (client, &gtk_primary_selection_device_interface,
258                            wl_resource_get_version (manager_resource), id);
259   wl_resource_set_implementation (cr, &primary_device_interface,
260                                   &seat->primary_legacy_data_device, unbind_resource);
261   wl_list_insert (&seat->primary_legacy_data_device.resource_list,
262                   wl_resource_get_link (cr));
263 
264   ensure_owners_changed_handler_connected (&seat->primary_legacy_data_device);
265 }
266 
267 static const struct gtk_primary_selection_device_manager_interface primary_manager_interface = {
268   primary_device_manager_create_source,
269   primary_device_manager_get_device,
270   default_destructor,
271 };
272 
273 static void
bind_primary_manager(struct wl_client * client,void * data,uint32_t version,uint32_t id)274 bind_primary_manager (struct wl_client *client,
275                       void             *data,
276                       uint32_t          version,
277                       uint32_t          id)
278 {
279   struct wl_resource *resource;
280 
281   resource = wl_resource_create (client, &gtk_primary_selection_device_manager_interface,
282                                  version, id);
283   wl_resource_set_implementation (resource, &primary_manager_interface, NULL, NULL);
284 }
285 
286 void
meta_wayland_data_device_primary_legacy_manager_init(MetaWaylandCompositor * compositor)287 meta_wayland_data_device_primary_legacy_manager_init (MetaWaylandCompositor *compositor)
288 {
289   if (wl_global_create (compositor->wayland_display,
290 			&gtk_primary_selection_device_manager_interface,
291 			META_GTK_PRIMARY_SELECTION_VERSION,
292 			NULL, bind_primary_manager) == NULL)
293     g_error ("Could not create data_device");
294 }
295 
296 void
meta_wayland_data_device_primary_legacy_init(MetaWaylandDataDevicePrimaryLegacy * data_device)297 meta_wayland_data_device_primary_legacy_init (MetaWaylandDataDevicePrimaryLegacy *data_device)
298 {
299   wl_list_init (&data_device->resource_list);
300   wl_list_init (&data_device->focus_resource_list);
301 }
302 
303 static struct wl_resource *
create_and_send_primary_offer(MetaWaylandDataDevicePrimaryLegacy * data_device,struct wl_resource * target)304 create_and_send_primary_offer (MetaWaylandDataDevicePrimaryLegacy *data_device,
305                                struct wl_resource                 *target)
306 {
307   MetaWaylandDataOffer *offer;
308   MetaDisplay *display = meta_get_display ();
309   struct wl_resource *resource;
310   GList *mimetypes, *l;
311 
312   mimetypes = meta_selection_get_mimetypes (meta_display_get_selection (display),
313                                             META_SELECTION_PRIMARY);
314   if (!mimetypes)
315     return NULL;
316 
317   offer = meta_wayland_data_offer_primary_legacy_new (target);
318   resource = meta_wayland_data_offer_get_resource (offer);
319 
320   gtk_primary_selection_device_send_data_offer (target, resource);
321 
322   for (l = mimetypes; l; l = l->next)
323     gtk_primary_selection_offer_send_offer (resource, l->data);
324 
325   g_list_free_full (mimetypes, g_free);
326 
327   return resource;
328 }
329 
330 void
meta_wayland_data_device_primary_legacy_set_keyboard_focus(MetaWaylandDataDevicePrimaryLegacy * data_device)331 meta_wayland_data_device_primary_legacy_set_keyboard_focus (MetaWaylandDataDevicePrimaryLegacy *data_device)
332 {
333   MetaWaylandSeat *seat = wl_container_of (data_device, seat, primary_legacy_data_device);
334   struct wl_client *focus_client;
335   struct wl_resource *data_device_resource;
336 
337   focus_client = meta_wayland_keyboard_get_focus_client (seat->keyboard);
338 
339   if (focus_client == data_device->focus_client)
340     return;
341 
342   data_device->focus_client = focus_client;
343   move_resources (&data_device->resource_list,
344                   &data_device->focus_resource_list);
345 
346   if (!focus_client)
347     return;
348 
349   move_resources_for_client (&data_device->focus_resource_list,
350                              &data_device->resource_list,
351                              focus_client);
352 
353   wl_resource_for_each (data_device_resource, &data_device->focus_resource_list)
354     {
355       struct wl_resource *offer;
356       offer = create_and_send_primary_offer (data_device, data_device_resource);
357       gtk_primary_selection_device_send_selection (data_device_resource, offer);
358     }
359 }
360