Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit 7d18812

Browse files
committed
xwayland: parse DND_ENTER messages
1 parent b547279 commit 7d18812

File tree

3 files changed

+212
-75
lines changed

3 files changed

+212
-75
lines changed

include/xwayland/selection.h

+2
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ bool primary_selection_source_is_xwayland(
6565
struct wlr_primary_selection_source *wlr_source);
6666

6767
void xwm_seat_handle_start_drag(struct wlr_xwm *xwm, struct wlr_drag *drag);
68+
int xwm_dnd_handle_xfixes_selection_notify(struct wlr_xwm *xwm,
69+
xcb_xfixes_selection_notify_event_t *event);
6870

6971
void xwm_selection_init(struct wlr_xwm *xwm);
7072
void xwm_selection_finish(struct wlr_xwm *xwm);

xwayland/selection/dnd.c

+184-53
Original file line numberDiff line numberDiff line change
@@ -163,76 +163,207 @@ static void xwm_dnd_send_leave(struct wlr_xwm *xwm) {
163163
xwm_dnd_send_event(xwm, xwm->atoms[DND_FINISHED], &data);
164164
}*/
165165

166-
int xwm_handle_selection_client_message(struct wlr_xwm *xwm,
167-
xcb_client_message_event_t *ev) {
168-
if (ev->type == xwm->atoms[DND_STATUS]) {
169-
if (xwm->drag == NULL) {
170-
wlr_log(L_DEBUG, "ignoring XdndStatus client message because "
171-
"there's no drag");
172-
return 1;
173-
}
166+
/**
167+
* Handle a status message for an outgoing DnD operation.
168+
*/
169+
static void xwm_handle_dnd_status(struct wlr_xwm *xwm,
170+
xcb_client_message_data_t *data) {
171+
if (xwm->drag == NULL) {
172+
wlr_log(L_DEBUG, "ignoring XdndStatus client message because "
173+
"there's no drag");
174+
return;
175+
}
174176

175-
xcb_client_message_data_t *data = &ev->data;
176-
xcb_window_t target_window = data->data32[0];
177-
bool accepted = data->data32[1] & 1;
178-
xcb_atom_t action_atom = data->data32[4];
177+
xcb_window_t target_window = data->data32[0];
178+
bool accepted = data->data32[1] & 1;
179+
xcb_atom_t action_atom = data->data32[4];
179180

180-
if (xwm->drag_focus == NULL ||
181-
target_window != xwm->drag_focus->window_id) {
182-
wlr_log(L_DEBUG, "ignoring XdndStatus client message because "
183-
"it doesn't match the current drag focus window ID");
184-
return 1;
185-
}
181+
if (xwm->drag_focus == NULL ||
182+
target_window != xwm->drag_focus->window_id) {
183+
wlr_log(L_DEBUG, "ignoring XdndStatus client message because "
184+
"it doesn't match the current drag focus window ID");
185+
return;
186+
}
186187

187-
enum wl_data_device_manager_dnd_action action =
188-
data_device_manager_dnd_action_from_atom(xwm, action_atom);
188+
enum wl_data_device_manager_dnd_action action =
189+
data_device_manager_dnd_action_from_atom(xwm, action_atom);
189190

190-
struct wlr_drag *drag = xwm->drag;
191-
assert(drag != NULL);
191+
struct wlr_drag *drag = xwm->drag;
192+
assert(drag != NULL);
192193

193-
drag->source->accepted = accepted;
194-
wlr_data_source_dnd_action(drag->source, action);
194+
drag->source->accepted = accepted;
195+
wlr_data_source_dnd_action(drag->source, action);
195196

196-
wlr_log(L_DEBUG, "DND_STATUS window=%d accepted=%d action=%d",
197-
target_window, accepted, action);
198-
return 1;
199-
} else if (ev->type == xwm->atoms[DND_FINISHED]) {
200-
// This should only happen after the drag has ended, but before the drag
201-
// source is destroyed
202-
if (xwm->seat == NULL || xwm->seat->drag_source == NULL ||
203-
xwm->drag != NULL) {
204-
wlr_log(L_DEBUG, "ignoring XdndFinished client message because "
205-
"there's no finished drag");
206-
return 1;
207-
}
197+
wlr_log(L_DEBUG, "DND_STATUS window=%d accepted=%d action=%d",
198+
target_window, accepted, action);
199+
}
208200

209-
struct wlr_data_source *source = xwm->seat->drag_source;
201+
/**
202+
* Handle a finish message for an outgoing DnD operation.
203+
*/
204+
static void xwm_handle_dnd_finished(struct wlr_xwm *xwm,
205+
xcb_client_message_data_t *data) {
206+
// This should only happen after the drag has ended, but before the drag
207+
// source is destroyed
208+
if (xwm->seat == NULL || xwm->seat->drag_source == NULL ||
209+
xwm->drag != NULL) {
210+
wlr_log(L_DEBUG, "ignoring XdndFinished client message because "
211+
"there's no finished drag");
212+
return;
213+
}
214+
215+
struct wlr_data_source *source = xwm->seat->drag_source;
216+
217+
xcb_window_t target_window = data->data32[0];
218+
bool performed = data->data32[1] & 1;
219+
xcb_atom_t action_atom = data->data32[2];
220+
221+
if (xwm->drag_focus == NULL ||
222+
target_window != xwm->drag_focus->window_id) {
223+
wlr_log(L_DEBUG, "ignoring XdndFinished client message because "
224+
"it doesn't match the finished drag focus window ID");
225+
return;
226+
}
227+
228+
enum wl_data_device_manager_dnd_action action =
229+
data_device_manager_dnd_action_from_atom(xwm, action_atom);
230+
231+
if (performed) {
232+
wlr_data_source_dnd_finish(source);
233+
}
210234

211-
xcb_client_message_data_t *data = &ev->data;
212-
xcb_window_t target_window = data->data32[0];
213-
bool performed = data->data32[1] & 1;
214-
xcb_atom_t action_atom = data->data32[2];
235+
wlr_log(L_DEBUG, "DND_FINISH window=%d performed=%d action=%d",
236+
target_window, performed, action);
237+
}
238+
239+
static bool xwm_add_atom_to_mime_types(struct wlr_xwm *xwm,
240+
struct wl_array *mime_types, xcb_atom_t atom) {
241+
char *mime_type = xwm_mime_type_from_atom(xwm, atom);
242+
if (mime_type == NULL) {
243+
return false;
244+
}
245+
char **mime_type_ptr =
246+
wl_array_add(mime_types, sizeof(*mime_type_ptr));
247+
if (mime_type_ptr == NULL) {
248+
return false;
249+
}
250+
*mime_type_ptr = mime_type;
251+
return true;
252+
}
253+
254+
static bool xwm_dnd_get_mime_types(struct wlr_xwm *xwm,
255+
struct wl_array *mime_types, xcb_window_t source) {
256+
xcb_get_property_cookie_t cookie = xcb_get_property(xwm->xcb_conn,
257+
1, // delete
258+
source,
259+
xwm->atoms[DND_TYPE_LIST],
260+
XCB_GET_PROPERTY_TYPE_ANY,
261+
0, // offset
262+
0x1fffffff // length
263+
);
264+
265+
xcb_get_property_reply_t *reply =
266+
xcb_get_property_reply(xwm->xcb_conn, cookie, NULL);
267+
if (reply == NULL) {
268+
return false;
269+
}
270+
if (reply->type != XCB_ATOM_ATOM || reply->value_len == 0) {
271+
wlr_log(L_ERROR, "invalid XdndTypeList property");
272+
goto error;
273+
}
215274

216-
if (xwm->drag_focus == NULL ||
217-
target_window != xwm->drag_focus->window_id) {
218-
wlr_log(L_DEBUG, "ignoring XdndFinished client message because "
219-
"it doesn't match the finished drag focus window ID");
220-
return 1;
275+
xcb_atom_t *atoms = xcb_get_property_value(reply);
276+
for (uint32_t i = 0; i < reply->value_len; ++i) {
277+
if (!xwm_add_atom_to_mime_types(xwm, mime_types, atoms[i])) {
278+
wlr_log(L_ERROR, "failed to add MIME type atom to list");
279+
goto error;
221280
}
281+
}
282+
283+
free(reply);
284+
return true;
285+
286+
error:
287+
free(reply);
288+
return false;
289+
}
290+
291+
/**
292+
* Handle an enter message for an incoming DnD operation.
293+
*/
294+
static void xwm_handle_dnd_enter(struct wlr_xwm *xwm,
295+
xcb_client_message_data_t *data) {
296+
if (xwm->seat == NULL) {
297+
wlr_log(L_DEBUG, "ignoring XdndEnter client message because "
298+
"there's no Xwayland seat");
299+
return;
300+
}
301+
302+
xcb_window_t source_window = data->data32[0];
222303

223-
enum wl_data_device_manager_dnd_action action =
224-
data_device_manager_dnd_action_from_atom(xwm, action_atom);
304+
if (source_window != xwm->dnd_selection.owner) {
305+
wlr_log(L_DEBUG, "ignoring XdndEnter client message because "
306+
"the source window hasn't set the drag-and-drop selection");
307+
return;
308+
}
225309

226-
if (performed) {
227-
wlr_data_source_dnd_finish(source);
310+
struct wl_array mime_types;
311+
wl_array_init(&mime_types);
312+
if ((data->data32[1] & 1) == 0) {
313+
// Less than 3 MIME types, those are in the message data
314+
for (size_t i = 0; i < 3; ++i) {
315+
xcb_atom_t atom = data->data32[2+i];
316+
if (atom == XCB_ATOM_NONE) {
317+
break;
318+
}
319+
if (!xwm_add_atom_to_mime_types(xwm, &mime_types, atom)) {
320+
wlr_log(L_ERROR, "failed to add MIME type atom to list");
321+
break;
322+
}
323+
}
324+
} else {
325+
if (!xwm_dnd_get_mime_types(xwm, &mime_types, source_window)) {
326+
wlr_log(L_ERROR, "failed to add MIME type atom to list");
228327
}
328+
}
229329

230-
wlr_log(L_DEBUG, "DND_FINISH window=%d performed=%d action=%d",
231-
target_window, performed, action);
330+
wlr_log(L_INFO, "parsed XdndEnter");
331+
}
332+
333+
int xwm_handle_selection_client_message(struct wlr_xwm *xwm,
334+
xcb_client_message_event_t *ev) {
335+
// Outgoing
336+
if (ev->type == xwm->atoms[DND_STATUS]) {
337+
xwm_handle_dnd_status(xwm, &ev->data);
232338
return 1;
339+
} else if (ev->type == xwm->atoms[DND_FINISHED]) {
340+
xwm_handle_dnd_finished(xwm, &ev->data);
341+
return 1;
342+
}
343+
344+
// Incoming
345+
if (ev->type == xwm->atoms[DND_ENTER]) {
346+
xwm_handle_dnd_enter(xwm, &ev->data);
347+
return 1;
348+
}
349+
350+
return 0;
351+
}
352+
353+
int xwm_dnd_handle_xfixes_selection_notify(struct wlr_xwm *xwm,
354+
xcb_xfixes_selection_notify_event_t *event) {
355+
assert(event->selection == xwm->atoms[DND_SELECTION]);
356+
struct wlr_xwm_selection *selection = &xwm->dnd_selection;
357+
358+
selection->owner = event->owner;
359+
360+
if (event->owner != XCB_ATOM_NONE) {
361+
// TODO: start grab
233362
} else {
234-
return 0;
363+
// TODO: end grab
235364
}
365+
366+
return 1;
236367
}
237368

238369
static void seat_handle_drag_focus(struct wl_listener *listener, void *data) {

xwayland/selection/incoming.c

+26-22
Original file line numberDiff line numberDiff line change
@@ -379,8 +379,7 @@ static void xwm_selection_get_targets(struct wlr_xwm_selection *selection) {
379379
void xwm_handle_selection_notify(struct wlr_xwm *xwm,
380380
xcb_selection_notify_event_t *event) {
381381
wlr_log(L_DEBUG, "XCB_SELECTION_NOTIFY (selection=%u, property=%u, target=%u)",
382-
event->selection, event->property,
383-
event->target);
382+
event->selection, event->property, event->target);
384383

385384
struct wlr_xwm_selection *selection =
386385
xwm_get_selection(xwm, event->selection);
@@ -410,6 +409,11 @@ int xwm_handle_xfixes_selection_notify(struct wlr_xwm *xwm,
410409
wlr_log(L_DEBUG, "XCB_XFIXES_SELECTION_NOTIFY (selection=%u, owner=%u)",
411410
event->selection, event->owner);
412411

412+
// Drag'n'drop works differently
413+
if (event->selection == xwm->atoms[DND_SELECTION]) {
414+
return xwm_dnd_handle_xfixes_selection_notify(xwm, event);
415+
}
416+
413417
struct wlr_xwm_selection *selection =
414418
xwm_get_selection(xwm, event->selection);
415419
if (selection == NULL) {
@@ -435,28 +439,28 @@ int xwm_handle_xfixes_selection_notify(struct wlr_xwm *xwm,
435439
}
436440

437441
selection->owner = XCB_WINDOW_NONE;
438-
return 1;
439-
}
440-
441-
selection->owner = event->owner;
442+
} else {
443+
selection->owner = event->owner;
444+
445+
// This is our selection window.
446+
// We have to use XCB_TIME_CURRENT_TIME when we claim the
447+
// selection, so grab the actual timestamp here so we can
448+
// answer TIMESTAMP conversion requests correctly.
449+
if (event->owner == selection->window) {
450+
selection->timestamp = event->timestamp;
451+
return 1;
452+
}
442453

443-
// We have to use XCB_TIME_CURRENT_TIME when we claim the
444-
// selection, so grab the actual timestamp here so we can
445-
// answer TIMESTAMP conversion requests correctly.
446-
if (event->owner == selection->window) {
447-
selection->timestamp = event->timestamp;
448-
return 1;
454+
struct wlr_xwm_selection_transfer *transfer = &selection->incoming;
455+
transfer->incr = false;
456+
// doing this will give a selection notify where we actually handle the sync
457+
xcb_convert_selection(xwm->xcb_conn, selection->window,
458+
selection->atom,
459+
xwm->atoms[TARGETS],
460+
xwm->atoms[WL_SELECTION],
461+
event->timestamp);
462+
xcb_flush(xwm->xcb_conn);
449463
}
450464

451-
struct wlr_xwm_selection_transfer *transfer = &selection->incoming;
452-
transfer->incr = false;
453-
// doing this will give a selection notify where we actually handle the sync
454-
xcb_convert_selection(xwm->xcb_conn, selection->window,
455-
selection->atom,
456-
xwm->atoms[TARGETS],
457-
xwm->atoms[WL_SELECTION],
458-
event->timestamp);
459-
xcb_flush(xwm->xcb_conn);
460-
461465
return 1;
462466
}

0 commit comments

Comments
 (0)