aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/xwayland/xwm.h3
-rw-r--r--xwayland/selection.c119
-rw-r--r--xwayland/xwm.c6
3 files changed, 80 insertions, 48 deletions
diff --git a/include/xwayland/xwm.h b/include/xwayland/xwm.h
index b6b26227..b85b5bae 100644
--- a/include/xwayland/xwm.h
+++ b/include/xwayland/xwm.h
@@ -150,13 +150,14 @@ void xwm_set_cursor(struct wlr_xwm *xwm, const uint8_t *pixels, uint32_t stride,
int xwm_handle_selection_event(struct wlr_xwm *xwm, xcb_generic_event_t *event);
int xwm_handle_selection_client_message(struct wlr_xwm *xwm,
- xcb_client_message_event_t *ev) ;
+ xcb_client_message_event_t *ev);
void xwm_selection_init(struct wlr_xwm *xwm);
void xwm_selection_finish(struct wlr_xwm *xwm);
void xwm_set_seat(struct wlr_xwm *xwm, struct wlr_seat *seat);
+char *xwm_get_atom_name(struct wlr_xwm *xwm, xcb_atom_t atom);
bool xwm_atoms_contains(struct wlr_xwm *xwm, xcb_atom_t *atoms,
size_t num_atoms, enum atom_name needle);
diff --git a/xwayland/selection.c b/xwayland/selection.c
index 740fac73..d5872f83 100644
--- a/xwayland/selection.c
+++ b/xwayland/selection.c
@@ -54,7 +54,8 @@ static void xwm_selection_send_notify(struct wlr_xwm_selection *selection,
0, // propagate
selection->request.requestor,
XCB_EVENT_MASK_NO_EVENT,
- (char *)&selection_notify);
+ (const char *)&selection_notify);
+ xcb_flush(selection->xwm->xcb_conn);
}
static int xwm_selection_flush_source_data(struct wlr_xwm_selection *selection) {
@@ -211,8 +212,56 @@ static void xwm_selection_source_send(struct wlr_xwm_selection *selection,
wlr_log(L_DEBUG, "not sending selection: no selection source available");
}
+static struct wl_array *xwm_selection_source_get_mime_types(
+ struct wlr_xwm_selection *selection) {
+ if (selection == &selection->xwm->clipboard_selection) {
+ struct wlr_data_source *source =
+ selection->xwm->seat->selection_data_source;
+ if (source != NULL) {
+ return &source->mime_types;
+ }
+ } else if (selection == &selection->xwm->primary_selection) {
+ struct wlr_primary_selection_source *source =
+ selection->xwm->seat->primary_selection_source;
+ if (source != NULL) {
+ return &source->mime_types;
+ }
+ } else if (selection == &selection->xwm->dnd_selection) {
+ if (selection->xwm->seat->drag != NULL &&
+ selection->xwm->seat->drag->source != NULL) {
+ return &selection->xwm->seat->drag->source->mime_types;
+ }
+ }
+ return NULL;
+}
+
static void xwm_selection_send_data(struct wlr_xwm_selection *selection,
xcb_atom_t target, const char *mime_type) {
+ // Check MIME type
+ struct wl_array *mime_types =
+ xwm_selection_source_get_mime_types(selection);
+ if (mime_types == NULL) {
+ wlr_log(L_ERROR, "not sending selection: no MIME type list available");
+ xwm_selection_send_notify(selection, XCB_ATOM_NONE);
+ return;
+ }
+
+ bool found = false;
+ char **mime_type_ptr;
+ wl_array_for_each(mime_type_ptr, mime_types) {
+ char *t = *mime_type_ptr;
+ if (strcmp(t, mime_type) == 0) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ wlr_log(L_ERROR, "not sending selection: "
+ "requested an unsupported MIME type %s", mime_type);
+ xwm_selection_send_notify(selection, XCB_ATOM_NONE);
+ return;
+ }
+
int p[2];
if (pipe(p) == -1) {
wlr_log(L_ERROR, "pipe failed: %m");
@@ -300,6 +349,8 @@ static void xwm_dnd_send_enter(struct wlr_xwm *xwm) {
data.data32[0] = xwm->dnd_selection.window;
data.data32[1] = XDND_VERSION << 24;
+ // If we have 3 MIME types or less, we can send them directly in the
+ // DND_ENTER message
size_t n = mime_types->size / sizeof(char *);
if (n <= 3) {
size_t i = 0;
@@ -393,31 +444,12 @@ static void xwm_dnd_send_leave(struct wlr_xwm *xwm) {
xwm_dnd_send_event(xwm, xwm->atoms[DND_FINISHED], &data);
}*/
-static struct wl_array *xwm_selection_source_get_mime_types(
- struct wlr_xwm_selection *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) {
- return &source->mime_types;
- }
- } else if (selection == &selection->xwm->primary_selection) {
- struct wlr_primary_selection_source *source =
- selection->xwm->seat->primary_selection_source;
- if (source != NULL) {
- return &source->mime_types;
- }
- }
- return NULL;
-}
-
static void xwm_selection_send_targets(struct wlr_xwm_selection *selection) {
struct wlr_xwm *xwm = selection->xwm;
struct wl_array *mime_types = xwm_selection_source_get_mime_types(selection);
if (mime_types == NULL) {
- wlr_log(L_DEBUG, "not sending selection targets: "
+ wlr_log(L_ERROR, "not sending selection targets: "
"no selection source available");
xwm_selection_send_notify(selection, XCB_ATOM_NONE);
return;
@@ -493,8 +525,10 @@ static void xwm_handle_selection_request(struct wlr_xwm *xwm,
// No xwayland surface focused, deny access to clipboard
if (xwm->focus_surface == NULL && xwm->drag_focus == NULL) {
- wlr_log(L_DEBUG, "denying read access to clipboard: "
- "no xwayland surface focused");
+ char *selection_name = xwm_get_atom_name(xwm, selection->atom);
+ wlr_log(L_DEBUG, "denying read access to selection %u (%s): "
+ "no xwayland surface focused", selection->atom, selection_name);
+ free(selection_name);
xwm_selection_send_notify(selection, XCB_ATOM_NONE);
return;
}
@@ -510,26 +544,15 @@ static void xwm_handle_selection_request(struct wlr_xwm *xwm,
xwm_selection_send_data(selection, selection_request->target,
"text/plain");
} else {
- xcb_get_atom_name_cookie_t name_cookie =
- xcb_get_atom_name(xwm->xcb_conn, selection_request->target);
- xcb_get_atom_name_reply_t *name_reply =
- xcb_get_atom_name_reply(xwm->xcb_conn, name_cookie, NULL);
- if (name_reply == NULL) {
- wlr_log(L_DEBUG, "not handling selection request: unknown atom");
- xwm_selection_send_notify(selection, XCB_ATOM_NONE);
- return;
- }
- size_t len = xcb_get_atom_name_name_length(name_reply);
- char *mime_type = malloc((len + 1) * sizeof(char));
+ char *mime_type = xwm_get_atom_name(xwm, selection_request->target);
if (mime_type == NULL) {
- free(name_reply);
+ wlr_log(L_ERROR, "ignoring selection request: unknown atom");
+ xwm_selection_send_notify(selection, XCB_ATOM_NONE);
return;
}
- memcpy(mime_type, xcb_get_atom_name_name(name_reply), len);
- mime_type[len] = '\0';
- xwm_selection_send_data(selection, selection_request->target, mime_type);
+ xwm_selection_send_data(selection, selection_request->target,
+ mime_type);
free(mime_type);
- free(name_reply);
}
}
@@ -961,10 +984,9 @@ int xwm_handle_selection_event(struct wlr_xwm *xwm,
int xwm_handle_selection_client_message(struct wlr_xwm *xwm,
xcb_client_message_event_t *ev) {
if (ev->type == xwm->atoms[DND_STATUS]) {
- struct wlr_drag *drag = xwm->drag;
- if (drag == NULL) {
- wlr_log(L_DEBUG, "Ignoring XdndStatus client message because "
- "there's no current drag");
+ if (xwm->drag == NULL) {
+ wlr_log(L_DEBUG, "ignoring XdndStatus client message because "
+ "there's no drag");
return 1;
}
@@ -973,9 +995,18 @@ int xwm_handle_selection_client_message(struct wlr_xwm *xwm,
bool accepted = data->data32[1] & 1;
xcb_atom_t action_atom = data->data32[4];
+ if (xwm->drag_focus == NULL ||
+ target_window != xwm->drag_focus->window_id) {
+ wlr_log(L_DEBUG, "ignoring XdndStatus client message because "
+ "it doesn't match the current drag focus window ID");
+ return 1;
+ }
+
enum wl_data_device_manager_dnd_action action =
data_device_manager_dnd_action_from_atom(xwm, action_atom);
+ struct wlr_drag *drag = xwm->drag;
+ assert(drag != NULL);
drag->source->accepted = accepted;
drag->source->current_dnd_action = action;
@@ -1038,7 +1069,6 @@ void xwm_selection_init(struct wlr_xwm *xwm) {
&version);
selection_init(xwm, &xwm->dnd_selection, xwm->atoms[DND_SELECTION]);
- wlr_log(L_DEBUG, "DND_SELECTION=%d", xwm->atoms[DND_SELECTION]);
}
void xwm_selection_finish(struct wlr_xwm *xwm) {
@@ -1182,6 +1212,7 @@ static void seat_handle_start_drag(struct wl_listener *listener, void *data) {
xwm_selection_set_owner(&xwm->dnd_selection, drag != NULL);
xwm->drag = drag;
+ xwm->drag_focus = NULL;
if (drag != NULL) {
wl_signal_add(&drag->events.focus, &xwm->seat_drag_focus);
diff --git a/xwayland/xwm.c b/xwayland/xwm.c
index f6668796..82210ce0 100644
--- a/xwayland/xwm.c
+++ b/xwayland/xwm.c
@@ -506,7 +506,7 @@ static void read_surface_net_wm_state(struct wlr_xwm *xwm,
}
}
-static char *get_atom_name(struct wlr_xwm *xwm, xcb_atom_t atom) {
+char *xwm_get_atom_name(struct wlr_xwm *xwm, xcb_atom_t atom) {
xcb_get_atom_name_cookie_t name_cookie =
xcb_get_atom_name(xwm->xcb_conn, atom);
xcb_get_atom_name_reply_t *name_reply =
@@ -558,7 +558,7 @@ static void read_surface_property(struct wlr_xwm *xwm,
} else if (property == xwm->atoms[MOTIF_WM_HINTS]) {
read_surface_motif_hints(xwm, xsurface, reply);
} else {
- char *prop_name = get_atom_name(xwm, property);
+ char *prop_name = xwm_get_atom_name(xwm, property);
wlr_log(L_DEBUG, "unhandled X11 property %u (%s) for window %u",
property, prop_name, xsurface->window_id);
free(prop_name);
@@ -967,7 +967,7 @@ static void xwm_handle_client_message(struct wlr_xwm *xwm,
} else if (ev->type == xwm->atoms[_NET_WM_MOVERESIZE]) {
xwm_handle_net_wm_moveresize_message(xwm, ev);
} else if (!xwm_handle_selection_client_message(xwm, ev)) {
- char *type_name = get_atom_name(xwm, ev->type);
+ char *type_name = xwm_get_atom_name(xwm, ev->type);
wlr_log(L_DEBUG, "unhandled x11 client message %u (%s)", ev->type,
type_name);
free(type_name);