[PATCH weston] editor: implement Cut,Copy,Paste

Manuel Bachmann manuel.bachmann at open.eurogiciel.org
Sun Mar 29 16:57:44 PDT 2015


From: Manuel Bachmann <manuel.bachmann at open.eurogiciel.org>

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 at open.eurogiciel.org>
---
 clients/editor.c | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 166 insertions(+), 3 deletions(-)

diff --git a/clients/editor.c b/clients/editor.c
index 9299a05..29cab34 100644
--- a/clients/editor.c
+++ b/clients/editor.c
@@ -28,6 +28,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <stdbool.h>
+#include <unistd.h>
 
 #include <linux/input.h>
 #include <cairo.h>
@@ -76,6 +77,8 @@ struct text_entry {
 
 struct editor {
 	struct wl_text_input_manager *text_input_manager;
+	struct wl_data_source *selection;
+	char *selected_text;
 	struct display *display;
 	struct window *window;
 	struct widget *widget;
@@ -554,6 +557,128 @@ static const struct wl_text_input_listener text_input_listener = {
 	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*
 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);
 
-	if (button == BTN_LEFT) {
+	switch (button) {
+	case BTN_LEFT:
 		entry->button_pressed = (state == WL_POINTER_BUTTON_STATE_PRESSED);
-
 		if (state == WL_POINTER_BUTTON_STATE_PRESSED)
 			input_grab(input, entry->widget, button);
 		else
 			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)) {
@@ -1139,7 +1269,8 @@ text_entry_button_handler(struct widget *widget,
 			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);
 
 		text_entry_activate(entry, seat);
@@ -1216,6 +1347,25 @@ keyboard_focus_handler(struct window *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
 key_handler(struct window *window,
 	    struct input *input, uint32_t time,
@@ -1226,6 +1376,7 @@ key_handler(struct window *window,
 	struct text_entry *entry;
 	const char *new_char;
 	char text[16];
+	uint32_t modifiers;
 
 	if (!editor->active_entry)
 		return;
@@ -1235,6 +1386,12 @@ key_handler(struct window *window,
 	if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
 		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) {
 		case XKB_KEY_BackSpace:
 			text_entry_commit_and_reset(entry);
@@ -1374,6 +1531,8 @@ main(int argc, char *argv[])
 	editor.editor = text_entry_create(&editor, "Numeric");
 	editor.editor->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_NUMBER;
 	editor.editor->click_to_show = click_to_show;
+	editor.selection = NULL;
+	editor.selected_text = NULL;
 
 	window_set_title(editor.window, "Text Editor");
 	window_set_key_handler(editor.window, key_handler);
@@ -1390,6 +1549,10 @@ main(int argc, char *argv[])
 
 	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.editor);
 	widget_destroy(editor.widget);
-- 
1.8.3.1



More information about the wayland-devel mailing list