blob: 311bdb5da721578900a3edccf23fa1b7c595d029 [file] [log] [blame]
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001/*
2 * Copyright © 2012 Openismus GmbH
Jan Arne Petersen4c265182012-09-09 23:08:30 +02003 * Copyright © 2012 Intel Corporation
Jan Arne Petersencba9e472012-06-21 21:52:19 +02004 *
Bryce Harrington1f6b0d12015-06-10 22:48:59 -07005 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
Jan Arne Petersencba9e472012-06-21 21:52:19 +020011 *
Bryce Harrington1f6b0d12015-06-10 22:48:59 -070012 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
Jan Arne Petersencba9e472012-06-21 21:52:19 +020023 */
24
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010025#include "config.h"
26
Philipp Brüschweiler591cfca2012-07-11 22:25:29 +020027#include <assert.h>
Jan Arne Petersencba9e472012-06-21 21:52:19 +020028#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +020031#include <stdbool.h>
Manuel Bachmann22f34302015-03-30 01:57:44 +020032#include <unistd.h>
Jan Arne Petersencba9e472012-06-21 21:52:19 +020033
34#include <linux/input.h>
35#include <cairo.h>
36
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010037#include <pango/pangocairo.h>
38
Jon Cruz35b2eaa2015-06-15 15:37:08 -070039#include "shared/helpers.h"
Jan Arne Petersencba9e472012-06-21 21:52:19 +020040#include "window.h"
Jonas Ådahl3bcba342015-11-17 16:00:29 +080041#include "text-input-unstable-v1-client-protocol.h"
Jan Arne Petersencba9e472012-06-21 21:52:19 +020042
43struct text_entry {
44 struct widget *widget;
Jan Arne Petersene829adc2012-08-10 16:47:22 +020045 struct window *window;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020046 char *text;
47 int active;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +020048 uint32_t cursor;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +020049 uint32_t anchor;
Jan Arne Petersen46535312013-01-16 21:26:38 +010050 struct {
51 char *text;
52 int32_t cursor;
53 char *commit;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010054 PangoAttrList *attr_list;
Jan Arne Petersen46535312013-01-16 21:26:38 +010055 } preedit;
56 struct {
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010057 PangoAttrList *attr_list;
Jan Arne Petersen46535312013-01-16 21:26:38 +010058 int32_t cursor;
59 } preedit_info;
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +010060 struct {
61 int32_t cursor;
62 int32_t anchor;
Jan Arne Petersen919bc142013-04-18 16:47:34 +020063 uint32_t delete_index;
64 uint32_t delete_length;
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +020065 bool invalid_delete;
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +010066 } pending_commit;
Jonas Ådahl3bcba342015-11-17 16:00:29 +080067 struct zwp_text_input_v1 *text_input;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010068 PangoLayout *layout;
Jan Arne Petersencd997062012-11-18 19:06:44 +010069 struct {
70 xkb_mod_mask_t shift_mask;
71 } keysym;
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +010072 uint32_t serial;
Jan Arne Petersen00191c72013-04-18 16:47:33 +020073 uint32_t reset_serial;
Jan Arne Petersen0558a932013-01-16 21:26:45 +010074 uint32_t content_purpose;
Jan Arne Petersen61381972013-01-31 15:52:21 +010075 uint32_t click_to_show;
Jan Arne Petersen9d419132013-04-18 16:47:16 +020076 char *preferred_language;
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +020077 bool button_pressed;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020078};
79
80struct editor {
Jonas Ådahl3bcba342015-11-17 16:00:29 +080081 struct zwp_text_input_manager_v1 *text_input_manager;
Manuel Bachmann22f34302015-03-30 01:57:44 +020082 struct wl_data_source *selection;
83 char *selected_text;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020084 struct display *display;
85 struct window *window;
86 struct widget *widget;
87 struct text_entry *entry;
88 struct text_entry *editor;
Rob Bradford9d1d32b2012-11-18 19:06:49 +010089 struct text_entry *active_entry;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020090};
91
Jan Arne Petersen6345faa2012-11-05 03:26:39 +010092static const char *
Jan Arne Petersen6345faa2012-11-05 03:26:39 +010093utf8_end_char(const char *p)
94{
95 while ((*p & 0xc0) == 0x80)
96 p++;
97 return p;
98}
99
100static const char *
Jan Arne Petersen68516862013-04-18 16:47:42 +0200101utf8_prev_char(const char *s, const char *p)
102{
103 for (--p; p >= s; --p) {
104 if ((*p & 0xc0) != 0x80)
105 return p;
106 }
107 return NULL;
108}
109
110static const char *
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100111utf8_next_char(const char *p)
112{
113 if (*p != 0)
114 return utf8_end_char(++p);
115 return NULL;
116}
117
Manuel Bachmann8986c182014-04-18 12:50:14 +0200118static void
119move_up(const char *p, uint32_t *cursor)
120{
121 const char *posr, *posr_i;
122 char text[16];
123
124 xkb_keysym_to_utf8(XKB_KEY_Return, text, sizeof(text));
125
126 posr = strstr(p, text);
127 while (posr) {
128 if (*cursor > (unsigned)(posr-p)) {
129 posr_i = strstr(posr+1, text);
130 if (!posr_i || !(*cursor > (unsigned)(posr_i-p))) {
131 *cursor = posr-p;
132 break;
133 }
134 posr = posr_i;
135 } else {
136 break;
137 }
138 }
139}
140
141static void
142move_down(const char *p, uint32_t *cursor)
143{
144 const char *posr;
145 char text[16];
146
147 xkb_keysym_to_utf8(XKB_KEY_Return, text, sizeof(text));
148
149 posr = strstr(p, text);
150 while (posr) {
151 if (*cursor <= (unsigned)(posr-p)) {
152 *cursor = posr-p + 1;
153 break;
154 }
155 posr = strstr(posr+1, text);
156 }
157}
158
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200159static void text_entry_redraw_handler(struct widget *widget, void *data);
160static void text_entry_button_handler(struct widget *widget,
161 struct input *input, uint32_t time,
162 uint32_t button,
163 enum wl_pointer_button_state state, void *data);
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -0800164static void text_entry_touch_handler(struct widget *widget, struct input *input,
165 uint32_t serial, uint32_t time, int32_t id,
166 float tx, float ty, void *data);
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +0200167static int text_entry_motion_handler(struct widget *widget,
168 struct input *input, uint32_t time,
169 float x, float y, void *data);
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100170static void text_entry_insert_at_cursor(struct text_entry *entry, const char *text,
171 int32_t cursor, int32_t anchor);
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200172static void text_entry_set_preedit(struct text_entry *entry,
173 const char *preedit_text,
174 int preedit_cursor);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200175static void text_entry_delete_text(struct text_entry *entry,
176 uint32_t index, uint32_t length);
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200177static void text_entry_delete_selected_text(struct text_entry *entry);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100178static void text_entry_reset_preedit(struct text_entry *entry);
179static void text_entry_commit_and_reset(struct text_entry *entry);
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200180static void text_entry_get_cursor_rectangle(struct text_entry *entry, struct rectangle *rectangle);
181static void text_entry_update(struct text_entry *entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200182
183static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200184text_input_commit_string(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800185 struct zwp_text_input_v1 *text_input,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100186 uint32_t serial,
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100187 const char *text)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200188{
189 struct text_entry *entry = data;
190
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200191 if ((entry->serial - serial) > (entry->serial - entry->reset_serial)) {
192 fprintf(stderr, "Ignore commit. Serial: %u, Current: %u, Reset: %u\n",
193 serial, entry->serial, entry->reset_serial);
194 return;
195 }
196
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200197 if (entry->pending_commit.invalid_delete) {
198 fprintf(stderr, "Ignore commit. Invalid previous delete_surrounding event.\n");
199 memset(&entry->pending_commit, 0, sizeof entry->pending_commit);
200 return;
201 }
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100202
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200203 text_entry_reset_preedit(entry);
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200204
205 if (entry->pending_commit.delete_length) {
206 text_entry_delete_text(entry,
207 entry->pending_commit.delete_index,
208 entry->pending_commit.delete_length);
Jan Arne Petersena96953d2013-05-30 13:57:02 +0200209 } else {
210 text_entry_delete_selected_text(entry);
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200211 }
212
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100213 text_entry_insert_at_cursor(entry, text,
214 entry->pending_commit.cursor,
215 entry->pending_commit.anchor);
216
217 memset(&entry->pending_commit, 0, sizeof entry->pending_commit);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200218
219 widget_schedule_redraw(entry->widget);
220}
221
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200222static void
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200223clear_pending_preedit(struct text_entry *entry)
224{
225 memset(&entry->pending_commit, 0, sizeof entry->pending_commit);
226
227 pango_attr_list_unref(entry->preedit_info.attr_list);
228
229 entry->preedit_info.cursor = 0;
230 entry->preedit_info.attr_list = NULL;
231
232 memset(&entry->preedit_info, 0, sizeof entry->preedit_info);
233}
234
235static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200236text_input_preedit_string(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800237 struct zwp_text_input_v1 *text_input,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100238 uint32_t serial,
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200239 const char *text,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100240 const char *commit)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200241{
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200242 struct text_entry *entry = data;
243
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200244 if ((entry->serial - serial) > (entry->serial - entry->reset_serial)) {
245 fprintf(stderr, "Ignore preedit_string. Serial: %u, Current: %u, Reset: %u\n",
246 serial, entry->serial, entry->reset_serial);
247 clear_pending_preedit(entry);
248 return;
249 }
250
251 if (entry->pending_commit.invalid_delete) {
252 fprintf(stderr, "Ignore preedit_string. Invalid previous delete_surrounding event.\n");
253 clear_pending_preedit(entry);
254 return;
255 }
256
Jan Arne Petersena96953d2013-05-30 13:57:02 +0200257 if (entry->pending_commit.delete_length) {
258 text_entry_delete_text(entry,
259 entry->pending_commit.delete_index,
260 entry->pending_commit.delete_length);
261 } else {
262 text_entry_delete_selected_text(entry);
263 }
Jan Arne Petersena96953d2013-05-30 13:57:02 +0200264
Jan Arne Petersen46535312013-01-16 21:26:38 +0100265 text_entry_set_preedit(entry, text, entry->preedit_info.cursor);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100266 entry->preedit.commit = strdup(commit);
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200267 entry->preedit.attr_list = pango_attr_list_ref(entry->preedit_info.attr_list);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100268
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200269 clear_pending_preedit(entry);
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200270
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200271 text_entry_update(entry);
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200272
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200273 widget_schedule_redraw(entry->widget);
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200274}
275
276static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200277text_input_delete_surrounding_text(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800278 struct zwp_text_input_v1 *text_input,
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200279 int32_t index,
280 uint32_t length)
281{
282 struct text_entry *entry = data;
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200283 uint32_t text_length;
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200284
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200285 entry->pending_commit.delete_index = entry->cursor + index;
286 entry->pending_commit.delete_length = length;
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200287 entry->pending_commit.invalid_delete = false;
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200288
Jan Arne Petersen68516862013-04-18 16:47:42 +0200289 text_length = strlen(entry->text);
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200290
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200291 if (entry->pending_commit.delete_index > text_length ||
292 length > text_length ||
Jan Arne Petersen895a1282013-05-30 13:57:04 +0200293 entry->pending_commit.delete_index + length > text_length) {
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200294 fprintf(stderr, "delete_surrounding_text: Invalid index: %d," \
295 "length %u'; cursor: %u text length: %u\n", index, length, entry->cursor, text_length);
296 entry->pending_commit.invalid_delete = true;
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200297 return;
298 }
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200299}
300
301static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200302text_input_cursor_position(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800303 struct zwp_text_input_v1 *text_input,
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100304 int32_t index,
305 int32_t anchor)
306{
307 struct text_entry *entry = data;
308
309 entry->pending_commit.cursor = index;
310 entry->pending_commit.anchor = anchor;
311}
312
313static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200314text_input_preedit_styling(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800315 struct zwp_text_input_v1 *text_input,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100316 uint32_t index,
317 uint32_t length,
318 uint32_t style)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200319{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100320 struct text_entry *entry = data;
321 PangoAttribute *attr1 = NULL;
322 PangoAttribute *attr2 = NULL;
323
324 if (!entry->preedit_info.attr_list)
325 entry->preedit_info.attr_list = pango_attr_list_new();
326
327 switch (style) {
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800328 case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_DEFAULT:
329 case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_UNDERLINE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100330 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
331 break;
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800332 case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_INCORRECT:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100333 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_ERROR);
334 attr2 = pango_attr_underline_color_new(65535, 0, 0);
335 break;
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800336 case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_SELECTION:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100337 attr1 = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
338 attr2 = pango_attr_foreground_new(65535, 65535, 65535);
339 break;
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800340 case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_HIGHLIGHT:
341 case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_ACTIVE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100342 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
343 attr2 = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
344 break;
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800345 case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_INACTIVE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100346 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
347 attr2 = pango_attr_foreground_new(0.3 * 65535, 0.3 * 65535, 0.3 * 65535);
348 break;
349 }
350
351 if (attr1) {
352 attr1->start_index = entry->cursor + index;
353 attr1->end_index = entry->cursor + index + length;
354 pango_attr_list_insert(entry->preedit_info.attr_list, attr1);
355 }
356
357 if (attr2) {
358 attr2->start_index = entry->cursor + index;
359 attr2->end_index = entry->cursor + index + length;
360 pango_attr_list_insert(entry->preedit_info.attr_list, attr2);
361 }
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200362}
363
364static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200365text_input_preedit_cursor(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800366 struct zwp_text_input_v1 *text_input,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100367 int32_t index)
368{
369 struct text_entry *entry = data;
370
371 entry->preedit_info.cursor = index;
372}
373
374static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200375text_input_modifiers_map(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800376 struct zwp_text_input_v1 *text_input,
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100377 struct wl_array *map)
378{
Jan Arne Petersencd997062012-11-18 19:06:44 +0100379 struct text_entry *entry = data;
380
381 entry->keysym.shift_mask = keysym_modifiers_get_mask(map, "Shift");
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100382}
383
384static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200385text_input_keysym(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800386 struct zwp_text_input_v1 *text_input,
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100387 uint32_t serial,
388 uint32_t time,
389 uint32_t key,
390 uint32_t state,
391 uint32_t modifiers)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200392{
Jan Arne Petersen8aba11d2012-09-17 15:28:07 +0200393 struct text_entry *entry = data;
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100394 const char *new_char;
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200395
Jan Arne Petersencd997062012-11-18 19:06:44 +0100396 if (key == XKB_KEY_Left ||
397 key == XKB_KEY_Right) {
398 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
399 return;
400
401 if (key == XKB_KEY_Left)
402 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
403 else
404 new_char = utf8_next_char(entry->text + entry->cursor);
405
406 if (new_char != NULL) {
407 entry->cursor = new_char - entry->text;
Jan Arne Petersencd997062012-11-18 19:06:44 +0100408 }
409
Jan Arne Petersen68516862013-04-18 16:47:42 +0200410 if (!(modifiers & entry->keysym.shift_mask))
411 entry->anchor = entry->cursor;
412 widget_schedule_redraw(entry->widget);
413
Jan Arne Petersencd997062012-11-18 19:06:44 +0100414 return;
415 }
416
Manuel Bachmann8986c182014-04-18 12:50:14 +0200417 if (key == XKB_KEY_Up ||
418 key == XKB_KEY_Down) {
419 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
420 return;
421
422 if (key == XKB_KEY_Up)
423 move_up(entry->text, &entry->cursor);
424 else
425 move_down(entry->text, &entry->cursor);
426
427 if (!(modifiers & entry->keysym.shift_mask))
428 entry->anchor = entry->cursor;
429 widget_schedule_redraw(entry->widget);
430
431 return;
432 }
433
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100434 if (key == XKB_KEY_BackSpace) {
435 const char *start, *end;
436
Jan Arne Petersendfd34462013-04-18 16:47:26 +0200437 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
438 return;
439
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100440 text_entry_commit_and_reset(entry);
441
442 start = utf8_prev_char(entry->text, entry->text + entry->cursor);
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100443 if (start == NULL)
444 return;
445
Daiki Uenob08b3292013-06-28 18:59:44 +0900446 end = utf8_next_char(start);
447
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100448 text_entry_delete_text(entry,
449 start - entry->text,
450 end - start);
451
452 return;
453 }
454
Manuel Bachmann8986c182014-04-18 12:50:14 +0200455 if (key == XKB_KEY_Tab ||
456 key == XKB_KEY_KP_Enter ||
457 key == XKB_KEY_Return) {
458 char text[16];
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200459
Manuel Bachmann8986c182014-04-18 12:50:14 +0200460 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
461 return;
462
463 xkb_keysym_to_utf8(key, text, sizeof(text));
464
465 text_entry_insert_at_cursor(entry, text, 0, 0);
466
467 return;
468 }
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200469}
470
471static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200472text_input_enter(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800473 struct zwp_text_input_v1 *text_input,
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200474 struct wl_surface *surface)
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200475{
476 struct text_entry *entry = data;
477
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200478 if (surface != window_get_wl_surface(entry->window))
479 return;
480
Derek Foreman237a6842014-12-17 09:43:58 -0600481 entry->active++;
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200482
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200483 text_entry_update(entry);
484 entry->reset_serial = entry->serial;
485
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200486 widget_schedule_redraw(entry->widget);
487}
488
489static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200490text_input_leave(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800491 struct zwp_text_input_v1 *text_input)
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200492{
493 struct text_entry *entry = data;
494
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100495 text_entry_commit_and_reset(entry);
Derek Foreman237a6842014-12-17 09:43:58 -0600496 entry->active--;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100497
Derek Foreman237a6842014-12-17 09:43:58 -0600498 if (!entry->active)
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800499 zwp_text_input_v1_hide_input_panel(text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100500
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200501 widget_schedule_redraw(entry->widget);
502}
503
Jan Arne Petersen61381972013-01-31 15:52:21 +0100504static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200505text_input_input_panel_state(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800506 struct zwp_text_input_v1 *text_input,
Jan Arne Petersen61381972013-01-31 15:52:21 +0100507 uint32_t state)
508{
509}
510
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200511static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200512text_input_language(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800513 struct zwp_text_input_v1 *text_input,
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200514 uint32_t serial,
515 const char *language)
516{
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200517 fprintf(stderr, "input language is %s \n", language);
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200518}
519
520static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200521text_input_text_direction(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800522 struct zwp_text_input_v1 *text_input,
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200523 uint32_t serial,
524 uint32_t direction)
525{
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200526 struct text_entry *entry = data;
527 PangoContext *context = pango_layout_get_context(entry->layout);
528 PangoDirection pango_direction;
529
530
531 switch (direction) {
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800532 case ZWP_TEXT_INPUT_V1_TEXT_DIRECTION_LTR:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200533 pango_direction = PANGO_DIRECTION_LTR;
534 break;
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800535 case ZWP_TEXT_INPUT_V1_TEXT_DIRECTION_RTL:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200536 pango_direction = PANGO_DIRECTION_RTL;
537 break;
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800538 case ZWP_TEXT_INPUT_V1_TEXT_DIRECTION_AUTO:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200539 default:
540 pango_direction = PANGO_DIRECTION_NEUTRAL;
541 }
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200542
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200543 pango_context_set_base_dir(context, pango_direction);
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200544}
545
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800546static const struct zwp_text_input_v1_listener text_input_listener = {
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200547 text_input_enter,
548 text_input_leave,
549 text_input_modifiers_map,
550 text_input_input_panel_state,
551 text_input_preedit_string,
552 text_input_preedit_styling,
553 text_input_preedit_cursor,
554 text_input_commit_string,
555 text_input_cursor_position,
556 text_input_delete_surrounding_text,
557 text_input_keysym,
558 text_input_language,
559 text_input_text_direction
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200560};
561
Manuel Bachmann22f34302015-03-30 01:57:44 +0200562static void
563data_source_target(void *data,
564 struct wl_data_source *source, const char *mime_type)
565{
566}
567
568static void
569data_source_send(void *data,
570 struct wl_data_source *source,
571 const char *mime_type, int32_t fd)
572{
573 struct editor *editor = data;
574
Bryce Harrington7dd12ec2015-05-19 15:32:09 -0700575 if (write(fd, editor->selected_text, strlen(editor->selected_text) + 1) < 0)
576 fprintf(stderr, "write failed: %m\n");
Manuel Bachmann22f34302015-03-30 01:57:44 +0200577}
578
579static void
580data_source_cancelled(void *data, struct wl_data_source *source)
581{
582 wl_data_source_destroy(source);
583}
584
585static const struct wl_data_source_listener data_source_listener = {
586 data_source_target,
587 data_source_send,
588 data_source_cancelled
589};
590
591static void
592paste_func(void *buffer, size_t len,
593 int32_t x, int32_t y, void *data)
594{
595 struct editor *editor = data;
596 struct text_entry *entry = editor->active_entry;
597 char *pasted_text;
598
599 if (!entry)
600 return;
601
602 pasted_text = malloc(len + 1);
603 strncpy(pasted_text, buffer, len);
604 pasted_text[len] = '\0';
605
606 text_entry_insert_at_cursor(entry, pasted_text, 0, 0);
607
608 free(pasted_text);
609}
610
611static void
612editor_copy_cut(struct editor *editor, struct input *input, bool cut)
613{
614 struct text_entry *entry = editor->active_entry;
615
616 if (!entry)
617 return;
Michael Vetter2a18a522015-05-15 17:17:47 +0200618
Manuel Bachmann22f34302015-03-30 01:57:44 +0200619 if (entry->cursor != entry->anchor) {
620 int start_index = MIN(entry->cursor, entry->anchor);
621 int end_index = MAX(entry->cursor, entry->anchor);
622 int len = end_index - start_index;
623
624 editor->selected_text = realloc(editor->selected_text, len + 1);
625 strncpy(editor->selected_text, &entry->text[start_index], len);
626 editor->selected_text[len] = '\0';
627
628 if (cut)
629 text_entry_delete_text(entry, start_index, len);
630
631 editor->selection =
632 display_create_data_source(editor->display);
633 wl_data_source_offer(editor->selection,
634 "text/plain;charset=utf-8");
635 wl_data_source_add_listener(editor->selection,
636 &data_source_listener, editor);
637 input_set_selection(input, editor->selection,
638 display_get_serial(editor->display));
639 }
640}
641
642static void
643editor_paste(struct editor *editor, struct input *input)
644{
645 input_receive_selection_data(input,
646 "text/plain;charset=utf-8",
647 paste_func, editor);
648}
649
650static void
651menu_func(void *data, struct input *input, int index)
652{
653 struct window *window = data;
654 struct editor *editor = window_get_user_data(window);
655
656 fprintf(stderr, "picked entry %d\n", index);
657
658 switch (index) {
659 case 0:
660 editor_copy_cut(editor, input, true);
661 break;
662 case 1:
663 editor_copy_cut(editor, input, false);
664 break;
665 case 2:
666 editor_paste(editor, input);
667 break;
668 }
669}
670
671static void
672show_menu(struct editor *editor, struct input *input, uint32_t time)
673{
674 int32_t x, y;
675 static const char *entries[] = {
676 "Cut", "Copy", "Paste"
677 };
678
679 input_get_position(input, &x, &y);
680 window_show_menu(editor->display, input, time, editor->window,
681 x + 10, y + 20, menu_func,
682 entries, ARRAY_LENGTH(entries));
683}
684
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200685static struct text_entry*
686text_entry_create(struct editor *editor, const char *text)
687{
688 struct text_entry *entry;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200689
Ryo Munakata5e653ca2015-08-07 20:20:46 +0900690 entry = xzalloc(sizeof *entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200691
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200692 entry->widget = widget_add_widget(editor->widget, entry);
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200693 entry->window = editor->window;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200694 entry->text = strdup(text);
695 entry->active = 0;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200696 entry->cursor = strlen(text);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200697 entry->anchor = entry->cursor;
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800698 entry->text_input =
699 zwp_text_input_manager_v1_create_text_input(editor->text_input_manager);
700 zwp_text_input_v1_add_listener(entry->text_input,
701 &text_input_listener, entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200702
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200703 widget_set_redraw_handler(entry->widget, text_entry_redraw_handler);
704 widget_set_button_handler(entry->widget, text_entry_button_handler);
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +0200705 widget_set_motion_handler(entry->widget, text_entry_motion_handler);
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -0800706 widget_set_touch_down_handler(entry->widget, text_entry_touch_handler);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200707
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200708 return entry;
709}
710
711static void
712text_entry_destroy(struct text_entry *entry)
713{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200714 widget_destroy(entry->widget);
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800715 zwp_text_input_v1_destroy(entry->text_input);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100716 g_clear_object(&entry->layout);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200717 free(entry->text);
718 free(entry);
719}
720
721static void
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200722redraw_handler(struct widget *widget, void *data)
723{
724 struct editor *editor = data;
725 cairo_surface_t *surface;
726 struct rectangle allocation;
727 cairo_t *cr;
728
729 surface = window_get_surface(editor->window);
730 widget_get_allocation(editor->widget, &allocation);
731
732 cr = cairo_create(surface);
733 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
734 cairo_clip(cr);
735
736 cairo_translate(cr, allocation.x, allocation.y);
737
738 /* Draw background */
739 cairo_push_group(cr);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200740 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200741 cairo_set_source_rgba(cr, 1, 1, 1, 1);
742 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
743 cairo_fill(cr);
744
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200745 cairo_pop_group_to_source(cr);
746 cairo_paint(cr);
747
748 cairo_destroy(cr);
749 cairo_surface_destroy(surface);
750}
751
752static void
753text_entry_allocate(struct text_entry *entry, int32_t x, int32_t y,
754 int32_t width, int32_t height)
755{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200756 widget_set_allocation(entry->widget, x, y, width, height);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200757}
758
759static void
760resize_handler(struct widget *widget,
761 int32_t width, int32_t height, void *data)
762{
763 struct editor *editor = data;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200764 struct rectangle allocation;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200765
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200766 widget_get_allocation(editor->widget, &allocation);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200767
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200768 text_entry_allocate(editor->entry,
769 allocation.x + 20, allocation.y + 20,
770 width - 40, height / 2 - 40);
771 text_entry_allocate(editor->editor,
772 allocation.x + 20, allocation.y + height / 2 + 20,
773 width - 40, height / 2 - 40);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200774}
775
776static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200777text_entry_activate(struct text_entry *entry,
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200778 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200779{
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200780 struct wl_surface *surface = window_get_wl_surface(entry->window);
781
Jan Arne Petersen61381972013-01-31 15:52:21 +0100782 if (entry->click_to_show && entry->active) {
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800783 zwp_text_input_v1_show_input_panel(entry->text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100784
785 return;
786 }
787
788 if (!entry->click_to_show)
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800789 zwp_text_input_v1_show_input_panel(entry->text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100790
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800791 zwp_text_input_v1_activate(entry->text_input,
792 seat,
793 surface);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200794}
795
796static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200797text_entry_deactivate(struct text_entry *entry,
798 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200799{
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800800 zwp_text_input_v1_deactivate(entry->text_input,
801 seat);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200802}
803
804static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200805text_entry_update_layout(struct text_entry *entry)
806{
807 char *text;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100808 PangoAttrList *attr_list;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200809
Jan Arne Petersen68516862013-04-18 16:47:42 +0200810 assert(entry->cursor <= (strlen(entry->text) +
811 (entry->preedit.text ? strlen(entry->preedit.text) : 0)));
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200812
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100813 if (entry->preedit.text) {
Derek Foreman22044922014-11-20 15:42:35 -0600814 text = xmalloc(strlen(entry->text) + strlen(entry->preedit.text) + 1);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100815 strncpy(text, entry->text, entry->cursor);
816 strcpy(text + entry->cursor, entry->preedit.text);
817 strcpy(text + entry->cursor + strlen(entry->preedit.text),
818 entry->text + entry->cursor);
819 } else {
820 text = strdup(entry->text);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200821 }
822
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100823 if (entry->cursor != entry->anchor) {
824 int start_index = MIN(entry->cursor, entry->anchor);
825 int end_index = MAX(entry->cursor, entry->anchor);
826 PangoAttribute *attr;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200827
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100828 attr_list = pango_attr_list_copy(entry->preedit.attr_list);
829
830 if (!attr_list)
831 attr_list = pango_attr_list_new();
832
833 attr = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
834 attr->start_index = start_index;
835 attr->end_index = end_index;
836 pango_attr_list_insert(attr_list, attr);
837
838 attr = pango_attr_foreground_new(65535, 65535, 65535);
839 attr->start_index = start_index;
840 attr->end_index = end_index;
841 pango_attr_list_insert(attr_list, attr);
842 } else {
843 attr_list = pango_attr_list_ref(entry->preedit.attr_list);
844 }
845
846 if (entry->preedit.text && !entry->preedit.attr_list) {
847 PangoAttribute *attr;
848
849 if (!attr_list)
850 attr_list = pango_attr_list_new();
851
852 attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
853 attr->start_index = entry->cursor;
854 attr->end_index = entry->cursor + strlen(entry->preedit.text);
855 pango_attr_list_insert(attr_list, attr);
856 }
857
858 if (entry->layout) {
859 pango_layout_set_text(entry->layout, text, -1);
860 pango_layout_set_attributes(entry->layout, attr_list);
861 }
862
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200863 free(text);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100864 pango_attr_list_unref(attr_list);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200865}
866
867static void
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100868text_entry_update(struct text_entry *entry)
869{
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200870 struct rectangle cursor_rectangle;
871
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800872 zwp_text_input_v1_set_content_type(entry->text_input,
873 ZWP_TEXT_INPUT_V1_CONTENT_HINT_NONE,
874 entry->content_purpose);
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100875
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800876 zwp_text_input_v1_set_surrounding_text(entry->text_input,
877 entry->text,
878 entry->cursor,
879 entry->anchor);
Jan Arne Petersen0eabcaa2013-01-31 15:52:20 +0100880
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200881 if (entry->preferred_language)
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800882 zwp_text_input_v1_set_preferred_language(entry->text_input,
883 entry->preferred_language);
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200884
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200885 text_entry_get_cursor_rectangle(entry, &cursor_rectangle);
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800886 zwp_text_input_v1_set_cursor_rectangle(entry->text_input,
887 cursor_rectangle.x,
888 cursor_rectangle.y,
889 cursor_rectangle.width,
890 cursor_rectangle.height);
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200891
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800892 zwp_text_input_v1_commit_state(entry->text_input, ++entry->serial);
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100893}
894
895static void
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100896text_entry_insert_at_cursor(struct text_entry *entry, const char *text,
897 int32_t cursor, int32_t anchor)
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200898{
Derek Foreman22044922014-11-20 15:42:35 -0600899 char *new_text = xmalloc(strlen(entry->text) + strlen(text) + 1);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200900
901 strncpy(new_text, entry->text, entry->cursor);
902 strcpy(new_text + entry->cursor, text);
903 strcpy(new_text + entry->cursor + strlen(text),
904 entry->text + entry->cursor);
905
906 free(entry->text);
907 entry->text = new_text;
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100908 if (anchor >= 0)
909 entry->anchor = entry->cursor + strlen(text) + anchor;
910 else
911 entry->anchor = entry->cursor + 1 + anchor;
Jan Arne Petersen68516862013-04-18 16:47:42 +0200912
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100913 if (cursor >= 0)
914 entry->cursor += strlen(text) + cursor;
915 else
916 entry->cursor += 1 + cursor;
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200917
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200918 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100919
920 widget_schedule_redraw(entry->widget);
921
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100922 text_entry_update(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200923}
924
925static void
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100926text_entry_reset_preedit(struct text_entry *entry)
927{
928 entry->preedit.cursor = 0;
929
930 free(entry->preedit.text);
931 entry->preedit.text = NULL;
932
933 free(entry->preedit.commit);
934 entry->preedit.commit = NULL;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100935
936 pango_attr_list_unref(entry->preedit.attr_list);
937 entry->preedit.attr_list = NULL;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100938}
939
940static void
941text_entry_commit_and_reset(struct text_entry *entry)
942{
943 char *commit = NULL;
944
945 if (entry->preedit.commit)
946 commit = strdup(entry->preedit.commit);
947
948 text_entry_reset_preedit(entry);
949 if (commit) {
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100950 text_entry_insert_at_cursor(entry, commit, 0, 0);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100951 free(commit);
952 }
Jan Arne Petersen08015b62013-04-18 16:47:18 +0200953
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800954 zwp_text_input_v1_reset(entry->text_input);
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200955 text_entry_update(entry);
956 entry->reset_serial = entry->serial;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100957}
958
959static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200960text_entry_set_preedit(struct text_entry *entry,
961 const char *preedit_text,
962 int preedit_cursor)
963{
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100964 text_entry_reset_preedit(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200965
966 if (!preedit_text)
967 return;
968
Jan Arne Petersen46535312013-01-16 21:26:38 +0100969 entry->preedit.text = strdup(preedit_text);
970 entry->preedit.cursor = preedit_cursor;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200971
972 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100973
974 widget_schedule_redraw(entry->widget);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200975}
976
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100977static uint32_t
978text_entry_try_invoke_preedit_action(struct text_entry *entry,
979 int32_t x, int32_t y,
980 uint32_t button,
981 enum wl_pointer_button_state state)
982{
983 int index, trailing;
984 uint32_t cursor;
Jan Arne Petersen68516862013-04-18 16:47:42 +0200985 const char *text;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100986
987 if (!entry->preedit.text)
988 return 0;
989
990 pango_layout_xy_to_index(entry->layout,
991 x * PANGO_SCALE, y * PANGO_SCALE,
992 &index, &trailing);
Jan Arne Petersen68516862013-04-18 16:47:42 +0200993
994 text = pango_layout_get_text(entry->layout);
995 cursor = g_utf8_offset_to_pointer(text + index, trailing) - text;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100996
997 if (cursor < entry->cursor ||
998 cursor > entry->cursor + strlen(entry->preedit.text)) {
999 return 0;
1000 }
1001
1002 if (state == WL_POINTER_BUTTON_STATE_RELEASED)
Jonas Ådahl3bcba342015-11-17 16:00:29 +08001003 zwp_text_input_v1_invoke_action(entry->text_input,
1004 button,
1005 cursor - entry->cursor);
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001006
1007 return 1;
1008}
1009
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001010static bool
1011text_entry_has_preedit(struct text_entry *entry)
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001012{
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001013 return entry->preedit.text && (strlen(entry->preedit.text) > 0);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001014}
1015
1016static void
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001017text_entry_set_cursor_position(struct text_entry *entry,
1018 int32_t x, int32_t y,
1019 bool move_anchor)
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001020{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001021 int index, trailing;
Jan Arne Petersen68516862013-04-18 16:47:42 +02001022 const char *text;
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001023 uint32_t cursor;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001024
1025 pango_layout_xy_to_index(entry->layout,
1026 x * PANGO_SCALE, y * PANGO_SCALE,
1027 &index, &trailing);
Jan Arne Petersen68516862013-04-18 16:47:42 +02001028
1029 text = pango_layout_get_text(entry->layout);
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001030
1031 cursor = g_utf8_offset_to_pointer(text + index, trailing) - text;
1032
1033 if (move_anchor)
1034 entry->anchor = cursor;
1035
1036 if (text_entry_has_preedit(entry)) {
1037 text_entry_commit_and_reset(entry);
1038
1039 assert(!text_entry_has_preedit(entry));
1040 }
1041
1042 if (entry->cursor == cursor)
1043 return;
1044
1045 entry->cursor = cursor;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001046
1047 text_entry_update_layout(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001048
1049 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001050
Jan Arne Petersen0558a932013-01-16 21:26:45 +01001051 text_entry_update(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001052}
1053
1054static void
Jan Arne Petersene202bae2012-09-09 23:08:44 +02001055text_entry_delete_text(struct text_entry *entry,
1056 uint32_t index, uint32_t length)
1057{
Jan Arne Petersen68516862013-04-18 16:47:42 +02001058 uint32_t l;
1059
Jan Arne Petersen895a1282013-05-30 13:57:04 +02001060 assert(index <= strlen(entry->text));
1061 assert(index + length <= strlen(entry->text));
1062 assert(index + length >= length);
Jan Arne Petersen80ad1a92012-09-17 15:28:10 +02001063
Jan Arne Petersen68516862013-04-18 16:47:42 +02001064 l = strlen(entry->text + index + length);
1065 memmove(entry->text + index,
1066 entry->text + index + length,
1067 l + 1);
Jan Arne Petersene202bae2012-09-09 23:08:44 +02001068
Jan Arne Petersen9eaa8e52013-05-30 13:57:03 +02001069 if (entry->cursor > (index + length))
1070 entry->cursor -= length;
1071 else if (entry->cursor > index)
1072 entry->cursor = index;
1073
1074 entry->anchor = entry->cursor;
1075
Jan Arne Petersene202bae2012-09-09 23:08:44 +02001076 text_entry_update_layout(entry);
1077
1078 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001079
Jan Arne Petersen0558a932013-01-16 21:26:45 +01001080 text_entry_update(entry);
Jan Arne Petersene202bae2012-09-09 23:08:44 +02001081}
1082
1083static void
Jan Arne Petersene386dd22012-09-17 15:28:09 +02001084text_entry_delete_selected_text(struct text_entry *entry)
1085{
1086 uint32_t start_index = entry->anchor < entry->cursor ? entry->anchor : entry->cursor;
1087 uint32_t end_index = entry->anchor < entry->cursor ? entry->cursor : entry->anchor;
1088
1089 if (entry->anchor == entry->cursor)
1090 return;
1091
1092 text_entry_delete_text(entry, start_index, end_index - start_index);
1093
1094 entry->anchor = entry->cursor;
1095}
1096
1097static void
Jan Arne Petersenfe89e712013-04-18 16:47:27 +02001098text_entry_get_cursor_rectangle(struct text_entry *entry, struct rectangle *rectangle)
1099{
1100 struct rectangle allocation;
1101 PangoRectangle extents;
1102 PangoRectangle cursor_pos;
1103
1104 widget_get_allocation(entry->widget, &allocation);
1105
1106 if (entry->preedit.text && entry->preedit.cursor < 0) {
1107 rectangle->x = 0;
1108 rectangle->y = 0;
1109 rectangle->width = 0;
1110 rectangle->height = 0;
1111 return;
1112 }
1113
Jan Arne Petersen68516862013-04-18 16:47:42 +02001114
Jan Arne Petersenfe89e712013-04-18 16:47:27 +02001115 pango_layout_get_extents(entry->layout, &extents, NULL);
1116 pango_layout_get_cursor_pos(entry->layout,
1117 entry->cursor + entry->preedit.cursor,
1118 &cursor_pos, NULL);
1119
1120 rectangle->x = allocation.x + (allocation.height / 2) + PANGO_PIXELS(cursor_pos.x);
1121 rectangle->y = allocation.y + 10 + PANGO_PIXELS(cursor_pos.y);
1122 rectangle->width = PANGO_PIXELS(cursor_pos.width);
1123 rectangle->height = PANGO_PIXELS(cursor_pos.height);
1124}
1125
1126static void
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001127text_entry_draw_cursor(struct text_entry *entry, cairo_t *cr)
1128{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001129 PangoRectangle extents;
1130 PangoRectangle cursor_pos;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001131
Jan Arne Petersen46535312013-01-16 21:26:38 +01001132 if (entry->preedit.text && entry->preedit.cursor < 0)
1133 return;
1134
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001135 pango_layout_get_extents(entry->layout, &extents, NULL);
1136 pango_layout_get_cursor_pos(entry->layout,
1137 entry->cursor + entry->preedit.cursor,
1138 &cursor_pos, NULL);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001139
1140 cairo_set_line_width(cr, 1.0);
Peter Maatmanb9a23f42013-07-06 20:55:54 +02001141 cairo_move_to(cr, PANGO_PIXELS(cursor_pos.x), PANGO_PIXELS(cursor_pos.y));
1142 cairo_line_to(cr, PANGO_PIXELS(cursor_pos.x), PANGO_PIXELS(cursor_pos.y) + PANGO_PIXELS(cursor_pos.height));
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001143 cairo_stroke(cr);
1144}
1145
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001146static int
1147text_offset_left(struct rectangle *allocation)
1148{
1149 return 10;
1150}
1151
1152static int
1153text_offset_top(struct rectangle *allocation)
1154{
1155 return allocation->height / 2;
1156}
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +02001157
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +02001158static void
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001159text_entry_redraw_handler(struct widget *widget, void *data)
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001160{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001161 struct text_entry *entry = data;
1162 cairo_surface_t *surface;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001163 struct rectangle allocation;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001164 cairo_t *cr;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001165
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001166 surface = window_get_surface(entry->window);
1167 widget_get_allocation(entry->widget, &allocation);
1168
1169 cr = cairo_create(surface);
1170 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
1171 cairo_clip(cr);
1172
1173 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
1174
1175 cairo_push_group(cr);
1176 cairo_translate(cr, allocation.x, allocation.y);
1177
1178 cairo_set_source_rgba(cr, 1, 1, 1, 1);
1179 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
1180 cairo_fill(cr);
1181
1182 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
1183
1184 if (entry->active) {
1185 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
1186 cairo_set_line_width (cr, 3);
1187 cairo_set_source_rgba(cr, 0, 0, 1, 1.0);
1188 cairo_stroke(cr);
1189 }
1190
1191 cairo_set_source_rgba(cr, 0, 0, 0, 1);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001192
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001193 cairo_translate(cr,
1194 text_offset_left(&allocation),
1195 text_offset_top(&allocation));
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001196
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001197 if (!entry->layout)
1198 entry->layout = pango_cairo_create_layout(cr);
1199 else
1200 pango_cairo_update_layout(cr, entry->layout);
1201
1202 text_entry_update_layout(entry);
1203
1204 pango_cairo_show_layout(cr, entry->layout);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001205
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001206 text_entry_draw_cursor(entry, cr);
1207
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001208 cairo_pop_group_to_source(cr);
1209 cairo_paint(cr);
1210
1211 cairo_destroy(cr);
1212 cairo_surface_destroy(surface);
1213}
1214
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001215static int
1216text_entry_motion_handler(struct widget *widget,
1217 struct input *input, uint32_t time,
1218 float x, float y, void *data)
1219{
1220 struct text_entry *entry = data;
1221 struct rectangle allocation;
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001222 int tx, ty;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001223
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001224 if (!entry->button_pressed) {
1225 return CURSOR_IBEAM;
1226 }
1227
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001228 widget_get_allocation(entry->widget, &allocation);
1229
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001230 tx = x - allocation.x - text_offset_left(&allocation);
1231 ty = y - allocation.y - text_offset_top(&allocation);
1232
1233 text_entry_set_cursor_position(entry, tx, ty, false);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001234
1235 return CURSOR_IBEAM;
1236}
1237
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001238static void
1239text_entry_button_handler(struct widget *widget,
1240 struct input *input, uint32_t time,
1241 uint32_t button,
1242 enum wl_pointer_button_state state, void *data)
1243{
1244 struct text_entry *entry = data;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001245 struct rectangle allocation;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001246 struct editor *editor;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001247 int32_t x, y;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001248 uint32_t result;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001249
1250 widget_get_allocation(entry->widget, &allocation);
1251 input_get_position(input, &x, &y);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001252
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001253 x -= allocation.x + text_offset_left(&allocation);
1254 y -= allocation.y + text_offset_top(&allocation);
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001255
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001256 editor = window_get_user_data(entry->window);
1257
Manuel Bachmann22f34302015-03-30 01:57:44 +02001258 switch (button) {
1259 case BTN_LEFT:
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001260 entry->button_pressed = (state == WL_POINTER_BUTTON_STATE_PRESSED);
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001261 if (state == WL_POINTER_BUTTON_STATE_PRESSED)
1262 input_grab(input, entry->widget, button);
1263 else
1264 input_ungrab(input);
Manuel Bachmann22f34302015-03-30 01:57:44 +02001265 break;
1266 case BTN_RIGHT:
1267 if (state == WL_POINTER_BUTTON_STATE_PRESSED)
1268 show_menu(editor, input, time);
1269 break;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001270 }
1271
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001272 if (text_entry_has_preedit(entry)) {
1273 result = text_entry_try_invoke_preedit_action(entry, x, y, button, state);
1274
1275 if (result)
1276 return;
1277 }
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001278
Manuel Bachmann22f34302015-03-30 01:57:44 +02001279 if (state == WL_POINTER_BUTTON_STATE_PRESSED &&
1280 button == BTN_LEFT) {
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001281 struct wl_seat *seat = input_get_seat(input);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001282
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001283 text_entry_activate(entry, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001284 editor->active_entry = entry;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001285
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001286 text_entry_set_cursor_position(entry, x, y, true);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001287 }
1288}
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001289
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001290static void
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -08001291text_entry_touch_handler(struct widget *widget, struct input *input,
1292 uint32_t serial, uint32_t time, int32_t id,
1293 float tx, float ty, void *data)
1294{
1295 struct text_entry *entry = data;
1296 struct wl_seat *seat = input_get_seat(input);
1297 struct rectangle allocation;
1298 struct editor *editor;
1299 int32_t x, y;
1300
1301 widget_get_allocation(entry->widget, &allocation);
1302
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001303 x = tx - (allocation.x + text_offset_left(&allocation));
1304 y = ty - (allocation.y + text_offset_top(&allocation));
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -08001305
1306 editor = window_get_user_data(entry->window);
1307 text_entry_activate(entry, seat);
1308 editor->active_entry = entry;
1309
1310 text_entry_set_cursor_position(entry, x, y, true);
1311}
1312
1313static void
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001314editor_button_handler(struct widget *widget,
1315 struct input *input, uint32_t time,
1316 uint32_t button,
1317 enum wl_pointer_button_state state, void *data)
1318{
1319 struct editor *editor = data;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001320
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001321 if (button != BTN_LEFT) {
1322 return;
1323 }
Jan Arne Petersene829adc2012-08-10 16:47:22 +02001324
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001325 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
1326 struct wl_seat *seat = input_get_seat(input);
1327
Jan Arne Petersene829adc2012-08-10 16:47:22 +02001328 text_entry_deactivate(editor->entry, seat);
1329 text_entry_deactivate(editor->editor, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001330 editor->active_entry = NULL;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001331 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001332}
1333
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -08001334static void
1335editor_touch_handler(struct widget *widget, struct input *input,
1336 uint32_t serial, uint32_t time, int32_t id,
1337 float tx, float ty, void *data)
1338{
1339 struct editor *editor = data;
1340
1341 struct wl_seat *seat = input_get_seat(input);
1342
1343 text_entry_deactivate(editor->entry, seat);
1344 text_entry_deactivate(editor->editor, seat);
1345 editor->active_entry = NULL;
1346}
Kristian Høgsberg78858902014-01-01 23:57:42 -08001347
1348static void
1349keyboard_focus_handler(struct window *window,
1350 struct input *device, void *data)
1351{
1352 struct editor *editor = data;
1353
1354 window_schedule_redraw(editor->window);
1355}
1356
Manuel Bachmann22f34302015-03-30 01:57:44 +02001357static int
1358handle_bound_key(struct editor *editor,
1359 struct input *input, uint32_t sym, uint32_t time)
1360{
1361 switch (sym) {
1362 case XKB_KEY_X:
1363 editor_copy_cut(editor, input, true);
1364 return 1;
1365 case XKB_KEY_C:
1366 editor_copy_cut(editor, input, false);
1367 return 1;
1368 case XKB_KEY_V:
1369 editor_paste(editor, input);
1370 return 1;
1371 default:
1372 return 0;
1373 }
1374}
1375
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001376static void
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001377key_handler(struct window *window,
1378 struct input *input, uint32_t time,
1379 uint32_t key, uint32_t sym, enum wl_keyboard_key_state state,
1380 void *data)
1381{
1382 struct editor *editor = data;
1383 struct text_entry *entry;
Jan Arne Petersen68516862013-04-18 16:47:42 +02001384 const char *new_char;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001385 char text[16];
Manuel Bachmann22f34302015-03-30 01:57:44 +02001386 uint32_t modifiers;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001387
1388 if (!editor->active_entry)
1389 return;
1390
1391 entry = editor->active_entry;
1392
1393 if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
1394 return;
1395
Manuel Bachmann22f34302015-03-30 01:57:44 +02001396 modifiers = input_get_modifiers(input);
1397 if ((modifiers & MOD_CONTROL_MASK) &&
1398 (modifiers & MOD_SHIFT_MASK) &&
1399 handle_bound_key(editor, input, sym, time))
1400 return;
1401
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001402 switch (sym) {
1403 case XKB_KEY_BackSpace:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001404 text_entry_commit_and_reset(entry);
1405
Jan Arne Petersen68516862013-04-18 16:47:42 +02001406 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
1407 if (new_char != NULL)
1408 text_entry_delete_text(entry,
1409 new_char - entry->text,
1410 (entry->text + entry->cursor) - new_char);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001411 break;
1412 case XKB_KEY_Delete:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001413 text_entry_commit_and_reset(entry);
1414
Jan Arne Petersen68516862013-04-18 16:47:42 +02001415 new_char = utf8_next_char(entry->text + entry->cursor);
1416 if (new_char != NULL)
1417 text_entry_delete_text(entry,
1418 entry->cursor,
1419 new_char - (entry->text + entry->cursor));
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001420 break;
1421 case XKB_KEY_Left:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001422 text_entry_commit_and_reset(entry);
1423
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001424 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
1425 if (new_char != NULL) {
1426 entry->cursor = new_char - entry->text;
Rob Bradford70002832013-07-11 16:00:00 +01001427 if (!(input_get_modifiers(input) & MOD_SHIFT_MASK))
1428 entry->anchor = entry->cursor;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001429 widget_schedule_redraw(entry->widget);
1430 }
1431 break;
1432 case XKB_KEY_Right:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001433 text_entry_commit_and_reset(entry);
1434
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001435 new_char = utf8_next_char(entry->text + entry->cursor);
1436 if (new_char != NULL) {
1437 entry->cursor = new_char - entry->text;
Rob Bradford70002832013-07-11 16:00:00 +01001438 if (!(input_get_modifiers(input) & MOD_SHIFT_MASK))
1439 entry->anchor = entry->cursor;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001440 widget_schedule_redraw(entry->widget);
1441 }
1442 break;
Manuel Bachmann8986c182014-04-18 12:50:14 +02001443 case XKB_KEY_Up:
1444 text_entry_commit_and_reset(entry);
1445
1446 move_up(entry->text, &entry->cursor);
1447 if (!(input_get_modifiers(input) & MOD_SHIFT_MASK))
1448 entry->anchor = entry->cursor;
1449 widget_schedule_redraw(entry->widget);
1450 break;
1451 case XKB_KEY_Down:
1452 text_entry_commit_and_reset(entry);
1453
1454 move_down(entry->text, &entry->cursor);
1455 if (!(input_get_modifiers(input) & MOD_SHIFT_MASK))
1456 entry->anchor = entry->cursor;
1457 widget_schedule_redraw(entry->widget);
1458 break;
Peter Maatman08c38d42013-07-06 20:42:59 +02001459 case XKB_KEY_Escape:
1460 break;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001461 default:
1462 if (xkb_keysym_to_utf8(sym, text, sizeof(text)) <= 0)
1463 break;
1464
Peter Maatman08c38d42013-07-06 20:42:59 +02001465 text_entry_commit_and_reset(entry);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001466
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +01001467 text_entry_insert_at_cursor(entry, text, 0, 0);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001468 break;
1469 }
1470
1471 widget_schedule_redraw(entry->widget);
1472}
1473
1474static void
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001475global_handler(struct display *display, uint32_t name,
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001476 const char *interface, uint32_t version, void *data)
1477{
1478 struct editor *editor = data;
1479
Jonas Ådahl3bcba342015-11-17 16:00:29 +08001480 if (!strcmp(interface, "zwp_text_input_manager_v1")) {
Jan Arne Petersen78d00e42013-04-18 16:47:24 +02001481 editor->text_input_manager =
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001482 display_bind(display, name,
Jonas Ådahl3bcba342015-11-17 16:00:29 +08001483 &zwp_text_input_manager_v1_interface, 1);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001484 }
1485}
1486
1487int
1488main(int argc, char *argv[])
1489{
1490 struct editor editor;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001491 int i;
1492 uint32_t click_to_show = 0;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001493 const char *preferred_language = NULL;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001494
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001495 for (i = 1; i < argc; i++) {
Jan Arne Petersen61381972013-01-31 15:52:21 +01001496 if (strcmp("--click-to-show", argv[i]) == 0)
1497 click_to_show = 1;
Bill Spitzakbb0bb9c2014-08-08 12:59:58 -07001498 else if (strcmp("--preferred-language", argv[i]) == 0 &&
1499 i + 1 < argc) {
1500 preferred_language = argv[i + 1];
1501 i++;
1502 } else {
1503 printf("Usage: %s [OPTIONS]\n"
1504 " --click-to-show\n"
1505 " --preferred-language LANGUAGE\n",
1506 argv[0]);
1507 return 1;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001508 }
1509 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001510
Jan Arne Petersen25f6db52012-11-05 03:26:40 +01001511 memset(&editor, 0, sizeof editor);
1512
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001513#ifdef HAVE_PANGO
1514 g_type_init();
1515#endif
1516
Kristian Høgsberg4172f662013-02-20 15:27:49 -05001517 editor.display = display_create(&argc, argv);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001518 if (editor.display == NULL) {
1519 fprintf(stderr, "failed to create display: %m\n");
1520 return -1;
1521 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001522
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001523 display_set_user_data(editor.display, &editor);
1524 display_set_global_handler(editor.display, global_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001525
Olivier Blin30e1f3c2014-09-16 19:13:17 +02001526 if (editor.text_input_manager == NULL) {
1527 fprintf(stderr, "No text input manager global\n");
1528 return -1;
1529 }
1530
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001531 editor.window = window_create(editor.display);
Jason Ekstrandee7fefc2013-10-13 19:08:38 -05001532 editor.widget = window_frame_create(editor.window, &editor);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001533
1534 editor.entry = text_entry_create(&editor, "Entry");
Jan Arne Petersen61381972013-01-31 15:52:21 +01001535 editor.entry->click_to_show = click_to_show;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001536 if (preferred_language)
1537 editor.entry->preferred_language = strdup(preferred_language);
Jan Arne Petersen0558a932013-01-16 21:26:45 +01001538 editor.editor = text_entry_create(&editor, "Numeric");
Jonas Ådahl3bcba342015-11-17 16:00:29 +08001539 editor.editor->content_purpose = ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_NUMBER;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001540 editor.editor->click_to_show = click_to_show;
Manuel Bachmann22f34302015-03-30 01:57:44 +02001541 editor.selection = NULL;
1542 editor.selected_text = NULL;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001543
1544 window_set_title(editor.window, "Text Editor");
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001545 window_set_key_handler(editor.window, key_handler);
Kristian Høgsberg78858902014-01-01 23:57:42 -08001546 window_set_keyboard_focus_handler(editor.window,
1547 keyboard_focus_handler);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001548 window_set_user_data(editor.window, &editor);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001549
1550 widget_set_redraw_handler(editor.widget, redraw_handler);
1551 widget_set_resize_handler(editor.widget, resize_handler);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001552 widget_set_button_handler(editor.widget, editor_button_handler);
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -08001553 widget_set_touch_down_handler(editor.widget, editor_touch_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001554
1555 window_schedule_resize(editor.window, 500, 400);
1556
1557 display_run(editor.display);
1558
Manuel Bachmann22f34302015-03-30 01:57:44 +02001559 if (editor.selected_text)
1560 free(editor.selected_text);
1561 if (editor.selection)
1562 wl_data_source_destroy(editor.selection);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001563 text_entry_destroy(editor.entry);
1564 text_entry_destroy(editor.editor);
vivek31732f72014-05-15 18:58:16 +05301565 widget_destroy(editor.widget);
1566 window_destroy(editor.window);
1567 display_destroy(editor.display);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001568
1569 return 0;
1570}