blob: f17e4cd05b5c9effc85d5d9e6a5716326032fa71 [file] [log] [blame]
Kristian Høgsbergf9cb3b12013-09-04 21:12:26 -07001/*
2 * Copyright © 2013 Intel Corporation
3 *
Bryce Harrington0a007dd2015-06-11 16:22:34 -07004 * 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:
Kristian Høgsbergf9cb3b12013-09-04 21:12:26 -070011 *
Bryce Harrington0a007dd2015-06-11 16:22:34 -070012 * 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.
Kristian Høgsbergf9cb3b12013-09-04 21:12:26 -070024 */
25
26#include "config.h"
27
28#include <stdlib.h>
29#include <stdio.h>
30#include <string.h>
31#include <sys/socket.h>
32#include <sys/un.h>
33#include <fcntl.h>
34#include <errno.h>
35#include <unistd.h>
36#include <signal.h>
37#include <X11/Xcursor/Xcursor.h>
38
39#include "xwayland.h"
40
Kristian Høgsberg2ba10df2013-12-03 16:38:15 -080041#include "cairo-util.h"
42#include "compositor.h"
Kristian Høgsbergf9cb3b12013-09-04 21:12:26 -070043#include "hash.h"
44
45static void
46weston_dnd_start(struct weston_wm *wm, xcb_window_t owner)
47{
48 uint32_t values[1], version = 4;
49
50 wm->dnd_window = xcb_generate_id(wm->conn);
51 values[0] =
52 XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
53 XCB_EVENT_MASK_PROPERTY_CHANGE;
54
55 xcb_create_window(wm->conn,
56 XCB_COPY_FROM_PARENT,
57 wm->dnd_window,
58 wm->screen->root,
59 0, 0,
60 8192, 8192,
61 0,
62 XCB_WINDOW_CLASS_INPUT_ONLY,
63 wm->screen->root_visual,
64 XCB_CW_EVENT_MASK, values);
65 xcb_change_property(wm->conn,
66 XCB_PROP_MODE_REPLACE,
67 wm->dnd_window,
68 wm->atom.xdnd_aware,
69 XCB_ATOM_ATOM,
70 32, /* format */
71 1, &version);
72
73 xcb_map_window(wm->conn, wm->dnd_window);
74 wm->dnd_owner = owner;
75}
76
77static void
78weston_dnd_stop(struct weston_wm *wm)
79{
80 xcb_destroy_window(wm->conn, wm->dnd_window);
81 wm->dnd_window = XCB_WINDOW_NONE;
82}
83
84struct dnd_data_source {
85 struct weston_data_source base;
86 struct weston_wm *wm;
87 int version;
88 uint32_t window;
89};
90
91static void
92data_source_accept(struct weston_data_source *base,
93 uint32_t time, const char *mime_type)
94{
95 struct dnd_data_source *source = (struct dnd_data_source *) base;
96 xcb_client_message_event_t client_message;
97 struct weston_wm *wm = source->wm;
98
99 weston_log("got accept, mime-type %s\n", mime_type);
100
101 /* FIXME: If we rewrote UTF8_STRING to
102 * text/plain;charset=utf-8 and the source doesn't support the
103 * mime-type, we'll have to rewrite the mime-type back to
104 * UTF8_STRING here. */
105
106 client_message.response_type = XCB_CLIENT_MESSAGE;
107 client_message.format = 32;
108 client_message.window = wm->dnd_window;
109 client_message.type = wm->atom.xdnd_status;
110 client_message.data.data32[0] = wm->dnd_window;
111 client_message.data.data32[1] = 2;
112 if (mime_type)
113 client_message.data.data32[1] |= 1;
114 client_message.data.data32[2] = 0;
115 client_message.data.data32[3] = 0;
116 client_message.data.data32[4] = wm->atom.xdnd_action_copy;
117
118 xcb_send_event(wm->conn, 0, wm->dnd_owner,
119 XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
120 (char *) &client_message);
121}
122
123static void
124data_source_send(struct weston_data_source *base,
125 const char *mime_type, int32_t fd)
126{
127 struct dnd_data_source *source = (struct dnd_data_source *) base;
128 struct weston_wm *wm = source->wm;
129
130 weston_log("got send, %s\n", mime_type);
131
132 /* Get data for the utf8_string target */
133 xcb_convert_selection(wm->conn,
134 wm->selection_window,
135 wm->atom.xdnd_selection,
136 wm->atom.utf8_string,
137 wm->atom.wl_selection,
138 XCB_TIME_CURRENT_TIME);
139
140 xcb_flush(wm->conn);
141
142 fcntl(fd, F_SETFL, O_WRONLY | O_NONBLOCK);
143 wm->data_source_fd = fd;
144}
145
146static void
147data_source_cancel(struct weston_data_source *source)
148{
149 weston_log("got cancel\n");
150}
151
152static void
153handle_enter(struct weston_wm *wm, xcb_client_message_event_t *client_message)
154{
155 struct dnd_data_source *source;
156 struct weston_seat *seat = weston_wm_pick_seat(wm);
Derek Foreman1281a362015-07-31 16:55:32 -0500157 struct weston_pointer *pointer = weston_seat_get_pointer(seat);
Kristian Høgsbergf9cb3b12013-09-04 21:12:26 -0700158 char **p;
159 const char *name;
160 uint32_t *types;
161 int i, length, has_text;
162 xcb_get_property_cookie_t cookie;
163 xcb_get_property_reply_t *reply;
164
Carlos Garnachobeb7a9f2016-02-01 20:28:15 +0100165 source = zalloc(sizeof *source);
Kristian Høgsbergf9cb3b12013-09-04 21:12:26 -0700166 if (source == NULL)
167 return;
168
169 wl_signal_init(&source->base.destroy_signal);
170 source->base.accept = data_source_accept;
171 source->base.send = data_source_send;
172 source->base.cancel = data_source_cancel;
173 source->wm = wm;
174 source->window = client_message->data.data32[0];
175 source->version = client_message->data.data32[1] >> 24;
176
177 if (client_message->data.data32[1] & 1) {
178 cookie = xcb_get_property(wm->conn,
179 0, /* delete */
180 source->window,
181 wm->atom.xdnd_type_list,
182 XCB_ATOM_ANY, 0, 2048);
183 reply = xcb_get_property_reply(wm->conn, cookie, NULL);
184 types = xcb_get_property_value(reply);
185 length = reply->value_len;
186 } else {
187 reply = NULL;
188 types = &client_message->data.data32[2];
189 length = 3;
190 }
191
192 wl_array_init(&source->base.mime_types);
193 has_text = 0;
194 for (i = 0; i < length; i++) {
195 if (types[i] == XCB_ATOM_NONE)
196 continue;
197
198 name = get_atom_name(wm->conn, types[i]);
199 if (types[i] == wm->atom.utf8_string ||
200 types[i] == wm->atom.text_plain_utf8 ||
201 types[i] == wm->atom.text_plain) {
202 if (has_text)
203 continue;
204
205 has_text = 1;
206 p = wl_array_add(&source->base.mime_types, sizeof *p);
207 if (p)
208 *p = strdup("text/plain;charset=utf-8");
209 } else if (strchr(name, '/')) {
210 p = wl_array_add(&source->base.mime_types, sizeof *p);
211 if (p)
212 *p = strdup(name);
213 }
214 }
215
216 free(reply);
Derek Foreman1281a362015-07-31 16:55:32 -0500217 weston_pointer_start_drag(pointer, &source->base, NULL, NULL);
Kristian Høgsbergf9cb3b12013-09-04 21:12:26 -0700218}
219
220int
221weston_wm_handle_dnd_event(struct weston_wm *wm,
222 xcb_generic_event_t *event)
223{
224 xcb_xfixes_selection_notify_event_t *xfixes_selection_notify =
225 (xcb_xfixes_selection_notify_event_t *) event;
226 xcb_client_message_event_t *client_message =
227 (xcb_client_message_event_t *) event;
228
229 switch (event->response_type - wm->xfixes->first_event) {
230 case XCB_XFIXES_SELECTION_NOTIFY:
231 if (xfixes_selection_notify->selection != wm->atom.xdnd_selection)
232 return 0;
233
234 weston_log("XdndSelection owner: %d!\n",
235 xfixes_selection_notify->owner);
236
237 if (xfixes_selection_notify->owner != XCB_WINDOW_NONE)
238 weston_dnd_start(wm, xfixes_selection_notify->owner);
239 else
240 weston_dnd_stop(wm);
241
242 return 1;
243 }
244
245 switch (EVENT_TYPE(event)) {
246 case XCB_CLIENT_MESSAGE:
247 if (client_message->type == wm->atom.xdnd_enter) {
248 handle_enter(wm, client_message);
249 return 1;
250 } else if (client_message->type == wm->atom.xdnd_leave) {
251 weston_log("got leave!\n");
252 return 1;
253 } else if (client_message->type == wm->atom.xdnd_drop) {
254 weston_log("got drop!\n");
255 return 1;
256 } else if (client_message->type == wm->atom.xdnd_drop) {
257 weston_log("got enter!\n");
258 return 1;
259 }
260 return 0;
261 }
262
263 return 0;
264}
265
266void
267weston_wm_dnd_init(struct weston_wm *wm)
268{
269 uint32_t mask;
270
271 mask =
272 XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER |
273 XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY |
274 XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE;
275 xcb_xfixes_select_selection_input(wm->conn, wm->selection_window,
276 wm->atom.xdnd_selection, mask);
277}