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