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

Commit a135eff

Browse files
committed
xwayland: start drag on dnd selection notify
1 parent 7d18812 commit a135eff

File tree

8 files changed

+169
-82
lines changed

8 files changed

+169
-82
lines changed

include/wlr/types/wlr_data_device.h

+4
Original file line numberDiff line numberDiff line change
@@ -221,4 +221,8 @@ void wlr_data_source_dnd_finish(struct wlr_data_source *source);
221221
void wlr_data_source_dnd_action(struct wlr_data_source *source,
222222
enum wl_data_device_manager_dnd_action action);
223223

224+
struct wlr_drag *wlr_seat_client_start_grab(struct wlr_seat_client *client,
225+
struct wlr_data_source *source, struct wlr_surface *icon_surface,
226+
struct wlr_touch_point *point);
227+
224228
#endif

include/wlr/types/wlr_seat.h

-1
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,6 @@ struct wlr_seat {
188188
// `drag` goes away before `drag_source`, when the implicit grab ends
189189
struct wlr_drag *drag;
190190
struct wlr_data_source *drag_source;
191-
uint32_t drag_serial;
192191

193192
struct wlr_seat_pointer_state pointer_state;
194193
struct wlr_seat_keyboard_state keyboard_state;

include/xwayland/selection.h

+18
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#ifndef XWAYLAND_SELECTION_H
22
#define XWAYLAND_SELECTION_H
33

4+
#include <wlr/types/wlr_data_device.h>
5+
#include <wlr/types/wlr_primary_selection.h>
46
#include <xcb/xfixes.h>
57

68
#define INCR_CHUNK_SIZE (64 * 1024)
@@ -39,6 +41,18 @@ struct wlr_xwm_selection {
3941
struct wl_list outgoing;
4042
};
4143

44+
struct wlr_xwayland_data_source {
45+
struct wlr_data_source base;
46+
struct wlr_xwm_selection *selection;
47+
struct wl_array mime_types_atoms;
48+
};
49+
50+
struct wlr_xwayland_primary_selection_source {
51+
struct wlr_primary_selection_source base;
52+
struct wlr_xwm_selection *selection;
53+
struct wl_array mime_types_atoms;
54+
};
55+
4256
void xwm_selection_transfer_remove_source(
4357
struct wlr_xwm_selection_transfer *transfer);
4458
void xwm_selection_transfer_close_source_fd(
@@ -63,6 +77,10 @@ int xwm_handle_xfixes_selection_notify(struct wlr_xwm *xwm,
6377
bool data_source_is_xwayland(struct wlr_data_source *wlr_source);
6478
bool primary_selection_source_is_xwayland(
6579
struct wlr_primary_selection_source *wlr_source);
80+
struct wlr_xwayland_data_source *xwayland_data_source_create(
81+
struct wlr_xwm_selection *selection);
82+
struct wlr_xwayland_data_source *xwayland_data_source_from_wlr_data_source(
83+
struct wlr_data_source *wlr_source);
6684

6785
void xwm_seat_handle_start_drag(struct wlr_xwm *xwm, struct wlr_drag *drag);
6886
int xwm_dnd_handle_xfixes_selection_notify(struct wlr_xwm *xwm,

include/xwayland/xwm.h

+1
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ struct wlr_xwm {
116116
struct wl_list surfaces; // wlr_xwayland_surface::link
117117
struct wl_list unpaired_surfaces; // wlr_xwayland_surface::unpaired_link
118118

119+
struct wlr_drag *incoming_drag;
119120
struct wlr_drag *drag;
120121
struct wlr_xwayland_surface *drag_focus;
121122

types/data_device/wlr_drag.c

+46-36
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ static void drag_set_focus(struct wlr_drag *drag,
5656
}
5757

5858
struct wlr_seat_client *focus_client = wlr_seat_client_for_wl_client(
59-
drag->seat_client->seat, wl_resource_get_client(surface->resource));
59+
drag->seat, wl_resource_get_client(surface->resource));
6060
if (!focus_client) {
6161
return;
6262
}
@@ -80,8 +80,7 @@ static void drag_set_focus(struct wlr_drag *drag,
8080
}
8181

8282
if (!wl_list_empty(&focus_client->data_devices)) {
83-
uint32_t serial =
84-
wl_display_next_serial(drag->seat_client->seat->display);
83+
uint32_t serial = wl_display_next_serial(drag->seat->display);
8584
struct wl_resource *resource;
8685
wl_resource_for_each(resource, &focus_client->data_devices) {
8786
wl_data_device_send_enter(resource, serial, surface->resource,
@@ -384,54 +383,33 @@ static void seat_handle_drag_source_destroy(struct wl_listener *listener,
384383
seat->drag_source = NULL;
385384
}
386385

387-
bool seat_client_start_drag(struct wlr_seat_client *client,
386+
struct wlr_drag *wlr_seat_client_start_grab(struct wlr_seat_client *client,
388387
struct wlr_data_source *source, struct wlr_surface *icon_surface,
389-
struct wlr_surface *origin, uint32_t serial) {
388+
struct wlr_touch_point *point) {
389+
struct wlr_seat *seat = client->seat;
390+
390391
struct wlr_drag *drag = calloc(1, sizeof(struct wlr_drag));
391392
if (drag == NULL) {
392-
return false;
393+
return NULL;
393394
}
394-
395+
drag->seat = seat;
395396
wl_signal_init(&drag->events.focus);
396397
wl_signal_init(&drag->events.motion);
397398
wl_signal_init(&drag->events.drop);
398399
wl_signal_init(&drag->events.destroy);
399400

400-
struct wlr_seat *seat = client->seat;
401-
drag->seat = seat;
402-
403-
drag->is_pointer_grab = !wl_list_empty(&client->pointers) &&
404-
seat->pointer_state.button_count == 1 &&
405-
seat->pointer_state.grab_serial == serial &&
406-
seat->pointer_state.focused_surface &&
407-
seat->pointer_state.focused_surface == origin;
408-
409-
bool is_touch_grab = !wl_list_empty(&client->touches) &&
410-
wlr_seat_touch_num_points(seat) == 1 &&
411-
seat->touch_state.grab_serial == serial;
412-
413-
// set in the iteration
414-
struct wlr_touch_point *point = NULL;
415-
if (is_touch_grab) {
416-
wl_list_for_each(point, &seat->touch_state.touch_points, link) {
417-
is_touch_grab = point->surface && point->surface == origin;
418-
break;
419-
}
420-
}
421-
422-
if (!drag->is_pointer_grab && !is_touch_grab) {
423-
free(drag);
424-
return true;
401+
if (point == NULL) {
402+
drag->is_pointer_grab = true;
425403
}
426404

427405
if (icon_surface) {
428-
int32_t touch_id = (point ? point->touch_id : 0);
406+
int32_t touch_id = point ? point->touch_id : 0;
429407
struct wlr_drag_icon *icon =
430408
drag_icon_create(icon_surface, client, drag->is_pointer_grab,
431409
touch_id);
432410
if (!icon) {
433411
free(drag);
434-
return false;
412+
return NULL;
435413
}
436414

437415
drag->icon = icon;
@@ -446,6 +424,7 @@ bool seat_client_start_drag(struct wlr_seat_client *client,
446424
}
447425

448426
drag->seat_client = client;
427+
449428
drag->pointer_grab.data = drag;
450429
drag->pointer_grab.interface = &data_device_pointer_drag_interface;
451430

@@ -468,7 +447,6 @@ bool seat_client_start_drag(struct wlr_seat_client *client,
468447
}
469448

470449
seat->drag = drag; // TODO: unset this thing somewhere
471-
seat->drag_serial = serial;
472450

473451
seat->drag_source = source;
474452
if (source != NULL) {
@@ -477,6 +455,38 @@ bool seat_client_start_drag(struct wlr_seat_client *client,
477455
}
478456

479457
wlr_signal_emit_safe(&seat->events.start_drag, drag);
458+
return drag;
459+
}
460+
461+
bool seat_client_start_drag(struct wlr_seat_client *client,
462+
struct wlr_data_source *source, struct wlr_surface *icon_surface,
463+
struct wlr_surface *origin, uint32_t serial) {
464+
struct wlr_seat *seat = client->seat;
465+
466+
bool is_pointer_grab = !wl_list_empty(&client->pointers) &&
467+
seat->pointer_state.button_count == 1 &&
468+
seat->pointer_state.grab_serial == serial &&
469+
seat->pointer_state.focused_surface &&
470+
seat->pointer_state.focused_surface == origin;
471+
472+
bool is_touch_grab = !wl_list_empty(&client->touches) &&
473+
wlr_seat_touch_num_points(seat) == 1 &&
474+
seat->touch_state.grab_serial == serial;
475+
476+
// set in the iteration
477+
struct wlr_touch_point *point = NULL;
478+
if (is_touch_grab) {
479+
wl_list_for_each(point, &seat->touch_state.touch_points, link) {
480+
is_touch_grab = point->surface && point->surface == origin;
481+
break;
482+
}
483+
}
484+
485+
if (!is_pointer_grab && !is_touch_grab) {
486+
return true;
487+
}
480488

481-
return true;
489+
struct wlr_drag *drag = wlr_seat_client_start_grab(client, source,
490+
icon_surface, point);
491+
return drag != NULL;
482492
}

xwayland/selection/dnd.c

+59-9
Original file line numberDiff line numberDiff line change
@@ -237,22 +237,33 @@ static void xwm_handle_dnd_finished(struct wlr_xwm *xwm,
237237
}
238238

239239
static bool xwm_add_atom_to_mime_types(struct wlr_xwm *xwm,
240-
struct wl_array *mime_types, xcb_atom_t atom) {
240+
struct wl_array *mime_types, struct wl_array *mime_types_atoms,
241+
xcb_atom_t atom) {
241242
char *mime_type = xwm_mime_type_from_atom(xwm, atom);
242243
if (mime_type == NULL) {
243244
return false;
244245
}
246+
245247
char **mime_type_ptr =
246248
wl_array_add(mime_types, sizeof(*mime_type_ptr));
247249
if (mime_type_ptr == NULL) {
248250
return false;
249251
}
250252
*mime_type_ptr = mime_type;
253+
254+
xcb_atom_t *mime_type_atom_ptr =
255+
wl_array_add(mime_types_atoms, sizeof(*mime_type_atom_ptr));
256+
if (mime_type_atom_ptr == NULL) {
257+
return false;
258+
}
259+
*mime_type_atom_ptr = atom;
260+
251261
return true;
252262
}
253263

254264
static bool xwm_dnd_get_mime_types(struct wlr_xwm *xwm,
255-
struct wl_array *mime_types, xcb_window_t source) {
265+
struct wl_array *mime_types, struct wl_array *mime_types_atoms,
266+
xcb_window_t source) {
256267
xcb_get_property_cookie_t cookie = xcb_get_property(xwm->xcb_conn,
257268
1, // delete
258269
source,
@@ -274,7 +285,8 @@ static bool xwm_dnd_get_mime_types(struct wlr_xwm *xwm,
274285

275286
xcb_atom_t *atoms = xcb_get_property_value(reply);
276287
for (uint32_t i = 0; i < reply->value_len; ++i) {
277-
if (!xwm_add_atom_to_mime_types(xwm, mime_types, atoms[i])) {
288+
if (!xwm_add_atom_to_mime_types(xwm, mime_types, mime_types_atoms,
289+
atoms[i])) {
278290
wlr_log(L_ERROR, "failed to add MIME type atom to list");
279291
goto error;
280292
}
@@ -307,22 +319,31 @@ static void xwm_handle_dnd_enter(struct wlr_xwm *xwm,
307319
return;
308320
}
309321

310-
struct wl_array mime_types;
311-
wl_array_init(&mime_types);
322+
if (xwm->incoming_drag == NULL) {
323+
wlr_log(L_DEBUG, "ignoring XdndEnter client message because "
324+
"no xwayland drag is being performed");
325+
return;
326+
}
327+
328+
struct wlr_xwayland_data_source *source =
329+
xwayland_data_source_from_wlr_data_source(xwm->incoming_drag->source);
330+
312331
if ((data->data32[1] & 1) == 0) {
313332
// Less than 3 MIME types, those are in the message data
314333
for (size_t i = 0; i < 3; ++i) {
315334
xcb_atom_t atom = data->data32[2+i];
316335
if (atom == XCB_ATOM_NONE) {
317336
break;
318337
}
319-
if (!xwm_add_atom_to_mime_types(xwm, &mime_types, atom)) {
338+
if (!xwm_add_atom_to_mime_types(xwm, &source->base.mime_types,
339+
&source->mime_types_atoms, atom)) {
320340
wlr_log(L_ERROR, "failed to add MIME type atom to list");
321341
break;
322342
}
323343
}
324344
} else {
325-
if (!xwm_dnd_get_mime_types(xwm, &mime_types, source_window)) {
345+
if (!xwm_dnd_get_mime_types(xwm, &source->base.mime_types,
346+
&source->mime_types_atoms, source_window)) {
326347
wlr_log(L_ERROR, "failed to add MIME type atom to list");
327348
}
328349
}
@@ -358,9 +379,38 @@ int xwm_dnd_handle_xfixes_selection_notify(struct wlr_xwm *xwm,
358379
selection->owner = event->owner;
359380

360381
if (event->owner != XCB_ATOM_NONE) {
361-
// TODO: start grab
382+
wlr_log(L_INFO, "start grab");
383+
384+
xcb_map_window(xwm->xcb_conn, xwm->dnd_window);
385+
const static uint32_t values[] = { XCB_STACK_MODE_ABOVE };
386+
xcb_configure_window(xwm->xcb_conn, xwm->dnd_window,
387+
XCB_CONFIG_WINDOW_STACK_MODE, values);
388+
389+
struct wlr_seat *seat = selection->xwm->seat;
390+
struct wlr_seat_client *seat_client = wlr_seat_client_for_wl_client(
391+
seat, selection->xwm->xwayland->client);
392+
393+
struct wlr_xwayland_data_source *source =
394+
xwayland_data_source_create(selection);
395+
if (source == NULL) {
396+
return 0;
397+
}
398+
399+
selection->xwm->incoming_drag =
400+
wlr_seat_client_start_grab(seat_client, &source->base, NULL, NULL);
401+
if (selection->xwm->incoming_drag == NULL) {
402+
wlr_log(L_ERROR, "could not start grab");
403+
}
362404
} else {
363-
// TODO: end grab
405+
wlr_log(L_INFO, "end grab");
406+
407+
const static uint32_t values[] = { XCB_STACK_MODE_BELOW };
408+
xcb_configure_window(xwm->xcb_conn, xwm->dnd_window,
409+
XCB_CONFIG_WINDOW_STACK_MODE, values);
410+
xcb_unmap_window(xwm->xcb_conn, xwm->dnd_window);
411+
412+
// TODO: drag_end(selection->xwm->incoming_drag)
413+
selection->xwm->incoming_drag = NULL;
364414
}
365415

366416
return 1;

0 commit comments

Comments
 (0)