Add proof-of-concept selection support to terminal

Next will be to support mouse selections so we can copy and paste
something more interesting than just 'selection data'.
dev
Kristian Høgsberg 14 years ago
parent 67cac8a565
commit 58eec36f68
  1. 87
      clients/terminal.c
  2. 120
      clients/window.c
  3. 9
      clients/window.h

@ -390,6 +390,11 @@ struct terminal {
struct terminal_color color_table[256];
cairo_font_extents_t extents;
cairo_scaled_font_t *font_normal, *font_bold;
uint32_t tag;
struct wl_selection *selection;
struct wl_selection_offer *selection_offer;
uint32_t selection_offer_has_text;
};
/* Create default tab stops, every 8 characters */
@ -1872,6 +1877,88 @@ terminal_data(struct terminal *terminal, const char *data, size_t length)
}
static void
selection_listener_send(void *data, struct wl_selection *selection,
const char *mime_type, int fd)
{
struct terminal *terminal = data;
static const char msg[] = "selection data";
fprintf(stderr, "selection send, fd is %d\n", fd);
write(fd, msg, sizeof msg);
close(fd);
}
static void
selection_listener_cancelled(void *data, struct wl_selection *selection)
{
struct terminal *terminal = data;
fprintf(stderr, "selection cancelled\n");
wl_selection_destroy(selection);
}
static const struct wl_selection_listener selection_listener = {
selection_listener_send,
selection_listener_cancelled
};
static gboolean
selection_io_func(GIOChannel *source, GIOCondition condition, gpointer data)
{
struct terminal *terminal = data;
char buffer[256];
unsigned int len;
int fd;
fd = g_io_channel_unix_get_fd(source);
len = read(fd, buffer, sizeof buffer);
fprintf(stderr, "read %d bytes: %.*s\n", len, len, buffer);
close(fd);
g_source_remove(terminal->tag);
g_io_channel_unref(source);
return TRUE;
}
static int
handle_bound_key(struct terminal *terminal,
struct input *input, uint32_t sym, uint32_t time)
{
struct wl_shell *shell;
GIOChannel *channel;
int fd;
switch (sym) {
case XK_C:
shell = display_get_shell(terminal->display);
terminal->selection = wl_shell_create_selection(shell);
wl_selection_add_listener(terminal->selection,
&selection_listener, terminal);
wl_selection_offer(terminal->selection, "text/plain");
wl_selection_activate(terminal->selection,
input_get_input_device(input), time);
return 1;
case XK_V:
if (input_offers_mime_type(input, "text/plain")) {
fd = input_receive_mime_type(input, "text/plain");
channel = g_io_channel_unix_new(fd);
terminal->tag = g_io_add_watch(channel, G_IO_IN,
selection_io_func,
terminal);
}
return 1;
case XK_X:
/* cut selection; terminal doesn't do cut */
return 0;
default:
return 0;
}
}
static void
key_handler(struct window *window, struct input *input, uint32_t time,
uint32_t key, uint32_t sym, uint32_t state, void *data)

@ -118,6 +118,7 @@ struct input {
struct wl_input_device *input_device;
struct window *pointer_focus;
struct window *keyboard_focus;
struct selection_offer *offer;
uint32_t current_pointer_image;
uint32_t modifiers;
int32_t x, y, sx, sy;
@ -1317,6 +1318,117 @@ display_add_input(struct display *d, uint32_t id)
wl_input_device_set_user_data(input->input_device, input);
}
struct selection_offer {
struct display *display;
struct wl_selection_offer *offer;
struct wl_array types;
struct input *input;
};
int
input_offers_mime_type(struct input *input, const char *type)
{
struct selection_offer *offer = input->offer;
char **p, **end;
if (offer == NULL)
return 0;
end = offer->types.data + offer->types.size;
for (p = offer->types.data; p < end; p++)
if (strcmp(*p, type) == 0)
return 1;
return 0;
}
int
input_receive_mime_type(struct input *input, const char *type)
{
struct selection_offer *offer = input->offer;
int p[2];
pipe(p);
/* FIXME: A number of things can go wrong here: the object may
* not be the current selection offer any more (which could
* still work, but the source may have gone away or just
* destroyed its wl_selection) or the offer may not have the
* requested type after all (programmer/client error,
* typically) */
wl_selection_offer_receive(offer->offer, type, p[1]);
close(p[1]);
return p[0];
}
static void
selection_offer_offer(void *data,
struct wl_selection_offer *selection_offer,
const char *type)
{
struct selection_offer *offer = data;
char **p;
p = wl_array_add(&offer->types, sizeof *p);
if (p)
*p = strdup(type);
};
static void
selection_offer_keyboard_focus(void *data,
struct wl_selection_offer *selection_offer,
struct wl_input_device *input_device)
{
struct selection_offer *offer = data;
struct input *input;
char **p, **end;
if (input_device == NULL) {
printf("selection offer retracted %p\n", selection_offer);
input = offer->input;
input->offer = NULL;
wl_selection_offer_destroy(selection_offer);
wl_array_release(&offer->types);
free(offer);
return;
}
input = wl_input_device_get_user_data(input_device);
printf("new selection offer %p:", selection_offer);
offer->input = input;
input->offer = offer;
end = offer->types.data + offer->types.size;
for (p = offer->types.data; p < end; p++)
printf(" %s", *p);
printf("\n");
}
struct wl_selection_offer_listener selection_offer_listener = {
selection_offer_offer,
selection_offer_keyboard_focus
};
static void
add_selection_offer(struct display *d, uint32_t id)
{
struct selection_offer *offer;
offer = malloc(sizeof *offer);
if (offer == NULL)
return;
offer->offer = wl_selection_offer_create(d->display, id);
offer->display = d;
wl_array_init(&offer->types);
offer->input = NULL;
wl_selection_offer_add_listener(offer->offer,
&selection_offer_listener, offer);
}
static void
display_handle_global(struct wl_display *display, uint32_t id,
const char *interface, uint32_t version, void *data)
@ -1338,6 +1450,8 @@ display_handle_global(struct wl_display *display, uint32_t id,
wl_drm_add_listener(d->drm, &drm_listener, d);
} else if (strcmp(interface, "shm") == 0) {
d->shm = wl_shm_create(display, id);
} else if (strcmp(interface, "selection_offer") == 0) {
add_selection_offer(d, id);
} else if (d->global_handler) {
d->global_handler(d, interface, id, version);
}
@ -1534,6 +1648,12 @@ display_get_egl_display(struct display *d)
return d->dpy;
}
struct wl_shell *
display_get_shell(struct display *display)
{
return display->shell;
}
void
display_run(struct display *d)
{

@ -47,6 +47,9 @@ display_get_display(struct display *display);
struct wl_compositor *
display_get_compositor(struct display *display);
struct wl_shell *
display_get_shell(struct display *display);
#ifdef EGL_NO_DISPLAY
EGLDisplay
display_get_egl_display(struct display *d);
@ -243,4 +246,10 @@ input_get_modifiers(struct input *input);
struct wl_input_device *
input_get_input_device(struct input *input);
int
input_offers_mime_type(struct input *input, const char *type);
int
input_receive_mime_type(struct input *input, const char *type);
#endif

Loading…
Cancel
Save