blob: 5407337c023e7943c10214a19245e7af6c0035f8 [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 *
5 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the copyright holders not be used in
10 * advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. The copyright holders make
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
14 *
15 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 */
23
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010024#include "config.h"
25
Philipp Brüschweiler591cfca2012-07-11 22:25:29 +020026#include <assert.h>
Jan Arne Petersencba9e472012-06-21 21:52:19 +020027#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +020030#include <stdbool.h>
Manuel Bachmann22f34302015-03-30 01:57:44 +020031#include <unistd.h>
Jan Arne Petersencba9e472012-06-21 21:52:19 +020032
33#include <linux/input.h>
34#include <cairo.h>
35
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010036#include <pango/pangocairo.h>
37
Jan Arne Petersencba9e472012-06-21 21:52:19 +020038#include "window.h"
39#include "text-client-protocol.h"
40
41struct text_entry {
42 struct widget *widget;
Jan Arne Petersene829adc2012-08-10 16:47:22 +020043 struct window *window;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020044 char *text;
45 int active;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +020046 uint32_t cursor;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +020047 uint32_t anchor;
Jan Arne Petersen46535312013-01-16 21:26:38 +010048 struct {
49 char *text;
50 int32_t cursor;
51 char *commit;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010052 PangoAttrList *attr_list;
Jan Arne Petersen46535312013-01-16 21:26:38 +010053 } preedit;
54 struct {
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010055 PangoAttrList *attr_list;
Jan Arne Petersen46535312013-01-16 21:26:38 +010056 int32_t cursor;
57 } preedit_info;
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +010058 struct {
59 int32_t cursor;
60 int32_t anchor;
Jan Arne Petersen919bc142013-04-18 16:47:34 +020061 uint32_t delete_index;
62 uint32_t delete_length;
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +020063 bool invalid_delete;
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +010064 } pending_commit;
Jan Arne Petersen62ece762013-04-18 16:47:36 +020065 struct wl_text_input *text_input;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010066 PangoLayout *layout;
Jan Arne Petersencd997062012-11-18 19:06:44 +010067 struct {
68 xkb_mod_mask_t shift_mask;
69 } keysym;
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +010070 uint32_t serial;
Jan Arne Petersen00191c72013-04-18 16:47:33 +020071 uint32_t reset_serial;
Jan Arne Petersen0558a932013-01-16 21:26:45 +010072 uint32_t content_purpose;
Jan Arne Petersen61381972013-01-31 15:52:21 +010073 uint32_t click_to_show;
Jan Arne Petersen9d419132013-04-18 16:47:16 +020074 char *preferred_language;
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +020075 bool button_pressed;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020076};
77
78struct editor {
Jan Arne Petersen62ece762013-04-18 16:47:36 +020079 struct wl_text_input_manager *text_input_manager;
Manuel Bachmann22f34302015-03-30 01:57:44 +020080 struct wl_data_source *selection;
81 char *selected_text;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020082 struct display *display;
83 struct window *window;
84 struct widget *widget;
85 struct text_entry *entry;
86 struct text_entry *editor;
Rob Bradford9d1d32b2012-11-18 19:06:49 +010087 struct text_entry *active_entry;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020088};
89
Jan Arne Petersen6345faa2012-11-05 03:26:39 +010090static const char *
Jan Arne Petersen6345faa2012-11-05 03:26:39 +010091utf8_end_char(const char *p)
92{
93 while ((*p & 0xc0) == 0x80)
94 p++;
95 return p;
96}
97
98static const char *
Jan Arne Petersen68516862013-04-18 16:47:42 +020099utf8_prev_char(const char *s, const char *p)
100{
101 for (--p; p >= s; --p) {
102 if ((*p & 0xc0) != 0x80)
103 return p;
104 }
105 return NULL;
106}
107
108static const char *
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100109utf8_next_char(const char *p)
110{
111 if (*p != 0)
112 return utf8_end_char(++p);
113 return NULL;
114}
115
Manuel Bachmann8986c182014-04-18 12:50:14 +0200116static void
117move_up(const char *p, uint32_t *cursor)
118{
119 const char *posr, *posr_i;
120 char text[16];
121
122 xkb_keysym_to_utf8(XKB_KEY_Return, text, sizeof(text));
123
124 posr = strstr(p, text);
125 while (posr) {
126 if (*cursor > (unsigned)(posr-p)) {
127 posr_i = strstr(posr+1, text);
128 if (!posr_i || !(*cursor > (unsigned)(posr_i-p))) {
129 *cursor = posr-p;
130 break;
131 }
132 posr = posr_i;
133 } else {
134 break;
135 }
136 }
137}
138
139static void
140move_down(const char *p, uint32_t *cursor)
141{
142 const char *posr;
143 char text[16];
144
145 xkb_keysym_to_utf8(XKB_KEY_Return, text, sizeof(text));
146
147 posr = strstr(p, text);
148 while (posr) {
149 if (*cursor <= (unsigned)(posr-p)) {
150 *cursor = posr-p + 1;
151 break;
152 }
153 posr = strstr(posr+1, text);
154 }
155}
156
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200157static void text_entry_redraw_handler(struct widget *widget, void *data);
158static void text_entry_button_handler(struct widget *widget,
159 struct input *input, uint32_t time,
160 uint32_t button,
161 enum wl_pointer_button_state state, void *data);
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -0800162static void text_entry_touch_handler(struct widget *widget, struct input *input,
163 uint32_t serial, uint32_t time, int32_t id,
164 float tx, float ty, void *data);
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +0200165static int text_entry_motion_handler(struct widget *widget,
166 struct input *input, uint32_t time,
167 float x, float y, void *data);
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100168static void text_entry_insert_at_cursor(struct text_entry *entry, const char *text,
169 int32_t cursor, int32_t anchor);
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200170static void text_entry_set_preedit(struct text_entry *entry,
171 const char *preedit_text,
172 int preedit_cursor);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200173static void text_entry_delete_text(struct text_entry *entry,
174 uint32_t index, uint32_t length);
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200175static void text_entry_delete_selected_text(struct text_entry *entry);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100176static void text_entry_reset_preedit(struct text_entry *entry);
177static void text_entry_commit_and_reset(struct text_entry *entry);
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200178static void text_entry_get_cursor_rectangle(struct text_entry *entry, struct rectangle *rectangle);
179static void text_entry_update(struct text_entry *entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200180
181static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200182text_input_commit_string(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200183 struct wl_text_input *text_input,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100184 uint32_t serial,
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100185 const char *text)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200186{
187 struct text_entry *entry = data;
188
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200189 if ((entry->serial - serial) > (entry->serial - entry->reset_serial)) {
190 fprintf(stderr, "Ignore commit. Serial: %u, Current: %u, Reset: %u\n",
191 serial, entry->serial, entry->reset_serial);
192 return;
193 }
194
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200195 if (entry->pending_commit.invalid_delete) {
196 fprintf(stderr, "Ignore commit. Invalid previous delete_surrounding event.\n");
197 memset(&entry->pending_commit, 0, sizeof entry->pending_commit);
198 return;
199 }
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100200
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200201 text_entry_reset_preedit(entry);
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200202
203 if (entry->pending_commit.delete_length) {
204 text_entry_delete_text(entry,
205 entry->pending_commit.delete_index,
206 entry->pending_commit.delete_length);
Jan Arne Petersena96953d2013-05-30 13:57:02 +0200207 } else {
208 text_entry_delete_selected_text(entry);
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200209 }
210
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100211 text_entry_insert_at_cursor(entry, text,
212 entry->pending_commit.cursor,
213 entry->pending_commit.anchor);
214
215 memset(&entry->pending_commit, 0, sizeof entry->pending_commit);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200216
217 widget_schedule_redraw(entry->widget);
218}
219
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200220static void
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200221clear_pending_preedit(struct text_entry *entry)
222{
223 memset(&entry->pending_commit, 0, sizeof entry->pending_commit);
224
225 pango_attr_list_unref(entry->preedit_info.attr_list);
226
227 entry->preedit_info.cursor = 0;
228 entry->preedit_info.attr_list = NULL;
229
230 memset(&entry->preedit_info, 0, sizeof entry->preedit_info);
231}
232
233static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200234text_input_preedit_string(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200235 struct wl_text_input *text_input,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100236 uint32_t serial,
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200237 const char *text,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100238 const char *commit)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200239{
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200240 struct text_entry *entry = data;
241
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200242 if ((entry->serial - serial) > (entry->serial - entry->reset_serial)) {
243 fprintf(stderr, "Ignore preedit_string. Serial: %u, Current: %u, Reset: %u\n",
244 serial, entry->serial, entry->reset_serial);
245 clear_pending_preedit(entry);
246 return;
247 }
248
249 if (entry->pending_commit.invalid_delete) {
250 fprintf(stderr, "Ignore preedit_string. Invalid previous delete_surrounding event.\n");
251 clear_pending_preedit(entry);
252 return;
253 }
254
Jan Arne Petersena96953d2013-05-30 13:57:02 +0200255 if (entry->pending_commit.delete_length) {
256 text_entry_delete_text(entry,
257 entry->pending_commit.delete_index,
258 entry->pending_commit.delete_length);
259 } else {
260 text_entry_delete_selected_text(entry);
261 }
Jan Arne Petersena96953d2013-05-30 13:57:02 +0200262
Jan Arne Petersen46535312013-01-16 21:26:38 +0100263 text_entry_set_preedit(entry, text, entry->preedit_info.cursor);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100264 entry->preedit.commit = strdup(commit);
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200265 entry->preedit.attr_list = pango_attr_list_ref(entry->preedit_info.attr_list);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100266
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200267 clear_pending_preedit(entry);
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200268
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200269 text_entry_update(entry);
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200270
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200271 widget_schedule_redraw(entry->widget);
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200272}
273
274static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200275text_input_delete_surrounding_text(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200276 struct wl_text_input *text_input,
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200277 int32_t index,
278 uint32_t length)
279{
280 struct text_entry *entry = data;
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200281 uint32_t text_length;
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200282
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200283 entry->pending_commit.delete_index = entry->cursor + index;
284 entry->pending_commit.delete_length = length;
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200285 entry->pending_commit.invalid_delete = false;
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200286
Jan Arne Petersen68516862013-04-18 16:47:42 +0200287 text_length = strlen(entry->text);
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200288
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200289 if (entry->pending_commit.delete_index > text_length ||
290 length > text_length ||
Jan Arne Petersen895a1282013-05-30 13:57:04 +0200291 entry->pending_commit.delete_index + length > text_length) {
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200292 fprintf(stderr, "delete_surrounding_text: Invalid index: %d," \
293 "length %u'; cursor: %u text length: %u\n", index, length, entry->cursor, text_length);
294 entry->pending_commit.invalid_delete = true;
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200295 return;
296 }
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200297}
298
299static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200300text_input_cursor_position(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200301 struct wl_text_input *text_input,
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100302 int32_t index,
303 int32_t anchor)
304{
305 struct text_entry *entry = data;
306
307 entry->pending_commit.cursor = index;
308 entry->pending_commit.anchor = anchor;
309}
310
311static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200312text_input_preedit_styling(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200313 struct wl_text_input *text_input,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100314 uint32_t index,
315 uint32_t length,
316 uint32_t style)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200317{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100318 struct text_entry *entry = data;
319 PangoAttribute *attr1 = NULL;
320 PangoAttribute *attr2 = NULL;
321
322 if (!entry->preedit_info.attr_list)
323 entry->preedit_info.attr_list = pango_attr_list_new();
324
325 switch (style) {
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200326 case WL_TEXT_INPUT_PREEDIT_STYLE_DEFAULT:
327 case WL_TEXT_INPUT_PREEDIT_STYLE_UNDERLINE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100328 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
329 break;
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200330 case WL_TEXT_INPUT_PREEDIT_STYLE_INCORRECT:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100331 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_ERROR);
332 attr2 = pango_attr_underline_color_new(65535, 0, 0);
333 break;
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200334 case WL_TEXT_INPUT_PREEDIT_STYLE_SELECTION:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100335 attr1 = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
336 attr2 = pango_attr_foreground_new(65535, 65535, 65535);
337 break;
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200338 case WL_TEXT_INPUT_PREEDIT_STYLE_HIGHLIGHT:
339 case WL_TEXT_INPUT_PREEDIT_STYLE_ACTIVE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100340 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
341 attr2 = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
342 break;
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200343 case WL_TEXT_INPUT_PREEDIT_STYLE_INACTIVE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100344 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
345 attr2 = pango_attr_foreground_new(0.3 * 65535, 0.3 * 65535, 0.3 * 65535);
346 break;
347 }
348
349 if (attr1) {
350 attr1->start_index = entry->cursor + index;
351 attr1->end_index = entry->cursor + index + length;
352 pango_attr_list_insert(entry->preedit_info.attr_list, attr1);
353 }
354
355 if (attr2) {
356 attr2->start_index = entry->cursor + index;
357 attr2->end_index = entry->cursor + index + length;
358 pango_attr_list_insert(entry->preedit_info.attr_list, attr2);
359 }
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200360}
361
362static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200363text_input_preedit_cursor(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200364 struct wl_text_input *text_input,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100365 int32_t index)
366{
367 struct text_entry *entry = data;
368
369 entry->preedit_info.cursor = index;
370}
371
372static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200373text_input_modifiers_map(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200374 struct wl_text_input *text_input,
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100375 struct wl_array *map)
376{
Jan Arne Petersencd997062012-11-18 19:06:44 +0100377 struct text_entry *entry = data;
378
379 entry->keysym.shift_mask = keysym_modifiers_get_mask(map, "Shift");
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100380}
381
382static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200383text_input_keysym(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200384 struct wl_text_input *text_input,
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100385 uint32_t serial,
386 uint32_t time,
387 uint32_t key,
388 uint32_t state,
389 uint32_t modifiers)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200390{
Jan Arne Petersen8aba11d2012-09-17 15:28:07 +0200391 struct text_entry *entry = data;
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100392 const char *new_char;
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200393
Jan Arne Petersencd997062012-11-18 19:06:44 +0100394 if (key == XKB_KEY_Left ||
395 key == XKB_KEY_Right) {
396 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
397 return;
398
399 if (key == XKB_KEY_Left)
400 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
401 else
402 new_char = utf8_next_char(entry->text + entry->cursor);
403
404 if (new_char != NULL) {
405 entry->cursor = new_char - entry->text;
Jan Arne Petersencd997062012-11-18 19:06:44 +0100406 }
407
Jan Arne Petersen68516862013-04-18 16:47:42 +0200408 if (!(modifiers & entry->keysym.shift_mask))
409 entry->anchor = entry->cursor;
410 widget_schedule_redraw(entry->widget);
411
Jan Arne Petersencd997062012-11-18 19:06:44 +0100412 return;
413 }
414
Manuel Bachmann8986c182014-04-18 12:50:14 +0200415 if (key == XKB_KEY_Up ||
416 key == XKB_KEY_Down) {
417 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
418 return;
419
420 if (key == XKB_KEY_Up)
421 move_up(entry->text, &entry->cursor);
422 else
423 move_down(entry->text, &entry->cursor);
424
425 if (!(modifiers & entry->keysym.shift_mask))
426 entry->anchor = entry->cursor;
427 widget_schedule_redraw(entry->widget);
428
429 return;
430 }
431
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100432 if (key == XKB_KEY_BackSpace) {
433 const char *start, *end;
434
Jan Arne Petersendfd34462013-04-18 16:47:26 +0200435 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
436 return;
437
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100438 text_entry_commit_and_reset(entry);
439
440 start = utf8_prev_char(entry->text, entry->text + entry->cursor);
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100441 if (start == NULL)
442 return;
443
Daiki Uenob08b3292013-06-28 18:59:44 +0900444 end = utf8_next_char(start);
445
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100446 text_entry_delete_text(entry,
447 start - entry->text,
448 end - start);
449
450 return;
451 }
452
Manuel Bachmann8986c182014-04-18 12:50:14 +0200453 if (key == XKB_KEY_Tab ||
454 key == XKB_KEY_KP_Enter ||
455 key == XKB_KEY_Return) {
456 char text[16];
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200457
Manuel Bachmann8986c182014-04-18 12:50:14 +0200458 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
459 return;
460
461 xkb_keysym_to_utf8(key, text, sizeof(text));
462
463 text_entry_insert_at_cursor(entry, text, 0, 0);
464
465 return;
466 }
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200467}
468
469static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200470text_input_enter(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200471 struct wl_text_input *text_input,
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200472 struct wl_surface *surface)
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200473{
474 struct text_entry *entry = data;
475
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200476 if (surface != window_get_wl_surface(entry->window))
477 return;
478
Derek Foreman237a6842014-12-17 09:43:58 -0600479 entry->active++;
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200480
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200481 text_entry_update(entry);
482 entry->reset_serial = entry->serial;
483
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200484 widget_schedule_redraw(entry->widget);
485}
486
487static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200488text_input_leave(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200489 struct wl_text_input *text_input)
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200490{
491 struct text_entry *entry = data;
492
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100493 text_entry_commit_and_reset(entry);
Derek Foreman237a6842014-12-17 09:43:58 -0600494 entry->active--;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100495
Derek Foreman237a6842014-12-17 09:43:58 -0600496 if (!entry->active)
497 wl_text_input_hide_input_panel(text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100498
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200499 widget_schedule_redraw(entry->widget);
500}
501
Jan Arne Petersen61381972013-01-31 15:52:21 +0100502static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200503text_input_input_panel_state(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200504 struct wl_text_input *text_input,
Jan Arne Petersen61381972013-01-31 15:52:21 +0100505 uint32_t state)
506{
507}
508
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200509static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200510text_input_language(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200511 struct wl_text_input *text_input,
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200512 uint32_t serial,
513 const char *language)
514{
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200515 fprintf(stderr, "input language is %s \n", language);
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200516}
517
518static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200519text_input_text_direction(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200520 struct wl_text_input *text_input,
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200521 uint32_t serial,
522 uint32_t direction)
523{
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200524 struct text_entry *entry = data;
525 PangoContext *context = pango_layout_get_context(entry->layout);
526 PangoDirection pango_direction;
527
528
529 switch (direction) {
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200530 case WL_TEXT_INPUT_TEXT_DIRECTION_LTR:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200531 pango_direction = PANGO_DIRECTION_LTR;
532 break;
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200533 case WL_TEXT_INPUT_TEXT_DIRECTION_RTL:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200534 pango_direction = PANGO_DIRECTION_RTL;
535 break;
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200536 case WL_TEXT_INPUT_TEXT_DIRECTION_AUTO:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200537 default:
538 pango_direction = PANGO_DIRECTION_NEUTRAL;
539 }
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200540
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200541 pango_context_set_base_dir(context, pango_direction);
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200542}
543
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200544static const struct wl_text_input_listener text_input_listener = {
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200545 text_input_enter,
546 text_input_leave,
547 text_input_modifiers_map,
548 text_input_input_panel_state,
549 text_input_preedit_string,
550 text_input_preedit_styling,
551 text_input_preedit_cursor,
552 text_input_commit_string,
553 text_input_cursor_position,
554 text_input_delete_surrounding_text,
555 text_input_keysym,
556 text_input_language,
557 text_input_text_direction
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200558};
559
Manuel Bachmann22f34302015-03-30 01:57:44 +0200560static void
561data_source_target(void *data,
562 struct wl_data_source *source, const char *mime_type)
563{
564}
565
566static void
567data_source_send(void *data,
568 struct wl_data_source *source,
569 const char *mime_type, int32_t fd)
570{
571 struct editor *editor = data;
572
Bryce Harrington7dd12ec2015-05-19 15:32:09 -0700573 if (write(fd, editor->selected_text, strlen(editor->selected_text) + 1) < 0)
574 fprintf(stderr, "write failed: %m\n");
Manuel Bachmann22f34302015-03-30 01:57:44 +0200575}
576
577static void
578data_source_cancelled(void *data, struct wl_data_source *source)
579{
580 wl_data_source_destroy(source);
581}
582
583static const struct wl_data_source_listener data_source_listener = {
584 data_source_target,
585 data_source_send,
586 data_source_cancelled
587};
588
589static void
590paste_func(void *buffer, size_t len,
591 int32_t x, int32_t y, void *data)
592{
593 struct editor *editor = data;
594 struct text_entry *entry = editor->active_entry;
595 char *pasted_text;
596
597 if (!entry)
598 return;
599
600 pasted_text = malloc(len + 1);
601 strncpy(pasted_text, buffer, len);
602 pasted_text[len] = '\0';
603
604 text_entry_insert_at_cursor(entry, pasted_text, 0, 0);
605
606 free(pasted_text);
607}
608
609static void
610editor_copy_cut(struct editor *editor, struct input *input, bool cut)
611{
612 struct text_entry *entry = editor->active_entry;
613
614 if (!entry)
615 return;
Michael Vetter2a18a522015-05-15 17:17:47 +0200616
Manuel Bachmann22f34302015-03-30 01:57:44 +0200617 if (entry->cursor != entry->anchor) {
618 int start_index = MIN(entry->cursor, entry->anchor);
619 int end_index = MAX(entry->cursor, entry->anchor);
620 int len = end_index - start_index;
621
622 editor->selected_text = realloc(editor->selected_text, len + 1);
623 strncpy(editor->selected_text, &entry->text[start_index], len);
624 editor->selected_text[len] = '\0';
625
626 if (cut)
627 text_entry_delete_text(entry, start_index, len);
628
629 editor->selection =
630 display_create_data_source(editor->display);
631 wl_data_source_offer(editor->selection,
632 "text/plain;charset=utf-8");
633 wl_data_source_add_listener(editor->selection,
634 &data_source_listener, editor);
635 input_set_selection(input, editor->selection,
636 display_get_serial(editor->display));
637 }
638}
639
640static void
641editor_paste(struct editor *editor, struct input *input)
642{
643 input_receive_selection_data(input,
644 "text/plain;charset=utf-8",
645 paste_func, editor);
646}
647
648static void
649menu_func(void *data, struct input *input, int index)
650{
651 struct window *window = data;
652 struct editor *editor = window_get_user_data(window);
653
654 fprintf(stderr, "picked entry %d\n", index);
655
656 switch (index) {
657 case 0:
658 editor_copy_cut(editor, input, true);
659 break;
660 case 1:
661 editor_copy_cut(editor, input, false);
662 break;
663 case 2:
664 editor_paste(editor, input);
665 break;
666 }
667}
668
669static void
670show_menu(struct editor *editor, struct input *input, uint32_t time)
671{
672 int32_t x, y;
673 static const char *entries[] = {
674 "Cut", "Copy", "Paste"
675 };
676
677 input_get_position(input, &x, &y);
678 window_show_menu(editor->display, input, time, editor->window,
679 x + 10, y + 20, menu_func,
680 entries, ARRAY_LENGTH(entries));
681}
682
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200683static struct text_entry*
684text_entry_create(struct editor *editor, const char *text)
685{
686 struct text_entry *entry;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200687
Brian Lovinbc919262013-08-07 15:34:59 -0700688 entry = xmalloc(sizeof *entry);
689 memset(entry, 0, sizeof *entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200690
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200691 entry->widget = widget_add_widget(editor->widget, entry);
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200692 entry->window = editor->window;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200693 entry->text = strdup(text);
694 entry->active = 0;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200695 entry->cursor = strlen(text);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200696 entry->anchor = entry->cursor;
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200697 entry->text_input = wl_text_input_manager_create_text_input(editor->text_input_manager);
698 wl_text_input_add_listener(entry->text_input, &text_input_listener, entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200699
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200700 widget_set_redraw_handler(entry->widget, text_entry_redraw_handler);
701 widget_set_button_handler(entry->widget, text_entry_button_handler);
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +0200702 widget_set_motion_handler(entry->widget, text_entry_motion_handler);
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -0800703 widget_set_touch_down_handler(entry->widget, text_entry_touch_handler);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200704
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200705 return entry;
706}
707
708static void
709text_entry_destroy(struct text_entry *entry)
710{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200711 widget_destroy(entry->widget);
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200712 wl_text_input_destroy(entry->text_input);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100713 g_clear_object(&entry->layout);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200714 free(entry->text);
715 free(entry);
716}
717
718static void
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200719redraw_handler(struct widget *widget, void *data)
720{
721 struct editor *editor = data;
722 cairo_surface_t *surface;
723 struct rectangle allocation;
724 cairo_t *cr;
725
726 surface = window_get_surface(editor->window);
727 widget_get_allocation(editor->widget, &allocation);
728
729 cr = cairo_create(surface);
730 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
731 cairo_clip(cr);
732
733 cairo_translate(cr, allocation.x, allocation.y);
734
735 /* Draw background */
736 cairo_push_group(cr);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200737 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200738 cairo_set_source_rgba(cr, 1, 1, 1, 1);
739 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
740 cairo_fill(cr);
741
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200742 cairo_pop_group_to_source(cr);
743 cairo_paint(cr);
744
745 cairo_destroy(cr);
746 cairo_surface_destroy(surface);
747}
748
749static void
750text_entry_allocate(struct text_entry *entry, int32_t x, int32_t y,
751 int32_t width, int32_t height)
752{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200753 widget_set_allocation(entry->widget, x, y, width, height);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200754}
755
756static void
757resize_handler(struct widget *widget,
758 int32_t width, int32_t height, void *data)
759{
760 struct editor *editor = data;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200761 struct rectangle allocation;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200762
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200763 widget_get_allocation(editor->widget, &allocation);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200764
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200765 text_entry_allocate(editor->entry,
766 allocation.x + 20, allocation.y + 20,
767 width - 40, height / 2 - 40);
768 text_entry_allocate(editor->editor,
769 allocation.x + 20, allocation.y + height / 2 + 20,
770 width - 40, height / 2 - 40);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200771}
772
773static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200774text_entry_activate(struct text_entry *entry,
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200775 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200776{
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200777 struct wl_surface *surface = window_get_wl_surface(entry->window);
778
Jan Arne Petersen61381972013-01-31 15:52:21 +0100779 if (entry->click_to_show && entry->active) {
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200780 wl_text_input_show_input_panel(entry->text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100781
782 return;
783 }
784
785 if (!entry->click_to_show)
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200786 wl_text_input_show_input_panel(entry->text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100787
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200788 wl_text_input_activate(entry->text_input,
789 seat,
790 surface);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200791}
792
793static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200794text_entry_deactivate(struct text_entry *entry,
795 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200796{
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200797 wl_text_input_deactivate(entry->text_input,
798 seat);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200799}
800
801static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200802text_entry_update_layout(struct text_entry *entry)
803{
804 char *text;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100805 PangoAttrList *attr_list;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200806
Jan Arne Petersen68516862013-04-18 16:47:42 +0200807 assert(entry->cursor <= (strlen(entry->text) +
808 (entry->preedit.text ? strlen(entry->preedit.text) : 0)));
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200809
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100810 if (entry->preedit.text) {
Derek Foreman22044922014-11-20 15:42:35 -0600811 text = xmalloc(strlen(entry->text) + strlen(entry->preedit.text) + 1);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100812 strncpy(text, entry->text, entry->cursor);
813 strcpy(text + entry->cursor, entry->preedit.text);
814 strcpy(text + entry->cursor + strlen(entry->preedit.text),
815 entry->text + entry->cursor);
816 } else {
817 text = strdup(entry->text);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200818 }
819
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100820 if (entry->cursor != entry->anchor) {
821 int start_index = MIN(entry->cursor, entry->anchor);
822 int end_index = MAX(entry->cursor, entry->anchor);
823 PangoAttribute *attr;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200824
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100825 attr_list = pango_attr_list_copy(entry->preedit.attr_list);
826
827 if (!attr_list)
828 attr_list = pango_attr_list_new();
829
830 attr = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
831 attr->start_index = start_index;
832 attr->end_index = end_index;
833 pango_attr_list_insert(attr_list, attr);
834
835 attr = pango_attr_foreground_new(65535, 65535, 65535);
836 attr->start_index = start_index;
837 attr->end_index = end_index;
838 pango_attr_list_insert(attr_list, attr);
839 } else {
840 attr_list = pango_attr_list_ref(entry->preedit.attr_list);
841 }
842
843 if (entry->preedit.text && !entry->preedit.attr_list) {
844 PangoAttribute *attr;
845
846 if (!attr_list)
847 attr_list = pango_attr_list_new();
848
849 attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
850 attr->start_index = entry->cursor;
851 attr->end_index = entry->cursor + strlen(entry->preedit.text);
852 pango_attr_list_insert(attr_list, attr);
853 }
854
855 if (entry->layout) {
856 pango_layout_set_text(entry->layout, text, -1);
857 pango_layout_set_attributes(entry->layout, attr_list);
858 }
859
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200860 free(text);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100861 pango_attr_list_unref(attr_list);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200862}
863
864static void
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100865text_entry_update(struct text_entry *entry)
866{
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200867 struct rectangle cursor_rectangle;
868
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200869 wl_text_input_set_content_type(entry->text_input,
870 WL_TEXT_INPUT_CONTENT_HINT_NONE,
871 entry->content_purpose);
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100872
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200873 wl_text_input_set_surrounding_text(entry->text_input,
874 entry->text,
875 entry->cursor,
876 entry->anchor);
Jan Arne Petersen0eabcaa2013-01-31 15:52:20 +0100877
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200878 if (entry->preferred_language)
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200879 wl_text_input_set_preferred_language(entry->text_input,
880 entry->preferred_language);
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200881
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200882 text_entry_get_cursor_rectangle(entry, &cursor_rectangle);
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200883 wl_text_input_set_cursor_rectangle(entry->text_input, cursor_rectangle.x, cursor_rectangle.y,
884 cursor_rectangle.width, cursor_rectangle.height);
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200885
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200886 wl_text_input_commit_state(entry->text_input, ++entry->serial);
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100887}
888
889static void
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100890text_entry_insert_at_cursor(struct text_entry *entry, const char *text,
891 int32_t cursor, int32_t anchor)
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200892{
Derek Foreman22044922014-11-20 15:42:35 -0600893 char *new_text = xmalloc(strlen(entry->text) + strlen(text) + 1);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200894
895 strncpy(new_text, entry->text, entry->cursor);
896 strcpy(new_text + entry->cursor, text);
897 strcpy(new_text + entry->cursor + strlen(text),
898 entry->text + entry->cursor);
899
900 free(entry->text);
901 entry->text = new_text;
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100902 if (anchor >= 0)
903 entry->anchor = entry->cursor + strlen(text) + anchor;
904 else
905 entry->anchor = entry->cursor + 1 + anchor;
Jan Arne Petersen68516862013-04-18 16:47:42 +0200906
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100907 if (cursor >= 0)
908 entry->cursor += strlen(text) + cursor;
909 else
910 entry->cursor += 1 + cursor;
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200911
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200912 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100913
914 widget_schedule_redraw(entry->widget);
915
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100916 text_entry_update(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200917}
918
919static void
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100920text_entry_reset_preedit(struct text_entry *entry)
921{
922 entry->preedit.cursor = 0;
923
924 free(entry->preedit.text);
925 entry->preedit.text = NULL;
926
927 free(entry->preedit.commit);
928 entry->preedit.commit = NULL;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100929
930 pango_attr_list_unref(entry->preedit.attr_list);
931 entry->preedit.attr_list = NULL;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100932}
933
934static void
935text_entry_commit_and_reset(struct text_entry *entry)
936{
937 char *commit = NULL;
938
939 if (entry->preedit.commit)
940 commit = strdup(entry->preedit.commit);
941
942 text_entry_reset_preedit(entry);
943 if (commit) {
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100944 text_entry_insert_at_cursor(entry, commit, 0, 0);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100945 free(commit);
946 }
Jan Arne Petersen08015b62013-04-18 16:47:18 +0200947
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200948 wl_text_input_reset(entry->text_input);
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200949 text_entry_update(entry);
950 entry->reset_serial = entry->serial;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100951}
952
953static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200954text_entry_set_preedit(struct text_entry *entry,
955 const char *preedit_text,
956 int preedit_cursor)
957{
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100958 text_entry_reset_preedit(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200959
960 if (!preedit_text)
961 return;
962
Jan Arne Petersen46535312013-01-16 21:26:38 +0100963 entry->preedit.text = strdup(preedit_text);
964 entry->preedit.cursor = preedit_cursor;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200965
966 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100967
968 widget_schedule_redraw(entry->widget);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200969}
970
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100971static uint32_t
972text_entry_try_invoke_preedit_action(struct text_entry *entry,
973 int32_t x, int32_t y,
974 uint32_t button,
975 enum wl_pointer_button_state state)
976{
977 int index, trailing;
978 uint32_t cursor;
Jan Arne Petersen68516862013-04-18 16:47:42 +0200979 const char *text;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100980
981 if (!entry->preedit.text)
982 return 0;
983
984 pango_layout_xy_to_index(entry->layout,
985 x * PANGO_SCALE, y * PANGO_SCALE,
986 &index, &trailing);
Jan Arne Petersen68516862013-04-18 16:47:42 +0200987
988 text = pango_layout_get_text(entry->layout);
989 cursor = g_utf8_offset_to_pointer(text + index, trailing) - text;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100990
991 if (cursor < entry->cursor ||
992 cursor > entry->cursor + strlen(entry->preedit.text)) {
993 return 0;
994 }
995
996 if (state == WL_POINTER_BUTTON_STATE_RELEASED)
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200997 wl_text_input_invoke_action(entry->text_input,
998 button,
999 cursor - entry->cursor);
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001000
1001 return 1;
1002}
1003
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001004static bool
1005text_entry_has_preedit(struct text_entry *entry)
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001006{
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001007 return entry->preedit.text && (strlen(entry->preedit.text) > 0);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001008}
1009
1010static void
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001011text_entry_set_cursor_position(struct text_entry *entry,
1012 int32_t x, int32_t y,
1013 bool move_anchor)
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001014{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001015 int index, trailing;
Jan Arne Petersen68516862013-04-18 16:47:42 +02001016 const char *text;
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001017 uint32_t cursor;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001018
1019 pango_layout_xy_to_index(entry->layout,
1020 x * PANGO_SCALE, y * PANGO_SCALE,
1021 &index, &trailing);
Jan Arne Petersen68516862013-04-18 16:47:42 +02001022
1023 text = pango_layout_get_text(entry->layout);
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001024
1025 cursor = g_utf8_offset_to_pointer(text + index, trailing) - text;
1026
1027 if (move_anchor)
1028 entry->anchor = cursor;
1029
1030 if (text_entry_has_preedit(entry)) {
1031 text_entry_commit_and_reset(entry);
1032
1033 assert(!text_entry_has_preedit(entry));
1034 }
1035
1036 if (entry->cursor == cursor)
1037 return;
1038
1039 entry->cursor = cursor;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001040
1041 text_entry_update_layout(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001042
1043 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001044
Jan Arne Petersen0558a932013-01-16 21:26:45 +01001045 text_entry_update(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001046}
1047
1048static void
Jan Arne Petersene202bae2012-09-09 23:08:44 +02001049text_entry_delete_text(struct text_entry *entry,
1050 uint32_t index, uint32_t length)
1051{
Jan Arne Petersen68516862013-04-18 16:47:42 +02001052 uint32_t l;
1053
Jan Arne Petersen895a1282013-05-30 13:57:04 +02001054 assert(index <= strlen(entry->text));
1055 assert(index + length <= strlen(entry->text));
1056 assert(index + length >= length);
Jan Arne Petersen80ad1a92012-09-17 15:28:10 +02001057
Jan Arne Petersen68516862013-04-18 16:47:42 +02001058 l = strlen(entry->text + index + length);
1059 memmove(entry->text + index,
1060 entry->text + index + length,
1061 l + 1);
Jan Arne Petersene202bae2012-09-09 23:08:44 +02001062
Jan Arne Petersen9eaa8e52013-05-30 13:57:03 +02001063 if (entry->cursor > (index + length))
1064 entry->cursor -= length;
1065 else if (entry->cursor > index)
1066 entry->cursor = index;
1067
1068 entry->anchor = entry->cursor;
1069
Jan Arne Petersene202bae2012-09-09 23:08:44 +02001070 text_entry_update_layout(entry);
1071
1072 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001073
Jan Arne Petersen0558a932013-01-16 21:26:45 +01001074 text_entry_update(entry);
Jan Arne Petersene202bae2012-09-09 23:08:44 +02001075}
1076
1077static void
Jan Arne Petersene386dd22012-09-17 15:28:09 +02001078text_entry_delete_selected_text(struct text_entry *entry)
1079{
1080 uint32_t start_index = entry->anchor < entry->cursor ? entry->anchor : entry->cursor;
1081 uint32_t end_index = entry->anchor < entry->cursor ? entry->cursor : entry->anchor;
1082
1083 if (entry->anchor == entry->cursor)
1084 return;
1085
1086 text_entry_delete_text(entry, start_index, end_index - start_index);
1087
1088 entry->anchor = entry->cursor;
1089}
1090
1091static void
Jan Arne Petersenfe89e712013-04-18 16:47:27 +02001092text_entry_get_cursor_rectangle(struct text_entry *entry, struct rectangle *rectangle)
1093{
1094 struct rectangle allocation;
1095 PangoRectangle extents;
1096 PangoRectangle cursor_pos;
1097
1098 widget_get_allocation(entry->widget, &allocation);
1099
1100 if (entry->preedit.text && entry->preedit.cursor < 0) {
1101 rectangle->x = 0;
1102 rectangle->y = 0;
1103 rectangle->width = 0;
1104 rectangle->height = 0;
1105 return;
1106 }
1107
Jan Arne Petersen68516862013-04-18 16:47:42 +02001108
Jan Arne Petersenfe89e712013-04-18 16:47:27 +02001109 pango_layout_get_extents(entry->layout, &extents, NULL);
1110 pango_layout_get_cursor_pos(entry->layout,
1111 entry->cursor + entry->preedit.cursor,
1112 &cursor_pos, NULL);
1113
1114 rectangle->x = allocation.x + (allocation.height / 2) + PANGO_PIXELS(cursor_pos.x);
1115 rectangle->y = allocation.y + 10 + PANGO_PIXELS(cursor_pos.y);
1116 rectangle->width = PANGO_PIXELS(cursor_pos.width);
1117 rectangle->height = PANGO_PIXELS(cursor_pos.height);
1118}
1119
1120static void
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001121text_entry_draw_cursor(struct text_entry *entry, cairo_t *cr)
1122{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001123 PangoRectangle extents;
1124 PangoRectangle cursor_pos;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001125
Jan Arne Petersen46535312013-01-16 21:26:38 +01001126 if (entry->preedit.text && entry->preedit.cursor < 0)
1127 return;
1128
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001129 pango_layout_get_extents(entry->layout, &extents, NULL);
1130 pango_layout_get_cursor_pos(entry->layout,
1131 entry->cursor + entry->preedit.cursor,
1132 &cursor_pos, NULL);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001133
1134 cairo_set_line_width(cr, 1.0);
Peter Maatmanb9a23f42013-07-06 20:55:54 +02001135 cairo_move_to(cr, PANGO_PIXELS(cursor_pos.x), PANGO_PIXELS(cursor_pos.y));
1136 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 +02001137 cairo_stroke(cr);
1138}
1139
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001140static int
1141text_offset_left(struct rectangle *allocation)
1142{
1143 return 10;
1144}
1145
1146static int
1147text_offset_top(struct rectangle *allocation)
1148{
1149 return allocation->height / 2;
1150}
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +02001151
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +02001152static void
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001153text_entry_redraw_handler(struct widget *widget, void *data)
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001154{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001155 struct text_entry *entry = data;
1156 cairo_surface_t *surface;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001157 struct rectangle allocation;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001158 cairo_t *cr;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001159
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001160 surface = window_get_surface(entry->window);
1161 widget_get_allocation(entry->widget, &allocation);
1162
1163 cr = cairo_create(surface);
1164 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
1165 cairo_clip(cr);
1166
1167 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
1168
1169 cairo_push_group(cr);
1170 cairo_translate(cr, allocation.x, allocation.y);
1171
1172 cairo_set_source_rgba(cr, 1, 1, 1, 1);
1173 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
1174 cairo_fill(cr);
1175
1176 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
1177
1178 if (entry->active) {
1179 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
1180 cairo_set_line_width (cr, 3);
1181 cairo_set_source_rgba(cr, 0, 0, 1, 1.0);
1182 cairo_stroke(cr);
1183 }
1184
1185 cairo_set_source_rgba(cr, 0, 0, 0, 1);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001186
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001187 cairo_translate(cr,
1188 text_offset_left(&allocation),
1189 text_offset_top(&allocation));
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001190
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001191 if (!entry->layout)
1192 entry->layout = pango_cairo_create_layout(cr);
1193 else
1194 pango_cairo_update_layout(cr, entry->layout);
1195
1196 text_entry_update_layout(entry);
1197
1198 pango_cairo_show_layout(cr, entry->layout);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001199
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001200 text_entry_draw_cursor(entry, cr);
1201
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001202 cairo_pop_group_to_source(cr);
1203 cairo_paint(cr);
1204
1205 cairo_destroy(cr);
1206 cairo_surface_destroy(surface);
1207}
1208
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001209static int
1210text_entry_motion_handler(struct widget *widget,
1211 struct input *input, uint32_t time,
1212 float x, float y, void *data)
1213{
1214 struct text_entry *entry = data;
1215 struct rectangle allocation;
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001216 int tx, ty;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001217
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001218 if (!entry->button_pressed) {
1219 return CURSOR_IBEAM;
1220 }
1221
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001222 widget_get_allocation(entry->widget, &allocation);
1223
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001224 tx = x - allocation.x - text_offset_left(&allocation);
1225 ty = y - allocation.y - text_offset_top(&allocation);
1226
1227 text_entry_set_cursor_position(entry, tx, ty, false);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001228
1229 return CURSOR_IBEAM;
1230}
1231
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001232static void
1233text_entry_button_handler(struct widget *widget,
1234 struct input *input, uint32_t time,
1235 uint32_t button,
1236 enum wl_pointer_button_state state, void *data)
1237{
1238 struct text_entry *entry = data;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001239 struct rectangle allocation;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001240 struct editor *editor;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001241 int32_t x, y;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001242 uint32_t result;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001243
1244 widget_get_allocation(entry->widget, &allocation);
1245 input_get_position(input, &x, &y);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001246
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001247 x -= allocation.x + text_offset_left(&allocation);
1248 y -= allocation.y + text_offset_top(&allocation);
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001249
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001250 editor = window_get_user_data(entry->window);
1251
Manuel Bachmann22f34302015-03-30 01:57:44 +02001252 switch (button) {
1253 case BTN_LEFT:
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001254 entry->button_pressed = (state == WL_POINTER_BUTTON_STATE_PRESSED);
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001255 if (state == WL_POINTER_BUTTON_STATE_PRESSED)
1256 input_grab(input, entry->widget, button);
1257 else
1258 input_ungrab(input);
Manuel Bachmann22f34302015-03-30 01:57:44 +02001259 break;
1260 case BTN_RIGHT:
1261 if (state == WL_POINTER_BUTTON_STATE_PRESSED)
1262 show_menu(editor, input, time);
1263 break;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001264 }
1265
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001266 if (text_entry_has_preedit(entry)) {
1267 result = text_entry_try_invoke_preedit_action(entry, x, y, button, state);
1268
1269 if (result)
1270 return;
1271 }
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001272
Manuel Bachmann22f34302015-03-30 01:57:44 +02001273 if (state == WL_POINTER_BUTTON_STATE_PRESSED &&
1274 button == BTN_LEFT) {
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001275 struct wl_seat *seat = input_get_seat(input);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001276
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001277 text_entry_activate(entry, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001278 editor->active_entry = entry;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001279
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001280 text_entry_set_cursor_position(entry, x, y, true);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001281 }
1282}
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001283
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001284static void
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -08001285text_entry_touch_handler(struct widget *widget, struct input *input,
1286 uint32_t serial, uint32_t time, int32_t id,
1287 float tx, float ty, void *data)
1288{
1289 struct text_entry *entry = data;
1290 struct wl_seat *seat = input_get_seat(input);
1291 struct rectangle allocation;
1292 struct editor *editor;
1293 int32_t x, y;
1294
1295 widget_get_allocation(entry->widget, &allocation);
1296
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001297 x = tx - (allocation.x + text_offset_left(&allocation));
1298 y = ty - (allocation.y + text_offset_top(&allocation));
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -08001299
1300 editor = window_get_user_data(entry->window);
1301 text_entry_activate(entry, seat);
1302 editor->active_entry = entry;
1303
1304 text_entry_set_cursor_position(entry, x, y, true);
1305}
1306
1307static void
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001308editor_button_handler(struct widget *widget,
1309 struct input *input, uint32_t time,
1310 uint32_t button,
1311 enum wl_pointer_button_state state, void *data)
1312{
1313 struct editor *editor = data;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001314
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001315 if (button != BTN_LEFT) {
1316 return;
1317 }
Jan Arne Petersene829adc2012-08-10 16:47:22 +02001318
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001319 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
1320 struct wl_seat *seat = input_get_seat(input);
1321
Jan Arne Petersene829adc2012-08-10 16:47:22 +02001322 text_entry_deactivate(editor->entry, seat);
1323 text_entry_deactivate(editor->editor, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001324 editor->active_entry = NULL;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001325 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001326}
1327
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -08001328static void
1329editor_touch_handler(struct widget *widget, struct input *input,
1330 uint32_t serial, uint32_t time, int32_t id,
1331 float tx, float ty, void *data)
1332{
1333 struct editor *editor = data;
1334
1335 struct wl_seat *seat = input_get_seat(input);
1336
1337 text_entry_deactivate(editor->entry, seat);
1338 text_entry_deactivate(editor->editor, seat);
1339 editor->active_entry = NULL;
1340}
Kristian Høgsberg78858902014-01-01 23:57:42 -08001341
1342static void
1343keyboard_focus_handler(struct window *window,
1344 struct input *device, void *data)
1345{
1346 struct editor *editor = data;
1347
1348 window_schedule_redraw(editor->window);
1349}
1350
Manuel Bachmann22f34302015-03-30 01:57:44 +02001351static int
1352handle_bound_key(struct editor *editor,
1353 struct input *input, uint32_t sym, uint32_t time)
1354{
1355 switch (sym) {
1356 case XKB_KEY_X:
1357 editor_copy_cut(editor, input, true);
1358 return 1;
1359 case XKB_KEY_C:
1360 editor_copy_cut(editor, input, false);
1361 return 1;
1362 case XKB_KEY_V:
1363 editor_paste(editor, input);
1364 return 1;
1365 default:
1366 return 0;
1367 }
1368}
1369
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001370static void
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001371key_handler(struct window *window,
1372 struct input *input, uint32_t time,
1373 uint32_t key, uint32_t sym, enum wl_keyboard_key_state state,
1374 void *data)
1375{
1376 struct editor *editor = data;
1377 struct text_entry *entry;
Jan Arne Petersen68516862013-04-18 16:47:42 +02001378 const char *new_char;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001379 char text[16];
Manuel Bachmann22f34302015-03-30 01:57:44 +02001380 uint32_t modifiers;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001381
1382 if (!editor->active_entry)
1383 return;
1384
1385 entry = editor->active_entry;
1386
1387 if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
1388 return;
1389
Manuel Bachmann22f34302015-03-30 01:57:44 +02001390 modifiers = input_get_modifiers(input);
1391 if ((modifiers & MOD_CONTROL_MASK) &&
1392 (modifiers & MOD_SHIFT_MASK) &&
1393 handle_bound_key(editor, input, sym, time))
1394 return;
1395
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001396 switch (sym) {
1397 case XKB_KEY_BackSpace:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001398 text_entry_commit_and_reset(entry);
1399
Jan Arne Petersen68516862013-04-18 16:47:42 +02001400 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
1401 if (new_char != NULL)
1402 text_entry_delete_text(entry,
1403 new_char - entry->text,
1404 (entry->text + entry->cursor) - new_char);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001405 break;
1406 case XKB_KEY_Delete:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001407 text_entry_commit_and_reset(entry);
1408
Jan Arne Petersen68516862013-04-18 16:47:42 +02001409 new_char = utf8_next_char(entry->text + entry->cursor);
1410 if (new_char != NULL)
1411 text_entry_delete_text(entry,
1412 entry->cursor,
1413 new_char - (entry->text + entry->cursor));
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001414 break;
1415 case XKB_KEY_Left:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001416 text_entry_commit_and_reset(entry);
1417
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001418 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
1419 if (new_char != NULL) {
1420 entry->cursor = new_char - entry->text;
Rob Bradford70002832013-07-11 16:00:00 +01001421 if (!(input_get_modifiers(input) & MOD_SHIFT_MASK))
1422 entry->anchor = entry->cursor;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001423 widget_schedule_redraw(entry->widget);
1424 }
1425 break;
1426 case XKB_KEY_Right:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001427 text_entry_commit_and_reset(entry);
1428
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001429 new_char = utf8_next_char(entry->text + entry->cursor);
1430 if (new_char != NULL) {
1431 entry->cursor = new_char - entry->text;
Rob Bradford70002832013-07-11 16:00:00 +01001432 if (!(input_get_modifiers(input) & MOD_SHIFT_MASK))
1433 entry->anchor = entry->cursor;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001434 widget_schedule_redraw(entry->widget);
1435 }
1436 break;
Manuel Bachmann8986c182014-04-18 12:50:14 +02001437 case XKB_KEY_Up:
1438 text_entry_commit_and_reset(entry);
1439
1440 move_up(entry->text, &entry->cursor);
1441 if (!(input_get_modifiers(input) & MOD_SHIFT_MASK))
1442 entry->anchor = entry->cursor;
1443 widget_schedule_redraw(entry->widget);
1444 break;
1445 case XKB_KEY_Down:
1446 text_entry_commit_and_reset(entry);
1447
1448 move_down(entry->text, &entry->cursor);
1449 if (!(input_get_modifiers(input) & MOD_SHIFT_MASK))
1450 entry->anchor = entry->cursor;
1451 widget_schedule_redraw(entry->widget);
1452 break;
Peter Maatman08c38d42013-07-06 20:42:59 +02001453 case XKB_KEY_Escape:
1454 break;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001455 default:
1456 if (xkb_keysym_to_utf8(sym, text, sizeof(text)) <= 0)
1457 break;
1458
Peter Maatman08c38d42013-07-06 20:42:59 +02001459 text_entry_commit_and_reset(entry);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001460
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +01001461 text_entry_insert_at_cursor(entry, text, 0, 0);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001462 break;
1463 }
1464
1465 widget_schedule_redraw(entry->widget);
1466}
1467
1468static void
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001469global_handler(struct display *display, uint32_t name,
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001470 const char *interface, uint32_t version, void *data)
1471{
1472 struct editor *editor = data;
1473
Jan Arne Petersen62ece762013-04-18 16:47:36 +02001474 if (!strcmp(interface, "wl_text_input_manager")) {
Jan Arne Petersen78d00e42013-04-18 16:47:24 +02001475 editor->text_input_manager =
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001476 display_bind(display, name,
Jan Arne Petersen62ece762013-04-18 16:47:36 +02001477 &wl_text_input_manager_interface, 1);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001478 }
1479}
1480
1481int
1482main(int argc, char *argv[])
1483{
1484 struct editor editor;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001485 int i;
1486 uint32_t click_to_show = 0;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001487 const char *preferred_language = NULL;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001488
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001489 for (i = 1; i < argc; i++) {
Jan Arne Petersen61381972013-01-31 15:52:21 +01001490 if (strcmp("--click-to-show", argv[i]) == 0)
1491 click_to_show = 1;
Bill Spitzakbb0bb9c2014-08-08 12:59:58 -07001492 else if (strcmp("--preferred-language", argv[i]) == 0 &&
1493 i + 1 < argc) {
1494 preferred_language = argv[i + 1];
1495 i++;
1496 } else {
1497 printf("Usage: %s [OPTIONS]\n"
1498 " --click-to-show\n"
1499 " --preferred-language LANGUAGE\n",
1500 argv[0]);
1501 return 1;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001502 }
1503 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001504
Jan Arne Petersen25f6db52012-11-05 03:26:40 +01001505 memset(&editor, 0, sizeof editor);
1506
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001507#ifdef HAVE_PANGO
1508 g_type_init();
1509#endif
1510
Kristian Høgsberg4172f662013-02-20 15:27:49 -05001511 editor.display = display_create(&argc, argv);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001512 if (editor.display == NULL) {
1513 fprintf(stderr, "failed to create display: %m\n");
1514 return -1;
1515 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001516
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001517 display_set_user_data(editor.display, &editor);
1518 display_set_global_handler(editor.display, global_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001519
Olivier Blin30e1f3c2014-09-16 19:13:17 +02001520 if (editor.text_input_manager == NULL) {
1521 fprintf(stderr, "No text input manager global\n");
1522 return -1;
1523 }
1524
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001525 editor.window = window_create(editor.display);
Jason Ekstrandee7fefc2013-10-13 19:08:38 -05001526 editor.widget = window_frame_create(editor.window, &editor);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001527
1528 editor.entry = text_entry_create(&editor, "Entry");
Jan Arne Petersen61381972013-01-31 15:52:21 +01001529 editor.entry->click_to_show = click_to_show;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001530 if (preferred_language)
1531 editor.entry->preferred_language = strdup(preferred_language);
Jan Arne Petersen0558a932013-01-16 21:26:45 +01001532 editor.editor = text_entry_create(&editor, "Numeric");
Jan Arne Petersen62ece762013-04-18 16:47:36 +02001533 editor.editor->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_NUMBER;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001534 editor.editor->click_to_show = click_to_show;
Manuel Bachmann22f34302015-03-30 01:57:44 +02001535 editor.selection = NULL;
1536 editor.selected_text = NULL;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001537
1538 window_set_title(editor.window, "Text Editor");
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001539 window_set_key_handler(editor.window, key_handler);
Kristian Høgsberg78858902014-01-01 23:57:42 -08001540 window_set_keyboard_focus_handler(editor.window,
1541 keyboard_focus_handler);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001542 window_set_user_data(editor.window, &editor);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001543
1544 widget_set_redraw_handler(editor.widget, redraw_handler);
1545 widget_set_resize_handler(editor.widget, resize_handler);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001546 widget_set_button_handler(editor.widget, editor_button_handler);
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -08001547 widget_set_touch_down_handler(editor.widget, editor_touch_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001548
1549 window_schedule_resize(editor.window, 500, 400);
1550
1551 display_run(editor.display);
1552
Manuel Bachmann22f34302015-03-30 01:57:44 +02001553 if (editor.selected_text)
1554 free(editor.selected_text);
1555 if (editor.selection)
1556 wl_data_source_destroy(editor.selection);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001557 text_entry_destroy(editor.entry);
1558 text_entry_destroy(editor.editor);
vivek31732f72014-05-15 18:58:16 +05301559 widget_destroy(editor.widget);
1560 window_destroy(editor.window);
1561 display_destroy(editor.display);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001562
1563 return 0;
1564}