wlt: terminal: implement copy/paste support

This implements copy/paste support for the terminal widgets via the
recently introduced helpers.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
This commit is contained in:
David Herrmann 2012-10-07 15:21:46 +02:00
parent 166dcc5a09
commit 7f1bff5cc6
3 changed files with 168 additions and 0 deletions

View File

@ -240,6 +240,10 @@ static void print_help()
"\t Shortcut to increase font size\n"
"\t --grab-zoom-out <grab> [<Ctrl>minus]\n"
"\t Shortcut to decrease font size\n"
"\t --grab-copy <grab> [<Logo>c]\n"
"\t Copy selected text\n"
"\t --grab-paste <grab> [<Logo>v]\n"
"\t Paste selection buffer\n"
"\n"
"Font Options:\n"
"\t --font-engine <engine> [pango]\n"
@ -343,6 +347,16 @@ static struct conf_grab def_grab_zoom_out = {
.keysym = XKB_KEY_minus,
};
static struct conf_grab def_grab_copy = {
.mods = SHL_LOGO_MASK,
.keysym = XKB_KEY_c,
};
static struct conf_grab def_grab_paste = {
.mods = SHL_LOGO_MASK,
.keysym = XKB_KEY_v,
};
struct conf_option options[] = {
CONF_OPTION_BOOL('h', "help", aftercheck_help, &wlt_conf.help, false),
CONF_OPTION_BOOL('v', "verbose", NULL, &wlt_conf.verbose, false),
@ -361,6 +375,8 @@ struct conf_option options[] = {
CONF_OPTION_GRAB(0, "grab-fullscreen", NULL, &wlt_conf.grab_fullscreen, &def_grab_fullscreen),
CONF_OPTION_GRAB(0, "grab-zoom-in", NULL, &wlt_conf.grab_zoom_in, &def_grab_zoom_in),
CONF_OPTION_GRAB(0, "grab-zoom-out", NULL, &wlt_conf.grab_zoom_out, &def_grab_zoom_out),
CONF_OPTION_GRAB(0, "grab-copy", NULL, &wlt_conf.grab_copy, &def_grab_copy),
CONF_OPTION_GRAB(0, "grab-paste", NULL, &wlt_conf.grab_paste, &def_grab_paste),
CONF_OPTION_STRING(0, "font-engine", NULL, &wlt_conf.font_engine, "pango"),
CONF_OPTION_UINT(0, "font-size", NULL, &wlt_conf.font_size, 12),

View File

@ -71,6 +71,10 @@ struct wlt_conf_t {
struct conf_grab *grab_zoom_in;
/* font-zoom-out grab */
struct conf_grab *grab_zoom_out;
/* copy grab */
struct conf_grab *grab_copy;
/* paste grab */
struct conf_grab *grab_paste;
/* font engine */
char *font_engine;

View File

@ -32,6 +32,7 @@
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <wayland-client.h>
#include <xkbcommon/xkbcommon.h>
#include "conf.h"
@ -52,6 +53,7 @@
struct wlt_terminal {
struct ev_eloop *eloop;
struct wlt_window *wnd;
struct wlt_display *disp;
struct wlt_widget *widget;
struct wlt_shm_buffer buffer;
struct wlt_rect alloc;
@ -76,6 +78,12 @@ struct wlt_terminal {
bool selection_started;
int sel_start_x;
int sel_start_y;
int paste_fd;
struct ev_fd *paste;
struct wl_data_source *copy;
char *copy_buf;
int copy_len;
};
static int draw_cell(struct tsm_screen *scr,
@ -318,6 +326,77 @@ static void widget_prepare_resize(struct wlt_widget *widget,
}
}
static void paste_event(struct ev_fd *fd, int mask, void *data)
{
struct wlt_terminal *term = data;
char buf[4096];
int ret;
if (mask & EV_READABLE) {
ret = read(term->paste_fd, buf, sizeof(buf));
if (ret == 0) {
goto err_close;
} else if (ret < 0) {
if (errno == EAGAIN)
return;
log_error("error on paste-fd (%d): %m", errno);
goto err_close;
}
kmscon_pty_write(term->pty, buf, ret);
return;
}
if (mask & EV_ERR) {
log_error("error on paste FD");
goto err_close;
}
if (mask & EV_HUP)
goto err_close;
return;
err_close:
close(term->paste_fd);
ev_eloop_rm_fd(term->paste);
term->paste = NULL;
}
static void copy_target(void *data, struct wl_data_source *w_source,
const char *target)
{
}
static void copy_send(void *data, struct wl_data_source *w_source,
const char *mime, int32_t fd)
{
struct wlt_terminal *term = data;
int ret;
/* TODO: make this non-blocking */
ret = write(fd, term->copy_buf, term->copy_len);
if (ret != term->copy_len)
log_warning("cannot write whole selection: %d/%d", ret,
term->copy_len);
close(fd);
}
static void copy_cancelled(void *data, struct wl_data_source *w_source)
{
struct wlt_terminal *term = data;
wl_data_source_destroy(w_source);
if (term->copy == w_source)
term->copy = NULL;
}
static const struct wl_data_source_listener copy_listener = {
.target = copy_target,
.send = copy_send,
.cancelled = copy_cancelled,
};
static bool widget_key(struct wlt_widget *widget, unsigned int mask,
uint32_t sym, uint32_t state, bool handled, void *data)
{
@ -393,6 +472,70 @@ static bool widget_key(struct wlt_widget *widget, unsigned int mask,
return true;
}
if (SHL_HAS_BITS(mask, wlt_conf.grab_paste->mods) &&
sym == wlt_conf.grab_paste->keysym) {
if (term->paste) {
log_debug("cannot paste selection, previous paste still in progress");
return true;
}
ret = wlt_display_get_selection_fd(term->disp,
"text/plain;charset=utf-8");
if (ret == -ENOENT) {
log_debug("no selection to paste");
return true;
} else if (ret == -EAGAIN) {
log_debug("unknown mime-time for pasting selection");
return true;
} else if (ret < 0) {
log_error("cannot paste selection: %d", ret);
return true;
}
term->paste_fd = ret;
ret = ev_eloop_new_fd(term->eloop, &term->paste, ret,
EV_READABLE, paste_event, term);
if (ret) {
close(ret);
log_error("cannot create eloop fd: %d", ret);
return true;
}
return true;
}
if (SHL_HAS_BITS(mask, wlt_conf.grab_copy->mods) &&
sym == wlt_conf.grab_copy->keysym) {
if (term->copy) {
wl_data_source_destroy(term->copy);
free(term->copy_buf);
term->copy = NULL;
}
ret = wlt_display_new_data_source(term->disp, &term->copy);
if (ret) {
log_error("cannot create data source");
return true;
}
term->copy_len = tsm_screen_selection_copy(term->scr,
&term->copy_buf);
if (term->copy_len < 0) {
if (term->copy_len != -ENOENT)
log_error("cannot copy TSM selection: %d",
term->copy_len);
wl_data_source_destroy(term->copy);
term->copy = NULL;
return true;
}
wl_data_source_offer(term->copy, "text/plain;charset=utf-8");
wl_data_source_add_listener(term->copy, &copy_listener, term);
wlt_display_set_selection(term->disp, term->copy);
return true;
}
if (tsm_vte_handle_keyboard(term->vte, sym, mask, ucs4)) {
tsm_screen_sb_reset(term->scr);
wlt_window_schedule_redraw(term->wnd);
@ -516,6 +659,10 @@ static void widget_destroy(struct wlt_widget *widget, void *data)
{
struct wlt_terminal *term = data;
if (term->paste) {
ev_eloop_rm_fd(term->paste);
close(term->paste_fd);
}
tsm_vte_unref(term->vte);
tsm_screen_unref(term->scr);
free(term);
@ -534,6 +681,7 @@ int wlt_terminal_new(struct wlt_terminal **out, struct wlt_window *wnd)
return -ENOMEM;
memset(term, 0, sizeof(*term));
term->wnd = wnd;
term->disp = wlt_window_get_display(wnd);
term->eloop = wlt_window_get_eloop(wnd);
term->cols = 80;
term->rows = 24;