blob: eb9c5dd127cc7ebd52d9903477b013302578cc05 [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);
157 char **p;
158 const char *name;
159 uint32_t *types;
160 int i, length, has_text;
161 xcb_get_property_cookie_t cookie;
162 xcb_get_property_reply_t *reply;
163
164 source = malloc(sizeof *source);
165 if (source == NULL)
166 return;
167
168 wl_signal_init(&source->base.destroy_signal);
169 source->base.accept = data_source_accept;
170 source->base.send = data_source_send;
171 source->base.cancel = data_source_cancel;
172 source->wm = wm;
173 source->window = client_message->data.data32[0];
174 source->version = client_message->data.data32[1] >> 24;
175
176 if (client_message->data.data32[1] & 1) {
177 cookie = xcb_get_property(wm->conn,
178 0, /* delete */
179 source->window,
180 wm->atom.xdnd_type_list,
181 XCB_ATOM_ANY, 0, 2048);
182 reply = xcb_get_property_reply(wm->conn, cookie, NULL);
183 types = xcb_get_property_value(reply);
184 length = reply->value_len;
185 } else {
186 reply = NULL;
187 types = &client_message->data.data32[2];
188 length = 3;
189 }
190
191 wl_array_init(&source->base.mime_types);
192 has_text = 0;
193 for (i = 0; i < length; i++) {
194 if (types[i] == XCB_ATOM_NONE)
195 continue;
196
197 name = get_atom_name(wm->conn, types[i]);
198 if (types[i] == wm->atom.utf8_string ||
199 types[i] == wm->atom.text_plain_utf8 ||
200 types[i] == wm->atom.text_plain) {
201 if (has_text)
202 continue;
203
204 has_text = 1;
205 p = wl_array_add(&source->base.mime_types, sizeof *p);
206 if (p)
207 *p = strdup("text/plain;charset=utf-8");
208 } else if (strchr(name, '/')) {
209 p = wl_array_add(&source->base.mime_types, sizeof *p);
210 if (p)
211 *p = strdup(name);
212 }
213 }
214
215 free(reply);
Xiong Zhangfd51e7b2013-11-25 18:42:49 +0800216 weston_pointer_start_drag(seat->pointer, &source->base, NULL, NULL);
Kristian Høgsbergf9cb3b12013-09-04 21:12:26 -0700217}
218
219int
220weston_wm_handle_dnd_event(struct weston_wm *wm,
221 xcb_generic_event_t *event)
222{
223 xcb_xfixes_selection_notify_event_t *xfixes_selection_notify =
224 (xcb_xfixes_selection_notify_event_t *) event;
225 xcb_client_message_event_t *client_message =
226 (xcb_client_message_event_t *) event;
227
228 switch (event->response_type - wm->xfixes->first_event) {
229 case XCB_XFIXES_SELECTION_NOTIFY:
230 if (xfixes_selection_notify->selection != wm->atom.xdnd_selection)
231 return 0;
232
233 weston_log("XdndSelection owner: %d!\n",
234 xfixes_selection_notify->owner);
235
236 if (xfixes_selection_notify->owner != XCB_WINDOW_NONE)
237 weston_dnd_start(wm, xfixes_selection_notify->owner);
238 else
239 weston_dnd_stop(wm);
240
241 return 1;
242 }
243
244 switch (EVENT_TYPE(event)) {
245 case XCB_CLIENT_MESSAGE:
246 if (client_message->type == wm->atom.xdnd_enter) {
247 handle_enter(wm, client_message);
248 return 1;
249 } else if (client_message->type == wm->atom.xdnd_leave) {
250 weston_log("got leave!\n");
251 return 1;
252 } else if (client_message->type == wm->atom.xdnd_drop) {
253 weston_log("got drop!\n");
254 return 1;
255 } else if (client_message->type == wm->atom.xdnd_drop) {
256 weston_log("got enter!\n");
257 return 1;
258 }
259 return 0;
260 }
261
262 return 0;
263}
264
265void
266weston_wm_dnd_init(struct weston_wm *wm)
267{
268 uint32_t mask;
269
270 mask =
271 XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER |
272 XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY |
273 XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE;
274 xcb_xfixes_select_selection_input(wm->conn, wm->selection_window,
275 wm->atom.xdnd_selection, mask);
276}