blob: a86c590e4f65b768d3de32b9edc7b83370f30589 [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
Jan Arne Petersencba9e472012-06-21 21:52:19 +020039#include "window.h"
40#include "text-client-protocol.h"
41
42struct text_entry {
43 struct widget *widget;
Jan Arne Petersene829adc2012-08-10 16:47:22 +020044 struct window *window;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020045 char *text;
46 int active;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +020047 uint32_t cursor;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +020048 uint32_t anchor;
Jan Arne Petersen46535312013-01-16 21:26:38 +010049 struct {
50 char *text;
51 int32_t cursor;
52 char *commit;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010053 PangoAttrList *attr_list;
Jan Arne Petersen46535312013-01-16 21:26:38 +010054 } preedit;
55 struct {
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010056 PangoAttrList *attr_list;
Jan Arne Petersen46535312013-01-16 21:26:38 +010057 int32_t cursor;
58 } preedit_info;
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +010059 struct {
60 int32_t cursor;
61 int32_t anchor;
Jan Arne Petersen919bc142013-04-18 16:47:34 +020062 uint32_t delete_index;
63 uint32_t delete_length;
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +020064 bool invalid_delete;
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +010065 } pending_commit;
Jan Arne Petersen62ece762013-04-18 16:47:36 +020066 struct wl_text_input *text_input;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010067 PangoLayout *layout;
Jan Arne Petersencd997062012-11-18 19:06:44 +010068 struct {
69 xkb_mod_mask_t shift_mask;
70 } keysym;
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +010071 uint32_t serial;
Jan Arne Petersen00191c72013-04-18 16:47:33 +020072 uint32_t reset_serial;
Jan Arne Petersen0558a932013-01-16 21:26:45 +010073 uint32_t content_purpose;
Jan Arne Petersen61381972013-01-31 15:52:21 +010074 uint32_t click_to_show;
Jan Arne Petersen9d419132013-04-18 16:47:16 +020075 char *preferred_language;
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +020076 bool button_pressed;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020077};
78
79struct editor {
Jan Arne Petersen62ece762013-04-18 16:47:36 +020080 struct wl_text_input_manager *text_input_manager;
Manuel Bachmann22f34302015-03-30 01:57:44 +020081 struct wl_data_source *selection;
82 char *selected_text;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020083 struct display *display;
84 struct window *window;
85 struct widget *widget;
86 struct text_entry *entry;
87 struct text_entry *editor;
Rob Bradford9d1d32b2012-11-18 19:06:49 +010088 struct text_entry *active_entry;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020089};
90
Jan Arne Petersen6345faa2012-11-05 03:26:39 +010091static const char *
Jan Arne Petersen6345faa2012-11-05 03:26:39 +010092utf8_end_char(const char *p)
93{
94 while ((*p & 0xc0) == 0x80)
95 p++;
96 return p;
97}
98
99static const char *
Jan Arne Petersen68516862013-04-18 16:47:42 +0200100utf8_prev_char(const char *s, const char *p)
101{
102 for (--p; p >= s; --p) {
103 if ((*p & 0xc0) != 0x80)
104 return p;
105 }
106 return NULL;
107}
108
109static const char *
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100110utf8_next_char(const char *p)
111{
112 if (*p != 0)
113 return utf8_end_char(++p);
114 return NULL;
115}
116
Manuel Bachmann8986c182014-04-18 12:50:14 +0200117static void
118move_up(const char *p, uint32_t *cursor)
119{
120 const char *posr, *posr_i;
121 char text[16];
122
123 xkb_keysym_to_utf8(XKB_KEY_Return, text, sizeof(text));
124
125 posr = strstr(p, text);
126 while (posr) {
127 if (*cursor > (unsigned)(posr-p)) {
128 posr_i = strstr(posr+1, text);
129 if (!posr_i || !(*cursor > (unsigned)(posr_i-p))) {
130 *cursor = posr-p;
131 break;
132 }
133 posr = posr_i;
134 } else {
135 break;
136 }
137 }
138}
139
140static void
141move_down(const char *p, uint32_t *cursor)
142{
143 const char *posr;
144 char text[16];
145
146 xkb_keysym_to_utf8(XKB_KEY_Return, text, sizeof(text));
147
148 posr = strstr(p, text);
149 while (posr) {
150 if (*cursor <= (unsigned)(posr-p)) {
151 *cursor = posr-p + 1;
152 break;
153 }
154 posr = strstr(posr+1, text);
155 }
156}
157
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200158static void text_entry_redraw_handler(struct widget *widget, void *data);
159static void text_entry_button_handler(struct widget *widget,
160 struct input *input, uint32_t time,
161 uint32_t button,
162 enum wl_pointer_button_state state, void *data);
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -0800163static void text_entry_touch_handler(struct widget *widget, struct input *input,
164 uint32_t serial, uint32_t time, int32_t id,
165 float tx, float ty, void *data);
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +0200166static int text_entry_motion_handler(struct widget *widget,
167 struct input *input, uint32_t time,
168 float x, float y, void *data);
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100169static void text_entry_insert_at_cursor(struct text_entry *entry, const char *text,
170 int32_t cursor, int32_t anchor);
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200171static void text_entry_set_preedit(struct text_entry *entry,
172 const char *preedit_text,
173 int preedit_cursor);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200174static void text_entry_delete_text(struct text_entry *entry,
175 uint32_t index, uint32_t length);
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200176static void text_entry_delete_selected_text(struct text_entry *entry);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100177static void text_entry_reset_preedit(struct text_entry *entry);
178static void text_entry_commit_and_reset(struct text_entry *entry);
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200179static void text_entry_get_cursor_rectangle(struct text_entry *entry, struct rectangle *rectangle);
180static void text_entry_update(struct text_entry *entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200181
182static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200183text_input_commit_string(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200184 struct wl_text_input *text_input,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100185 uint32_t serial,
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100186 const char *text)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200187{
188 struct text_entry *entry = data;
189
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200190 if ((entry->serial - serial) > (entry->serial - entry->reset_serial)) {
191 fprintf(stderr, "Ignore commit. Serial: %u, Current: %u, Reset: %u\n",
192 serial, entry->serial, entry->reset_serial);
193 return;
194 }
195
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200196 if (entry->pending_commit.invalid_delete) {
197 fprintf(stderr, "Ignore commit. Invalid previous delete_surrounding event.\n");
198 memset(&entry->pending_commit, 0, sizeof entry->pending_commit);
199 return;
200 }
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100201
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200202 text_entry_reset_preedit(entry);
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200203
204 if (entry->pending_commit.delete_length) {
205 text_entry_delete_text(entry,
206 entry->pending_commit.delete_index,
207 entry->pending_commit.delete_length);
Jan Arne Petersena96953d2013-05-30 13:57:02 +0200208 } else {
209 text_entry_delete_selected_text(entry);
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200210 }
211
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100212 text_entry_insert_at_cursor(entry, text,
213 entry->pending_commit.cursor,
214 entry->pending_commit.anchor);
215
216 memset(&entry->pending_commit, 0, sizeof entry->pending_commit);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200217
218 widget_schedule_redraw(entry->widget);
219}
220
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200221static void
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200222clear_pending_preedit(struct text_entry *entry)
223{
224 memset(&entry->pending_commit, 0, sizeof entry->pending_commit);
225
226 pango_attr_list_unref(entry->preedit_info.attr_list);
227
228 entry->preedit_info.cursor = 0;
229 entry->preedit_info.attr_list = NULL;
230
231 memset(&entry->preedit_info, 0, sizeof entry->preedit_info);
232}
233
234static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200235text_input_preedit_string(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200236 struct wl_text_input *text_input,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100237 uint32_t serial,
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200238 const char *text,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100239 const char *commit)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200240{
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200241 struct text_entry *entry = data;
242
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200243 if ((entry->serial - serial) > (entry->serial - entry->reset_serial)) {
244 fprintf(stderr, "Ignore preedit_string. Serial: %u, Current: %u, Reset: %u\n",
245 serial, entry->serial, entry->reset_serial);
246 clear_pending_preedit(entry);
247 return;
248 }
249
250 if (entry->pending_commit.invalid_delete) {
251 fprintf(stderr, "Ignore preedit_string. Invalid previous delete_surrounding event.\n");
252 clear_pending_preedit(entry);
253 return;
254 }
255
Jan Arne Petersena96953d2013-05-30 13:57:02 +0200256 if (entry->pending_commit.delete_length) {
257 text_entry_delete_text(entry,
258 entry->pending_commit.delete_index,
259 entry->pending_commit.delete_length);
260 } else {
261 text_entry_delete_selected_text(entry);
262 }
Jan Arne Petersena96953d2013-05-30 13:57:02 +0200263
Jan Arne Petersen46535312013-01-16 21:26:38 +0100264 text_entry_set_preedit(entry, text, entry->preedit_info.cursor);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100265 entry->preedit.commit = strdup(commit);
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200266 entry->preedit.attr_list = pango_attr_list_ref(entry->preedit_info.attr_list);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100267
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200268 clear_pending_preedit(entry);
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200269
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200270 text_entry_update(entry);
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200271
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200272 widget_schedule_redraw(entry->widget);
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200273}
274
275static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200276text_input_delete_surrounding_text(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200277 struct wl_text_input *text_input,
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200278 int32_t index,
279 uint32_t length)
280{
281 struct text_entry *entry = data;
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200282 uint32_t text_length;
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200283
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200284 entry->pending_commit.delete_index = entry->cursor + index;
285 entry->pending_commit.delete_length = length;
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200286 entry->pending_commit.invalid_delete = false;
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200287
Jan Arne Petersen68516862013-04-18 16:47:42 +0200288 text_length = strlen(entry->text);
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200289
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200290 if (entry->pending_commit.delete_index > text_length ||
291 length > text_length ||
Jan Arne Petersen895a1282013-05-30 13:57:04 +0200292 entry->pending_commit.delete_index + length > text_length) {
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200293 fprintf(stderr, "delete_surrounding_text: Invalid index: %d," \
294 "length %u'; cursor: %u text length: %u\n", index, length, entry->cursor, text_length);
295 entry->pending_commit.invalid_delete = true;
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200296 return;
297 }
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200298}
299
300static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200301text_input_cursor_position(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200302 struct wl_text_input *text_input,
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100303 int32_t index,
304 int32_t anchor)
305{
306 struct text_entry *entry = data;
307
308 entry->pending_commit.cursor = index;
309 entry->pending_commit.anchor = anchor;
310}
311
312static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200313text_input_preedit_styling(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200314 struct wl_text_input *text_input,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100315 uint32_t index,
316 uint32_t length,
317 uint32_t style)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200318{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100319 struct text_entry *entry = data;
320 PangoAttribute *attr1 = NULL;
321 PangoAttribute *attr2 = NULL;
322
323 if (!entry->preedit_info.attr_list)
324 entry->preedit_info.attr_list = pango_attr_list_new();
325
326 switch (style) {
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200327 case WL_TEXT_INPUT_PREEDIT_STYLE_DEFAULT:
328 case WL_TEXT_INPUT_PREEDIT_STYLE_UNDERLINE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100329 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
330 break;
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200331 case WL_TEXT_INPUT_PREEDIT_STYLE_INCORRECT:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100332 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_ERROR);
333 attr2 = pango_attr_underline_color_new(65535, 0, 0);
334 break;
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200335 case WL_TEXT_INPUT_PREEDIT_STYLE_SELECTION:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100336 attr1 = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
337 attr2 = pango_attr_foreground_new(65535, 65535, 65535);
338 break;
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200339 case WL_TEXT_INPUT_PREEDIT_STYLE_HIGHLIGHT:
340 case WL_TEXT_INPUT_PREEDIT_STYLE_ACTIVE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100341 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
342 attr2 = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
343 break;
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200344 case WL_TEXT_INPUT_PREEDIT_STYLE_INACTIVE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100345 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
346 attr2 = pango_attr_foreground_new(0.3 * 65535, 0.3 * 65535, 0.3 * 65535);
347 break;
348 }
349
350 if (attr1) {
351 attr1->start_index = entry->cursor + index;
352 attr1->end_index = entry->cursor + index + length;
353 pango_attr_list_insert(entry->preedit_info.attr_list, attr1);
354 }
355
356 if (attr2) {
357 attr2->start_index = entry->cursor + index;
358 attr2->end_index = entry->cursor + index + length;
359 pango_attr_list_insert(entry->preedit_info.attr_list, attr2);
360 }
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200361}
362
363static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200364text_input_preedit_cursor(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200365 struct wl_text_input *text_input,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100366 int32_t index)
367{
368 struct text_entry *entry = data;
369
370 entry->preedit_info.cursor = index;
371}
372
373static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200374text_input_modifiers_map(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200375 struct wl_text_input *text_input,
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100376 struct wl_array *map)
377{
Jan Arne Petersencd997062012-11-18 19:06:44 +0100378 struct text_entry *entry = data;
379
380 entry->keysym.shift_mask = keysym_modifiers_get_mask(map, "Shift");
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100381}
382
383static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200384text_input_keysym(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200385 struct wl_text_input *text_input,
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100386 uint32_t serial,
387 uint32_t time,
388 uint32_t key,
389 uint32_t state,
390 uint32_t modifiers)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200391{
Jan Arne Petersen8aba11d2012-09-17 15:28:07 +0200392 struct text_entry *entry = data;
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100393 const char *new_char;
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200394
Jan Arne Petersencd997062012-11-18 19:06:44 +0100395 if (key == XKB_KEY_Left ||
396 key == XKB_KEY_Right) {
397 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
398 return;
399
400 if (key == XKB_KEY_Left)
401 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
402 else
403 new_char = utf8_next_char(entry->text + entry->cursor);
404
405 if (new_char != NULL) {
406 entry->cursor = new_char - entry->text;
Jan Arne Petersencd997062012-11-18 19:06:44 +0100407 }
408
Jan Arne Petersen68516862013-04-18 16:47:42 +0200409 if (!(modifiers & entry->keysym.shift_mask))
410 entry->anchor = entry->cursor;
411 widget_schedule_redraw(entry->widget);
412
Jan Arne Petersencd997062012-11-18 19:06:44 +0100413 return;
414 }
415
Manuel Bachmann8986c182014-04-18 12:50:14 +0200416 if (key == XKB_KEY_Up ||
417 key == XKB_KEY_Down) {
418 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
419 return;
420
421 if (key == XKB_KEY_Up)
422 move_up(entry->text, &entry->cursor);
423 else
424 move_down(entry->text, &entry->cursor);
425
426 if (!(modifiers & entry->keysym.shift_mask))
427 entry->anchor = entry->cursor;
428 widget_schedule_redraw(entry->widget);
429
430 return;
431 }
432
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100433 if (key == XKB_KEY_BackSpace) {
434 const char *start, *end;
435
Jan Arne Petersendfd34462013-04-18 16:47:26 +0200436 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
437 return;
438
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100439 text_entry_commit_and_reset(entry);
440
441 start = utf8_prev_char(entry->text, entry->text + entry->cursor);
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100442 if (start == NULL)
443 return;
444
Daiki Uenob08b3292013-06-28 18:59:44 +0900445 end = utf8_next_char(start);
446
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100447 text_entry_delete_text(entry,
448 start - entry->text,
449 end - start);
450
451 return;
452 }
453
Manuel Bachmann8986c182014-04-18 12:50:14 +0200454 if (key == XKB_KEY_Tab ||
455 key == XKB_KEY_KP_Enter ||
456 key == XKB_KEY_Return) {
457 char text[16];
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200458
Manuel Bachmann8986c182014-04-18 12:50:14 +0200459 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
460 return;
461
462 xkb_keysym_to_utf8(key, text, sizeof(text));
463
464 text_entry_insert_at_cursor(entry, text, 0, 0);
465
466 return;
467 }
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200468}
469
470static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200471text_input_enter(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200472 struct wl_text_input *text_input,
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200473 struct wl_surface *surface)
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200474{
475 struct text_entry *entry = data;
476
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200477 if (surface != window_get_wl_surface(entry->window))
478 return;
479
Derek Foreman237a6842014-12-17 09:43:58 -0600480 entry->active++;
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200481
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200482 text_entry_update(entry);
483 entry->reset_serial = entry->serial;
484
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200485 widget_schedule_redraw(entry->widget);
486}
487
488static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200489text_input_leave(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200490 struct wl_text_input *text_input)
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200491{
492 struct text_entry *entry = data;
493
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100494 text_entry_commit_and_reset(entry);
Derek Foreman237a6842014-12-17 09:43:58 -0600495 entry->active--;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100496
Derek Foreman237a6842014-12-17 09:43:58 -0600497 if (!entry->active)
498 wl_text_input_hide_input_panel(text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100499
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200500 widget_schedule_redraw(entry->widget);
501}
502
Jan Arne Petersen61381972013-01-31 15:52:21 +0100503static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200504text_input_input_panel_state(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200505 struct wl_text_input *text_input,
Jan Arne Petersen61381972013-01-31 15:52:21 +0100506 uint32_t state)
507{
508}
509
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200510static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200511text_input_language(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200512 struct wl_text_input *text_input,
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200513 uint32_t serial,
514 const char *language)
515{
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200516 fprintf(stderr, "input language is %s \n", language);
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200517}
518
519static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200520text_input_text_direction(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200521 struct wl_text_input *text_input,
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200522 uint32_t serial,
523 uint32_t direction)
524{
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200525 struct text_entry *entry = data;
526 PangoContext *context = pango_layout_get_context(entry->layout);
527 PangoDirection pango_direction;
528
529
530 switch (direction) {
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200531 case WL_TEXT_INPUT_TEXT_DIRECTION_LTR:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200532 pango_direction = PANGO_DIRECTION_LTR;
533 break;
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200534 case WL_TEXT_INPUT_TEXT_DIRECTION_RTL:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200535 pango_direction = PANGO_DIRECTION_RTL;
536 break;
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200537 case WL_TEXT_INPUT_TEXT_DIRECTION_AUTO:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200538 default:
539 pango_direction = PANGO_DIRECTION_NEUTRAL;
540 }
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200541
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200542 pango_context_set_base_dir(context, pango_direction);
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200543}
544
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200545static const struct wl_text_input_listener text_input_listener = {
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200546 text_input_enter,
547 text_input_leave,
548 text_input_modifiers_map,
549 text_input_input_panel_state,
550 text_input_preedit_string,
551 text_input_preedit_styling,
552 text_input_preedit_cursor,
553 text_input_commit_string,
554 text_input_cursor_position,
555 text_input_delete_surrounding_text,
556 text_input_keysym,
557 text_input_language,
558 text_input_text_direction
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200559};
560
Manuel Bachmann22f34302015-03-30 01:57:44 +0200561static void
562data_source_target(void *data,
563 struct wl_data_source *source, const char *mime_type)
564{
565}
566
567static void
568data_source_send(void *data,
569 struct wl_data_source *source,
570 const char *mime_type, int32_t fd)
571{
572 struct editor *editor = data;
573
Bryce Harrington7dd12ec2015-05-19 15:32:09 -0700574 if (write(fd, editor->selected_text, strlen(editor->selected_text) + 1) < 0)
575 fprintf(stderr, "write failed: %m\n");
Manuel Bachmann22f34302015-03-30 01:57:44 +0200576}
577
578static void
579data_source_cancelled(void *data, struct wl_data_source *source)
580{
581 wl_data_source_destroy(source);
582}
583
584static const struct wl_data_source_listener data_source_listener = {
585 data_source_target,
586 data_source_send,
587 data_source_cancelled
588};
589
590static void
591paste_func(void *buffer, size_t len,
592 int32_t x, int32_t y, void *data)
593{
594 struct editor *editor = data;
595 struct text_entry *entry = editor->active_entry;
596 char *pasted_text;
597
598 if (!entry)
599 return;
600
601 pasted_text = malloc(len + 1);
602 strncpy(pasted_text, buffer, len);
603 pasted_text[len] = '\0';
604
605 text_entry_insert_at_cursor(entry, pasted_text, 0, 0);
606
607 free(pasted_text);
608}
609
610static void
611editor_copy_cut(struct editor *editor, struct input *input, bool cut)
612{
613 struct text_entry *entry = editor->active_entry;
614
615 if (!entry)
616 return;
Michael Vetter2a18a522015-05-15 17:17:47 +0200617
Manuel Bachmann22f34302015-03-30 01:57:44 +0200618 if (entry->cursor != entry->anchor) {
619 int start_index = MIN(entry->cursor, entry->anchor);
620 int end_index = MAX(entry->cursor, entry->anchor);
621 int len = end_index - start_index;
622
623 editor->selected_text = realloc(editor->selected_text, len + 1);
624 strncpy(editor->selected_text, &entry->text[start_index], len);
625 editor->selected_text[len] = '\0';
626
627 if (cut)
628 text_entry_delete_text(entry, start_index, len);
629
630 editor->selection =
631 display_create_data_source(editor->display);
632 wl_data_source_offer(editor->selection,
633 "text/plain;charset=utf-8");
634 wl_data_source_add_listener(editor->selection,
635 &data_source_listener, editor);
636 input_set_selection(input, editor->selection,
637 display_get_serial(editor->display));
638 }
639}
640
641static void
642editor_paste(struct editor *editor, struct input *input)
643{
644 input_receive_selection_data(input,
645 "text/plain;charset=utf-8",
646 paste_func, editor);
647}
648
649static void
650menu_func(void *data, struct input *input, int index)
651{
652 struct window *window = data;
653 struct editor *editor = window_get_user_data(window);
654
655 fprintf(stderr, "picked entry %d\n", index);
656
657 switch (index) {
658 case 0:
659 editor_copy_cut(editor, input, true);
660 break;
661 case 1:
662 editor_copy_cut(editor, input, false);
663 break;
664 case 2:
665 editor_paste(editor, input);
666 break;
667 }
668}
669
670static void
671show_menu(struct editor *editor, struct input *input, uint32_t time)
672{
673 int32_t x, y;
674 static const char *entries[] = {
675 "Cut", "Copy", "Paste"
676 };
677
678 input_get_position(input, &x, &y);
679 window_show_menu(editor->display, input, time, editor->window,
680 x + 10, y + 20, menu_func,
681 entries, ARRAY_LENGTH(entries));
682}
683
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200684static struct text_entry*
685text_entry_create(struct editor *editor, const char *text)
686{
687 struct text_entry *entry;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200688
Brian Lovinbc919262013-08-07 15:34:59 -0700689 entry = xmalloc(sizeof *entry);
690 memset(entry, 0, 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;
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200698 entry->text_input = wl_text_input_manager_create_text_input(editor->text_input_manager);
699 wl_text_input_add_listener(entry->text_input, &text_input_listener, entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200700
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200701 widget_set_redraw_handler(entry->widget, text_entry_redraw_handler);
702 widget_set_button_handler(entry->widget, text_entry_button_handler);
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +0200703 widget_set_motion_handler(entry->widget, text_entry_motion_handler);
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -0800704 widget_set_touch_down_handler(entry->widget, text_entry_touch_handler);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200705
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200706 return entry;
707}
708
709static void
710text_entry_destroy(struct text_entry *entry)
711{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200712 widget_destroy(entry->widget);
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200713 wl_text_input_destroy(entry->text_input);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100714 g_clear_object(&entry->layout);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200715 free(entry->text);
716 free(entry);
717}
718
719static void
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200720redraw_handler(struct widget *widget, void *data)
721{
722 struct editor *editor = data;
723 cairo_surface_t *surface;
724 struct rectangle allocation;
725 cairo_t *cr;
726
727 surface = window_get_surface(editor->window);
728 widget_get_allocation(editor->widget, &allocation);
729
730 cr = cairo_create(surface);
731 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
732 cairo_clip(cr);
733
734 cairo_translate(cr, allocation.x, allocation.y);
735
736 /* Draw background */
737 cairo_push_group(cr);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200738 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200739 cairo_set_source_rgba(cr, 1, 1, 1, 1);
740 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
741 cairo_fill(cr);
742
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200743 cairo_pop_group_to_source(cr);
744 cairo_paint(cr);
745
746 cairo_destroy(cr);
747 cairo_surface_destroy(surface);
748}
749
750static void
751text_entry_allocate(struct text_entry *entry, int32_t x, int32_t y,
752 int32_t width, int32_t height)
753{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200754 widget_set_allocation(entry->widget, x, y, width, height);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200755}
756
757static void
758resize_handler(struct widget *widget,
759 int32_t width, int32_t height, void *data)
760{
761 struct editor *editor = data;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200762 struct rectangle allocation;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200763
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200764 widget_get_allocation(editor->widget, &allocation);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200765
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200766 text_entry_allocate(editor->entry,
767 allocation.x + 20, allocation.y + 20,
768 width - 40, height / 2 - 40);
769 text_entry_allocate(editor->editor,
770 allocation.x + 20, allocation.y + height / 2 + 20,
771 width - 40, height / 2 - 40);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200772}
773
774static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200775text_entry_activate(struct text_entry *entry,
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200776 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200777{
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200778 struct wl_surface *surface = window_get_wl_surface(entry->window);
779
Jan Arne Petersen61381972013-01-31 15:52:21 +0100780 if (entry->click_to_show && entry->active) {
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200781 wl_text_input_show_input_panel(entry->text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100782
783 return;
784 }
785
786 if (!entry->click_to_show)
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200787 wl_text_input_show_input_panel(entry->text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100788
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200789 wl_text_input_activate(entry->text_input,
790 seat,
791 surface);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200792}
793
794static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200795text_entry_deactivate(struct text_entry *entry,
796 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200797{
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200798 wl_text_input_deactivate(entry->text_input,
799 seat);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200800}
801
802static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200803text_entry_update_layout(struct text_entry *entry)
804{
805 char *text;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100806 PangoAttrList *attr_list;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200807
Jan Arne Petersen68516862013-04-18 16:47:42 +0200808 assert(entry->cursor <= (strlen(entry->text) +
809 (entry->preedit.text ? strlen(entry->preedit.text) : 0)));
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200810
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100811 if (entry->preedit.text) {
Derek Foreman22044922014-11-20 15:42:35 -0600812 text = xmalloc(strlen(entry->text) + strlen(entry->preedit.text) + 1);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100813 strncpy(text, entry->text, entry->cursor);
814 strcpy(text + entry->cursor, entry->preedit.text);
815 strcpy(text + entry->cursor + strlen(entry->preedit.text),
816 entry->text + entry->cursor);
817 } else {
818 text = strdup(entry->text);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200819 }
820
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100821 if (entry->cursor != entry->anchor) {
822 int start_index = MIN(entry->cursor, entry->anchor);
823 int end_index = MAX(entry->cursor, entry->anchor);
824 PangoAttribute *attr;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200825
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100826 attr_list = pango_attr_list_copy(entry->preedit.attr_list);
827
828 if (!attr_list)
829 attr_list = pango_attr_list_new();
830
831 attr = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
832 attr->start_index = start_index;
833 attr->end_index = end_index;
834 pango_attr_list_insert(attr_list, attr);
835
836 attr = pango_attr_foreground_new(65535, 65535, 65535);
837 attr->start_index = start_index;
838 attr->end_index = end_index;
839 pango_attr_list_insert(attr_list, attr);
840 } else {
841 attr_list = pango_attr_list_ref(entry->preedit.attr_list);
842 }
843
844 if (entry->preedit.text && !entry->preedit.attr_list) {
845 PangoAttribute *attr;
846
847 if (!attr_list)
848 attr_list = pango_attr_list_new();
849
850 attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
851 attr->start_index = entry->cursor;
852 attr->end_index = entry->cursor + strlen(entry->preedit.text);
853 pango_attr_list_insert(attr_list, attr);
854 }
855
856 if (entry->layout) {
857 pango_layout_set_text(entry->layout, text, -1);
858 pango_layout_set_attributes(entry->layout, attr_list);
859 }
860
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200861 free(text);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100862 pango_attr_list_unref(attr_list);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200863}
864
865static void
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100866text_entry_update(struct text_entry *entry)
867{
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200868 struct rectangle cursor_rectangle;
869
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200870 wl_text_input_set_content_type(entry->text_input,
871 WL_TEXT_INPUT_CONTENT_HINT_NONE,
872 entry->content_purpose);
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100873
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200874 wl_text_input_set_surrounding_text(entry->text_input,
875 entry->text,
876 entry->cursor,
877 entry->anchor);
Jan Arne Petersen0eabcaa2013-01-31 15:52:20 +0100878
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200879 if (entry->preferred_language)
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200880 wl_text_input_set_preferred_language(entry->text_input,
881 entry->preferred_language);
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200882
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200883 text_entry_get_cursor_rectangle(entry, &cursor_rectangle);
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200884 wl_text_input_set_cursor_rectangle(entry->text_input, cursor_rectangle.x, cursor_rectangle.y,
885 cursor_rectangle.width, cursor_rectangle.height);
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200886
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200887 wl_text_input_commit_state(entry->text_input, ++entry->serial);
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100888}
889
890static void
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100891text_entry_insert_at_cursor(struct text_entry *entry, const char *text,
892 int32_t cursor, int32_t anchor)
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200893{
Derek Foreman22044922014-11-20 15:42:35 -0600894 char *new_text = xmalloc(strlen(entry->text) + strlen(text) + 1);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200895
896 strncpy(new_text, entry->text, entry->cursor);
897 strcpy(new_text + entry->cursor, text);
898 strcpy(new_text + entry->cursor + strlen(text),
899 entry->text + entry->cursor);
900
901 free(entry->text);
902 entry->text = new_text;
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100903 if (anchor >= 0)
904 entry->anchor = entry->cursor + strlen(text) + anchor;
905 else
906 entry->anchor = entry->cursor + 1 + anchor;
Jan Arne Petersen68516862013-04-18 16:47:42 +0200907
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100908 if (cursor >= 0)
909 entry->cursor += strlen(text) + cursor;
910 else
911 entry->cursor += 1 + cursor;
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200912
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200913 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100914
915 widget_schedule_redraw(entry->widget);
916
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100917 text_entry_update(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200918}
919
920static void
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100921text_entry_reset_preedit(struct text_entry *entry)
922{
923 entry->preedit.cursor = 0;
924
925 free(entry->preedit.text);
926 entry->preedit.text = NULL;
927
928 free(entry->preedit.commit);
929 entry->preedit.commit = NULL;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100930
931 pango_attr_list_unref(entry->preedit.attr_list);
932 entry->preedit.attr_list = NULL;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100933}
934
935static void
936text_entry_commit_and_reset(struct text_entry *entry)
937{
938 char *commit = NULL;
939
940 if (entry->preedit.commit)
941 commit = strdup(entry->preedit.commit);
942
943 text_entry_reset_preedit(entry);
944 if (commit) {
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100945 text_entry_insert_at_cursor(entry, commit, 0, 0);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100946 free(commit);
947 }
Jan Arne Petersen08015b62013-04-18 16:47:18 +0200948
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200949 wl_text_input_reset(entry->text_input);
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200950 text_entry_update(entry);
951 entry->reset_serial = entry->serial;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100952}
953
954static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200955text_entry_set_preedit(struct text_entry *entry,
956 const char *preedit_text,
957 int preedit_cursor)
958{
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100959 text_entry_reset_preedit(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200960
961 if (!preedit_text)
962 return;
963
Jan Arne Petersen46535312013-01-16 21:26:38 +0100964 entry->preedit.text = strdup(preedit_text);
965 entry->preedit.cursor = preedit_cursor;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200966
967 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100968
969 widget_schedule_redraw(entry->widget);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200970}
971
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100972static uint32_t
973text_entry_try_invoke_preedit_action(struct text_entry *entry,
974 int32_t x, int32_t y,
975 uint32_t button,
976 enum wl_pointer_button_state state)
977{
978 int index, trailing;
979 uint32_t cursor;
Jan Arne Petersen68516862013-04-18 16:47:42 +0200980 const char *text;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100981
982 if (!entry->preedit.text)
983 return 0;
984
985 pango_layout_xy_to_index(entry->layout,
986 x * PANGO_SCALE, y * PANGO_SCALE,
987 &index, &trailing);
Jan Arne Petersen68516862013-04-18 16:47:42 +0200988
989 text = pango_layout_get_text(entry->layout);
990 cursor = g_utf8_offset_to_pointer(text + index, trailing) - text;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100991
992 if (cursor < entry->cursor ||
993 cursor > entry->cursor + strlen(entry->preedit.text)) {
994 return 0;
995 }
996
997 if (state == WL_POINTER_BUTTON_STATE_RELEASED)
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200998 wl_text_input_invoke_action(entry->text_input,
999 button,
1000 cursor - entry->cursor);
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001001
1002 return 1;
1003}
1004
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001005static bool
1006text_entry_has_preedit(struct text_entry *entry)
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001007{
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001008 return entry->preedit.text && (strlen(entry->preedit.text) > 0);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001009}
1010
1011static void
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001012text_entry_set_cursor_position(struct text_entry *entry,
1013 int32_t x, int32_t y,
1014 bool move_anchor)
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001015{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001016 int index, trailing;
Jan Arne Petersen68516862013-04-18 16:47:42 +02001017 const char *text;
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001018 uint32_t cursor;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001019
1020 pango_layout_xy_to_index(entry->layout,
1021 x * PANGO_SCALE, y * PANGO_SCALE,
1022 &index, &trailing);
Jan Arne Petersen68516862013-04-18 16:47:42 +02001023
1024 text = pango_layout_get_text(entry->layout);
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001025
1026 cursor = g_utf8_offset_to_pointer(text + index, trailing) - text;
1027
1028 if (move_anchor)
1029 entry->anchor = cursor;
1030
1031 if (text_entry_has_preedit(entry)) {
1032 text_entry_commit_and_reset(entry);
1033
1034 assert(!text_entry_has_preedit(entry));
1035 }
1036
1037 if (entry->cursor == cursor)
1038 return;
1039
1040 entry->cursor = cursor;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001041
1042 text_entry_update_layout(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001043
1044 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001045
Jan Arne Petersen0558a932013-01-16 21:26:45 +01001046 text_entry_update(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001047}
1048
1049static void
Jan Arne Petersene202bae2012-09-09 23:08:44 +02001050text_entry_delete_text(struct text_entry *entry,
1051 uint32_t index, uint32_t length)
1052{
Jan Arne Petersen68516862013-04-18 16:47:42 +02001053 uint32_t l;
1054
Jan Arne Petersen895a1282013-05-30 13:57:04 +02001055 assert(index <= strlen(entry->text));
1056 assert(index + length <= strlen(entry->text));
1057 assert(index + length >= length);
Jan Arne Petersen80ad1a92012-09-17 15:28:10 +02001058
Jan Arne Petersen68516862013-04-18 16:47:42 +02001059 l = strlen(entry->text + index + length);
1060 memmove(entry->text + index,
1061 entry->text + index + length,
1062 l + 1);
Jan Arne Petersene202bae2012-09-09 23:08:44 +02001063
Jan Arne Petersen9eaa8e52013-05-30 13:57:03 +02001064 if (entry->cursor > (index + length))
1065 entry->cursor -= length;
1066 else if (entry->cursor > index)
1067 entry->cursor = index;
1068
1069 entry->anchor = entry->cursor;
1070
Jan Arne Petersene202bae2012-09-09 23:08:44 +02001071 text_entry_update_layout(entry);
1072
1073 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001074
Jan Arne Petersen0558a932013-01-16 21:26:45 +01001075 text_entry_update(entry);
Jan Arne Petersene202bae2012-09-09 23:08:44 +02001076}
1077
1078static void
Jan Arne Petersene386dd22012-09-17 15:28:09 +02001079text_entry_delete_selected_text(struct text_entry *entry)
1080{
1081 uint32_t start_index = entry->anchor < entry->cursor ? entry->anchor : entry->cursor;
1082 uint32_t end_index = entry->anchor < entry->cursor ? entry->cursor : entry->anchor;
1083
1084 if (entry->anchor == entry->cursor)
1085 return;
1086
1087 text_entry_delete_text(entry, start_index, end_index - start_index);
1088
1089 entry->anchor = entry->cursor;
1090}
1091
1092static void
Jan Arne Petersenfe89e712013-04-18 16:47:27 +02001093text_entry_get_cursor_rectangle(struct text_entry *entry, struct rectangle *rectangle)
1094{
1095 struct rectangle allocation;
1096 PangoRectangle extents;
1097 PangoRectangle cursor_pos;
1098
1099 widget_get_allocation(entry->widget, &allocation);
1100
1101 if (entry->preedit.text && entry->preedit.cursor < 0) {
1102 rectangle->x = 0;
1103 rectangle->y = 0;
1104 rectangle->width = 0;
1105 rectangle->height = 0;
1106 return;
1107 }
1108
Jan Arne Petersen68516862013-04-18 16:47:42 +02001109
Jan Arne Petersenfe89e712013-04-18 16:47:27 +02001110 pango_layout_get_extents(entry->layout, &extents, NULL);
1111 pango_layout_get_cursor_pos(entry->layout,
1112 entry->cursor + entry->preedit.cursor,
1113 &cursor_pos, NULL);
1114
1115 rectangle->x = allocation.x + (allocation.height / 2) + PANGO_PIXELS(cursor_pos.x);
1116 rectangle->y = allocation.y + 10 + PANGO_PIXELS(cursor_pos.y);
1117 rectangle->width = PANGO_PIXELS(cursor_pos.width);
1118 rectangle->height = PANGO_PIXELS(cursor_pos.height);
1119}
1120
1121static void
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001122text_entry_draw_cursor(struct text_entry *entry, cairo_t *cr)
1123{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001124 PangoRectangle extents;
1125 PangoRectangle cursor_pos;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001126
Jan Arne Petersen46535312013-01-16 21:26:38 +01001127 if (entry->preedit.text && entry->preedit.cursor < 0)
1128 return;
1129
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001130 pango_layout_get_extents(entry->layout, &extents, NULL);
1131 pango_layout_get_cursor_pos(entry->layout,
1132 entry->cursor + entry->preedit.cursor,
1133 &cursor_pos, NULL);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001134
1135 cairo_set_line_width(cr, 1.0);
Peter Maatmanb9a23f42013-07-06 20:55:54 +02001136 cairo_move_to(cr, PANGO_PIXELS(cursor_pos.x), PANGO_PIXELS(cursor_pos.y));
1137 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 +02001138 cairo_stroke(cr);
1139}
1140
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001141static int
1142text_offset_left(struct rectangle *allocation)
1143{
1144 return 10;
1145}
1146
1147static int
1148text_offset_top(struct rectangle *allocation)
1149{
1150 return allocation->height / 2;
1151}
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +02001152
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +02001153static void
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001154text_entry_redraw_handler(struct widget *widget, void *data)
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001155{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001156 struct text_entry *entry = data;
1157 cairo_surface_t *surface;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001158 struct rectangle allocation;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001159 cairo_t *cr;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001160
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001161 surface = window_get_surface(entry->window);
1162 widget_get_allocation(entry->widget, &allocation);
1163
1164 cr = cairo_create(surface);
1165 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
1166 cairo_clip(cr);
1167
1168 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
1169
1170 cairo_push_group(cr);
1171 cairo_translate(cr, allocation.x, allocation.y);
1172
1173 cairo_set_source_rgba(cr, 1, 1, 1, 1);
1174 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
1175 cairo_fill(cr);
1176
1177 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
1178
1179 if (entry->active) {
1180 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
1181 cairo_set_line_width (cr, 3);
1182 cairo_set_source_rgba(cr, 0, 0, 1, 1.0);
1183 cairo_stroke(cr);
1184 }
1185
1186 cairo_set_source_rgba(cr, 0, 0, 0, 1);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001187
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001188 cairo_translate(cr,
1189 text_offset_left(&allocation),
1190 text_offset_top(&allocation));
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001191
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001192 if (!entry->layout)
1193 entry->layout = pango_cairo_create_layout(cr);
1194 else
1195 pango_cairo_update_layout(cr, entry->layout);
1196
1197 text_entry_update_layout(entry);
1198
1199 pango_cairo_show_layout(cr, entry->layout);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001200
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001201 text_entry_draw_cursor(entry, cr);
1202
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001203 cairo_pop_group_to_source(cr);
1204 cairo_paint(cr);
1205
1206 cairo_destroy(cr);
1207 cairo_surface_destroy(surface);
1208}
1209
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001210static int
1211text_entry_motion_handler(struct widget *widget,
1212 struct input *input, uint32_t time,
1213 float x, float y, void *data)
1214{
1215 struct text_entry *entry = data;
1216 struct rectangle allocation;
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001217 int tx, ty;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001218
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001219 if (!entry->button_pressed) {
1220 return CURSOR_IBEAM;
1221 }
1222
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001223 widget_get_allocation(entry->widget, &allocation);
1224
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001225 tx = x - allocation.x - text_offset_left(&allocation);
1226 ty = y - allocation.y - text_offset_top(&allocation);
1227
1228 text_entry_set_cursor_position(entry, tx, ty, false);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001229
1230 return CURSOR_IBEAM;
1231}
1232
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001233static void
1234text_entry_button_handler(struct widget *widget,
1235 struct input *input, uint32_t time,
1236 uint32_t button,
1237 enum wl_pointer_button_state state, void *data)
1238{
1239 struct text_entry *entry = data;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001240 struct rectangle allocation;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001241 struct editor *editor;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001242 int32_t x, y;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001243 uint32_t result;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001244
1245 widget_get_allocation(entry->widget, &allocation);
1246 input_get_position(input, &x, &y);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001247
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001248 x -= allocation.x + text_offset_left(&allocation);
1249 y -= allocation.y + text_offset_top(&allocation);
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001250
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001251 editor = window_get_user_data(entry->window);
1252
Manuel Bachmann22f34302015-03-30 01:57:44 +02001253 switch (button) {
1254 case BTN_LEFT:
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001255 entry->button_pressed = (state == WL_POINTER_BUTTON_STATE_PRESSED);
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001256 if (state == WL_POINTER_BUTTON_STATE_PRESSED)
1257 input_grab(input, entry->widget, button);
1258 else
1259 input_ungrab(input);
Manuel Bachmann22f34302015-03-30 01:57:44 +02001260 break;
1261 case BTN_RIGHT:
1262 if (state == WL_POINTER_BUTTON_STATE_PRESSED)
1263 show_menu(editor, input, time);
1264 break;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001265 }
1266
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001267 if (text_entry_has_preedit(entry)) {
1268 result = text_entry_try_invoke_preedit_action(entry, x, y, button, state);
1269
1270 if (result)
1271 return;
1272 }
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001273
Manuel Bachmann22f34302015-03-30 01:57:44 +02001274 if (state == WL_POINTER_BUTTON_STATE_PRESSED &&
1275 button == BTN_LEFT) {
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001276 struct wl_seat *seat = input_get_seat(input);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001277
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001278 text_entry_activate(entry, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001279 editor->active_entry = entry;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001280
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001281 text_entry_set_cursor_position(entry, x, y, true);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001282 }
1283}
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001284
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001285static void
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -08001286text_entry_touch_handler(struct widget *widget, struct input *input,
1287 uint32_t serial, uint32_t time, int32_t id,
1288 float tx, float ty, void *data)
1289{
1290 struct text_entry *entry = data;
1291 struct wl_seat *seat = input_get_seat(input);
1292 struct rectangle allocation;
1293 struct editor *editor;
1294 int32_t x, y;
1295
1296 widget_get_allocation(entry->widget, &allocation);
1297
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001298 x = tx - (allocation.x + text_offset_left(&allocation));
1299 y = ty - (allocation.y + text_offset_top(&allocation));
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -08001300
1301 editor = window_get_user_data(entry->window);
1302 text_entry_activate(entry, seat);
1303 editor->active_entry = entry;
1304
1305 text_entry_set_cursor_position(entry, x, y, true);
1306}
1307
1308static void
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001309editor_button_handler(struct widget *widget,
1310 struct input *input, uint32_t time,
1311 uint32_t button,
1312 enum wl_pointer_button_state state, void *data)
1313{
1314 struct editor *editor = data;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001315
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001316 if (button != BTN_LEFT) {
1317 return;
1318 }
Jan Arne Petersene829adc2012-08-10 16:47:22 +02001319
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001320 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
1321 struct wl_seat *seat = input_get_seat(input);
1322
Jan Arne Petersene829adc2012-08-10 16:47:22 +02001323 text_entry_deactivate(editor->entry, seat);
1324 text_entry_deactivate(editor->editor, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001325 editor->active_entry = NULL;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001326 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001327}
1328
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -08001329static void
1330editor_touch_handler(struct widget *widget, struct input *input,
1331 uint32_t serial, uint32_t time, int32_t id,
1332 float tx, float ty, void *data)
1333{
1334 struct editor *editor = data;
1335
1336 struct wl_seat *seat = input_get_seat(input);
1337
1338 text_entry_deactivate(editor->entry, seat);
1339 text_entry_deactivate(editor->editor, seat);
1340 editor->active_entry = NULL;
1341}
Kristian Høgsberg78858902014-01-01 23:57:42 -08001342
1343static void
1344keyboard_focus_handler(struct window *window,
1345 struct input *device, void *data)
1346{
1347 struct editor *editor = data;
1348
1349 window_schedule_redraw(editor->window);
1350}
1351
Manuel Bachmann22f34302015-03-30 01:57:44 +02001352static int
1353handle_bound_key(struct editor *editor,
1354 struct input *input, uint32_t sym, uint32_t time)
1355{
1356 switch (sym) {
1357 case XKB_KEY_X:
1358 editor_copy_cut(editor, input, true);
1359 return 1;
1360 case XKB_KEY_C:
1361 editor_copy_cut(editor, input, false);
1362 return 1;
1363 case XKB_KEY_V:
1364 editor_paste(editor, input);
1365 return 1;
1366 default:
1367 return 0;
1368 }
1369}
1370
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001371static void
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001372key_handler(struct window *window,
1373 struct input *input, uint32_t time,
1374 uint32_t key, uint32_t sym, enum wl_keyboard_key_state state,
1375 void *data)
1376{
1377 struct editor *editor = data;
1378 struct text_entry *entry;
Jan Arne Petersen68516862013-04-18 16:47:42 +02001379 const char *new_char;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001380 char text[16];
Manuel Bachmann22f34302015-03-30 01:57:44 +02001381 uint32_t modifiers;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001382
1383 if (!editor->active_entry)
1384 return;
1385
1386 entry = editor->active_entry;
1387
1388 if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
1389 return;
1390
Manuel Bachmann22f34302015-03-30 01:57:44 +02001391 modifiers = input_get_modifiers(input);
1392 if ((modifiers & MOD_CONTROL_MASK) &&
1393 (modifiers & MOD_SHIFT_MASK) &&
1394 handle_bound_key(editor, input, sym, time))
1395 return;
1396
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001397 switch (sym) {
1398 case XKB_KEY_BackSpace:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001399 text_entry_commit_and_reset(entry);
1400
Jan Arne Petersen68516862013-04-18 16:47:42 +02001401 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
1402 if (new_char != NULL)
1403 text_entry_delete_text(entry,
1404 new_char - entry->text,
1405 (entry->text + entry->cursor) - new_char);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001406 break;
1407 case XKB_KEY_Delete:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001408 text_entry_commit_and_reset(entry);
1409
Jan Arne Petersen68516862013-04-18 16:47:42 +02001410 new_char = utf8_next_char(entry->text + entry->cursor);
1411 if (new_char != NULL)
1412 text_entry_delete_text(entry,
1413 entry->cursor,
1414 new_char - (entry->text + entry->cursor));
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001415 break;
1416 case XKB_KEY_Left:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001417 text_entry_commit_and_reset(entry);
1418
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001419 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
1420 if (new_char != NULL) {
1421 entry->cursor = new_char - entry->text;
Rob Bradford70002832013-07-11 16:00:00 +01001422 if (!(input_get_modifiers(input) & MOD_SHIFT_MASK))
1423 entry->anchor = entry->cursor;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001424 widget_schedule_redraw(entry->widget);
1425 }
1426 break;
1427 case XKB_KEY_Right:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001428 text_entry_commit_and_reset(entry);
1429
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001430 new_char = utf8_next_char(entry->text + entry->cursor);
1431 if (new_char != NULL) {
1432 entry->cursor = new_char - entry->text;
Rob Bradford70002832013-07-11 16:00:00 +01001433 if (!(input_get_modifiers(input) & MOD_SHIFT_MASK))
1434 entry->anchor = entry->cursor;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001435 widget_schedule_redraw(entry->widget);
1436 }
1437 break;
Manuel Bachmann8986c182014-04-18 12:50:14 +02001438 case XKB_KEY_Up:
1439 text_entry_commit_and_reset(entry);
1440
1441 move_up(entry->text, &entry->cursor);
1442 if (!(input_get_modifiers(input) & MOD_SHIFT_MASK))
1443 entry->anchor = entry->cursor;
1444 widget_schedule_redraw(entry->widget);
1445 break;
1446 case XKB_KEY_Down:
1447 text_entry_commit_and_reset(entry);
1448
1449 move_down(entry->text, &entry->cursor);
1450 if (!(input_get_modifiers(input) & MOD_SHIFT_MASK))
1451 entry->anchor = entry->cursor;
1452 widget_schedule_redraw(entry->widget);
1453 break;
Peter Maatman08c38d42013-07-06 20:42:59 +02001454 case XKB_KEY_Escape:
1455 break;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001456 default:
1457 if (xkb_keysym_to_utf8(sym, text, sizeof(text)) <= 0)
1458 break;
1459
Peter Maatman08c38d42013-07-06 20:42:59 +02001460 text_entry_commit_and_reset(entry);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001461
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +01001462 text_entry_insert_at_cursor(entry, text, 0, 0);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001463 break;
1464 }
1465
1466 widget_schedule_redraw(entry->widget);
1467}
1468
1469static void
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001470global_handler(struct display *display, uint32_t name,
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001471 const char *interface, uint32_t version, void *data)
1472{
1473 struct editor *editor = data;
1474
Jan Arne Petersen62ece762013-04-18 16:47:36 +02001475 if (!strcmp(interface, "wl_text_input_manager")) {
Jan Arne Petersen78d00e42013-04-18 16:47:24 +02001476 editor->text_input_manager =
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001477 display_bind(display, name,
Jan Arne Petersen62ece762013-04-18 16:47:36 +02001478 &wl_text_input_manager_interface, 1);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001479 }
1480}
1481
1482int
1483main(int argc, char *argv[])
1484{
1485 struct editor editor;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001486 int i;
1487 uint32_t click_to_show = 0;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001488 const char *preferred_language = NULL;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001489
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001490 for (i = 1; i < argc; i++) {
Jan Arne Petersen61381972013-01-31 15:52:21 +01001491 if (strcmp("--click-to-show", argv[i]) == 0)
1492 click_to_show = 1;
Bill Spitzakbb0bb9c2014-08-08 12:59:58 -07001493 else if (strcmp("--preferred-language", argv[i]) == 0 &&
1494 i + 1 < argc) {
1495 preferred_language = argv[i + 1];
1496 i++;
1497 } else {
1498 printf("Usage: %s [OPTIONS]\n"
1499 " --click-to-show\n"
1500 " --preferred-language LANGUAGE\n",
1501 argv[0]);
1502 return 1;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001503 }
1504 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001505
Jan Arne Petersen25f6db52012-11-05 03:26:40 +01001506 memset(&editor, 0, sizeof editor);
1507
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001508#ifdef HAVE_PANGO
1509 g_type_init();
1510#endif
1511
Kristian Høgsberg4172f662013-02-20 15:27:49 -05001512 editor.display = display_create(&argc, argv);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001513 if (editor.display == NULL) {
1514 fprintf(stderr, "failed to create display: %m\n");
1515 return -1;
1516 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001517
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001518 display_set_user_data(editor.display, &editor);
1519 display_set_global_handler(editor.display, global_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001520
Olivier Blin30e1f3c2014-09-16 19:13:17 +02001521 if (editor.text_input_manager == NULL) {
1522 fprintf(stderr, "No text input manager global\n");
1523 return -1;
1524 }
1525
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001526 editor.window = window_create(editor.display);
Jason Ekstrandee7fefc2013-10-13 19:08:38 -05001527 editor.widget = window_frame_create(editor.window, &editor);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001528
1529 editor.entry = text_entry_create(&editor, "Entry");
Jan Arne Petersen61381972013-01-31 15:52:21 +01001530 editor.entry->click_to_show = click_to_show;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001531 if (preferred_language)
1532 editor.entry->preferred_language = strdup(preferred_language);
Jan Arne Petersen0558a932013-01-16 21:26:45 +01001533 editor.editor = text_entry_create(&editor, "Numeric");
Jan Arne Petersen62ece762013-04-18 16:47:36 +02001534 editor.editor->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_NUMBER;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001535 editor.editor->click_to_show = click_to_show;
Manuel Bachmann22f34302015-03-30 01:57:44 +02001536 editor.selection = NULL;
1537 editor.selected_text = NULL;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001538
1539 window_set_title(editor.window, "Text Editor");
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001540 window_set_key_handler(editor.window, key_handler);
Kristian Høgsberg78858902014-01-01 23:57:42 -08001541 window_set_keyboard_focus_handler(editor.window,
1542 keyboard_focus_handler);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001543 window_set_user_data(editor.window, &editor);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001544
1545 widget_set_redraw_handler(editor.widget, redraw_handler);
1546 widget_set_resize_handler(editor.widget, resize_handler);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001547 widget_set_button_handler(editor.widget, editor_button_handler);
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -08001548 widget_set_touch_down_handler(editor.widget, editor_touch_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001549
1550 window_schedule_resize(editor.window, 500, 400);
1551
1552 display_run(editor.display);
1553
Manuel Bachmann22f34302015-03-30 01:57:44 +02001554 if (editor.selected_text)
1555 free(editor.selected_text);
1556 if (editor.selection)
1557 wl_data_source_destroy(editor.selection);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001558 text_entry_destroy(editor.entry);
1559 text_entry_destroy(editor.editor);
vivek31732f72014-05-15 18:58:16 +05301560 widget_destroy(editor.widget);
1561 window_destroy(editor.window);
1562 display_destroy(editor.display);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001563
1564 return 0;
1565}