aboutsummaryrefslogtreecommitdiff
path: root/xwayland
diff options
context:
space:
mode:
Diffstat (limited to 'xwayland')
-rw-r--r--xwayland/selection.c87
1 files changed, 73 insertions, 14 deletions
diff --git a/xwayland/selection.c b/xwayland/selection.c
index 8e5905df..d1dfbdaa 100644
--- a/xwayland/selection.c
+++ b/xwayland/selection.c
@@ -12,7 +12,7 @@
static const size_t incr_chunk_size = 64 * 1024;
-/*static xcb_atom_t data_device_manager_dnd_action_to_atom(
+static xcb_atom_t data_device_manager_dnd_action_to_atom(
struct wlr_xwm *xwm, enum wl_data_device_manager_dnd_action action) {
if (action & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY) {
return xwm->atoms[DND_ACTION_COPY];
@@ -24,7 +24,7 @@ static const size_t incr_chunk_size = 64 * 1024;
return XCB_ATOM_NONE;
}
-static enum wl_data_device_manager_dnd_action
+/*static enum wl_data_device_manager_dnd_action
data_device_manager_dnd_action_from_atom(struct wlr_xwm *xwm,
enum atom_name atom) {
if (atom == xwm->atoms[DND_ACTION_COPY] ||
@@ -183,7 +183,8 @@ error_out:
static void xwm_selection_source_send(struct wlr_xwm_selection *selection,
const char *mime_type, int32_t fd) {
- if (selection == &selection->xwm->clipboard_selection) {
+ if (selection == &selection->xwm->clipboard_selection ||
+ selection == &selection->xwm->dnd_selection) {
struct wlr_data_source *source =
selection->xwm->seat->selection_data_source;
if (source != NULL) {
@@ -260,8 +261,9 @@ static xcb_atom_t xwm_get_mime_type_atom(struct wlr_xwm *xwm, char *mime_type) {
return atom;
}
-static void xwm_dnd_send_enter(struct wlr_xwm *xwm, struct wlr_drag *drag,
- struct wlr_xwayland_surface *dest) {
+static void xwm_dnd_send_enter(struct wlr_xwm *xwm) {
+ struct wlr_drag *drag = xwm->drag;
+ struct wlr_xwayland_surface *dest = xwm->drag_focus;
struct wl_array *mime_types = &drag->source->mime_types;
xcb_client_message_data_t data = { 0 };
@@ -316,9 +318,38 @@ static void xwm_dnd_send_enter(struct wlr_xwm *xwm, struct wlr_drag *drag,
(const char *)&event);
}
+static void xwm_dnd_send_position(struct wlr_xwm *xwm, uint32_t time, int16_t x,
+ int16_t y) {
+ struct wlr_drag *drag = xwm->drag;
+ struct wlr_xwayland_surface *dest = xwm->drag_focus;
+
+ xcb_client_message_data_t data = { 0 };
+ data.data32[0] = xwm->dnd_selection.window;
+ data.data32[2] = (x << 16) | y;
+ data.data32[3] = time;
+ data.data32[4] =
+ data_device_manager_dnd_action_to_atom(xwm, drag->source->actions);
+
+ xcb_client_message_event_t event = {
+ .response_type = XCB_CLIENT_MESSAGE,
+ .format = 32,
+ .sequence = 0,
+ .window = dest->window_id,
+ .type = xwm->atoms[DND_POSITION],
+ .data = data,
+ };
+
+ xcb_send_event(xwm->xcb_conn,
+ 0, // propagate
+ dest->window_id,
+ XCB_EVENT_MASK_NO_EVENT,
+ (const char *)&event);
+}
+
static struct wl_array *xwm_selection_source_get_mime_types(
struct wlr_xwm_selection *selection) {
- if (selection == &selection->xwm->clipboard_selection) {
+ if (selection == &selection->xwm->clipboard_selection ||
+ selection == &selection->xwm->dnd_selection) {
struct wlr_data_source *source =
selection->xwm->seat->selection_data_source;
if (source != NULL) {
@@ -414,7 +445,7 @@ static void xwm_handle_selection_request(struct wlr_xwm *xwm,
selection->flush_property_on_delete = 0;
// No xwayland surface focused, deny access to clipboard
- if (xwm->focus_surface == NULL) {
+ if (xwm->focus_surface == NULL && xwm->drag_focus == NULL) {
wlr_log(L_DEBUG, "denying read access to clipboard: "
"no xwayland surface focused");
xwm_selection_send_notify(selection, XCB_ATOM_NONE);
@@ -714,7 +745,8 @@ static void xwm_selection_get_targets(struct wlr_xwm_selection *selection) {
// set the wayland selection to the X11 selection
struct wlr_xwm *xwm = selection->xwm;
- if (selection == &xwm->clipboard_selection) {
+ if (selection == &xwm->clipboard_selection ||
+ selection == &xwm->dnd_selection) {
struct x11_data_source *source =
calloc(1, sizeof(struct x11_data_source));
if (source == NULL) {
@@ -725,6 +757,8 @@ static void xwm_selection_get_targets(struct wlr_xwm_selection *selection) {
source->base.send = data_source_send;
source->base.cancel = data_source_cancel;
+ // TODO: DND
+
source->selection = selection;
wl_array_init(&source->mime_types_atoms);
@@ -816,6 +850,11 @@ static int xwm_handle_xfixes_selection_notify(struct wlr_xwm *xwm,
} else if (selection == &xwm->primary_selection) {
wlr_seat_set_primary_selection(xwm->seat, NULL,
wl_display_next_serial(xwm->xwayland->wl_display));
+ } else if (selection == &xwm->dnd_selection) {
+ // TODO: DND
+ } else {
+ wlr_log(L_DEBUG, "X11 selection has been cleared, but cannot "
+ "clear Wayland selection");
}
}
@@ -1009,7 +1048,21 @@ static void seat_handle_drag_focus(struct wl_listener *listener, void *data) {
return;
}
- xwm_dnd_send_enter(xwm, drag, surface);
+ xwm->drag_focus = surface;
+ xwm_dnd_send_enter(xwm);
+}
+
+static void seat_handle_drag_motion(struct wl_listener *listener, void *data) {
+ struct wlr_xwm *xwm = wl_container_of(listener, xwm, seat_drag_motion);
+ struct wlr_drag_motion_event *event = data;
+ struct wlr_xwayland_surface *surface = xwm->drag_focus;
+
+ if (surface == NULL) {
+ return; // No xwayland surface focused
+ }
+
+ xwm_dnd_send_position(xwm, event->time, surface->x + (int16_t)event->sx,
+ surface->y + (int16_t)event->sy);
}
static void seat_handle_drag_destroy(struct wl_listener *listener, void *data) {
@@ -1017,6 +1070,7 @@ static void seat_handle_drag_destroy(struct wl_listener *listener, void *data) {
wl_list_remove(&xwm->seat_drag_focus.link);
wl_list_remove(&xwm->seat_drag_destroy.link);
+ xwm->drag = NULL;
}
static void seat_handle_start_drag(struct wl_listener *listener, void *data) {
@@ -1024,11 +1078,16 @@ static void seat_handle_start_drag(struct wl_listener *listener, void *data) {
struct wlr_xwm *xwm = wl_container_of(listener, xwm, seat_start_drag);
xwm_selection_set_owner(&xwm->dnd_selection, drag != NULL);
-
- wl_signal_add(&drag->events.focus, &xwm->seat_drag_focus);
- xwm->seat_drag_focus.notify = seat_handle_drag_focus;
- wl_signal_add(&drag->events.destroy, &xwm->seat_drag_destroy);
- xwm->seat_drag_destroy.notify = seat_handle_drag_destroy;
+ xwm->drag = drag;
+
+ if (drag != NULL) {
+ wl_signal_add(&drag->events.focus, &xwm->seat_drag_focus);
+ xwm->seat_drag_focus.notify = seat_handle_drag_focus;
+ wl_signal_add(&drag->events.motion, &xwm->seat_drag_motion);
+ xwm->seat_drag_motion.notify = seat_handle_drag_motion;
+ wl_signal_add(&drag->events.destroy, &xwm->seat_drag_destroy);
+ xwm->seat_drag_destroy.notify = seat_handle_drag_destroy;
+ }
}
void xwm_set_seat(struct wlr_xwm *xwm, struct wlr_seat *seat) {