selection: add support for different mime-types

Add support for `text/plain`, `text/plain;charset=utf-8` and
`text/uri-list` to regular copy operations (both from clipboard and
primary selection) and drag-and-drop operations.
This commit is contained in:
Daniel Eklöf 2020-10-28 19:16:04 +01:00
parent cad0ae957d
commit be22fefdc7
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
3 changed files with 329 additions and 90 deletions

View file

@ -21,10 +21,18 @@
#include "grid.h" #include "grid.h"
#include "misc.h" #include "misc.h"
#include "render.h" #include "render.h"
#include "uri.h"
#include "util.h" #include "util.h"
#include "vt.h" #include "vt.h"
#include "xmalloc.h" #include "xmalloc.h"
static const char *const mime_type_map[] = {
[DATA_OFFER_MIME_UNSET] = NULL,
[DATA_OFFER_MIME_TEXT_PLAIN] = "text/plain",
[DATA_OFFER_MIME_TEXT_UTF8] = "text/plain;charset=utf-8",
[DATA_OFFER_MIME_URI_LIST] = "text/uri-list",
};
bool bool
selection_enabled(const struct terminal *term, struct seat *seat) selection_enabled(const struct terminal *term, struct seat *seat)
{ {
@ -1096,7 +1104,7 @@ text_to_clipboard(struct seat *seat, struct terminal *term, char *text, uint32_t
clipboard->text = text; clipboard->text = text;
/* Configure source */ /* Configure source */
wl_data_source_offer(clipboard->data_source, "text/plain;charset=utf-8"); wl_data_source_offer(clipboard->data_source, mime_type_map[DATA_OFFER_MIME_TEXT_UTF8]);
wl_data_source_add_listener(clipboard->data_source, &data_source_listener, seat); wl_data_source_add_listener(clipboard->data_source, &data_source_listener, seat);
wl_data_device_set_selection(seat->data_device, clipboard->data_source, serial); wl_data_device_set_selection(seat->data_device, clipboard->data_source, serial);
@ -1124,7 +1132,7 @@ struct clipboard_receive {
struct itimerspec timeout; struct itimerspec timeout;
/* Callback data */ /* Callback data */
void (*cb)(const char *data, size_t size, void *user); void (*cb)(char *data, size_t size, void *user);
void (*done)(void *user); void (*done)(void *user);
void *user; void *user;
}; };
@ -1195,7 +1203,7 @@ fdm_receive(struct fdm *fdm, int fd, int events, void *data)
break; break;
/* Call cb while at same time replacing \r\n with \n */ /* Call cb while at same time replacing \r\n with \n */
const char *p = text; char *p = text;
size_t left = count; size_t left = count;
again: again:
for (size_t i = 0; i < left - 1; i++) { for (size_t i = 0; i < left - 1; i++) {
@ -1220,7 +1228,7 @@ done:
static void static void
begin_receive_clipboard(struct terminal *term, int read_fd, begin_receive_clipboard(struct terminal *term, int read_fd,
void (*cb)(const char *data, size_t size, void *user), void (*cb)(char *data, size_t size, void *user),
void (*done)(void *user), void *user) void (*done)(void *user), void *user)
{ {
int timeout_fd = -1; int timeout_fd = -1;
@ -1273,7 +1281,7 @@ err:
void void
text_from_clipboard(struct seat *seat, struct terminal *term, text_from_clipboard(struct seat *seat, struct terminal *term,
void (*cb)(const char *data, size_t size, void *user), void (*cb)(char *data, size_t size, void *user),
void (*done)(void *user), void *user) void (*done)(void *user), void *user)
{ {
struct wl_clipboard *clipboard = &seat->clipboard; struct wl_clipboard *clipboard = &seat->clipboard;
@ -1295,7 +1303,7 @@ text_from_clipboard(struct seat *seat, struct terminal *term,
/* Give write-end of pipe to other client */ /* Give write-end of pipe to other client */
wl_data_offer_receive( wl_data_offer_receive(
clipboard->data_offer, "text/plain;charset=utf-8", write_fd); clipboard->data_offer, mime_type_map[clipboard->mime_type], write_fd);
/* Don't keep our copy of the write-end open (or we'll never get EOF) */ /* Don't keep our copy of the write-end open (or we'll never get EOF) */
close(write_fd); close(write_fd);
@ -1303,18 +1311,94 @@ text_from_clipboard(struct seat *seat, struct terminal *term,
begin_receive_clipboard(term, read_fd, cb, done, user); begin_receive_clipboard(term, read_fd, cb, done, user);
} }
struct receive_offer_context {
struct terminal *term;
/* URI state */
bool add_space;
struct {
char *data;
size_t sz;
size_t idx;
} buf;
union {
struct wl_data_offer *data_offer;
struct zwp_primary_selection_offer_v1 *primary_offer;
};
};
static void static void
from_clipboard_cb(const char *data, size_t size, void *user) receive_offer_text(char *data, size_t size, void *user)
{ {
struct terminal *term = user; struct receive_offer_context *ctx = user;
assert(term->is_sending_paste_data); assert(ctx->term->is_sending_paste_data);
term_paste_data_to_slave(term, data, size); term_paste_data_to_slave(ctx->term, data, size);
} }
static void static void
from_clipboard_done(void *user) receive_offer_uri(char *data, size_t size, void *user)
{ {
struct terminal *term = user; struct receive_offer_context *ctx = user;
while (ctx->buf.idx + size > ctx->buf.sz) {
size_t new_sz = ctx->buf.sz == 0 ? size : 2 * ctx->buf.sz;
ctx->buf.data = xrealloc(ctx->buf.data, new_sz);
ctx->buf.sz = new_sz;
}
memcpy(&ctx->buf.data[ctx->buf.idx], data, size);
ctx->buf.idx += size;
char *start = ctx->buf.data;
char *end = NULL;
while ((end = memchr(start, '\n', ctx->buf.idx - (start - ctx->buf.data))) != NULL) {
const size_t len = end - start;
LOG_DBG("URI: \"%.*s\"", (int)len, start);
char *scheme, *host, *path;
if (!uri_parse(start, len, &scheme, NULL, NULL, &host, NULL, &path, NULL, NULL)) {
LOG_ERR("drag-and-drop: invalid URI: %.*s", (int)len, start);
start = end + 1;
continue;
}
if (ctx->add_space)
receive_offer_text(" ", 1, ctx);
ctx->add_space = true;
receive_offer_text("'", 1, ctx);
if (strcmp(scheme, "file") == 0 && hostname_is_localhost(host))
receive_offer_text(path, strlen(path), ctx);
else
receive_offer_text(start, len, ctx);
receive_offer_text("'", 1, ctx);
start = end + 1;
free(scheme);
free(host);
free(path);
}
const size_t ofs = start - ctx->buf.data;
const size_t left = ctx->buf.idx - ofs;
memmove(&ctx->buf.data[0], &ctx->buf.data[ofs], left);
ctx->buf.idx = left;
}
static void
receive_offer_done(void *user)
{
struct receive_offer_context *ctx = user;
struct terminal *term = ctx->term;
free(ctx->buf.data);
free(ctx);
if (term->bracketed_paste) if (term->bracketed_paste)
term_paste_data_to_slave(term, "\033[201~", 6); term_paste_data_to_slave(term, "\033[201~", 6);
@ -1343,8 +1427,18 @@ selection_from_clipboard(struct seat *seat, struct terminal *term, uint32_t seri
if (term->bracketed_paste) if (term->bracketed_paste)
term_paste_data_to_slave(term, "\033[200~", 6); term_paste_data_to_slave(term, "\033[200~", 6);
struct receive_offer_context *ctx = xmalloc(sizeof(*ctx));
*ctx = (struct receive_offer_context) {
.term = term,
.data_offer = clipboard->data_offer,
};
text_from_clipboard( text_from_clipboard(
seat, term, &from_clipboard_cb, &from_clipboard_done, term); seat, term,
(clipboard->mime_type == DATA_OFFER_MIME_URI_LIST
? &receive_offer_uri
: &receive_offer_text),
&receive_offer_done, ctx);
} }
bool bool
@ -1383,7 +1477,7 @@ text_to_primary(struct seat *seat, struct terminal *term, char *text, uint32_t s
primary->text = text; primary->text = text;
/* Configure source */ /* Configure source */
zwp_primary_selection_source_v1_offer(primary->data_source, "text/plain;charset=utf-8"); zwp_primary_selection_source_v1_offer(primary->data_source, mime_type_map[DATA_OFFER_MIME_TEXT_UTF8]);
zwp_primary_selection_source_v1_add_listener(primary->data_source, &primary_selection_source_listener, seat); zwp_primary_selection_source_v1_add_listener(primary->data_source, &primary_selection_source_listener, seat);
zwp_primary_selection_device_v1_set_selection(seat->primary_selection_device, primary->data_source, serial); zwp_primary_selection_device_v1_set_selection(seat->primary_selection_device, primary->data_source, serial);
@ -1407,7 +1501,7 @@ selection_to_primary(struct seat *seat, struct terminal *term, uint32_t serial)
void void
text_from_primary( text_from_primary(
struct seat *seat, struct terminal *term, struct seat *seat, struct terminal *term,
void (*cb)(const char *data, size_t size, void *user), void (*cb)(char *data, size_t size, void *user),
void (*done)(void *user), void *user) void (*done)(void *user), void *user)
{ {
if (term->wl->primary_selection_device_manager == NULL) { if (term->wl->primary_selection_device_manager == NULL) {
@ -1434,7 +1528,7 @@ text_from_primary(
/* Give write-end of pipe to other client */ /* Give write-end of pipe to other client */
zwp_primary_selection_offer_v1_receive( zwp_primary_selection_offer_v1_receive(
primary->data_offer, "text/plain;charset=utf-8", write_fd); primary->data_offer, mime_type_map[primary->mime_type], write_fd);
/* Don't keep our copy of the write-end open (or we'll never get EOF) */ /* Don't keep our copy of the write-end open (or we'll never get EOF) */
close(write_fd); close(write_fd);
@ -1461,27 +1555,157 @@ selection_from_primary(struct seat *seat, struct terminal *term)
if (term->bracketed_paste) if (term->bracketed_paste)
term_paste_data_to_slave(term, "\033[200~", 6); term_paste_data_to_slave(term, "\033[200~", 6);
text_from_primary(seat, term, &from_clipboard_cb, &from_clipboard_done, term); struct receive_offer_context *ctx = xmalloc(sizeof(*ctx));
*ctx = (struct receive_offer_context){
.term = term,
.primary_offer = primary->data_offer,
};
text_from_primary(
seat, term,
(primary->mime_type == DATA_OFFER_MIME_URI_LIST
? &receive_offer_uri
: &receive_offer_text),
&receive_offer_done, ctx);
}
static void
select_mime_type_for_offer(const char *_mime_type,
enum data_offer_mime_type *type)
{
enum data_offer_mime_type mime_type = DATA_OFFER_MIME_UNSET;
/* Translate offered mime type to our mime type enum */
for (size_t i = 0; i < ALEN(mime_type_map); i++) {
if (mime_type_map[i] == NULL)
continue;
if (strcmp(_mime_type, mime_type_map[i]) == 0) {
mime_type = i;
break;
}
}
LOG_DBG("mime-type: %s -> %s (offered type was %s)",
mime_type_map[*type], mime_type_map[mime_type], _mime_type);
/* Mime-type transition; if the new mime-type is "better" than
* previously offered types, use the new type */
switch (mime_type) {
case DATA_OFFER_MIME_TEXT_PLAIN:
/* text/plain is our least preferred type. Only use if current
* type is unset */
switch (*type) {
case DATA_OFFER_MIME_UNSET:
*type = mime_type;
break;
default:
break;
}
break;
case DATA_OFFER_MIME_TEXT_UTF8:
/* text/plain;charset=utf-8 is preferred over text/plain */
switch (*type) {
case DATA_OFFER_MIME_UNSET:
case DATA_OFFER_MIME_TEXT_PLAIN:
*type = mime_type;
break;
default:
break;
}
break;
case DATA_OFFER_MIME_URI_LIST:
/* text/uri-list is always used when offered */
*type = mime_type;
break;
case DATA_OFFER_MIME_UNSET:
break;
}
}
static void
data_offer_reset(struct wl_clipboard *clipboard)
{
if (clipboard->data_offer != NULL) {
wl_data_offer_destroy(clipboard->data_offer);
clipboard->data_offer = NULL;
}
clipboard->window = NULL;
clipboard->mime_type = DATA_OFFER_MIME_UNSET;
} }
#if 1
static void static void
offer(void *data, struct wl_data_offer *wl_data_offer, const char *mime_type) offer(void *data, struct wl_data_offer *wl_data_offer, const char *mime_type)
{ {
LOG_DBG("OFFER: %s", mime_type); struct seat *seat = data;
select_mime_type_for_offer(mime_type, &seat->clipboard.mime_type);
} }
static void static void
source_actions(void *data, struct wl_data_offer *wl_data_offer, source_actions(void *data, struct wl_data_offer *wl_data_offer,
uint32_t source_actions) uint32_t source_actions)
{ {
LOG_DBG("ACTIONS: 0x%08x", source_actions); #if defined(_DEBUG) && LOG_ENABLE_DBG
char actions_as_string[1024];
size_t idx = 0;
actions_as_string[0] = '\0';
actions_as_string[sizeof(actions_as_string) - 1] = '\0';
for (size_t i = 0; i < 31; i++) {
if (((source_actions >> i) & 1) == 0)
continue;
enum wl_data_device_manager_dnd_action action = 1 << i;
const char *s = NULL;
switch (action) {
case WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE: s = NULL; break;
case WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY: s = "copy"; break;
case WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE: s = "move"; break;
case WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK: s = "ask"; break;
}
if (s == NULL)
continue;
strncat(actions_as_string, s, sizeof(actions_as_string) - idx - 1);
idx += strlen(s);
strncat(actions_as_string, ", ", sizeof(actions_as_string) - idx - 1);
idx += 2;
}
/* Strip trailing ", " */
if (strlen(actions_as_string) > 2)
actions_as_string[strlen(actions_as_string) - 2] = '\0';
LOG_DBG("DnD actions: %s (0x%08x)", actions_as_string, source_actions);
#endif
} }
static void static void
offer_action(void *data, struct wl_data_offer *wl_data_offer, uint32_t dnd_action) offer_action(void *data, struct wl_data_offer *wl_data_offer, uint32_t dnd_action)
{ {
LOG_DBG("OFFER ACTION: 0x%08x", dnd_action); #if defined(_DEBUG) && LOG_ENABLE_DBG
const char *s = NULL;
switch (dnd_action) {
case WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE: s = "<none>"; break;
case WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY: s = "copy"; break;
case WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE: s = "move"; break;
case WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK: s = "ask"; break;
}
LOG_DBG("DnD offer action: %s (0x%08x)", s, dnd_action);
#endif
} }
static const struct wl_data_offer_listener data_offer_listener = { static const struct wl_data_offer_listener data_offer_listener = {
@ -1489,57 +1713,56 @@ static const struct wl_data_offer_listener data_offer_listener = {
.source_actions = &source_actions, .source_actions = &source_actions,
.action = &offer_action, .action = &offer_action,
}; };
#endif
static void static void
data_offer(void *data, struct wl_data_device *wl_data_device, data_offer(void *data, struct wl_data_device *wl_data_device,
struct wl_data_offer *id) struct wl_data_offer *offer)
{ {
wl_data_offer_add_listener(id, &data_offer_listener, data); struct seat *seat = data;
data_offer_reset(&seat->clipboard);
seat->clipboard.data_offer = offer;
wl_data_offer_add_listener(offer, &data_offer_listener, seat);
} }
static void static void
enter(void *data, struct wl_data_device *wl_data_device, uint32_t serial, enter(void *data, struct wl_data_device *wl_data_device, uint32_t serial,
struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y, struct wl_surface *surface, wl_fixed_t x, wl_fixed_t y,
struct wl_data_offer *id) struct wl_data_offer *offer)
{ {
struct seat *seat = data; struct seat *seat = data;
struct wayland *wayl = seat->wayl; struct wayland *wayl = seat->wayl;
assert(seat->dnd_term == NULL); assert(offer == seat->clipboard.data_offer);
/* Remember current DnD offer */
/* Remmeber _which_ terminal the current DnD offer is targetting */ /* Remmeber _which_ terminal the current DnD offer is targetting */
assert(seat->clipboard.window == NULL);
tll_foreach(wayl->terms, it) { tll_foreach(wayl->terms, it) {
if (term_surface_kind(it->item, surface) == TERM_SURF_GRID && if (term_surface_kind(it->item, surface) == TERM_SURF_GRID &&
!it->item->is_sending_paste_data) !it->item->is_sending_paste_data)
{ {
wl_data_offer_accept(id, serial, "text/plain;charset=utf-8"); wl_data_offer_accept(
offer, serial, mime_type_map[seat->clipboard.mime_type]);
wl_data_offer_set_actions( wl_data_offer_set_actions(
id, offer,
WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE, WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY,
WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY); WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY);
seat->dnd_term = it->item; seat->clipboard.window = it->item->window;
seat->dnd_term->window->dnd_offer = id;
return; return;
} }
} }
/* Either terminal is alraedy busy sending paste data, or mouse /* Either terminal is alraedy busy sending paste data, or mouse
* pointer isnt over the grid */ * pointer isnt over the grid */
seat->dnd_term = NULL; seat->clipboard.window = NULL;
wl_data_offer_set_actions(id, 0, WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY); wl_data_offer_set_actions(offer, 0, 0);
} }
static void static void
leave(void *data, struct wl_data_device *wl_data_device) leave(void *data, struct wl_data_device *wl_data_device)
{ {
struct seat *seat = data; struct seat *seat = data;
if (seat->dnd_term != NULL) seat->clipboard.window = NULL;
seat->dnd_term->window->dnd_offer = NULL;
seat->dnd_term = NULL;
} }
static void static void
@ -1549,18 +1772,12 @@ motion(void *data, struct wl_data_device *wl_data_device, uint32_t time,
} }
static void static void
dnd_done(void *user) receive_dnd_done(void *user)
{ {
struct terminal *term = user; struct receive_offer_context *ctx = user;
struct wl_data_offer *offer = term->window->dnd_offer;
assert(offer != NULL); wl_data_offer_finish(ctx->data_offer);
term->window->dnd_offer = NULL; receive_offer_done(user);
wl_data_offer_finish(offer);
wl_data_offer_destroy(offer);
from_clipboard_done(user);
} }
static void static void
@ -1568,25 +1785,33 @@ drop(void *data, struct wl_data_device *wl_data_device)
{ {
struct seat *seat = data; struct seat *seat = data;
struct terminal *term = seat->dnd_term; assert(seat->clipboard.window != NULL);
assert(term != NULL); struct terminal *term = seat->clipboard.window->term;
struct wl_data_offer *offer = term->window->dnd_offer; struct wl_clipboard *clipboard = &seat->clipboard;
assert(offer != NULL);
seat->dnd_term = NULL; struct receive_offer_context *ctx = xmalloc(sizeof(*ctx));
*ctx = (struct receive_offer_context){
.term = term,
.data_offer = clipboard->data_offer,
};
/* Prepare a pipe the other client can write its selection to us */ /* Prepare a pipe the other client can write its selection to us */
int fds[2]; int fds[2];
if (pipe2(fds, O_CLOEXEC) == -1) { if (pipe2(fds, O_CLOEXEC) == -1) {
LOG_ERRNO("failed to create pipe"); LOG_ERRNO("failed to create pipe");
goto err; free(ctx);
return;
} }
int read_fd = fds[0]; int read_fd = fds[0];
int write_fd = fds[1]; int write_fd = fds[1];
LOG_DBG("DnD drop: mime-type=%s", mime_type_map[clipboard->mime_type]);
/* Give write-end of pipe to other client */ /* Give write-end of pipe to other client */
wl_data_offer_receive(offer, "text/plain;charset=utf-8", write_fd); wl_data_offer_receive(
clipboard->data_offer, mime_type_map[clipboard->mime_type], write_fd);
/* Don't keep our copy of the write-end open (or we'll never get EOF) */ /* Don't keep our copy of the write-end open (or we'll never get EOF) */
close(write_fd); close(write_fd);
@ -1596,26 +1821,24 @@ drop(void *data, struct wl_data_device *wl_data_device)
if (term->bracketed_paste) if (term->bracketed_paste)
term_paste_data_to_slave(term, "\033[200~", 6); term_paste_data_to_slave(term, "\033[200~", 6);
begin_receive_clipboard(term, read_fd, &from_clipboard_cb, &dnd_done, term); begin_receive_clipboard(
return; term, read_fd,
(clipboard->mime_type == DATA_OFFER_MIME_URI_LIST
err: ? &receive_offer_uri
wl_data_offer_destroy(offer); : &receive_offer_text),
&receive_dnd_done, ctx);
} }
static void static void
selection(void *data, struct wl_data_device *wl_data_device, selection(void *data, struct wl_data_device *wl_data_device,
struct wl_data_offer *id) struct wl_data_offer *offer)
{ {
/* Selection offer from other client */ /* Selection offer from other client */
struct seat *seat = data; struct seat *seat = data;
struct wl_clipboard *clipboard = &seat->clipboard; if (offer == NULL)
data_offer_reset(&seat->clipboard);
if (clipboard->data_offer != NULL) else
wl_data_offer_destroy(clipboard->data_offer); assert(offer == seat->clipboard.data_offer);
clipboard->data_offer = id;
} }
const struct wl_data_device_listener data_device_listener = { const struct wl_data_device_listener data_device_listener = {
@ -1627,46 +1850,55 @@ const struct wl_data_device_listener data_device_listener = {
.selection = &selection, .selection = &selection,
}; };
#if 0
static void static void
primary_offer(void *data, primary_offer(void *data,
struct zwp_primary_selection_offer_v1 *zwp_primary_selection_offer, struct zwp_primary_selection_offer_v1 *zwp_primary_selection_offer,
const char *mime_type) const char *mime_type)
{ {
LOG_DBG("primary offer: %s", mime_type);
struct seat *seat = data;
select_mime_type_for_offer(mime_type, &seat->primary.mime_type);
} }
static const struct zwp_primary_selection_offer_v1_listener primary_selection_offer_listener = { static const struct zwp_primary_selection_offer_v1_listener primary_selection_offer_listener = {
.offer = &primary_offer, .offer = &primary_offer,
}; };
#endif
static void
primary_offer_reset(struct wl_primary *primary)
{
if (primary->data_offer != NULL) {
zwp_primary_selection_offer_v1_destroy(primary->data_offer);
primary->data_offer = NULL;
}
primary->mime_type = DATA_OFFER_MIME_UNSET;
}
static void static void
primary_data_offer(void *data, primary_data_offer(void *data,
struct zwp_primary_selection_device_v1 *zwp_primary_selection_device, struct zwp_primary_selection_device_v1 *zwp_primary_selection_device,
struct zwp_primary_selection_offer_v1 *offer) struct zwp_primary_selection_offer_v1 *offer)
{ {
struct seat *seat = data;
primary_offer_reset(&seat->primary);
seat->primary.data_offer = offer;
zwp_primary_selection_offer_v1_add_listener(
offer, &primary_selection_offer_listener, seat);
} }
static void static void
primary_selection(void *data, primary_selection(void *data,
struct zwp_primary_selection_device_v1 *zwp_primary_selection_device, struct zwp_primary_selection_device_v1 *zwp_primary_selection_device,
struct zwp_primary_selection_offer_v1 *id) struct zwp_primary_selection_offer_v1 *offer)
{ {
/* Selection offer from other client, for primary */ /* Selection offer from other client, for primary */
struct seat *seat = data; struct seat *seat = data;
struct wl_primary *primary = &seat->primary; if (offer == NULL)
primary_offer_reset(&seat->primary);
if (primary->data_offer != NULL) else
zwp_primary_selection_offer_v1_destroy(primary->data_offer); assert(seat->primary.data_offer == offer);
primary->data_offer = id;
#if 0
if (id != NULL) {
zwp_primary_selection_offer_v1_add_listener(
id, &primary_selection_offer_listener, term);
}
#endif
} }
const struct zwp_primary_selection_device_v1_listener primary_selection_device_listener = { const struct zwp_primary_selection_device_v1_listener primary_selection_device_listener = {

View file

@ -67,12 +67,12 @@ bool text_to_primary(
*/ */
void text_from_clipboard( void text_from_clipboard(
struct seat *seat, struct terminal *term, struct seat *seat, struct terminal *term,
void (*cb)(const char *data, size_t size, void *user), void (*cb)(char *data, size_t size, void *user),
void (*done)(void *user), void *user); void (*done)(void *user), void *user);
void text_from_primary( void text_from_primary(
struct seat *seat, struct terminal *term, struct seat *seat, struct terminal *term,
void (*cb)(const char *data, size_t size, void *user), void (*cb)(char *data, size_t size, void *user),
void (*dont)(void *user), void *user); void (*dont)(void *user), void *user);
void selection_start_scroll_timer( void selection_start_scroll_timer(

View file

@ -101,9 +101,20 @@ struct key_binding_search {
enum bind_action_search action; enum bind_action_search action;
}; };
/* Mime-types we support when dealing with data offers (e.g. copy-paste, or DnD) */
enum data_offer_mime_type {
DATA_OFFER_MIME_UNSET,
DATA_OFFER_MIME_TEXT_PLAIN,
DATA_OFFER_MIME_TEXT_UTF8,
DATA_OFFER_MIME_URI_LIST,
};
struct wl_window;
struct wl_clipboard { struct wl_clipboard {
struct wl_window *window; /* For DnD */
struct wl_data_source *data_source; struct wl_data_source *data_source;
struct wl_data_offer *data_offer; struct wl_data_offer *data_offer;
enum data_offer_mime_type mime_type;
char *text; char *text;
uint32_t serial; uint32_t serial;
}; };
@ -111,6 +122,7 @@ struct wl_clipboard {
struct wl_primary { struct wl_primary {
struct zwp_primary_selection_source_v1 *data_source; struct zwp_primary_selection_source_v1 *data_source;
struct zwp_primary_selection_offer_v1 *data_offer; struct zwp_primary_selection_offer_v1 *data_offer;
enum data_offer_mime_type mime_type;
char *text; char *text;
uint32_t serial; uint32_t serial;
}; };
@ -205,9 +217,6 @@ struct seat {
struct wl_clipboard clipboard; struct wl_clipboard clipboard;
struct wl_primary primary; struct wl_primary primary;
/* Drag n drop */
struct terminal *dnd_term;
}; };
enum csd_surface { enum csd_surface {
@ -312,8 +321,6 @@ struct wl_window {
struct wl_callback *frame_callback; struct wl_callback *frame_callback;
struct wl_data_offer *dnd_offer;
tll(const struct monitor *) on_outputs; /* Outputs we're mapped on */ tll(const struct monitor *) on_outputs; /* Outputs we're mapped on */
bool is_configured; bool is_configured;