blob: 34fbf239d92edeefcf1aaa6bc3bf836e6058d37e [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>
30
31#include <linux/input.h>
32#include <cairo.h>
33
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010034#include <pango/pangocairo.h>
35
Jan Arne Petersencba9e472012-06-21 21:52:19 +020036#include "window.h"
37#include "text-client-protocol.h"
38
39struct text_entry {
40 struct widget *widget;
Jan Arne Petersene829adc2012-08-10 16:47:22 +020041 struct window *window;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020042 char *text;
43 int active;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +020044 uint32_t cursor;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +020045 uint32_t anchor;
Jan Arne Petersen46535312013-01-16 21:26:38 +010046 struct {
47 char *text;
48 int32_t cursor;
49 char *commit;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010050 PangoAttrList *attr_list;
Jan Arne Petersen46535312013-01-16 21:26:38 +010051 } preedit;
52 struct {
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010053 PangoAttrList *attr_list;
Jan Arne Petersen46535312013-01-16 21:26:38 +010054 int32_t cursor;
55 } preedit_info;
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +010056 struct {
57 int32_t cursor;
58 int32_t anchor;
Jan Arne Petersen919bc142013-04-18 16:47:34 +020059 uint32_t delete_index;
60 uint32_t delete_length;
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +010061 } pending_commit;
Jan Arne Petersen62ece762013-04-18 16:47:36 +020062 struct wl_text_input *text_input;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010063 PangoLayout *layout;
Jan Arne Petersencd997062012-11-18 19:06:44 +010064 struct {
65 xkb_mod_mask_t shift_mask;
66 } keysym;
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +010067 uint32_t serial;
Jan Arne Petersen00191c72013-04-18 16:47:33 +020068 uint32_t reset_serial;
Jan Arne Petersen0558a932013-01-16 21:26:45 +010069 uint32_t content_purpose;
Jan Arne Petersen61381972013-01-31 15:52:21 +010070 uint32_t click_to_show;
Jan Arne Petersen9d419132013-04-18 16:47:16 +020071 char *preferred_language;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020072};
73
74struct editor {
Jan Arne Petersen62ece762013-04-18 16:47:36 +020075 struct wl_text_input_manager *text_input_manager;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020076 struct display *display;
77 struct window *window;
78 struct widget *widget;
79 struct text_entry *entry;
80 struct text_entry *editor;
Rob Bradford9d1d32b2012-11-18 19:06:49 +010081 struct text_entry *active_entry;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020082};
83
Jan Arne Petersen6345faa2012-11-05 03:26:39 +010084static const char *
Jan Arne Petersen6345faa2012-11-05 03:26:39 +010085utf8_end_char(const char *p)
86{
87 while ((*p & 0xc0) == 0x80)
88 p++;
89 return p;
90}
91
92static const char *
Jan Arne Petersen68516862013-04-18 16:47:42 +020093utf8_prev_char(const char *s, const char *p)
94{
95 for (--p; p >= s; --p) {
96 if ((*p & 0xc0) != 0x80)
97 return p;
98 }
99 return NULL;
100}
101
102static const char *
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100103utf8_next_char(const char *p)
104{
105 if (*p != 0)
106 return utf8_end_char(++p);
107 return NULL;
108}
109
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200110static uint32_t
111utf8_characters(const char *p)
112{
113 uint32_t offset;
114
115 for (offset = 0; *p != 0; offset++)
116 p = utf8_next_char(p);
117
118 return offset;
119}
120
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200121static void text_entry_redraw_handler(struct widget *widget, void *data);
122static void text_entry_button_handler(struct widget *widget,
123 struct input *input, uint32_t time,
124 uint32_t button,
125 enum wl_pointer_button_state state, void *data);
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100126static void text_entry_insert_at_cursor(struct text_entry *entry, const char *text,
127 int32_t cursor, int32_t anchor);
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200128static void text_entry_set_preedit(struct text_entry *entry,
129 const char *preedit_text,
130 int preedit_cursor);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200131static void text_entry_delete_text(struct text_entry *entry,
132 uint32_t index, uint32_t length);
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200133static void text_entry_delete_selected_text(struct text_entry *entry);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100134static void text_entry_reset_preedit(struct text_entry *entry);
135static void text_entry_commit_and_reset(struct text_entry *entry);
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200136static void text_entry_get_cursor_rectangle(struct text_entry *entry, struct rectangle *rectangle);
137static void text_entry_update(struct text_entry *entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200138
139static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200140text_input_commit_string(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200141 struct wl_text_input *text_input,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100142 uint32_t serial,
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100143 const char *text)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200144{
145 struct text_entry *entry = data;
146
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200147 if ((entry->serial - serial) > (entry->serial - entry->reset_serial)) {
148 fprintf(stderr, "Ignore commit. Serial: %u, Current: %u, Reset: %u\n",
149 serial, entry->serial, entry->reset_serial);
150 return;
151 }
152
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100153 text_entry_reset_preedit(entry);
154
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200155 text_entry_delete_selected_text(entry);
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200156
157 if (entry->pending_commit.delete_length) {
158 text_entry_delete_text(entry,
159 entry->pending_commit.delete_index,
160 entry->pending_commit.delete_length);
161 }
162
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100163 text_entry_insert_at_cursor(entry, text,
164 entry->pending_commit.cursor,
165 entry->pending_commit.anchor);
166
167 memset(&entry->pending_commit, 0, sizeof entry->pending_commit);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200168
169 widget_schedule_redraw(entry->widget);
170}
171
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200172static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200173text_input_preedit_string(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200174 struct wl_text_input *text_input,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100175 uint32_t serial,
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200176 const char *text,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100177 const char *commit)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200178{
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200179 struct text_entry *entry = data;
180
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200181 text_entry_delete_selected_text(entry);
Jan Arne Petersen46535312013-01-16 21:26:38 +0100182 text_entry_set_preedit(entry, text, entry->preedit_info.cursor);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100183 entry->preedit.commit = strdup(commit);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100184 entry->preedit.attr_list = entry->preedit_info.attr_list;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100185
186 entry->preedit_info.cursor = 0;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100187 entry->preedit_info.attr_list = NULL;
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200188
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200189 text_entry_update(entry);
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200190
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200191 widget_schedule_redraw(entry->widget);
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200192}
193
194static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200195text_input_delete_surrounding_text(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200196 struct wl_text_input *text_input,
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200197 int32_t index,
198 uint32_t length)
199{
200 struct text_entry *entry = data;
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200201 uint32_t text_length;
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200202
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200203 entry->pending_commit.delete_index = entry->cursor + index;
204 entry->pending_commit.delete_length = length;
205
Jan Arne Petersen68516862013-04-18 16:47:42 +0200206 text_length = strlen(entry->text);
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200207
208 if (entry->pending_commit.delete_index > text_length) {
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200209 fprintf(stderr, "Invalid cursor index %d\n", index);
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200210 entry->pending_commit.delete_length = 0;
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200211 return;
212 }
213
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200214 if (entry->pending_commit.delete_index + length > text_length) {
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200215 fprintf(stderr, "Invalid length %d\n", length);
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200216 entry->pending_commit.delete_length = 0;
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200217 return;
218 }
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200219}
220
221static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200222text_input_cursor_position(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200223 struct wl_text_input *text_input,
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100224 int32_t index,
225 int32_t anchor)
226{
227 struct text_entry *entry = data;
228
229 entry->pending_commit.cursor = index;
230 entry->pending_commit.anchor = anchor;
231}
232
233static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200234text_input_preedit_styling(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200235 struct wl_text_input *text_input,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100236 uint32_t index,
237 uint32_t length,
238 uint32_t style)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200239{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100240 struct text_entry *entry = data;
241 PangoAttribute *attr1 = NULL;
242 PangoAttribute *attr2 = NULL;
243
244 if (!entry->preedit_info.attr_list)
245 entry->preedit_info.attr_list = pango_attr_list_new();
246
247 switch (style) {
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200248 case WL_TEXT_INPUT_PREEDIT_STYLE_DEFAULT:
249 case WL_TEXT_INPUT_PREEDIT_STYLE_UNDERLINE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100250 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
251 break;
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200252 case WL_TEXT_INPUT_PREEDIT_STYLE_INCORRECT:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100253 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_ERROR);
254 attr2 = pango_attr_underline_color_new(65535, 0, 0);
255 break;
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200256 case WL_TEXT_INPUT_PREEDIT_STYLE_SELECTION:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100257 attr1 = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
258 attr2 = pango_attr_foreground_new(65535, 65535, 65535);
259 break;
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200260 case WL_TEXT_INPUT_PREEDIT_STYLE_HIGHLIGHT:
261 case WL_TEXT_INPUT_PREEDIT_STYLE_ACTIVE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100262 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
263 attr2 = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
264 break;
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200265 case WL_TEXT_INPUT_PREEDIT_STYLE_INACTIVE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100266 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
267 attr2 = pango_attr_foreground_new(0.3 * 65535, 0.3 * 65535, 0.3 * 65535);
268 break;
269 }
270
271 if (attr1) {
272 attr1->start_index = entry->cursor + index;
273 attr1->end_index = entry->cursor + index + length;
274 pango_attr_list_insert(entry->preedit_info.attr_list, attr1);
275 }
276
277 if (attr2) {
278 attr2->start_index = entry->cursor + index;
279 attr2->end_index = entry->cursor + index + length;
280 pango_attr_list_insert(entry->preedit_info.attr_list, attr2);
281 }
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200282}
283
284static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200285text_input_preedit_cursor(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200286 struct wl_text_input *text_input,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100287 int32_t index)
288{
289 struct text_entry *entry = data;
290
291 entry->preedit_info.cursor = index;
292}
293
294static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200295text_input_modifiers_map(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200296 struct wl_text_input *text_input,
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100297 struct wl_array *map)
298{
Jan Arne Petersencd997062012-11-18 19:06:44 +0100299 struct text_entry *entry = data;
300
301 entry->keysym.shift_mask = keysym_modifiers_get_mask(map, "Shift");
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100302}
303
304static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200305text_input_keysym(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200306 struct wl_text_input *text_input,
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100307 uint32_t serial,
308 uint32_t time,
309 uint32_t key,
310 uint32_t state,
311 uint32_t modifiers)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200312{
Jan Arne Petersen8aba11d2012-09-17 15:28:07 +0200313 struct text_entry *entry = data;
Jan Arne Petersencd997062012-11-18 19:06:44 +0100314 const char *state_label = "release";
315 const char *key_label = "Unknown";
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100316 const char *new_char;
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200317
318 if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
319 state_label = "pressed";
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200320 }
321
Jan Arne Petersencd997062012-11-18 19:06:44 +0100322 if (key == XKB_KEY_Left ||
323 key == XKB_KEY_Right) {
324 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
325 return;
326
327 if (key == XKB_KEY_Left)
328 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
329 else
330 new_char = utf8_next_char(entry->text + entry->cursor);
331
332 if (new_char != NULL) {
333 entry->cursor = new_char - entry->text;
Jan Arne Petersencd997062012-11-18 19:06:44 +0100334 }
335
Jan Arne Petersen68516862013-04-18 16:47:42 +0200336 if (!(modifiers & entry->keysym.shift_mask))
337 entry->anchor = entry->cursor;
338 widget_schedule_redraw(entry->widget);
339
Jan Arne Petersencd997062012-11-18 19:06:44 +0100340 return;
341 }
342
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100343 if (key == XKB_KEY_BackSpace) {
344 const char *start, *end;
345
Jan Arne Petersendfd34462013-04-18 16:47:26 +0200346 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
347 return;
348
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100349 text_entry_commit_and_reset(entry);
350
351 start = utf8_prev_char(entry->text, entry->text + entry->cursor);
Jan Arne Petersen68516862013-04-18 16:47:42 +0200352 end = utf8_next_char(start);
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100353
354 if (start == NULL)
355 return;
356
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100357 text_entry_delete_text(entry,
358 start - entry->text,
359 end - start);
360
361 return;
362 }
363
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200364 switch (key) {
365 case XKB_KEY_Tab:
366 key_label = "Tab";
367 break;
368 case XKB_KEY_KP_Enter:
Jan Arne Petersencd997062012-11-18 19:06:44 +0100369 case XKB_KEY_Return:
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200370 key_label = "Enter";
371 break;
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200372 }
373
374 fprintf(stderr, "%s key was %s.\n", key_label, state_label);
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200375}
376
377static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200378text_input_enter(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200379 struct wl_text_input *text_input,
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200380 struct wl_surface *surface)
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200381{
382 struct text_entry *entry = data;
383
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200384 if (surface != window_get_wl_surface(entry->window))
385 return;
386
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200387 entry->active = 1;
388
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200389 text_entry_update(entry);
390 entry->reset_serial = entry->serial;
391
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200392 widget_schedule_redraw(entry->widget);
393}
394
395static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200396text_input_leave(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200397 struct wl_text_input *text_input)
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200398{
399 struct text_entry *entry = data;
400
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100401 text_entry_commit_and_reset(entry);
402
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200403 entry->active = 0;
404
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200405 wl_text_input_hide_input_panel(text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100406
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200407 widget_schedule_redraw(entry->widget);
408}
409
Jan Arne Petersen61381972013-01-31 15:52:21 +0100410static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200411text_input_input_panel_state(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200412 struct wl_text_input *text_input,
Jan Arne Petersen61381972013-01-31 15:52:21 +0100413 uint32_t state)
414{
415}
416
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200417static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200418text_input_language(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200419 struct wl_text_input *text_input,
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200420 uint32_t serial,
421 const char *language)
422{
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200423 fprintf(stderr, "input language is %s \n", language);
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200424}
425
426static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200427text_input_text_direction(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200428 struct wl_text_input *text_input,
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200429 uint32_t serial,
430 uint32_t direction)
431{
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200432 struct text_entry *entry = data;
433 PangoContext *context = pango_layout_get_context(entry->layout);
434 PangoDirection pango_direction;
435
436
437 switch (direction) {
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200438 case WL_TEXT_INPUT_TEXT_DIRECTION_LTR:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200439 pango_direction = PANGO_DIRECTION_LTR;
440 break;
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200441 case WL_TEXT_INPUT_TEXT_DIRECTION_RTL:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200442 pango_direction = PANGO_DIRECTION_RTL;
443 break;
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200444 case WL_TEXT_INPUT_TEXT_DIRECTION_AUTO:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200445 default:
446 pango_direction = PANGO_DIRECTION_NEUTRAL;
447 }
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200448
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200449 pango_context_set_base_dir(context, pango_direction);
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200450}
451
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200452static const struct wl_text_input_listener text_input_listener = {
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200453 text_input_enter,
454 text_input_leave,
455 text_input_modifiers_map,
456 text_input_input_panel_state,
457 text_input_preedit_string,
458 text_input_preedit_styling,
459 text_input_preedit_cursor,
460 text_input_commit_string,
461 text_input_cursor_position,
462 text_input_delete_surrounding_text,
463 text_input_keysym,
464 text_input_language,
465 text_input_text_direction
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200466};
467
468static struct text_entry*
469text_entry_create(struct editor *editor, const char *text)
470{
471 struct text_entry *entry;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200472
Jan Arne Petersencd997062012-11-18 19:06:44 +0100473 entry = calloc(1, sizeof *entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200474
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200475 entry->widget = widget_add_widget(editor->widget, entry);
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200476 entry->window = editor->window;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200477 entry->text = strdup(text);
478 entry->active = 0;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200479 entry->cursor = strlen(text);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200480 entry->anchor = entry->cursor;
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200481 entry->text_input = wl_text_input_manager_create_text_input(editor->text_input_manager);
482 wl_text_input_add_listener(entry->text_input, &text_input_listener, entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200483
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200484 widget_set_redraw_handler(entry->widget, text_entry_redraw_handler);
485 widget_set_button_handler(entry->widget, text_entry_button_handler);
486
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200487 return entry;
488}
489
490static void
491text_entry_destroy(struct text_entry *entry)
492{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200493 widget_destroy(entry->widget);
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200494 wl_text_input_destroy(entry->text_input);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100495 g_clear_object(&entry->layout);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200496 free(entry->text);
497 free(entry);
498}
499
500static void
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200501redraw_handler(struct widget *widget, void *data)
502{
503 struct editor *editor = data;
504 cairo_surface_t *surface;
505 struct rectangle allocation;
506 cairo_t *cr;
507
508 surface = window_get_surface(editor->window);
509 widget_get_allocation(editor->widget, &allocation);
510
511 cr = cairo_create(surface);
512 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
513 cairo_clip(cr);
514
515 cairo_translate(cr, allocation.x, allocation.y);
516
517 /* Draw background */
518 cairo_push_group(cr);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200519 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200520 cairo_set_source_rgba(cr, 1, 1, 1, 1);
521 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
522 cairo_fill(cr);
523
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200524 cairo_pop_group_to_source(cr);
525 cairo_paint(cr);
526
527 cairo_destroy(cr);
528 cairo_surface_destroy(surface);
529}
530
531static void
532text_entry_allocate(struct text_entry *entry, int32_t x, int32_t y,
533 int32_t width, int32_t height)
534{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200535 widget_set_allocation(entry->widget, x, y, width, height);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200536}
537
538static void
539resize_handler(struct widget *widget,
540 int32_t width, int32_t height, void *data)
541{
542 struct editor *editor = data;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200543 struct rectangle allocation;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200544
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200545 widget_get_allocation(editor->widget, &allocation);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200546
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200547 text_entry_allocate(editor->entry,
548 allocation.x + 20, allocation.y + 20,
549 width - 40, height / 2 - 40);
550 text_entry_allocate(editor->editor,
551 allocation.x + 20, allocation.y + height / 2 + 20,
552 width - 40, height / 2 - 40);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200553}
554
555static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200556text_entry_activate(struct text_entry *entry,
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200557 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200558{
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200559 struct wl_surface *surface = window_get_wl_surface(entry->window);
560
Jan Arne Petersen61381972013-01-31 15:52:21 +0100561 if (entry->click_to_show && entry->active) {
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200562 wl_text_input_show_input_panel(entry->text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100563
564 return;
565 }
566
567 if (!entry->click_to_show)
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200568 wl_text_input_show_input_panel(entry->text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100569
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200570 wl_text_input_activate(entry->text_input,
571 seat,
572 surface);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200573}
574
575static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200576text_entry_deactivate(struct text_entry *entry,
577 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200578{
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200579 wl_text_input_deactivate(entry->text_input,
580 seat);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200581}
582
583static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200584text_entry_update_layout(struct text_entry *entry)
585{
586 char *text;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100587 PangoAttrList *attr_list;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200588
Jan Arne Petersen68516862013-04-18 16:47:42 +0200589 assert(entry->cursor <= (strlen(entry->text) +
590 (entry->preedit.text ? strlen(entry->preedit.text) : 0)));
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200591
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100592 if (entry->preedit.text) {
593 text = malloc(strlen(entry->text) + strlen(entry->preedit.text) + 1);
594 strncpy(text, entry->text, entry->cursor);
595 strcpy(text + entry->cursor, entry->preedit.text);
596 strcpy(text + entry->cursor + strlen(entry->preedit.text),
597 entry->text + entry->cursor);
598 } else {
599 text = strdup(entry->text);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200600 }
601
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100602 if (entry->cursor != entry->anchor) {
603 int start_index = MIN(entry->cursor, entry->anchor);
604 int end_index = MAX(entry->cursor, entry->anchor);
605 PangoAttribute *attr;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200606
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100607 attr_list = pango_attr_list_copy(entry->preedit.attr_list);
608
609 if (!attr_list)
610 attr_list = pango_attr_list_new();
611
612 attr = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
613 attr->start_index = start_index;
614 attr->end_index = end_index;
615 pango_attr_list_insert(attr_list, attr);
616
617 attr = pango_attr_foreground_new(65535, 65535, 65535);
618 attr->start_index = start_index;
619 attr->end_index = end_index;
620 pango_attr_list_insert(attr_list, attr);
621 } else {
622 attr_list = pango_attr_list_ref(entry->preedit.attr_list);
623 }
624
625 if (entry->preedit.text && !entry->preedit.attr_list) {
626 PangoAttribute *attr;
627
628 if (!attr_list)
629 attr_list = pango_attr_list_new();
630
631 attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
632 attr->start_index = entry->cursor;
633 attr->end_index = entry->cursor + strlen(entry->preedit.text);
634 pango_attr_list_insert(attr_list, attr);
635 }
636
637 if (entry->layout) {
638 pango_layout_set_text(entry->layout, text, -1);
639 pango_layout_set_attributes(entry->layout, attr_list);
640 }
641
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200642 free(text);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100643 pango_attr_list_unref(attr_list);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200644}
645
646static void
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100647text_entry_update(struct text_entry *entry)
648{
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200649 struct rectangle cursor_rectangle;
650
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200651 wl_text_input_set_content_type(entry->text_input,
652 WL_TEXT_INPUT_CONTENT_HINT_NONE,
653 entry->content_purpose);
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100654
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200655 wl_text_input_set_surrounding_text(entry->text_input,
656 entry->text,
657 entry->cursor,
658 entry->anchor);
Jan Arne Petersen0eabcaa2013-01-31 15:52:20 +0100659
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200660 if (entry->preferred_language)
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200661 wl_text_input_set_preferred_language(entry->text_input,
662 entry->preferred_language);
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200663
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200664 text_entry_get_cursor_rectangle(entry, &cursor_rectangle);
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200665 wl_text_input_set_cursor_rectangle(entry->text_input, cursor_rectangle.x, cursor_rectangle.y,
666 cursor_rectangle.width, cursor_rectangle.height);
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200667
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200668 wl_text_input_commit_state(entry->text_input, ++entry->serial);
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100669}
670
671static void
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100672text_entry_insert_at_cursor(struct text_entry *entry, const char *text,
673 int32_t cursor, int32_t anchor)
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200674{
675 char *new_text = malloc(strlen(entry->text) + strlen(text) + 1);
676
677 strncpy(new_text, entry->text, entry->cursor);
678 strcpy(new_text + entry->cursor, text);
679 strcpy(new_text + entry->cursor + strlen(text),
680 entry->text + entry->cursor);
681
682 free(entry->text);
683 entry->text = new_text;
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100684 if (anchor >= 0)
685 entry->anchor = entry->cursor + strlen(text) + anchor;
686 else
687 entry->anchor = entry->cursor + 1 + anchor;
Jan Arne Petersen68516862013-04-18 16:47:42 +0200688
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100689 if (cursor >= 0)
690 entry->cursor += strlen(text) + cursor;
691 else
692 entry->cursor += 1 + cursor;
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200693
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200694 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100695
696 widget_schedule_redraw(entry->widget);
697
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100698 text_entry_update(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200699}
700
701static void
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100702text_entry_reset_preedit(struct text_entry *entry)
703{
704 entry->preedit.cursor = 0;
705
706 free(entry->preedit.text);
707 entry->preedit.text = NULL;
708
709 free(entry->preedit.commit);
710 entry->preedit.commit = NULL;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100711
712 pango_attr_list_unref(entry->preedit.attr_list);
713 entry->preedit.attr_list = NULL;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100714}
715
716static void
717text_entry_commit_and_reset(struct text_entry *entry)
718{
719 char *commit = NULL;
720
721 if (entry->preedit.commit)
722 commit = strdup(entry->preedit.commit);
723
724 text_entry_reset_preedit(entry);
725 if (commit) {
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100726 text_entry_insert_at_cursor(entry, commit, 0, 0);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100727 free(commit);
728 }
Jan Arne Petersen08015b62013-04-18 16:47:18 +0200729
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200730 wl_text_input_reset(entry->text_input);
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200731 text_entry_update(entry);
732 entry->reset_serial = entry->serial;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100733}
734
735static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200736text_entry_set_preedit(struct text_entry *entry,
737 const char *preedit_text,
738 int preedit_cursor)
739{
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100740 text_entry_reset_preedit(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200741
742 if (!preedit_text)
743 return;
744
Jan Arne Petersen46535312013-01-16 21:26:38 +0100745 entry->preedit.text = strdup(preedit_text);
746 entry->preedit.cursor = preedit_cursor;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200747
748 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100749
750 widget_schedule_redraw(entry->widget);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200751}
752
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100753static uint32_t
754text_entry_try_invoke_preedit_action(struct text_entry *entry,
755 int32_t x, int32_t y,
756 uint32_t button,
757 enum wl_pointer_button_state state)
758{
759 int index, trailing;
760 uint32_t cursor;
Jan Arne Petersen68516862013-04-18 16:47:42 +0200761 const char *text;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100762
763 if (!entry->preedit.text)
764 return 0;
765
766 pango_layout_xy_to_index(entry->layout,
767 x * PANGO_SCALE, y * PANGO_SCALE,
768 &index, &trailing);
Jan Arne Petersen68516862013-04-18 16:47:42 +0200769
770 text = pango_layout_get_text(entry->layout);
771 cursor = g_utf8_offset_to_pointer(text + index, trailing) - text;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100772
773 if (cursor < entry->cursor ||
774 cursor > entry->cursor + strlen(entry->preedit.text)) {
775 return 0;
776 }
777
778 if (state == WL_POINTER_BUTTON_STATE_RELEASED)
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200779 wl_text_input_invoke_action(entry->text_input,
780 button,
781 cursor - entry->cursor);
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100782
783 return 1;
784}
785
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200786static void
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200787text_entry_set_cursor_position(struct text_entry *entry,
788 int32_t x, int32_t y)
789{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100790 int index, trailing;
Jan Arne Petersen68516862013-04-18 16:47:42 +0200791 const char *text;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100792
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100793 text_entry_commit_and_reset(entry);
794
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100795 pango_layout_xy_to_index(entry->layout,
796 x * PANGO_SCALE, y * PANGO_SCALE,
797 &index, &trailing);
Jan Arne Petersen68516862013-04-18 16:47:42 +0200798
799 text = pango_layout_get_text(entry->layout);
800 entry->cursor = g_utf8_offset_to_pointer(text + index, trailing) - text;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200801
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200802 text_entry_update_layout(entry);
803
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200804 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100805
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100806 text_entry_update(entry);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200807}
808
809static void
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200810text_entry_set_anchor_position(struct text_entry *entry,
811 int32_t x, int32_t y)
812{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100813 int index, trailing;
Jan Arne Petersen68516862013-04-18 16:47:42 +0200814 const char *text;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100815
816 pango_layout_xy_to_index(entry->layout,
817 x * PANGO_SCALE, y * PANGO_SCALE,
818 &index, &trailing);
Jan Arne Petersen68516862013-04-18 16:47:42 +0200819
820 text = pango_layout_get_text(entry->layout);
821 entry->anchor = g_utf8_offset_to_pointer(text + index, trailing) - text;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100822
823 text_entry_update_layout(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200824
825 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100826
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100827 text_entry_update(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200828}
829
830static void
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200831text_entry_delete_text(struct text_entry *entry,
832 uint32_t index, uint32_t length)
833{
Jan Arne Petersen68516862013-04-18 16:47:42 +0200834 uint32_t l;
835
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200836 if (entry->cursor > index)
837 entry->cursor -= length;
838
Jan Arne Petersen80ad1a92012-09-17 15:28:10 +0200839 entry->anchor = entry->cursor;
840
Jan Arne Petersen68516862013-04-18 16:47:42 +0200841 l = strlen(entry->text + index + length);
842 memmove(entry->text + index,
843 entry->text + index + length,
844 l + 1);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200845
846 text_entry_update_layout(entry);
847
848 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100849
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100850 text_entry_update(entry);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200851}
852
853static void
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200854text_entry_delete_selected_text(struct text_entry *entry)
855{
856 uint32_t start_index = entry->anchor < entry->cursor ? entry->anchor : entry->cursor;
857 uint32_t end_index = entry->anchor < entry->cursor ? entry->cursor : entry->anchor;
858
859 if (entry->anchor == entry->cursor)
860 return;
861
862 text_entry_delete_text(entry, start_index, end_index - start_index);
863
864 entry->anchor = entry->cursor;
865}
866
867static void
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200868text_entry_get_cursor_rectangle(struct text_entry *entry, struct rectangle *rectangle)
869{
870 struct rectangle allocation;
871 PangoRectangle extents;
872 PangoRectangle cursor_pos;
873
874 widget_get_allocation(entry->widget, &allocation);
875
876 if (entry->preedit.text && entry->preedit.cursor < 0) {
877 rectangle->x = 0;
878 rectangle->y = 0;
879 rectangle->width = 0;
880 rectangle->height = 0;
881 return;
882 }
883
Jan Arne Petersen68516862013-04-18 16:47:42 +0200884
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200885 pango_layout_get_extents(entry->layout, &extents, NULL);
886 pango_layout_get_cursor_pos(entry->layout,
887 entry->cursor + entry->preedit.cursor,
888 &cursor_pos, NULL);
889
890 rectangle->x = allocation.x + (allocation.height / 2) + PANGO_PIXELS(cursor_pos.x);
891 rectangle->y = allocation.y + 10 + PANGO_PIXELS(cursor_pos.y);
892 rectangle->width = PANGO_PIXELS(cursor_pos.width);
893 rectangle->height = PANGO_PIXELS(cursor_pos.height);
894}
895
896static void
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200897text_entry_draw_cursor(struct text_entry *entry, cairo_t *cr)
898{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100899 PangoRectangle extents;
900 PangoRectangle cursor_pos;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200901
Jan Arne Petersen46535312013-01-16 21:26:38 +0100902 if (entry->preedit.text && entry->preedit.cursor < 0)
903 return;
904
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100905 pango_layout_get_extents(entry->layout, &extents, NULL);
906 pango_layout_get_cursor_pos(entry->layout,
907 entry->cursor + entry->preedit.cursor,
908 &cursor_pos, NULL);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200909
910 cairo_set_line_width(cr, 1.0);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100911 cairo_move_to(cr, PANGO_PIXELS(cursor_pos.x), PANGO_PIXELS(extents.height) + 2);
912 cairo_line_to(cr, PANGO_PIXELS(cursor_pos.x), - 2);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200913 cairo_stroke(cr);
914}
915
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200916static const int text_offset_left = 10;
917
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200918static void
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200919text_entry_redraw_handler(struct widget *widget, void *data)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200920{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200921 struct text_entry *entry = data;
922 cairo_surface_t *surface;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200923 struct rectangle allocation;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200924 cairo_t *cr;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200925
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200926 surface = window_get_surface(entry->window);
927 widget_get_allocation(entry->widget, &allocation);
928
929 cr = cairo_create(surface);
930 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
931 cairo_clip(cr);
932
933 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
934
935 cairo_push_group(cr);
936 cairo_translate(cr, allocation.x, allocation.y);
937
938 cairo_set_source_rgba(cr, 1, 1, 1, 1);
939 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
940 cairo_fill(cr);
941
942 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
943
944 if (entry->active) {
945 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
946 cairo_set_line_width (cr, 3);
947 cairo_set_source_rgba(cr, 0, 0, 1, 1.0);
948 cairo_stroke(cr);
949 }
950
951 cairo_set_source_rgba(cr, 0, 0, 0, 1);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200952
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200953 cairo_translate(cr, text_offset_left, allocation.height / 2);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200954
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100955 if (!entry->layout)
956 entry->layout = pango_cairo_create_layout(cr);
957 else
958 pango_cairo_update_layout(cr, entry->layout);
959
960 text_entry_update_layout(entry);
961
962 pango_cairo_show_layout(cr, entry->layout);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200963
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200964 text_entry_draw_cursor(entry, cr);
965
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200966 cairo_pop_group_to_source(cr);
967 cairo_paint(cr);
968
969 cairo_destroy(cr);
970 cairo_surface_destroy(surface);
971}
972
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200973static int
974text_entry_motion_handler(struct widget *widget,
975 struct input *input, uint32_t time,
976 float x, float y, void *data)
977{
978 struct text_entry *entry = data;
979 struct rectangle allocation;
980
981 widget_get_allocation(entry->widget, &allocation);
982
983 text_entry_set_cursor_position(entry,
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200984 x - allocation.x - text_offset_left,
985 y - allocation.y - text_offset_left);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200986
987 return CURSOR_IBEAM;
988}
989
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200990static void
991text_entry_button_handler(struct widget *widget,
992 struct input *input, uint32_t time,
993 uint32_t button,
994 enum wl_pointer_button_state state, void *data)
995{
996 struct text_entry *entry = data;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200997 struct rectangle allocation;
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100998 struct editor *editor;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200999 int32_t x, y;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001000 uint32_t result;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001001
1002 widget_get_allocation(entry->widget, &allocation);
1003 input_get_position(input, &x, &y);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001004
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001005 x -= allocation.x + text_offset_left;
1006 y -= allocation.y + text_offset_left;
1007
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001008 editor = window_get_user_data(entry->window);
1009
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001010 result = text_entry_try_invoke_preedit_action(entry, x, y, button, state);
1011
1012 if (result)
1013 return;
1014
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001015 if (button != BTN_LEFT) {
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001016 return;
1017 }
1018
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001019 text_entry_set_cursor_position(entry, x, y);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001020
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001021 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
1022 struct wl_seat *seat = input_get_seat(input);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001023
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001024 text_entry_activate(entry, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001025 editor->active_entry = entry;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001026
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001027 text_entry_set_anchor_position(entry, x, y);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001028
1029 widget_set_motion_handler(entry->widget, text_entry_motion_handler);
1030 } else {
1031 widget_set_motion_handler(entry->widget, NULL);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001032 }
1033}
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001034
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001035static void
1036editor_button_handler(struct widget *widget,
1037 struct input *input, uint32_t time,
1038 uint32_t button,
1039 enum wl_pointer_button_state state, void *data)
1040{
1041 struct editor *editor = data;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001042
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001043 if (button != BTN_LEFT) {
1044 return;
1045 }
Jan Arne Petersene829adc2012-08-10 16:47:22 +02001046
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001047 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
1048 struct wl_seat *seat = input_get_seat(input);
1049
Jan Arne Petersene829adc2012-08-10 16:47:22 +02001050 text_entry_deactivate(editor->entry, seat);
1051 text_entry_deactivate(editor->editor, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001052 editor->active_entry = NULL;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001053 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001054}
1055
1056static void
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001057key_handler(struct window *window,
1058 struct input *input, uint32_t time,
1059 uint32_t key, uint32_t sym, enum wl_keyboard_key_state state,
1060 void *data)
1061{
1062 struct editor *editor = data;
1063 struct text_entry *entry;
Jan Arne Petersen68516862013-04-18 16:47:42 +02001064 const char *new_char;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001065 char text[16];
1066
1067 if (!editor->active_entry)
1068 return;
1069
1070 entry = editor->active_entry;
1071
1072 if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
1073 return;
1074
1075 switch (sym) {
1076 case XKB_KEY_BackSpace:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001077 text_entry_commit_and_reset(entry);
1078
Jan Arne Petersen68516862013-04-18 16:47:42 +02001079 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
1080 if (new_char != NULL)
1081 text_entry_delete_text(entry,
1082 new_char - entry->text,
1083 (entry->text + entry->cursor) - new_char);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001084 break;
1085 case XKB_KEY_Delete:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001086 text_entry_commit_and_reset(entry);
1087
Jan Arne Petersen68516862013-04-18 16:47:42 +02001088 new_char = utf8_next_char(entry->text + entry->cursor);
1089 if (new_char != NULL)
1090 text_entry_delete_text(entry,
1091 entry->cursor,
1092 new_char - (entry->text + entry->cursor));
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001093 break;
1094 case XKB_KEY_Left:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001095 text_entry_commit_and_reset(entry);
1096
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001097 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
1098 if (new_char != NULL) {
1099 entry->cursor = new_char - entry->text;
1100 entry->anchor = entry->cursor;
1101 widget_schedule_redraw(entry->widget);
1102 }
1103 break;
1104 case XKB_KEY_Right:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001105 text_entry_commit_and_reset(entry);
1106
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001107 new_char = utf8_next_char(entry->text + entry->cursor);
1108 if (new_char != NULL) {
1109 entry->cursor = new_char - entry->text;
1110 entry->anchor = entry->cursor;
1111 widget_schedule_redraw(entry->widget);
1112 }
1113 break;
1114 default:
1115 if (xkb_keysym_to_utf8(sym, text, sizeof(text)) <= 0)
1116 break;
1117
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001118 text_entry_commit_and_reset(entry);
1119
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +01001120 text_entry_insert_at_cursor(entry, text, 0, 0);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001121 break;
1122 }
1123
1124 widget_schedule_redraw(entry->widget);
1125}
1126
1127static void
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001128global_handler(struct display *display, uint32_t name,
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001129 const char *interface, uint32_t version, void *data)
1130{
1131 struct editor *editor = data;
1132
Jan Arne Petersen62ece762013-04-18 16:47:36 +02001133 if (!strcmp(interface, "wl_text_input_manager")) {
Jan Arne Petersen78d00e42013-04-18 16:47:24 +02001134 editor->text_input_manager =
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001135 display_bind(display, name,
Jan Arne Petersen62ece762013-04-18 16:47:36 +02001136 &wl_text_input_manager_interface, 1);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001137 }
1138}
1139
1140int
1141main(int argc, char *argv[])
1142{
1143 struct editor editor;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001144 int i;
1145 uint32_t click_to_show = 0;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001146 const char *preferred_language = NULL;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001147
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001148 for (i = 1; i < argc; i++) {
Jan Arne Petersen61381972013-01-31 15:52:21 +01001149 if (strcmp("--click-to-show", argv[i]) == 0)
1150 click_to_show = 1;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001151 else if (strcmp("--preferred-language", argv[i]) == 0) {
1152 if (i + 1 < argc) {
1153 preferred_language = argv[i + 1];
1154 i++;
1155 }
1156 }
1157 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001158
Jan Arne Petersen25f6db52012-11-05 03:26:40 +01001159 memset(&editor, 0, sizeof editor);
1160
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001161#ifdef HAVE_PANGO
1162 g_type_init();
1163#endif
1164
Kristian Høgsberg4172f662013-02-20 15:27:49 -05001165 editor.display = display_create(&argc, argv);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001166 if (editor.display == NULL) {
1167 fprintf(stderr, "failed to create display: %m\n");
1168 return -1;
1169 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001170
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001171 display_set_user_data(editor.display, &editor);
1172 display_set_global_handler(editor.display, global_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001173
1174 editor.window = window_create(editor.display);
1175 editor.widget = frame_create(editor.window, &editor);
1176
1177 editor.entry = text_entry_create(&editor, "Entry");
Jan Arne Petersen61381972013-01-31 15:52:21 +01001178 editor.entry->click_to_show = click_to_show;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001179 if (preferred_language)
1180 editor.entry->preferred_language = strdup(preferred_language);
Jan Arne Petersen0558a932013-01-16 21:26:45 +01001181 editor.editor = text_entry_create(&editor, "Numeric");
Jan Arne Petersen62ece762013-04-18 16:47:36 +02001182 editor.editor->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_NUMBER;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001183 editor.editor->click_to_show = click_to_show;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001184
1185 window_set_title(editor.window, "Text Editor");
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001186 window_set_key_handler(editor.window, key_handler);
1187 window_set_user_data(editor.window, &editor);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001188
1189 widget_set_redraw_handler(editor.widget, redraw_handler);
1190 widget_set_resize_handler(editor.widget, resize_handler);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001191 widget_set_button_handler(editor.widget, editor_button_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001192
1193 window_schedule_resize(editor.window, 500, 400);
1194
1195 display_run(editor.display);
1196
1197 text_entry_destroy(editor.entry);
1198 text_entry_destroy(editor.editor);
1199
1200 return 0;
1201}