|
|
|
@ -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);
|
|
|
|
|