editor: implement Cut,Copy,Paste

weston-editor is the only stock client spawning the virtual
keyboard ; which means it may be the only client able to
obtain some special characters (depending on the user's
keyboard layout).

If we implement Cut, Copy and Paste, the user has now a way
to copy such characters to other useful clients (such as
weston-terminal). Plus, it demonstrates text data exchange
between two clients of different nature.

Functionality is implemented in a right-click menu and the
Ctrl+Shift+X/C/V bindings, just as in weston-terminal.

Signed-off-by: Manuel Bachmann <manuel.bachmann@open.eurogiciel.org>
Reviewed-by: Bryce Harrington <bryce@osg.samsung.com>
Tested-by: Bryce Harrington <bryce@osg.samsung.com>
dev
Manuel Bachmann 10 years ago committed by Bryce Harrington
parent 71c9ac6c7f
commit 22f3430175
  1. 169
      clients/editor.c

@ -28,6 +28,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdbool.h> #include <stdbool.h>
#include <unistd.h>
#include <linux/input.h> #include <linux/input.h>
#include <cairo.h> #include <cairo.h>
@ -76,6 +77,8 @@ struct text_entry {
struct editor { struct editor {
struct wl_text_input_manager *text_input_manager; struct wl_text_input_manager *text_input_manager;
struct wl_data_source *selection;
char *selected_text;
struct display *display; struct display *display;
struct window *window; struct window *window;
struct widget *widget; struct widget *widget;
@ -554,6 +557,128 @@ static const struct wl_text_input_listener text_input_listener = {
text_input_text_direction text_input_text_direction
}; };
static void
data_source_target(void *data,
struct wl_data_source *source, const char *mime_type)
{
}
static void
data_source_send(void *data,
struct wl_data_source *source,
const char *mime_type, int32_t fd)
{
struct editor *editor = data;
write(fd, editor->selected_text, strlen(editor->selected_text) + 1);
}
static void
data_source_cancelled(void *data, struct wl_data_source *source)
{
wl_data_source_destroy(source);
}
static const struct wl_data_source_listener data_source_listener = {
data_source_target,
data_source_send,
data_source_cancelled
};
static void
paste_func(void *buffer, size_t len,
int32_t x, int32_t y, void *data)
{
struct editor *editor = data;
struct text_entry *entry = editor->active_entry;
char *pasted_text;
if (!entry)
return;
pasted_text = malloc(len + 1);
strncpy(pasted_text, buffer, len);
pasted_text[len] = '\0';
text_entry_insert_at_cursor(entry, pasted_text, 0, 0);
free(pasted_text);
}
static void
editor_copy_cut(struct editor *editor, struct input *input, bool cut)
{
struct text_entry *entry = editor->active_entry;
if (!entry)
return;
if (entry->cursor != entry->anchor) {
int start_index = MIN(entry->cursor, entry->anchor);
int end_index = MAX(entry->cursor, entry->anchor);
int len = end_index - start_index;
editor->selected_text = realloc(editor->selected_text, len + 1);
strncpy(editor->selected_text, &entry->text[start_index], len);
editor->selected_text[len] = '\0';
if (cut)
text_entry_delete_text(entry, start_index, len);
editor->selection =
display_create_data_source(editor->display);
wl_data_source_offer(editor->selection,
"text/plain;charset=utf-8");
wl_data_source_add_listener(editor->selection,
&data_source_listener, editor);
input_set_selection(input, editor->selection,
display_get_serial(editor->display));
}
}
static void
editor_paste(struct editor *editor, struct input *input)
{
input_receive_selection_data(input,
"text/plain;charset=utf-8",
paste_func, editor);
}
static void
menu_func(void *data, struct input *input, int index)
{
struct window *window = data;
struct editor *editor = window_get_user_data(window);
fprintf(stderr, "picked entry %d\n", index);
switch (index) {
case 0:
editor_copy_cut(editor, input, true);
break;
case 1:
editor_copy_cut(editor, input, false);
break;
case 2:
editor_paste(editor, input);
break;
}
}
static void
show_menu(struct editor *editor, struct input *input, uint32_t time)
{
int32_t x, y;
static const char *entries[] = {
"Cut", "Copy", "Paste"
};
input_get_position(input, &x, &y);
window_show_menu(editor->display, input, time, editor->window,
x + 10, y + 20, menu_func,
entries, ARRAY_LENGTH(entries));
}
static struct text_entry* static struct text_entry*
text_entry_create(struct editor *editor, const char *text) text_entry_create(struct editor *editor, const char *text)
{ {
@ -1123,13 +1248,18 @@ text_entry_button_handler(struct widget *widget,
editor = window_get_user_data(entry->window); editor = window_get_user_data(entry->window);
if (button == BTN_LEFT) { switch (button) {
case BTN_LEFT:
entry->button_pressed = (state == WL_POINTER_BUTTON_STATE_PRESSED); entry->button_pressed = (state == WL_POINTER_BUTTON_STATE_PRESSED);
if (state == WL_POINTER_BUTTON_STATE_PRESSED) if (state == WL_POINTER_BUTTON_STATE_PRESSED)
input_grab(input, entry->widget, button); input_grab(input, entry->widget, button);
else else
input_ungrab(input); input_ungrab(input);
break;
case BTN_RIGHT:
if (state == WL_POINTER_BUTTON_STATE_PRESSED)
show_menu(editor, input, time);
break;
} }
if (text_entry_has_preedit(entry)) { if (text_entry_has_preedit(entry)) {
@ -1139,7 +1269,8 @@ text_entry_button_handler(struct widget *widget,
return; return;
} }
if (state == WL_POINTER_BUTTON_STATE_PRESSED) { if (state == WL_POINTER_BUTTON_STATE_PRESSED &&
button == BTN_LEFT) {
struct wl_seat *seat = input_get_seat(input); struct wl_seat *seat = input_get_seat(input);
text_entry_activate(entry, seat); text_entry_activate(entry, seat);
@ -1216,6 +1347,25 @@ keyboard_focus_handler(struct window *window,
window_schedule_redraw(editor->window); window_schedule_redraw(editor->window);
} }
static int
handle_bound_key(struct editor *editor,
struct input *input, uint32_t sym, uint32_t time)
{
switch (sym) {
case XKB_KEY_X:
editor_copy_cut(editor, input, true);
return 1;
case XKB_KEY_C:
editor_copy_cut(editor, input, false);
return 1;
case XKB_KEY_V:
editor_paste(editor, input);
return 1;
default:
return 0;
}
}
static void static void
key_handler(struct window *window, key_handler(struct window *window,
struct input *input, uint32_t time, struct input *input, uint32_t time,
@ -1226,6 +1376,7 @@ key_handler(struct window *window,
struct text_entry *entry; struct text_entry *entry;
const char *new_char; const char *new_char;
char text[16]; char text[16];
uint32_t modifiers;
if (!editor->active_entry) if (!editor->active_entry)
return; return;
@ -1235,6 +1386,12 @@ key_handler(struct window *window,
if (state != WL_KEYBOARD_KEY_STATE_PRESSED) if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
return; return;
modifiers = input_get_modifiers(input);
if ((modifiers & MOD_CONTROL_MASK) &&
(modifiers & MOD_SHIFT_MASK) &&
handle_bound_key(editor, input, sym, time))
return;
switch (sym) { switch (sym) {
case XKB_KEY_BackSpace: case XKB_KEY_BackSpace:
text_entry_commit_and_reset(entry); text_entry_commit_and_reset(entry);
@ -1374,6 +1531,8 @@ main(int argc, char *argv[])
editor.editor = text_entry_create(&editor, "Numeric"); editor.editor = text_entry_create(&editor, "Numeric");
editor.editor->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_NUMBER; editor.editor->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_NUMBER;
editor.editor->click_to_show = click_to_show; editor.editor->click_to_show = click_to_show;
editor.selection = NULL;
editor.selected_text = NULL;
window_set_title(editor.window, "Text Editor"); window_set_title(editor.window, "Text Editor");
window_set_key_handler(editor.window, key_handler); window_set_key_handler(editor.window, key_handler);
@ -1390,6 +1549,10 @@ main(int argc, char *argv[])
display_run(editor.display); display_run(editor.display);
if (editor.selected_text)
free(editor.selected_text);
if (editor.selection)
wl_data_source_destroy(editor.selection);
text_entry_destroy(editor.entry); text_entry_destroy(editor.entry);
text_entry_destroy(editor.editor); text_entry_destroy(editor.editor);
widget_destroy(editor.widget); widget_destroy(editor.widget);

Loading…
Cancel
Save