blob: e081a5b8b73c20b061f51a56f4d9c316ed7c6393 [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"
Bryce Harringtone99e4bf2016-03-16 14:15:18 -070040#include "shared/xalloc.h"
Jan Arne Petersencba9e472012-06-21 21:52:19 +020041#include "window.h"
Jonas Ådahl3bcba342015-11-17 16:00:29 +080042#include "text-input-unstable-v1-client-protocol.h"
Jan Arne Petersencba9e472012-06-21 21:52:19 +020043
44struct text_entry {
45 struct widget *widget;
Jan Arne Petersene829adc2012-08-10 16:47:22 +020046 struct window *window;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020047 char *text;
48 int active;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +020049 uint32_t cursor;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +020050 uint32_t anchor;
Jan Arne Petersen46535312013-01-16 21:26:38 +010051 struct {
52 char *text;
53 int32_t cursor;
54 char *commit;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010055 PangoAttrList *attr_list;
Jan Arne Petersen46535312013-01-16 21:26:38 +010056 } preedit;
57 struct {
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010058 PangoAttrList *attr_list;
Jan Arne Petersen46535312013-01-16 21:26:38 +010059 int32_t cursor;
60 } preedit_info;
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +010061 struct {
62 int32_t cursor;
63 int32_t anchor;
Jan Arne Petersen919bc142013-04-18 16:47:34 +020064 uint32_t delete_index;
65 uint32_t delete_length;
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +020066 bool invalid_delete;
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +010067 } pending_commit;
Jonas Ådahl3bcba342015-11-17 16:00:29 +080068 struct zwp_text_input_v1 *text_input;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010069 PangoLayout *layout;
Jan Arne Petersencd997062012-11-18 19:06:44 +010070 struct {
71 xkb_mod_mask_t shift_mask;
72 } keysym;
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +010073 uint32_t serial;
Jan Arne Petersen00191c72013-04-18 16:47:33 +020074 uint32_t reset_serial;
Jan Arne Petersen0558a932013-01-16 21:26:45 +010075 uint32_t content_purpose;
Jan Arne Petersen61381972013-01-31 15:52:21 +010076 uint32_t click_to_show;
Jan Arne Petersen9d419132013-04-18 16:47:16 +020077 char *preferred_language;
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +020078 bool button_pressed;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020079};
80
81struct editor {
Jonas Ådahl3bcba342015-11-17 16:00:29 +080082 struct zwp_text_input_manager_v1 *text_input_manager;
Manuel Bachmann22f34302015-03-30 01:57:44 +020083 struct wl_data_source *selection;
84 char *selected_text;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020085 struct display *display;
86 struct window *window;
87 struct widget *widget;
88 struct text_entry *entry;
89 struct text_entry *editor;
Rob Bradford9d1d32b2012-11-18 19:06:49 +010090 struct text_entry *active_entry;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020091};
92
Jan Arne Petersen6345faa2012-11-05 03:26:39 +010093static const char *
Jan Arne Petersen6345faa2012-11-05 03:26:39 +010094utf8_end_char(const char *p)
95{
96 while ((*p & 0xc0) == 0x80)
97 p++;
98 return p;
99}
100
101static const char *
Jan Arne Petersen68516862013-04-18 16:47:42 +0200102utf8_prev_char(const char *s, const char *p)
103{
104 for (--p; p >= s; --p) {
105 if ((*p & 0xc0) != 0x80)
106 return p;
107 }
108 return NULL;
109}
110
111static const char *
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100112utf8_next_char(const char *p)
113{
114 if (*p != 0)
115 return utf8_end_char(++p);
116 return NULL;
117}
118
Manuel Bachmann8986c182014-04-18 12:50:14 +0200119static void
120move_up(const char *p, uint32_t *cursor)
121{
122 const char *posr, *posr_i;
123 char text[16];
124
125 xkb_keysym_to_utf8(XKB_KEY_Return, text, sizeof(text));
126
127 posr = strstr(p, text);
128 while (posr) {
129 if (*cursor > (unsigned)(posr-p)) {
130 posr_i = strstr(posr+1, text);
131 if (!posr_i || !(*cursor > (unsigned)(posr_i-p))) {
132 *cursor = posr-p;
133 break;
134 }
135 posr = posr_i;
136 } else {
137 break;
138 }
139 }
140}
141
142static void
143move_down(const char *p, uint32_t *cursor)
144{
145 const char *posr;
146 char text[16];
147
148 xkb_keysym_to_utf8(XKB_KEY_Return, text, sizeof(text));
149
150 posr = strstr(p, text);
151 while (posr) {
152 if (*cursor <= (unsigned)(posr-p)) {
153 *cursor = posr-p + 1;
154 break;
155 }
156 posr = strstr(posr+1, text);
157 }
158}
159
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200160static void text_entry_redraw_handler(struct widget *widget, void *data);
161static void text_entry_button_handler(struct widget *widget,
162 struct input *input, uint32_t time,
163 uint32_t button,
164 enum wl_pointer_button_state state, void *data);
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -0800165static void text_entry_touch_handler(struct widget *widget, struct input *input,
166 uint32_t serial, uint32_t time, int32_t id,
167 float tx, float ty, void *data);
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +0200168static int text_entry_motion_handler(struct widget *widget,
169 struct input *input, uint32_t time,
170 float x, float y, void *data);
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100171static void text_entry_insert_at_cursor(struct text_entry *entry, const char *text,
172 int32_t cursor, int32_t anchor);
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200173static void text_entry_set_preedit(struct text_entry *entry,
174 const char *preedit_text,
175 int preedit_cursor);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200176static void text_entry_delete_text(struct text_entry *entry,
177 uint32_t index, uint32_t length);
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200178static void text_entry_delete_selected_text(struct text_entry *entry);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100179static void text_entry_reset_preedit(struct text_entry *entry);
180static void text_entry_commit_and_reset(struct text_entry *entry);
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200181static void text_entry_get_cursor_rectangle(struct text_entry *entry, struct rectangle *rectangle);
182static void text_entry_update(struct text_entry *entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200183
184static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200185text_input_commit_string(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800186 struct zwp_text_input_v1 *text_input,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100187 uint32_t serial,
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100188 const char *text)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200189{
190 struct text_entry *entry = data;
191
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200192 if ((entry->serial - serial) > (entry->serial - entry->reset_serial)) {
193 fprintf(stderr, "Ignore commit. Serial: %u, Current: %u, Reset: %u\n",
194 serial, entry->serial, entry->reset_serial);
195 return;
196 }
197
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200198 if (entry->pending_commit.invalid_delete) {
199 fprintf(stderr, "Ignore commit. Invalid previous delete_surrounding event.\n");
200 memset(&entry->pending_commit, 0, sizeof entry->pending_commit);
201 return;
202 }
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100203
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200204 text_entry_reset_preedit(entry);
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200205
206 if (entry->pending_commit.delete_length) {
207 text_entry_delete_text(entry,
208 entry->pending_commit.delete_index,
209 entry->pending_commit.delete_length);
Jan Arne Petersena96953d2013-05-30 13:57:02 +0200210 } else {
211 text_entry_delete_selected_text(entry);
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200212 }
213
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100214 text_entry_insert_at_cursor(entry, text,
215 entry->pending_commit.cursor,
216 entry->pending_commit.anchor);
217
218 memset(&entry->pending_commit, 0, sizeof entry->pending_commit);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200219
220 widget_schedule_redraw(entry->widget);
221}
222
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200223static void
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200224clear_pending_preedit(struct text_entry *entry)
225{
226 memset(&entry->pending_commit, 0, sizeof entry->pending_commit);
227
228 pango_attr_list_unref(entry->preedit_info.attr_list);
229
230 entry->preedit_info.cursor = 0;
231 entry->preedit_info.attr_list = NULL;
232
233 memset(&entry->preedit_info, 0, sizeof entry->preedit_info);
234}
235
236static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200237text_input_preedit_string(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800238 struct zwp_text_input_v1 *text_input,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100239 uint32_t serial,
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200240 const char *text,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100241 const char *commit)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200242{
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200243 struct text_entry *entry = data;
244
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200245 if ((entry->serial - serial) > (entry->serial - entry->reset_serial)) {
246 fprintf(stderr, "Ignore preedit_string. Serial: %u, Current: %u, Reset: %u\n",
247 serial, entry->serial, entry->reset_serial);
248 clear_pending_preedit(entry);
249 return;
250 }
251
252 if (entry->pending_commit.invalid_delete) {
253 fprintf(stderr, "Ignore preedit_string. Invalid previous delete_surrounding event.\n");
254 clear_pending_preedit(entry);
255 return;
256 }
257
Jan Arne Petersena96953d2013-05-30 13:57:02 +0200258 if (entry->pending_commit.delete_length) {
259 text_entry_delete_text(entry,
260 entry->pending_commit.delete_index,
261 entry->pending_commit.delete_length);
262 } else {
263 text_entry_delete_selected_text(entry);
264 }
Jan Arne Petersena96953d2013-05-30 13:57:02 +0200265
Jan Arne Petersen46535312013-01-16 21:26:38 +0100266 text_entry_set_preedit(entry, text, entry->preedit_info.cursor);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100267 entry->preedit.commit = strdup(commit);
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200268 entry->preedit.attr_list = pango_attr_list_ref(entry->preedit_info.attr_list);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100269
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200270 clear_pending_preedit(entry);
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200271
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200272 text_entry_update(entry);
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200273
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200274 widget_schedule_redraw(entry->widget);
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200275}
276
277static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200278text_input_delete_surrounding_text(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800279 struct zwp_text_input_v1 *text_input,
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200280 int32_t index,
281 uint32_t length)
282{
283 struct text_entry *entry = data;
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200284 uint32_t text_length;
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200285
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200286 entry->pending_commit.delete_index = entry->cursor + index;
287 entry->pending_commit.delete_length = length;
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200288 entry->pending_commit.invalid_delete = false;
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200289
Jan Arne Petersen68516862013-04-18 16:47:42 +0200290 text_length = strlen(entry->text);
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200291
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200292 if (entry->pending_commit.delete_index > text_length ||
293 length > text_length ||
Jan Arne Petersen895a1282013-05-30 13:57:04 +0200294 entry->pending_commit.delete_index + length > text_length) {
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200295 fprintf(stderr, "delete_surrounding_text: Invalid index: %d," \
296 "length %u'; cursor: %u text length: %u\n", index, length, entry->cursor, text_length);
297 entry->pending_commit.invalid_delete = true;
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200298 return;
299 }
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200300}
301
302static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200303text_input_cursor_position(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800304 struct zwp_text_input_v1 *text_input,
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100305 int32_t index,
306 int32_t anchor)
307{
308 struct text_entry *entry = data;
309
310 entry->pending_commit.cursor = index;
311 entry->pending_commit.anchor = anchor;
312}
313
314static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200315text_input_preedit_styling(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800316 struct zwp_text_input_v1 *text_input,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100317 uint32_t index,
318 uint32_t length,
319 uint32_t style)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200320{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100321 struct text_entry *entry = data;
322 PangoAttribute *attr1 = NULL;
323 PangoAttribute *attr2 = NULL;
324
325 if (!entry->preedit_info.attr_list)
326 entry->preedit_info.attr_list = pango_attr_list_new();
327
328 switch (style) {
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800329 case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_DEFAULT:
330 case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_UNDERLINE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100331 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
332 break;
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800333 case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_INCORRECT:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100334 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_ERROR);
335 attr2 = pango_attr_underline_color_new(65535, 0, 0);
336 break;
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800337 case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_SELECTION:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100338 attr1 = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
339 attr2 = pango_attr_foreground_new(65535, 65535, 65535);
340 break;
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800341 case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_HIGHLIGHT:
342 case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_ACTIVE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100343 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
344 attr2 = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
345 break;
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800346 case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_INACTIVE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100347 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
348 attr2 = pango_attr_foreground_new(0.3 * 65535, 0.3 * 65535, 0.3 * 65535);
349 break;
350 }
351
352 if (attr1) {
353 attr1->start_index = entry->cursor + index;
354 attr1->end_index = entry->cursor + index + length;
355 pango_attr_list_insert(entry->preedit_info.attr_list, attr1);
356 }
357
358 if (attr2) {
359 attr2->start_index = entry->cursor + index;
360 attr2->end_index = entry->cursor + index + length;
361 pango_attr_list_insert(entry->preedit_info.attr_list, attr2);
362 }
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200363}
364
365static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200366text_input_preedit_cursor(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800367 struct zwp_text_input_v1 *text_input,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100368 int32_t index)
369{
370 struct text_entry *entry = data;
371
372 entry->preedit_info.cursor = index;
373}
374
375static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200376text_input_modifiers_map(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800377 struct zwp_text_input_v1 *text_input,
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100378 struct wl_array *map)
379{
Jan Arne Petersencd997062012-11-18 19:06:44 +0100380 struct text_entry *entry = data;
381
382 entry->keysym.shift_mask = keysym_modifiers_get_mask(map, "Shift");
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100383}
384
385static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200386text_input_keysym(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800387 struct zwp_text_input_v1 *text_input,
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100388 uint32_t serial,
389 uint32_t time,
390 uint32_t key,
391 uint32_t state,
392 uint32_t modifiers)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200393{
Jan Arne Petersen8aba11d2012-09-17 15:28:07 +0200394 struct text_entry *entry = data;
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100395 const char *new_char;
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200396
Jan Arne Petersencd997062012-11-18 19:06:44 +0100397 if (key == XKB_KEY_Left ||
398 key == XKB_KEY_Right) {
399 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
400 return;
401
402 if (key == XKB_KEY_Left)
403 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
404 else
405 new_char = utf8_next_char(entry->text + entry->cursor);
406
407 if (new_char != NULL) {
408 entry->cursor = new_char - entry->text;
Jan Arne Petersencd997062012-11-18 19:06:44 +0100409 }
410
Jan Arne Petersen68516862013-04-18 16:47:42 +0200411 if (!(modifiers & entry->keysym.shift_mask))
412 entry->anchor = entry->cursor;
413 widget_schedule_redraw(entry->widget);
414
Jan Arne Petersencd997062012-11-18 19:06:44 +0100415 return;
416 }
417
Manuel Bachmann8986c182014-04-18 12:50:14 +0200418 if (key == XKB_KEY_Up ||
419 key == XKB_KEY_Down) {
420 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
421 return;
422
423 if (key == XKB_KEY_Up)
424 move_up(entry->text, &entry->cursor);
425 else
426 move_down(entry->text, &entry->cursor);
427
428 if (!(modifiers & entry->keysym.shift_mask))
429 entry->anchor = entry->cursor;
430 widget_schedule_redraw(entry->widget);
431
432 return;
433 }
434
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100435 if (key == XKB_KEY_BackSpace) {
436 const char *start, *end;
437
Jan Arne Petersendfd34462013-04-18 16:47:26 +0200438 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
439 return;
440
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100441 text_entry_commit_and_reset(entry);
442
443 start = utf8_prev_char(entry->text, entry->text + entry->cursor);
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100444 if (start == NULL)
445 return;
446
Daiki Uenob08b3292013-06-28 18:59:44 +0900447 end = utf8_next_char(start);
448
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100449 text_entry_delete_text(entry,
450 start - entry->text,
451 end - start);
452
453 return;
454 }
455
Manuel Bachmann8986c182014-04-18 12:50:14 +0200456 if (key == XKB_KEY_Tab ||
457 key == XKB_KEY_KP_Enter ||
458 key == XKB_KEY_Return) {
459 char text[16];
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200460
Manuel Bachmann8986c182014-04-18 12:50:14 +0200461 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
462 return;
463
464 xkb_keysym_to_utf8(key, text, sizeof(text));
465
466 text_entry_insert_at_cursor(entry, text, 0, 0);
467
468 return;
469 }
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200470}
471
472static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200473text_input_enter(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800474 struct zwp_text_input_v1 *text_input,
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200475 struct wl_surface *surface)
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200476{
477 struct text_entry *entry = data;
478
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200479 if (surface != window_get_wl_surface(entry->window))
480 return;
481
Derek Foreman237a6842014-12-17 09:43:58 -0600482 entry->active++;
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200483
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200484 text_entry_update(entry);
485 entry->reset_serial = entry->serial;
486
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200487 widget_schedule_redraw(entry->widget);
488}
489
490static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200491text_input_leave(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800492 struct zwp_text_input_v1 *text_input)
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200493{
494 struct text_entry *entry = data;
495
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100496 text_entry_commit_and_reset(entry);
Derek Foreman237a6842014-12-17 09:43:58 -0600497 entry->active--;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100498
Derek Foreman237a6842014-12-17 09:43:58 -0600499 if (!entry->active)
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800500 zwp_text_input_v1_hide_input_panel(text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100501
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200502 widget_schedule_redraw(entry->widget);
503}
504
Jan Arne Petersen61381972013-01-31 15:52:21 +0100505static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200506text_input_input_panel_state(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800507 struct zwp_text_input_v1 *text_input,
Jan Arne Petersen61381972013-01-31 15:52:21 +0100508 uint32_t state)
509{
510}
511
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200512static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200513text_input_language(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800514 struct zwp_text_input_v1 *text_input,
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200515 uint32_t serial,
516 const char *language)
517{
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200518 fprintf(stderr, "input language is %s \n", language);
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200519}
520
521static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200522text_input_text_direction(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800523 struct zwp_text_input_v1 *text_input,
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200524 uint32_t serial,
525 uint32_t direction)
526{
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200527 struct text_entry *entry = data;
528 PangoContext *context = pango_layout_get_context(entry->layout);
529 PangoDirection pango_direction;
530
531
532 switch (direction) {
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800533 case ZWP_TEXT_INPUT_V1_TEXT_DIRECTION_LTR:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200534 pango_direction = PANGO_DIRECTION_LTR;
535 break;
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800536 case ZWP_TEXT_INPUT_V1_TEXT_DIRECTION_RTL:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200537 pango_direction = PANGO_DIRECTION_RTL;
538 break;
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800539 case ZWP_TEXT_INPUT_V1_TEXT_DIRECTION_AUTO:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200540 default:
541 pango_direction = PANGO_DIRECTION_NEUTRAL;
542 }
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200543
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200544 pango_context_set_base_dir(context, pango_direction);
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200545}
546
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800547static const struct zwp_text_input_v1_listener text_input_listener = {
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200548 text_input_enter,
549 text_input_leave,
550 text_input_modifiers_map,
551 text_input_input_panel_state,
552 text_input_preedit_string,
553 text_input_preedit_styling,
554 text_input_preedit_cursor,
555 text_input_commit_string,
556 text_input_cursor_position,
557 text_input_delete_surrounding_text,
558 text_input_keysym,
559 text_input_language,
560 text_input_text_direction
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200561};
562
Manuel Bachmann22f34302015-03-30 01:57:44 +0200563static void
564data_source_target(void *data,
565 struct wl_data_source *source, const char *mime_type)
566{
567}
568
569static void
570data_source_send(void *data,
571 struct wl_data_source *source,
572 const char *mime_type, int32_t fd)
573{
574 struct editor *editor = data;
575
Bryce Harrington7dd12ec2015-05-19 15:32:09 -0700576 if (write(fd, editor->selected_text, strlen(editor->selected_text) + 1) < 0)
577 fprintf(stderr, "write failed: %m\n");
Manuel Bachmann22f34302015-03-30 01:57:44 +0200578}
579
580static void
581data_source_cancelled(void *data, struct wl_data_source *source)
582{
583 wl_data_source_destroy(source);
584}
585
586static const struct wl_data_source_listener data_source_listener = {
587 data_source_target,
588 data_source_send,
589 data_source_cancelled
590};
591
592static void
593paste_func(void *buffer, size_t len,
594 int32_t x, int32_t y, void *data)
595{
596 struct editor *editor = data;
597 struct text_entry *entry = editor->active_entry;
598 char *pasted_text;
599
600 if (!entry)
601 return;
602
603 pasted_text = malloc(len + 1);
604 strncpy(pasted_text, buffer, len);
605 pasted_text[len] = '\0';
606
607 text_entry_insert_at_cursor(entry, pasted_text, 0, 0);
608
609 free(pasted_text);
610}
611
612static void
613editor_copy_cut(struct editor *editor, struct input *input, bool cut)
614{
615 struct text_entry *entry = editor->active_entry;
616
617 if (!entry)
618 return;
Michael Vetter2a18a522015-05-15 17:17:47 +0200619
Manuel Bachmann22f34302015-03-30 01:57:44 +0200620 if (entry->cursor != entry->anchor) {
621 int start_index = MIN(entry->cursor, entry->anchor);
622 int end_index = MAX(entry->cursor, entry->anchor);
623 int len = end_index - start_index;
624
625 editor->selected_text = realloc(editor->selected_text, len + 1);
626 strncpy(editor->selected_text, &entry->text[start_index], len);
627 editor->selected_text[len] = '\0';
628
629 if (cut)
630 text_entry_delete_text(entry, start_index, len);
631
632 editor->selection =
633 display_create_data_source(editor->display);
634 wl_data_source_offer(editor->selection,
635 "text/plain;charset=utf-8");
636 wl_data_source_add_listener(editor->selection,
637 &data_source_listener, editor);
638 input_set_selection(input, editor->selection,
639 display_get_serial(editor->display));
640 }
641}
642
643static void
644editor_paste(struct editor *editor, struct input *input)
645{
646 input_receive_selection_data(input,
647 "text/plain;charset=utf-8",
648 paste_func, editor);
649}
650
651static void
652menu_func(void *data, struct input *input, int index)
653{
654 struct window *window = data;
655 struct editor *editor = window_get_user_data(window);
656
657 fprintf(stderr, "picked entry %d\n", index);
658
659 switch (index) {
660 case 0:
661 editor_copy_cut(editor, input, true);
662 break;
663 case 1:
664 editor_copy_cut(editor, input, false);
665 break;
666 case 2:
667 editor_paste(editor, input);
668 break;
669 }
670}
671
672static void
673show_menu(struct editor *editor, struct input *input, uint32_t time)
674{
675 int32_t x, y;
676 static const char *entries[] = {
677 "Cut", "Copy", "Paste"
678 };
679
680 input_get_position(input, &x, &y);
681 window_show_menu(editor->display, input, time, editor->window,
682 x + 10, y + 20, menu_func,
683 entries, ARRAY_LENGTH(entries));
684}
685
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200686static struct text_entry*
687text_entry_create(struct editor *editor, const char *text)
688{
689 struct text_entry *entry;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200690
Ryo Munakata5e653ca2015-08-07 20:20:46 +0900691 entry = xzalloc(sizeof *entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200692
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200693 entry->widget = widget_add_widget(editor->widget, entry);
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200694 entry->window = editor->window;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200695 entry->text = strdup(text);
696 entry->active = 0;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200697 entry->cursor = strlen(text);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200698 entry->anchor = entry->cursor;
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800699 entry->text_input =
700 zwp_text_input_manager_v1_create_text_input(editor->text_input_manager);
701 zwp_text_input_v1_add_listener(entry->text_input,
702 &text_input_listener, entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200703
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200704 widget_set_redraw_handler(entry->widget, text_entry_redraw_handler);
705 widget_set_button_handler(entry->widget, text_entry_button_handler);
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +0200706 widget_set_motion_handler(entry->widget, text_entry_motion_handler);
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -0800707 widget_set_touch_down_handler(entry->widget, text_entry_touch_handler);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200708
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200709 return entry;
710}
711
712static void
713text_entry_destroy(struct text_entry *entry)
714{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200715 widget_destroy(entry->widget);
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800716 zwp_text_input_v1_destroy(entry->text_input);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100717 g_clear_object(&entry->layout);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200718 free(entry->text);
719 free(entry);
720}
721
722static void
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200723redraw_handler(struct widget *widget, void *data)
724{
725 struct editor *editor = data;
726 cairo_surface_t *surface;
727 struct rectangle allocation;
728 cairo_t *cr;
729
730 surface = window_get_surface(editor->window);
731 widget_get_allocation(editor->widget, &allocation);
732
733 cr = cairo_create(surface);
734 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
735 cairo_clip(cr);
736
737 cairo_translate(cr, allocation.x, allocation.y);
738
739 /* Draw background */
740 cairo_push_group(cr);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200741 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200742 cairo_set_source_rgba(cr, 1, 1, 1, 1);
743 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
744 cairo_fill(cr);
745
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200746 cairo_pop_group_to_source(cr);
747 cairo_paint(cr);
748
749 cairo_destroy(cr);
750 cairo_surface_destroy(surface);
751}
752
753static void
754text_entry_allocate(struct text_entry *entry, int32_t x, int32_t y,
755 int32_t width, int32_t height)
756{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200757 widget_set_allocation(entry->widget, x, y, width, height);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200758}
759
760static void
761resize_handler(struct widget *widget,
762 int32_t width, int32_t height, void *data)
763{
764 struct editor *editor = data;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200765 struct rectangle allocation;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200766
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200767 widget_get_allocation(editor->widget, &allocation);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200768
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200769 text_entry_allocate(editor->entry,
770 allocation.x + 20, allocation.y + 20,
771 width - 40, height / 2 - 40);
772 text_entry_allocate(editor->editor,
773 allocation.x + 20, allocation.y + height / 2 + 20,
774 width - 40, height / 2 - 40);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200775}
776
777static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200778text_entry_activate(struct text_entry *entry,
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200779 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200780{
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200781 struct wl_surface *surface = window_get_wl_surface(entry->window);
782
Jan Arne Petersen61381972013-01-31 15:52:21 +0100783 if (entry->click_to_show && entry->active) {
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800784 zwp_text_input_v1_show_input_panel(entry->text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100785
786 return;
787 }
788
789 if (!entry->click_to_show)
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800790 zwp_text_input_v1_show_input_panel(entry->text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100791
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800792 zwp_text_input_v1_activate(entry->text_input,
793 seat,
794 surface);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200795}
796
797static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200798text_entry_deactivate(struct text_entry *entry,
799 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200800{
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800801 zwp_text_input_v1_deactivate(entry->text_input,
802 seat);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200803}
804
805static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200806text_entry_update_layout(struct text_entry *entry)
807{
808 char *text;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100809 PangoAttrList *attr_list;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200810
Jan Arne Petersen68516862013-04-18 16:47:42 +0200811 assert(entry->cursor <= (strlen(entry->text) +
812 (entry->preedit.text ? strlen(entry->preedit.text) : 0)));
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200813
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100814 if (entry->preedit.text) {
Derek Foreman22044922014-11-20 15:42:35 -0600815 text = xmalloc(strlen(entry->text) + strlen(entry->preedit.text) + 1);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100816 strncpy(text, entry->text, entry->cursor);
817 strcpy(text + entry->cursor, entry->preedit.text);
818 strcpy(text + entry->cursor + strlen(entry->preedit.text),
819 entry->text + entry->cursor);
820 } else {
821 text = strdup(entry->text);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200822 }
823
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100824 if (entry->cursor != entry->anchor) {
825 int start_index = MIN(entry->cursor, entry->anchor);
826 int end_index = MAX(entry->cursor, entry->anchor);
827 PangoAttribute *attr;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200828
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100829 attr_list = pango_attr_list_copy(entry->preedit.attr_list);
830
831 if (!attr_list)
832 attr_list = pango_attr_list_new();
833
834 attr = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
835 attr->start_index = start_index;
836 attr->end_index = end_index;
837 pango_attr_list_insert(attr_list, attr);
838
839 attr = pango_attr_foreground_new(65535, 65535, 65535);
840 attr->start_index = start_index;
841 attr->end_index = end_index;
842 pango_attr_list_insert(attr_list, attr);
843 } else {
844 attr_list = pango_attr_list_ref(entry->preedit.attr_list);
845 }
846
847 if (entry->preedit.text && !entry->preedit.attr_list) {
848 PangoAttribute *attr;
849
850 if (!attr_list)
851 attr_list = pango_attr_list_new();
852
853 attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
854 attr->start_index = entry->cursor;
855 attr->end_index = entry->cursor + strlen(entry->preedit.text);
856 pango_attr_list_insert(attr_list, attr);
857 }
858
859 if (entry->layout) {
860 pango_layout_set_text(entry->layout, text, -1);
861 pango_layout_set_attributes(entry->layout, attr_list);
862 }
863
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200864 free(text);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100865 pango_attr_list_unref(attr_list);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200866}
867
868static void
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100869text_entry_update(struct text_entry *entry)
870{
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200871 struct rectangle cursor_rectangle;
872
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800873 zwp_text_input_v1_set_content_type(entry->text_input,
874 ZWP_TEXT_INPUT_V1_CONTENT_HINT_NONE,
875 entry->content_purpose);
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100876
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800877 zwp_text_input_v1_set_surrounding_text(entry->text_input,
878 entry->text,
879 entry->cursor,
880 entry->anchor);
Jan Arne Petersen0eabcaa2013-01-31 15:52:20 +0100881
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200882 if (entry->preferred_language)
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800883 zwp_text_input_v1_set_preferred_language(entry->text_input,
884 entry->preferred_language);
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200885
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200886 text_entry_get_cursor_rectangle(entry, &cursor_rectangle);
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800887 zwp_text_input_v1_set_cursor_rectangle(entry->text_input,
888 cursor_rectangle.x,
889 cursor_rectangle.y,
890 cursor_rectangle.width,
891 cursor_rectangle.height);
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200892
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800893 zwp_text_input_v1_commit_state(entry->text_input, ++entry->serial);
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100894}
895
896static void
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100897text_entry_insert_at_cursor(struct text_entry *entry, const char *text,
898 int32_t cursor, int32_t anchor)
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200899{
Derek Foreman22044922014-11-20 15:42:35 -0600900 char *new_text = xmalloc(strlen(entry->text) + strlen(text) + 1);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200901
902 strncpy(new_text, entry->text, entry->cursor);
903 strcpy(new_text + entry->cursor, text);
904 strcpy(new_text + entry->cursor + strlen(text),
905 entry->text + entry->cursor);
906
907 free(entry->text);
908 entry->text = new_text;
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100909 if (anchor >= 0)
910 entry->anchor = entry->cursor + strlen(text) + anchor;
911 else
912 entry->anchor = entry->cursor + 1 + anchor;
Jan Arne Petersen68516862013-04-18 16:47:42 +0200913
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100914 if (cursor >= 0)
915 entry->cursor += strlen(text) + cursor;
916 else
917 entry->cursor += 1 + cursor;
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200918
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200919 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100920
921 widget_schedule_redraw(entry->widget);
922
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100923 text_entry_update(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200924}
925
926static void
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100927text_entry_reset_preedit(struct text_entry *entry)
928{
929 entry->preedit.cursor = 0;
930
931 free(entry->preedit.text);
932 entry->preedit.text = NULL;
933
934 free(entry->preedit.commit);
935 entry->preedit.commit = NULL;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100936
937 pango_attr_list_unref(entry->preedit.attr_list);
938 entry->preedit.attr_list = NULL;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100939}
940
941static void
942text_entry_commit_and_reset(struct text_entry *entry)
943{
944 char *commit = NULL;
945
946 if (entry->preedit.commit)
947 commit = strdup(entry->preedit.commit);
948
949 text_entry_reset_preedit(entry);
950 if (commit) {
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100951 text_entry_insert_at_cursor(entry, commit, 0, 0);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100952 free(commit);
953 }
Jan Arne Petersen08015b62013-04-18 16:47:18 +0200954
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800955 zwp_text_input_v1_reset(entry->text_input);
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200956 text_entry_update(entry);
957 entry->reset_serial = entry->serial;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100958}
959
960static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200961text_entry_set_preedit(struct text_entry *entry,
962 const char *preedit_text,
963 int preedit_cursor)
964{
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100965 text_entry_reset_preedit(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200966
967 if (!preedit_text)
968 return;
969
Jan Arne Petersen46535312013-01-16 21:26:38 +0100970 entry->preedit.text = strdup(preedit_text);
971 entry->preedit.cursor = preedit_cursor;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200972
973 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100974
975 widget_schedule_redraw(entry->widget);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200976}
977
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100978static uint32_t
979text_entry_try_invoke_preedit_action(struct text_entry *entry,
980 int32_t x, int32_t y,
981 uint32_t button,
982 enum wl_pointer_button_state state)
983{
984 int index, trailing;
985 uint32_t cursor;
Jan Arne Petersen68516862013-04-18 16:47:42 +0200986 const char *text;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100987
988 if (!entry->preedit.text)
989 return 0;
990
991 pango_layout_xy_to_index(entry->layout,
992 x * PANGO_SCALE, y * PANGO_SCALE,
993 &index, &trailing);
Jan Arne Petersen68516862013-04-18 16:47:42 +0200994
995 text = pango_layout_get_text(entry->layout);
996 cursor = g_utf8_offset_to_pointer(text + index, trailing) - text;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100997
998 if (cursor < entry->cursor ||
999 cursor > entry->cursor + strlen(entry->preedit.text)) {
1000 return 0;
1001 }
1002
1003 if (state == WL_POINTER_BUTTON_STATE_RELEASED)
Jonas Ådahl3bcba342015-11-17 16:00:29 +08001004 zwp_text_input_v1_invoke_action(entry->text_input,
1005 button,
1006 cursor - entry->cursor);
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001007
1008 return 1;
1009}
1010
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001011static bool
1012text_entry_has_preedit(struct text_entry *entry)
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001013{
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001014 return entry->preedit.text && (strlen(entry->preedit.text) > 0);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001015}
1016
1017static void
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001018text_entry_set_cursor_position(struct text_entry *entry,
1019 int32_t x, int32_t y,
1020 bool move_anchor)
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001021{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001022 int index, trailing;
Jan Arne Petersen68516862013-04-18 16:47:42 +02001023 const char *text;
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001024 uint32_t cursor;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001025
1026 pango_layout_xy_to_index(entry->layout,
1027 x * PANGO_SCALE, y * PANGO_SCALE,
1028 &index, &trailing);
Jan Arne Petersen68516862013-04-18 16:47:42 +02001029
1030 text = pango_layout_get_text(entry->layout);
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001031
1032 cursor = g_utf8_offset_to_pointer(text + index, trailing) - text;
1033
1034 if (move_anchor)
1035 entry->anchor = cursor;
1036
1037 if (text_entry_has_preedit(entry)) {
1038 text_entry_commit_and_reset(entry);
1039
1040 assert(!text_entry_has_preedit(entry));
1041 }
1042
1043 if (entry->cursor == cursor)
1044 return;
1045
1046 entry->cursor = cursor;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001047
1048 text_entry_update_layout(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001049
1050 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001051
Jan Arne Petersen0558a932013-01-16 21:26:45 +01001052 text_entry_update(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001053}
1054
1055static void
Jan Arne Petersene202bae2012-09-09 23:08:44 +02001056text_entry_delete_text(struct text_entry *entry,
1057 uint32_t index, uint32_t length)
1058{
Jan Arne Petersen68516862013-04-18 16:47:42 +02001059 uint32_t l;
1060
Jan Arne Petersen895a1282013-05-30 13:57:04 +02001061 assert(index <= strlen(entry->text));
1062 assert(index + length <= strlen(entry->text));
1063 assert(index + length >= length);
Jan Arne Petersen80ad1a92012-09-17 15:28:10 +02001064
Jan Arne Petersen68516862013-04-18 16:47:42 +02001065 l = strlen(entry->text + index + length);
1066 memmove(entry->text + index,
1067 entry->text + index + length,
1068 l + 1);
Jan Arne Petersene202bae2012-09-09 23:08:44 +02001069
Jan Arne Petersen9eaa8e52013-05-30 13:57:03 +02001070 if (entry->cursor > (index + length))
1071 entry->cursor -= length;
1072 else if (entry->cursor > index)
1073 entry->cursor = index;
1074
1075 entry->anchor = entry->cursor;
1076
Jan Arne Petersene202bae2012-09-09 23:08:44 +02001077 text_entry_update_layout(entry);
1078
1079 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001080
Jan Arne Petersen0558a932013-01-16 21:26:45 +01001081 text_entry_update(entry);
Jan Arne Petersene202bae2012-09-09 23:08:44 +02001082}
1083
1084static void
Jan Arne Petersene386dd22012-09-17 15:28:09 +02001085text_entry_delete_selected_text(struct text_entry *entry)
1086{
1087 uint32_t start_index = entry->anchor < entry->cursor ? entry->anchor : entry->cursor;
1088 uint32_t end_index = entry->anchor < entry->cursor ? entry->cursor : entry->anchor;
1089
1090 if (entry->anchor == entry->cursor)
1091 return;
1092
1093 text_entry_delete_text(entry, start_index, end_index - start_index);
1094
1095 entry->anchor = entry->cursor;
1096}
1097
1098static void
Jan Arne Petersenfe89e712013-04-18 16:47:27 +02001099text_entry_get_cursor_rectangle(struct text_entry *entry, struct rectangle *rectangle)
1100{
1101 struct rectangle allocation;
1102 PangoRectangle extents;
1103 PangoRectangle cursor_pos;
1104
1105 widget_get_allocation(entry->widget, &allocation);
1106
1107 if (entry->preedit.text && entry->preedit.cursor < 0) {
1108 rectangle->x = 0;
1109 rectangle->y = 0;
1110 rectangle->width = 0;
1111 rectangle->height = 0;
1112 return;
1113 }
1114
Jan Arne Petersen68516862013-04-18 16:47:42 +02001115
Jan Arne Petersenfe89e712013-04-18 16:47:27 +02001116 pango_layout_get_extents(entry->layout, &extents, NULL);
1117 pango_layout_get_cursor_pos(entry->layout,
1118 entry->cursor + entry->preedit.cursor,
1119 &cursor_pos, NULL);
1120
1121 rectangle->x = allocation.x + (allocation.height / 2) + PANGO_PIXELS(cursor_pos.x);
1122 rectangle->y = allocation.y + 10 + PANGO_PIXELS(cursor_pos.y);
1123 rectangle->width = PANGO_PIXELS(cursor_pos.width);
1124 rectangle->height = PANGO_PIXELS(cursor_pos.height);
1125}
1126
1127static void
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001128text_entry_draw_cursor(struct text_entry *entry, cairo_t *cr)
1129{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001130 PangoRectangle extents;
1131 PangoRectangle cursor_pos;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001132
Jan Arne Petersen46535312013-01-16 21:26:38 +01001133 if (entry->preedit.text && entry->preedit.cursor < 0)
1134 return;
1135
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001136 pango_layout_get_extents(entry->layout, &extents, NULL);
1137 pango_layout_get_cursor_pos(entry->layout,
1138 entry->cursor + entry->preedit.cursor,
1139 &cursor_pos, NULL);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001140
1141 cairo_set_line_width(cr, 1.0);
Peter Maatmanb9a23f42013-07-06 20:55:54 +02001142 cairo_move_to(cr, PANGO_PIXELS(cursor_pos.x), PANGO_PIXELS(cursor_pos.y));
1143 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 +02001144 cairo_stroke(cr);
1145}
1146
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001147static int
1148text_offset_left(struct rectangle *allocation)
1149{
1150 return 10;
1151}
1152
1153static int
1154text_offset_top(struct rectangle *allocation)
1155{
1156 return allocation->height / 2;
1157}
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +02001158
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +02001159static void
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001160text_entry_redraw_handler(struct widget *widget, void *data)
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001161{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001162 struct text_entry *entry = data;
1163 cairo_surface_t *surface;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001164 struct rectangle allocation;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001165 cairo_t *cr;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001166
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001167 surface = window_get_surface(entry->window);
1168 widget_get_allocation(entry->widget, &allocation);
1169
1170 cr = cairo_create(surface);
1171 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
1172 cairo_clip(cr);
1173
1174 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
1175
1176 cairo_push_group(cr);
1177 cairo_translate(cr, allocation.x, allocation.y);
1178
1179 cairo_set_source_rgba(cr, 1, 1, 1, 1);
1180 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
1181 cairo_fill(cr);
1182
1183 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
1184
1185 if (entry->active) {
1186 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
1187 cairo_set_line_width (cr, 3);
1188 cairo_set_source_rgba(cr, 0, 0, 1, 1.0);
1189 cairo_stroke(cr);
1190 }
1191
1192 cairo_set_source_rgba(cr, 0, 0, 0, 1);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001193
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001194 cairo_translate(cr,
1195 text_offset_left(&allocation),
1196 text_offset_top(&allocation));
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001197
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001198 if (!entry->layout)
1199 entry->layout = pango_cairo_create_layout(cr);
1200 else
1201 pango_cairo_update_layout(cr, entry->layout);
1202
1203 text_entry_update_layout(entry);
1204
1205 pango_cairo_show_layout(cr, entry->layout);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001206
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001207 text_entry_draw_cursor(entry, cr);
1208
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001209 cairo_pop_group_to_source(cr);
1210 cairo_paint(cr);
1211
1212 cairo_destroy(cr);
1213 cairo_surface_destroy(surface);
1214}
1215
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001216static int
1217text_entry_motion_handler(struct widget *widget,
1218 struct input *input, uint32_t time,
1219 float x, float y, void *data)
1220{
1221 struct text_entry *entry = data;
1222 struct rectangle allocation;
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001223 int tx, ty;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001224
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001225 if (!entry->button_pressed) {
1226 return CURSOR_IBEAM;
1227 }
1228
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001229 widget_get_allocation(entry->widget, &allocation);
1230
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001231 tx = x - allocation.x - text_offset_left(&allocation);
1232 ty = y - allocation.y - text_offset_top(&allocation);
1233
1234 text_entry_set_cursor_position(entry, tx, ty, false);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001235
1236 return CURSOR_IBEAM;
1237}
1238
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001239static void
1240text_entry_button_handler(struct widget *widget,
1241 struct input *input, uint32_t time,
1242 uint32_t button,
1243 enum wl_pointer_button_state state, void *data)
1244{
1245 struct text_entry *entry = data;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001246 struct rectangle allocation;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001247 struct editor *editor;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001248 int32_t x, y;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001249 uint32_t result;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001250
1251 widget_get_allocation(entry->widget, &allocation);
1252 input_get_position(input, &x, &y);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001253
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001254 x -= allocation.x + text_offset_left(&allocation);
1255 y -= allocation.y + text_offset_top(&allocation);
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001256
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001257 editor = window_get_user_data(entry->window);
1258
Manuel Bachmann22f34302015-03-30 01:57:44 +02001259 switch (button) {
1260 case BTN_LEFT:
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001261 entry->button_pressed = (state == WL_POINTER_BUTTON_STATE_PRESSED);
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001262 if (state == WL_POINTER_BUTTON_STATE_PRESSED)
1263 input_grab(input, entry->widget, button);
1264 else
1265 input_ungrab(input);
Manuel Bachmann22f34302015-03-30 01:57:44 +02001266 break;
1267 case BTN_RIGHT:
1268 if (state == WL_POINTER_BUTTON_STATE_PRESSED)
1269 show_menu(editor, input, time);
1270 break;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001271 }
1272
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001273 if (text_entry_has_preedit(entry)) {
1274 result = text_entry_try_invoke_preedit_action(entry, x, y, button, state);
1275
1276 if (result)
1277 return;
1278 }
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001279
Manuel Bachmann22f34302015-03-30 01:57:44 +02001280 if (state == WL_POINTER_BUTTON_STATE_PRESSED &&
1281 button == BTN_LEFT) {
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001282 struct wl_seat *seat = input_get_seat(input);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001283
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001284 text_entry_activate(entry, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001285 editor->active_entry = entry;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001286
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001287 text_entry_set_cursor_position(entry, x, y, true);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001288 }
1289}
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001290
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001291static void
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -08001292text_entry_touch_handler(struct widget *widget, struct input *input,
1293 uint32_t serial, uint32_t time, int32_t id,
1294 float tx, float ty, void *data)
1295{
1296 struct text_entry *entry = data;
1297 struct wl_seat *seat = input_get_seat(input);
1298 struct rectangle allocation;
1299 struct editor *editor;
1300 int32_t x, y;
1301
1302 widget_get_allocation(entry->widget, &allocation);
1303
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001304 x = tx - (allocation.x + text_offset_left(&allocation));
1305 y = ty - (allocation.y + text_offset_top(&allocation));
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -08001306
1307 editor = window_get_user_data(entry->window);
1308 text_entry_activate(entry, seat);
1309 editor->active_entry = entry;
1310
1311 text_entry_set_cursor_position(entry, x, y, true);
1312}
1313
1314static void
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001315editor_button_handler(struct widget *widget,
1316 struct input *input, uint32_t time,
1317 uint32_t button,
1318 enum wl_pointer_button_state state, void *data)
1319{
1320 struct editor *editor = data;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001321
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001322 if (button != BTN_LEFT) {
1323 return;
1324 }
Jan Arne Petersene829adc2012-08-10 16:47:22 +02001325
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001326 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
1327 struct wl_seat *seat = input_get_seat(input);
1328
Jan Arne Petersene829adc2012-08-10 16:47:22 +02001329 text_entry_deactivate(editor->entry, seat);
1330 text_entry_deactivate(editor->editor, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001331 editor->active_entry = NULL;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001332 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001333}
1334
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -08001335static void
1336editor_touch_handler(struct widget *widget, struct input *input,
1337 uint32_t serial, uint32_t time, int32_t id,
1338 float tx, float ty, void *data)
1339{
1340 struct editor *editor = data;
1341
1342 struct wl_seat *seat = input_get_seat(input);
1343
1344 text_entry_deactivate(editor->entry, seat);
1345 text_entry_deactivate(editor->editor, seat);
1346 editor->active_entry = NULL;
1347}
Kristian Høgsberg78858902014-01-01 23:57:42 -08001348
1349static void
1350keyboard_focus_handler(struct window *window,
1351 struct input *device, void *data)
1352{
1353 struct editor *editor = data;
1354
1355 window_schedule_redraw(editor->window);
1356}
1357
Manuel Bachmann22f34302015-03-30 01:57:44 +02001358static int
1359handle_bound_key(struct editor *editor,
1360 struct input *input, uint32_t sym, uint32_t time)
1361{
1362 switch (sym) {
1363 case XKB_KEY_X:
1364 editor_copy_cut(editor, input, true);
1365 return 1;
1366 case XKB_KEY_C:
1367 editor_copy_cut(editor, input, false);
1368 return 1;
1369 case XKB_KEY_V:
1370 editor_paste(editor, input);
1371 return 1;
1372 default:
1373 return 0;
1374 }
1375}
1376
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001377static void
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001378key_handler(struct window *window,
1379 struct input *input, uint32_t time,
1380 uint32_t key, uint32_t sym, enum wl_keyboard_key_state state,
1381 void *data)
1382{
1383 struct editor *editor = data;
1384 struct text_entry *entry;
Jan Arne Petersen68516862013-04-18 16:47:42 +02001385 const char *new_char;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001386 char text[16];
Manuel Bachmann22f34302015-03-30 01:57:44 +02001387 uint32_t modifiers;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001388
1389 if (!editor->active_entry)
1390 return;
1391
1392 entry = editor->active_entry;
1393
1394 if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
1395 return;
1396
Manuel Bachmann22f34302015-03-30 01:57:44 +02001397 modifiers = input_get_modifiers(input);
1398 if ((modifiers & MOD_CONTROL_MASK) &&
1399 (modifiers & MOD_SHIFT_MASK) &&
1400 handle_bound_key(editor, input, sym, time))
1401 return;
1402
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001403 switch (sym) {
1404 case XKB_KEY_BackSpace:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001405 text_entry_commit_and_reset(entry);
1406
Jan Arne Petersen68516862013-04-18 16:47:42 +02001407 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
1408 if (new_char != NULL)
1409 text_entry_delete_text(entry,
1410 new_char - entry->text,
1411 (entry->text + entry->cursor) - new_char);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001412 break;
1413 case XKB_KEY_Delete:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001414 text_entry_commit_and_reset(entry);
1415
Jan Arne Petersen68516862013-04-18 16:47:42 +02001416 new_char = utf8_next_char(entry->text + entry->cursor);
1417 if (new_char != NULL)
1418 text_entry_delete_text(entry,
1419 entry->cursor,
1420 new_char - (entry->text + entry->cursor));
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001421 break;
1422 case XKB_KEY_Left:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001423 text_entry_commit_and_reset(entry);
1424
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001425 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
1426 if (new_char != NULL) {
1427 entry->cursor = new_char - entry->text;
Rob Bradford70002832013-07-11 16:00:00 +01001428 if (!(input_get_modifiers(input) & MOD_SHIFT_MASK))
1429 entry->anchor = entry->cursor;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001430 widget_schedule_redraw(entry->widget);
1431 }
1432 break;
1433 case XKB_KEY_Right:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001434 text_entry_commit_and_reset(entry);
1435
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001436 new_char = utf8_next_char(entry->text + entry->cursor);
1437 if (new_char != NULL) {
1438 entry->cursor = new_char - entry->text;
Rob Bradford70002832013-07-11 16:00:00 +01001439 if (!(input_get_modifiers(input) & MOD_SHIFT_MASK))
1440 entry->anchor = entry->cursor;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001441 widget_schedule_redraw(entry->widget);
1442 }
1443 break;
Manuel Bachmann8986c182014-04-18 12:50:14 +02001444 case XKB_KEY_Up:
1445 text_entry_commit_and_reset(entry);
1446
1447 move_up(entry->text, &entry->cursor);
1448 if (!(input_get_modifiers(input) & MOD_SHIFT_MASK))
1449 entry->anchor = entry->cursor;
1450 widget_schedule_redraw(entry->widget);
1451 break;
1452 case XKB_KEY_Down:
1453 text_entry_commit_and_reset(entry);
1454
1455 move_down(entry->text, &entry->cursor);
1456 if (!(input_get_modifiers(input) & MOD_SHIFT_MASK))
1457 entry->anchor = entry->cursor;
1458 widget_schedule_redraw(entry->widget);
1459 break;
Peter Maatman08c38d42013-07-06 20:42:59 +02001460 case XKB_KEY_Escape:
1461 break;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001462 default:
1463 if (xkb_keysym_to_utf8(sym, text, sizeof(text)) <= 0)
1464 break;
1465
Peter Maatman08c38d42013-07-06 20:42:59 +02001466 text_entry_commit_and_reset(entry);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001467
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +01001468 text_entry_insert_at_cursor(entry, text, 0, 0);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001469 break;
1470 }
1471
1472 widget_schedule_redraw(entry->widget);
1473}
1474
1475static void
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001476global_handler(struct display *display, uint32_t name,
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001477 const char *interface, uint32_t version, void *data)
1478{
1479 struct editor *editor = data;
1480
Jonas Ådahl3bcba342015-11-17 16:00:29 +08001481 if (!strcmp(interface, "zwp_text_input_manager_v1")) {
Jan Arne Petersen78d00e42013-04-18 16:47:24 +02001482 editor->text_input_manager =
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001483 display_bind(display, name,
Jonas Ådahl3bcba342015-11-17 16:00:29 +08001484 &zwp_text_input_manager_v1_interface, 1);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001485 }
1486}
1487
1488int
1489main(int argc, char *argv[])
1490{
1491 struct editor editor;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001492 int i;
1493 uint32_t click_to_show = 0;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001494 const char *preferred_language = NULL;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001495
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001496 for (i = 1; i < argc; i++) {
Jan Arne Petersen61381972013-01-31 15:52:21 +01001497 if (strcmp("--click-to-show", argv[i]) == 0)
1498 click_to_show = 1;
Bill Spitzakbb0bb9c2014-08-08 12:59:58 -07001499 else if (strcmp("--preferred-language", argv[i]) == 0 &&
1500 i + 1 < argc) {
1501 preferred_language = argv[i + 1];
1502 i++;
1503 } else {
1504 printf("Usage: %s [OPTIONS]\n"
1505 " --click-to-show\n"
1506 " --preferred-language LANGUAGE\n",
1507 argv[0]);
1508 return 1;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001509 }
1510 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001511
Jan Arne Petersen25f6db52012-11-05 03:26:40 +01001512 memset(&editor, 0, sizeof editor);
1513
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001514#ifdef HAVE_PANGO
1515 g_type_init();
1516#endif
1517
Kristian Høgsberg4172f662013-02-20 15:27:49 -05001518 editor.display = display_create(&argc, argv);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001519 if (editor.display == NULL) {
1520 fprintf(stderr, "failed to create display: %m\n");
1521 return -1;
1522 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001523
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001524 display_set_user_data(editor.display, &editor);
1525 display_set_global_handler(editor.display, global_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001526
Olivier Blin30e1f3c2014-09-16 19:13:17 +02001527 if (editor.text_input_manager == NULL) {
1528 fprintf(stderr, "No text input manager global\n");
1529 return -1;
1530 }
1531
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001532 editor.window = window_create(editor.display);
Jason Ekstrandee7fefc2013-10-13 19:08:38 -05001533 editor.widget = window_frame_create(editor.window, &editor);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001534
1535 editor.entry = text_entry_create(&editor, "Entry");
Jan Arne Petersen61381972013-01-31 15:52:21 +01001536 editor.entry->click_to_show = click_to_show;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001537 if (preferred_language)
1538 editor.entry->preferred_language = strdup(preferred_language);
Jan Arne Petersen0558a932013-01-16 21:26:45 +01001539 editor.editor = text_entry_create(&editor, "Numeric");
Jonas Ådahl3bcba342015-11-17 16:00:29 +08001540 editor.editor->content_purpose = ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_NUMBER;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001541 editor.editor->click_to_show = click_to_show;
Manuel Bachmann22f34302015-03-30 01:57:44 +02001542 editor.selection = NULL;
1543 editor.selected_text = NULL;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001544
1545 window_set_title(editor.window, "Text Editor");
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001546 window_set_key_handler(editor.window, key_handler);
Kristian Høgsberg78858902014-01-01 23:57:42 -08001547 window_set_keyboard_focus_handler(editor.window,
1548 keyboard_focus_handler);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001549 window_set_user_data(editor.window, &editor);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001550
1551 widget_set_redraw_handler(editor.widget, redraw_handler);
1552 widget_set_resize_handler(editor.widget, resize_handler);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001553 widget_set_button_handler(editor.widget, editor_button_handler);
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -08001554 widget_set_touch_down_handler(editor.widget, editor_touch_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001555
1556 window_schedule_resize(editor.window, 500, 400);
1557
1558 display_run(editor.display);
1559
Manuel Bachmann22f34302015-03-30 01:57:44 +02001560 if (editor.selected_text)
1561 free(editor.selected_text);
1562 if (editor.selection)
1563 wl_data_source_destroy(editor.selection);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001564 text_entry_destroy(editor.entry);
1565 text_entry_destroy(editor.editor);
vivek31732f72014-05-15 18:58:16 +05301566 widget_destroy(editor.widget);
1567 window_destroy(editor.window);
1568 display_destroy(editor.display);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001569
1570 return 0;
1571}