#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
+#include <unistd.h>
#include <linux/input.h>
#include <cairo.h>
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;
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)
{
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)) {
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);
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,
struct text_entry *entry;
const char *new_char;
char text[16];
+ uint32_t modifiers;
if (!editor->active_entry)
return;
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);
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);
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);