blob: 27e490049a56f3379ec0ba0e9ac2107ac48730d8 [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 Petersen78d00e42013-04-18 16:47:24 +020062 struct 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 Petersen78d00e42013-04-18 16:47:24 +020075 struct 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 *
85utf8_start_char(const char *text, const char *p)
86{
87 for (; p >= text; --p) {
88 if ((*p & 0xc0) != 0x80)
89 return p;
90 }
91 return NULL;
92}
93
94static const char *
95utf8_prev_char(const char *text, const char *p)
96{
97 if (p > text)
98 return utf8_start_char(text, --p);
99 return NULL;
100}
101
102static const char *
103utf8_end_char(const char *p)
104{
105 while ((*p & 0xc0) == 0x80)
106 p++;
107 return p;
108}
109
110static const char *
111utf8_next_char(const char *p)
112{
113 if (*p != 0)
114 return utf8_end_char(++p);
115 return NULL;
116}
117
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200118static uint32_t
119utf8_characters(const char *p)
120{
121 uint32_t offset;
122
123 for (offset = 0; *p != 0; offset++)
124 p = utf8_next_char(p);
125
126 return offset;
127}
128
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200129static void text_entry_redraw_handler(struct widget *widget, void *data);
130static void text_entry_button_handler(struct widget *widget,
131 struct input *input, uint32_t time,
132 uint32_t button,
133 enum wl_pointer_button_state state, void *data);
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100134static void text_entry_insert_at_cursor(struct text_entry *entry, const char *text,
135 int32_t cursor, int32_t anchor);
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200136static void text_entry_set_preedit(struct text_entry *entry,
137 const char *preedit_text,
138 int preedit_cursor);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200139static void text_entry_delete_text(struct text_entry *entry,
140 uint32_t index, uint32_t length);
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200141static void text_entry_delete_selected_text(struct text_entry *entry);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100142static void text_entry_reset_preedit(struct text_entry *entry);
143static void text_entry_commit_and_reset(struct text_entry *entry);
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200144static void text_entry_get_cursor_rectangle(struct text_entry *entry, struct rectangle *rectangle);
145static void text_entry_update(struct text_entry *entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200146
147static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200148text_input_commit_string(void *data,
149 struct text_input *text_input,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100150 uint32_t serial,
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100151 const char *text)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200152{
153 struct text_entry *entry = data;
154
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200155 if ((entry->serial - serial) > (entry->serial - entry->reset_serial)) {
156 fprintf(stderr, "Ignore commit. Serial: %u, Current: %u, Reset: %u\n",
157 serial, entry->serial, entry->reset_serial);
158 return;
159 }
160
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100161 text_entry_reset_preedit(entry);
162
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200163 text_entry_delete_selected_text(entry);
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200164
165 if (entry->pending_commit.delete_length) {
166 text_entry_delete_text(entry,
167 entry->pending_commit.delete_index,
168 entry->pending_commit.delete_length);
169 }
170
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100171 text_entry_insert_at_cursor(entry, text,
172 entry->pending_commit.cursor,
173 entry->pending_commit.anchor);
174
175 memset(&entry->pending_commit, 0, sizeof entry->pending_commit);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200176
177 widget_schedule_redraw(entry->widget);
178}
179
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200180static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200181text_input_preedit_string(void *data,
182 struct text_input *text_input,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100183 uint32_t serial,
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200184 const char *text,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100185 const char *commit)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200186{
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200187 struct text_entry *entry = data;
188
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200189 text_entry_delete_selected_text(entry);
Jan Arne Petersen46535312013-01-16 21:26:38 +0100190 text_entry_set_preedit(entry, text, entry->preedit_info.cursor);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100191 entry->preedit.commit = strdup(commit);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100192 entry->preedit.attr_list = entry->preedit_info.attr_list;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100193
194 entry->preedit_info.cursor = 0;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100195 entry->preedit_info.attr_list = NULL;
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200196
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200197 text_entry_update(entry);
198
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200199 widget_schedule_redraw(entry->widget);
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200200}
201
202static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200203text_input_delete_surrounding_text(void *data,
204 struct text_input *text_input,
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200205 int32_t index,
206 uint32_t length)
207{
208 struct text_entry *entry = data;
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200209 uint32_t text_length;
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200210
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200211 entry->pending_commit.delete_index = entry->cursor + index;
212 entry->pending_commit.delete_length = length;
213
214 text_length = utf8_characters(entry->text);
215
216 if (entry->pending_commit.delete_index > text_length) {
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200217 fprintf(stderr, "Invalid cursor index %d\n", index);
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200218 entry->pending_commit.delete_length = 0;
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200219 return;
220 }
221
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200222 if (entry->pending_commit.delete_index + length > text_length) {
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200223 fprintf(stderr, "Invalid length %d\n", length);
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200224 entry->pending_commit.delete_length = 0;
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200225 return;
226 }
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200227}
228
229static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200230text_input_cursor_position(void *data,
231 struct text_input *text_input,
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100232 int32_t index,
233 int32_t anchor)
234{
235 struct text_entry *entry = data;
236
237 entry->pending_commit.cursor = index;
238 entry->pending_commit.anchor = anchor;
239}
240
241static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200242text_input_preedit_styling(void *data,
243 struct text_input *text_input,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100244 uint32_t index,
245 uint32_t length,
246 uint32_t style)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200247{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100248 struct text_entry *entry = data;
249 PangoAttribute *attr1 = NULL;
250 PangoAttribute *attr2 = NULL;
251
252 if (!entry->preedit_info.attr_list)
253 entry->preedit_info.attr_list = pango_attr_list_new();
254
255 switch (style) {
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200256 case TEXT_INPUT_PREEDIT_STYLE_DEFAULT:
257 case TEXT_INPUT_PREEDIT_STYLE_UNDERLINE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100258 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
259 break;
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200260 case TEXT_INPUT_PREEDIT_STYLE_INCORRECT:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100261 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_ERROR);
262 attr2 = pango_attr_underline_color_new(65535, 0, 0);
263 break;
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200264 case TEXT_INPUT_PREEDIT_STYLE_SELECTION:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100265 attr1 = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
266 attr2 = pango_attr_foreground_new(65535, 65535, 65535);
267 break;
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200268 case TEXT_INPUT_PREEDIT_STYLE_HIGHLIGHT:
269 case TEXT_INPUT_PREEDIT_STYLE_ACTIVE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100270 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
271 attr2 = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
272 break;
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200273 case TEXT_INPUT_PREEDIT_STYLE_INACTIVE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100274 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
275 attr2 = pango_attr_foreground_new(0.3 * 65535, 0.3 * 65535, 0.3 * 65535);
276 break;
277 }
278
279 if (attr1) {
280 attr1->start_index = entry->cursor + index;
281 attr1->end_index = entry->cursor + index + length;
282 pango_attr_list_insert(entry->preedit_info.attr_list, attr1);
283 }
284
285 if (attr2) {
286 attr2->start_index = entry->cursor + index;
287 attr2->end_index = entry->cursor + index + length;
288 pango_attr_list_insert(entry->preedit_info.attr_list, attr2);
289 }
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200290}
291
292static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200293text_input_preedit_cursor(void *data,
294 struct text_input *text_input,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100295 int32_t index)
296{
297 struct text_entry *entry = data;
298
299 entry->preedit_info.cursor = index;
300}
301
302static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200303text_input_modifiers_map(void *data,
304 struct text_input *text_input,
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100305 struct wl_array *map)
306{
Jan Arne Petersencd997062012-11-18 19:06:44 +0100307 struct text_entry *entry = data;
308
309 entry->keysym.shift_mask = keysym_modifiers_get_mask(map, "Shift");
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100310}
311
312static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200313text_input_keysym(void *data,
314 struct text_input *text_input,
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100315 uint32_t serial,
316 uint32_t time,
317 uint32_t key,
318 uint32_t state,
319 uint32_t modifiers)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200320{
Jan Arne Petersen8aba11d2012-09-17 15:28:07 +0200321 struct text_entry *entry = data;
Jan Arne Petersencd997062012-11-18 19:06:44 +0100322 const char *state_label = "release";
323 const char *key_label = "Unknown";
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100324 const char *new_char;
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200325
326 if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
327 state_label = "pressed";
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200328 }
329
Jan Arne Petersencd997062012-11-18 19:06:44 +0100330 if (key == XKB_KEY_Left ||
331 key == XKB_KEY_Right) {
332 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
333 return;
334
335 if (key == XKB_KEY_Left)
336 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
337 else
338 new_char = utf8_next_char(entry->text + entry->cursor);
339
340 if (new_char != NULL) {
341 entry->cursor = new_char - entry->text;
342 if (!(modifiers & entry->keysym.shift_mask))
343 entry->anchor = entry->cursor;
344 widget_schedule_redraw(entry->widget);
345 }
346
347 return;
348 }
349
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100350 if (key == XKB_KEY_BackSpace) {
351 const char *start, *end;
352
Jan Arne Petersendfd34462013-04-18 16:47:26 +0200353 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
354 return;
355
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100356 text_entry_commit_and_reset(entry);
357
358 start = utf8_prev_char(entry->text, entry->text + entry->cursor);
359
360 if (start == NULL)
361 return;
362
363 end = utf8_end_char(entry->text + entry->cursor);
364 text_entry_delete_text(entry,
365 start - entry->text,
366 end - start);
367
368 return;
369 }
370
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200371 switch (key) {
372 case XKB_KEY_Tab:
373 key_label = "Tab";
374 break;
375 case XKB_KEY_KP_Enter:
Jan Arne Petersencd997062012-11-18 19:06:44 +0100376 case XKB_KEY_Return:
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200377 key_label = "Enter";
378 break;
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200379 }
380
381 fprintf(stderr, "%s key was %s.\n", key_label, state_label);
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200382}
383
384static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200385text_input_enter(void *data,
386 struct text_input *text_input,
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200387 struct wl_surface *surface)
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200388{
389 struct text_entry *entry = data;
390
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200391 if (surface != window_get_wl_surface(entry->window))
392 return;
393
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200394 entry->active = 1;
395
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200396 text_entry_update(entry);
397 entry->reset_serial = entry->serial;
398
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200399 widget_schedule_redraw(entry->widget);
400}
401
402static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200403text_input_leave(void *data,
404 struct text_input *text_input)
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200405{
406 struct text_entry *entry = data;
407
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100408 text_entry_commit_and_reset(entry);
409
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200410 entry->active = 0;
411
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200412 text_input_hide_input_panel(text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100413
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200414 widget_schedule_redraw(entry->widget);
415}
416
Jan Arne Petersen61381972013-01-31 15:52:21 +0100417static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200418text_input_input_panel_state(void *data,
419 struct text_input *text_input,
Jan Arne Petersen61381972013-01-31 15:52:21 +0100420 uint32_t state)
421{
422}
423
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200424static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200425text_input_language(void *data,
426 struct text_input *text_input,
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200427 uint32_t serial,
428 const char *language)
429{
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200430 fprintf(stderr, "input language is %s \n", language);
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200431}
432
433static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200434text_input_text_direction(void *data,
435 struct text_input *text_input,
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200436 uint32_t serial,
437 uint32_t direction)
438{
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200439 struct text_entry *entry = data;
440 PangoContext *context = pango_layout_get_context(entry->layout);
441 PangoDirection pango_direction;
442
443
444 switch (direction) {
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200445 case TEXT_INPUT_TEXT_DIRECTION_LTR:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200446 pango_direction = PANGO_DIRECTION_LTR;
447 break;
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200448 case TEXT_INPUT_TEXT_DIRECTION_RTL:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200449 pango_direction = PANGO_DIRECTION_RTL;
450 break;
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200451 case TEXT_INPUT_TEXT_DIRECTION_AUTO:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200452 default:
453 pango_direction = PANGO_DIRECTION_NEUTRAL;
454 }
455
456 pango_context_set_base_dir(context, pango_direction);
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200457}
458
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200459static const struct text_input_listener text_input_listener = {
460 text_input_enter,
461 text_input_leave,
462 text_input_modifiers_map,
463 text_input_input_panel_state,
464 text_input_preedit_string,
465 text_input_preedit_styling,
466 text_input_preedit_cursor,
467 text_input_commit_string,
468 text_input_cursor_position,
469 text_input_delete_surrounding_text,
470 text_input_keysym,
471 text_input_language,
472 text_input_text_direction
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200473};
474
475static struct text_entry*
476text_entry_create(struct editor *editor, const char *text)
477{
478 struct text_entry *entry;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200479
Jan Arne Petersencd997062012-11-18 19:06:44 +0100480 entry = calloc(1, sizeof *entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200481
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200482 entry->widget = widget_add_widget(editor->widget, entry);
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200483 entry->window = editor->window;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200484 entry->text = strdup(text);
485 entry->active = 0;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200486 entry->cursor = strlen(text);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200487 entry->anchor = entry->cursor;
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200488 entry->text_input = text_input_manager_create_text_input(editor->text_input_manager);
489 text_input_add_listener(entry->text_input, &text_input_listener, entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200490
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200491 widget_set_redraw_handler(entry->widget, text_entry_redraw_handler);
492 widget_set_button_handler(entry->widget, text_entry_button_handler);
493
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200494 return entry;
495}
496
497static void
498text_entry_destroy(struct text_entry *entry)
499{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200500 widget_destroy(entry->widget);
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200501 text_input_destroy(entry->text_input);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100502 g_clear_object(&entry->layout);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200503 free(entry->text);
504 free(entry);
505}
506
507static void
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200508redraw_handler(struct widget *widget, void *data)
509{
510 struct editor *editor = data;
511 cairo_surface_t *surface;
512 struct rectangle allocation;
513 cairo_t *cr;
514
515 surface = window_get_surface(editor->window);
516 widget_get_allocation(editor->widget, &allocation);
517
518 cr = cairo_create(surface);
519 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
520 cairo_clip(cr);
521
522 cairo_translate(cr, allocation.x, allocation.y);
523
524 /* Draw background */
525 cairo_push_group(cr);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200526 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200527 cairo_set_source_rgba(cr, 1, 1, 1, 1);
528 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
529 cairo_fill(cr);
530
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200531 cairo_pop_group_to_source(cr);
532 cairo_paint(cr);
533
534 cairo_destroy(cr);
535 cairo_surface_destroy(surface);
536}
537
538static void
539text_entry_allocate(struct text_entry *entry, int32_t x, int32_t y,
540 int32_t width, int32_t height)
541{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200542 widget_set_allocation(entry->widget, x, y, width, height);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200543}
544
545static void
546resize_handler(struct widget *widget,
547 int32_t width, int32_t height, void *data)
548{
549 struct editor *editor = data;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200550 struct rectangle allocation;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200551
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200552 widget_get_allocation(editor->widget, &allocation);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200553
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200554 text_entry_allocate(editor->entry,
555 allocation.x + 20, allocation.y + 20,
556 width - 40, height / 2 - 40);
557 text_entry_allocate(editor->editor,
558 allocation.x + 20, allocation.y + height / 2 + 20,
559 width - 40, height / 2 - 40);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200560}
561
562static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200563text_entry_activate(struct text_entry *entry,
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200564 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200565{
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200566 struct wl_surface *surface = window_get_wl_surface(entry->window);
567
Jan Arne Petersen61381972013-01-31 15:52:21 +0100568 if (entry->click_to_show && entry->active) {
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200569 text_input_show_input_panel(entry->text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100570
571 return;
572 }
573
574 if (!entry->click_to_show)
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200575 text_input_show_input_panel(entry->text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100576
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200577 text_input_activate(entry->text_input,
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200578 seat,
579 surface);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200580}
581
582static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200583text_entry_deactivate(struct text_entry *entry,
584 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200585{
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200586 text_input_deactivate(entry->text_input,
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200587 seat);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200588}
589
590static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200591text_entry_update_layout(struct text_entry *entry)
592{
593 char *text;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100594 PangoAttrList *attr_list;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200595
Philipp Brüschweiler237358b2012-10-02 11:06:51 +0200596 assert(((unsigned int)entry->cursor) <= strlen(entry->text) +
Jan Arne Petersen46535312013-01-16 21:26:38 +0100597 (entry->preedit.text ? strlen(entry->preedit.text) : 0));
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200598
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100599 if (entry->preedit.text) {
600 text = malloc(strlen(entry->text) + strlen(entry->preedit.text) + 1);
601 strncpy(text, entry->text, entry->cursor);
602 strcpy(text + entry->cursor, entry->preedit.text);
603 strcpy(text + entry->cursor + strlen(entry->preedit.text),
604 entry->text + entry->cursor);
605 } else {
606 text = strdup(entry->text);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200607 }
608
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100609 if (entry->cursor != entry->anchor) {
610 int start_index = MIN(entry->cursor, entry->anchor);
611 int end_index = MAX(entry->cursor, entry->anchor);
612 PangoAttribute *attr;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200613
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100614 attr_list = pango_attr_list_copy(entry->preedit.attr_list);
615
616 if (!attr_list)
617 attr_list = pango_attr_list_new();
618
619 attr = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
620 attr->start_index = start_index;
621 attr->end_index = end_index;
622 pango_attr_list_insert(attr_list, attr);
623
624 attr = pango_attr_foreground_new(65535, 65535, 65535);
625 attr->start_index = start_index;
626 attr->end_index = end_index;
627 pango_attr_list_insert(attr_list, attr);
628 } else {
629 attr_list = pango_attr_list_ref(entry->preedit.attr_list);
630 }
631
632 if (entry->preedit.text && !entry->preedit.attr_list) {
633 PangoAttribute *attr;
634
635 if (!attr_list)
636 attr_list = pango_attr_list_new();
637
638 attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
639 attr->start_index = entry->cursor;
640 attr->end_index = entry->cursor + strlen(entry->preedit.text);
641 pango_attr_list_insert(attr_list, attr);
642 }
643
644 if (entry->layout) {
645 pango_layout_set_text(entry->layout, text, -1);
646 pango_layout_set_attributes(entry->layout, attr_list);
647 }
648
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200649 free(text);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100650 pango_attr_list_unref(attr_list);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200651}
652
653static void
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100654text_entry_update(struct text_entry *entry)
655{
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200656 struct rectangle cursor_rectangle;
657
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200658 text_input_set_content_type(entry->text_input,
659 TEXT_INPUT_CONTENT_HINT_NONE,
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100660 entry->content_purpose);
661
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200662 text_input_set_surrounding_text(entry->text_input,
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100663 entry->text,
664 entry->cursor,
665 entry->anchor);
Jan Arne Petersen0eabcaa2013-01-31 15:52:20 +0100666
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200667 if (entry->preferred_language)
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200668 text_input_set_preferred_language(entry->text_input,
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200669 entry->preferred_language);
670
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200671 text_entry_get_cursor_rectangle(entry, &cursor_rectangle);
672 text_input_set_cursor_rectangle(entry->text_input, cursor_rectangle.x, cursor_rectangle.y,
673 cursor_rectangle.width, cursor_rectangle.height);
674
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200675 text_input_commit_state(entry->text_input, ++entry->serial);
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100676}
677
678static void
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100679text_entry_insert_at_cursor(struct text_entry *entry, const char *text,
680 int32_t cursor, int32_t anchor)
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200681{
682 char *new_text = malloc(strlen(entry->text) + strlen(text) + 1);
683
684 strncpy(new_text, entry->text, entry->cursor);
685 strcpy(new_text + entry->cursor, text);
686 strcpy(new_text + entry->cursor + strlen(text),
687 entry->text + entry->cursor);
688
689 free(entry->text);
690 entry->text = new_text;
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100691 if (anchor >= 0)
692 entry->anchor = entry->cursor + strlen(text) + anchor;
693 else
694 entry->anchor = entry->cursor + 1 + anchor;
695 if (cursor >= 0)
696 entry->cursor += strlen(text) + cursor;
697 else
698 entry->cursor += 1 + cursor;
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200699
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200700 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100701
702 widget_schedule_redraw(entry->widget);
703
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100704 text_entry_update(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200705}
706
707static void
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100708text_entry_reset_preedit(struct text_entry *entry)
709{
710 entry->preedit.cursor = 0;
711
712 free(entry->preedit.text);
713 entry->preedit.text = NULL;
714
715 free(entry->preedit.commit);
716 entry->preedit.commit = NULL;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100717
718 pango_attr_list_unref(entry->preedit.attr_list);
719 entry->preedit.attr_list = NULL;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100720}
721
722static void
723text_entry_commit_and_reset(struct text_entry *entry)
724{
725 char *commit = NULL;
726
727 if (entry->preedit.commit)
728 commit = strdup(entry->preedit.commit);
729
730 text_entry_reset_preedit(entry);
731 if (commit) {
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100732 text_entry_insert_at_cursor(entry, commit, 0, 0);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100733 free(commit);
734 }
Jan Arne Petersen08015b62013-04-18 16:47:18 +0200735
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200736 text_input_reset(entry->text_input);
737 text_entry_update(entry);
738 entry->reset_serial = entry->serial;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100739}
740
741static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200742text_entry_set_preedit(struct text_entry *entry,
743 const char *preedit_text,
744 int preedit_cursor)
745{
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100746 text_entry_reset_preedit(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200747
748 if (!preedit_text)
749 return;
750
Jan Arne Petersen46535312013-01-16 21:26:38 +0100751 entry->preedit.text = strdup(preedit_text);
752 entry->preedit.cursor = preedit_cursor;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200753
754 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100755
756 widget_schedule_redraw(entry->widget);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200757}
758
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100759static uint32_t
760text_entry_try_invoke_preedit_action(struct text_entry *entry,
761 int32_t x, int32_t y,
762 uint32_t button,
763 enum wl_pointer_button_state state)
764{
765 int index, trailing;
766 uint32_t cursor;
767
768 if (!entry->preedit.text)
769 return 0;
770
771 pango_layout_xy_to_index(entry->layout,
772 x * PANGO_SCALE, y * PANGO_SCALE,
773 &index, &trailing);
774 cursor = index + trailing;
775
776 if (cursor < entry->cursor ||
777 cursor > entry->cursor + strlen(entry->preedit.text)) {
778 return 0;
779 }
780
781 if (state == WL_POINTER_BUTTON_STATE_RELEASED)
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200782 text_input_invoke_action(entry->text_input,
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100783 button,
784 cursor - entry->cursor);
785
786 return 1;
787}
788
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200789static void
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200790text_entry_set_cursor_position(struct text_entry *entry,
791 int32_t x, int32_t y)
792{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100793 int index, trailing;
794
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100795 text_entry_commit_and_reset(entry);
796
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100797 pango_layout_xy_to_index(entry->layout,
798 x * PANGO_SCALE, y * PANGO_SCALE,
799 &index, &trailing);
800 entry->cursor = index + trailing;
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;
814
815 pango_layout_xy_to_index(entry->layout,
816 x * PANGO_SCALE, y * PANGO_SCALE,
817 &index, &trailing);
818 entry->anchor = index + trailing;
819
820 text_entry_update_layout(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200821
822 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100823
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100824 text_entry_update(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200825}
826
827static void
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200828text_entry_delete_text(struct text_entry *entry,
829 uint32_t index, uint32_t length)
830{
831 if (entry->cursor > index)
832 entry->cursor -= length;
833
Jan Arne Petersen80ad1a92012-09-17 15:28:10 +0200834 entry->anchor = entry->cursor;
835
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200836 entry->text[index] = '\0';
837 strcat(entry->text, entry->text + index + length);
838
839 text_entry_update_layout(entry);
840
841 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100842
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100843 text_entry_update(entry);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200844}
845
846static void
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200847text_entry_delete_selected_text(struct text_entry *entry)
848{
849 uint32_t start_index = entry->anchor < entry->cursor ? entry->anchor : entry->cursor;
850 uint32_t end_index = entry->anchor < entry->cursor ? entry->cursor : entry->anchor;
851
852 if (entry->anchor == entry->cursor)
853 return;
854
855 text_entry_delete_text(entry, start_index, end_index - start_index);
856
857 entry->anchor = entry->cursor;
858}
859
860static void
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200861text_entry_get_cursor_rectangle(struct text_entry *entry, struct rectangle *rectangle)
862{
863 struct rectangle allocation;
864 PangoRectangle extents;
865 PangoRectangle cursor_pos;
866
867 widget_get_allocation(entry->widget, &allocation);
868
869 if (entry->preedit.text && entry->preedit.cursor < 0) {
870 rectangle->x = 0;
871 rectangle->y = 0;
872 rectangle->width = 0;
873 rectangle->height = 0;
874 return;
875 }
876
877 pango_layout_get_extents(entry->layout, &extents, NULL);
878 pango_layout_get_cursor_pos(entry->layout,
879 entry->cursor + entry->preedit.cursor,
880 &cursor_pos, NULL);
881
882 rectangle->x = allocation.x + (allocation.height / 2) + PANGO_PIXELS(cursor_pos.x);
883 rectangle->y = allocation.y + 10 + PANGO_PIXELS(cursor_pos.y);
884 rectangle->width = PANGO_PIXELS(cursor_pos.width);
885 rectangle->height = PANGO_PIXELS(cursor_pos.height);
886}
887
888static void
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200889text_entry_draw_cursor(struct text_entry *entry, cairo_t *cr)
890{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100891 PangoRectangle extents;
892 PangoRectangle cursor_pos;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200893
Jan Arne Petersen46535312013-01-16 21:26:38 +0100894 if (entry->preedit.text && entry->preedit.cursor < 0)
895 return;
896
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100897 pango_layout_get_extents(entry->layout, &extents, NULL);
898 pango_layout_get_cursor_pos(entry->layout,
899 entry->cursor + entry->preedit.cursor,
900 &cursor_pos, NULL);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200901
902 cairo_set_line_width(cr, 1.0);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100903 cairo_move_to(cr, PANGO_PIXELS(cursor_pos.x), PANGO_PIXELS(extents.height) + 2);
904 cairo_line_to(cr, PANGO_PIXELS(cursor_pos.x), - 2);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200905 cairo_stroke(cr);
906}
907
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200908static const int text_offset_left = 10;
909
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200910static void
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200911text_entry_redraw_handler(struct widget *widget, void *data)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200912{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200913 struct text_entry *entry = data;
914 cairo_surface_t *surface;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200915 struct rectangle allocation;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200916 cairo_t *cr;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200917
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200918 surface = window_get_surface(entry->window);
919 widget_get_allocation(entry->widget, &allocation);
920
921 cr = cairo_create(surface);
922 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
923 cairo_clip(cr);
924
925 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
926
927 cairo_push_group(cr);
928 cairo_translate(cr, allocation.x, allocation.y);
929
930 cairo_set_source_rgba(cr, 1, 1, 1, 1);
931 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
932 cairo_fill(cr);
933
934 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
935
936 if (entry->active) {
937 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
938 cairo_set_line_width (cr, 3);
939 cairo_set_source_rgba(cr, 0, 0, 1, 1.0);
940 cairo_stroke(cr);
941 }
942
943 cairo_set_source_rgba(cr, 0, 0, 0, 1);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200944
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200945 cairo_translate(cr, text_offset_left, allocation.height / 2);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200946
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100947 if (!entry->layout)
948 entry->layout = pango_cairo_create_layout(cr);
949 else
950 pango_cairo_update_layout(cr, entry->layout);
951
952 text_entry_update_layout(entry);
953
954 pango_cairo_show_layout(cr, entry->layout);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200955
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200956 text_entry_draw_cursor(entry, cr);
957
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200958 cairo_pop_group_to_source(cr);
959 cairo_paint(cr);
960
961 cairo_destroy(cr);
962 cairo_surface_destroy(surface);
963}
964
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200965static int
966text_entry_motion_handler(struct widget *widget,
967 struct input *input, uint32_t time,
968 float x, float y, void *data)
969{
970 struct text_entry *entry = data;
971 struct rectangle allocation;
972
973 widget_get_allocation(entry->widget, &allocation);
974
975 text_entry_set_cursor_position(entry,
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200976 x - allocation.x - text_offset_left,
977 y - allocation.y - text_offset_left);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200978
979 return CURSOR_IBEAM;
980}
981
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200982static void
983text_entry_button_handler(struct widget *widget,
984 struct input *input, uint32_t time,
985 uint32_t button,
986 enum wl_pointer_button_state state, void *data)
987{
988 struct text_entry *entry = data;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200989 struct rectangle allocation;
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100990 struct editor *editor;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200991 int32_t x, y;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100992 uint32_t result;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200993
994 widget_get_allocation(entry->widget, &allocation);
995 input_get_position(input, &x, &y);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200996
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100997 x -= allocation.x + text_offset_left;
998 y -= allocation.y + text_offset_left;
999
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001000 editor = window_get_user_data(entry->window);
1001
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001002 result = text_entry_try_invoke_preedit_action(entry, x, y, button, state);
1003
1004 if (result)
1005 return;
1006
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001007 if (button != BTN_LEFT) {
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001008 return;
1009 }
1010
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001011 text_entry_set_cursor_position(entry, x, y);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001012
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001013 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
1014 struct wl_seat *seat = input_get_seat(input);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001015
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001016 text_entry_activate(entry, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001017 editor->active_entry = entry;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001018
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001019 text_entry_set_anchor_position(entry, x, y);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001020
1021 widget_set_motion_handler(entry->widget, text_entry_motion_handler);
1022 } else {
1023 widget_set_motion_handler(entry->widget, NULL);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001024 }
1025}
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001026
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001027static void
1028editor_button_handler(struct widget *widget,
1029 struct input *input, uint32_t time,
1030 uint32_t button,
1031 enum wl_pointer_button_state state, void *data)
1032{
1033 struct editor *editor = data;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001034
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001035 if (button != BTN_LEFT) {
1036 return;
1037 }
Jan Arne Petersene829adc2012-08-10 16:47:22 +02001038
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001039 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
1040 struct wl_seat *seat = input_get_seat(input);
1041
Jan Arne Petersene829adc2012-08-10 16:47:22 +02001042 text_entry_deactivate(editor->entry, seat);
1043 text_entry_deactivate(editor->editor, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001044 editor->active_entry = NULL;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001045 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001046}
1047
1048static void
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001049key_handler(struct window *window,
1050 struct input *input, uint32_t time,
1051 uint32_t key, uint32_t sym, enum wl_keyboard_key_state state,
1052 void *data)
1053{
1054 struct editor *editor = data;
1055 struct text_entry *entry;
1056 const char *start, *end, *new_char;
1057 char text[16];
1058
1059 if (!editor->active_entry)
1060 return;
1061
1062 entry = editor->active_entry;
1063
1064 if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
1065 return;
1066
1067 switch (sym) {
1068 case XKB_KEY_BackSpace:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001069 text_entry_commit_and_reset(entry);
1070
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001071 start = utf8_prev_char(entry->text, entry->text + entry->cursor);
1072
1073 if (start == NULL)
1074 break;
1075
1076 end = utf8_end_char(entry->text + entry->cursor);
1077 text_entry_delete_text(entry,
1078 start - entry->text,
1079 end - start);
1080 break;
1081 case XKB_KEY_Delete:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001082 text_entry_commit_and_reset(entry);
1083
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001084 start = utf8_start_char(entry->text, entry->text + entry->cursor);
1085
1086 if (start == NULL)
1087 break;
1088
1089 end = utf8_next_char(start);
1090
1091 if (end == NULL)
1092 break;
1093
1094 text_entry_delete_text(entry,
1095 start - entry->text,
1096 end - start);
1097 break;
1098 case XKB_KEY_Left:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001099 text_entry_commit_and_reset(entry);
1100
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001101 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
1102 if (new_char != NULL) {
1103 entry->cursor = new_char - entry->text;
1104 entry->anchor = entry->cursor;
1105 widget_schedule_redraw(entry->widget);
1106 }
1107 break;
1108 case XKB_KEY_Right:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001109 text_entry_commit_and_reset(entry);
1110
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001111 new_char = utf8_next_char(entry->text + entry->cursor);
1112 if (new_char != NULL) {
1113 entry->cursor = new_char - entry->text;
1114 entry->anchor = entry->cursor;
1115 widget_schedule_redraw(entry->widget);
1116 }
1117 break;
1118 default:
1119 if (xkb_keysym_to_utf8(sym, text, sizeof(text)) <= 0)
1120 break;
1121
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001122 text_entry_commit_and_reset(entry);
1123
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +01001124 text_entry_insert_at_cursor(entry, text, 0, 0);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001125 break;
1126 }
1127
1128 widget_schedule_redraw(entry->widget);
1129}
1130
1131static void
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001132global_handler(struct display *display, uint32_t name,
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001133 const char *interface, uint32_t version, void *data)
1134{
1135 struct editor *editor = data;
1136
Jan Arne Petersen78d00e42013-04-18 16:47:24 +02001137 if (!strcmp(interface, "text_input_manager")) {
1138 editor->text_input_manager =
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001139 display_bind(display, name,
Jan Arne Petersen78d00e42013-04-18 16:47:24 +02001140 &text_input_manager_interface, 1);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001141 }
1142}
1143
1144int
1145main(int argc, char *argv[])
1146{
1147 struct editor editor;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001148 int i;
1149 uint32_t click_to_show = 0;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001150 const char *preferred_language = NULL;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001151
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001152 for (i = 1; i < argc; i++) {
Jan Arne Petersen61381972013-01-31 15:52:21 +01001153 if (strcmp("--click-to-show", argv[i]) == 0)
1154 click_to_show = 1;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001155 else if (strcmp("--preferred-language", argv[i]) == 0) {
1156 if (i + 1 < argc) {
1157 preferred_language = argv[i + 1];
1158 i++;
1159 }
1160 }
1161 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001162
Jan Arne Petersen25f6db52012-11-05 03:26:40 +01001163 memset(&editor, 0, sizeof editor);
1164
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001165#ifdef HAVE_PANGO
1166 g_type_init();
1167#endif
1168
Kristian Høgsberg4172f662013-02-20 15:27:49 -05001169 editor.display = display_create(&argc, argv);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001170 if (editor.display == NULL) {
1171 fprintf(stderr, "failed to create display: %m\n");
1172 return -1;
1173 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001174
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001175 display_set_user_data(editor.display, &editor);
1176 display_set_global_handler(editor.display, global_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001177
1178 editor.window = window_create(editor.display);
1179 editor.widget = frame_create(editor.window, &editor);
1180
1181 editor.entry = text_entry_create(&editor, "Entry");
Jan Arne Petersen61381972013-01-31 15:52:21 +01001182 editor.entry->click_to_show = click_to_show;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001183 if (preferred_language)
1184 editor.entry->preferred_language = strdup(preferred_language);
Jan Arne Petersen0558a932013-01-16 21:26:45 +01001185 editor.editor = text_entry_create(&editor, "Numeric");
Jan Arne Petersen78d00e42013-04-18 16:47:24 +02001186 editor.editor->content_purpose = TEXT_INPUT_CONTENT_PURPOSE_NUMBER;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001187 editor.editor->click_to_show = click_to_show;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001188
1189 window_set_title(editor.window, "Text Editor");
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001190 window_set_key_handler(editor.window, key_handler);
1191 window_set_user_data(editor.window, &editor);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001192
1193 widget_set_redraw_handler(editor.widget, redraw_handler);
1194 widget_set_resize_handler(editor.widget, resize_handler);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001195 widget_set_button_handler(editor.widget, editor_button_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001196
1197 window_schedule_resize(editor.window, 500, 400);
1198
1199 display_run(editor.display);
1200
1201 text_entry_destroy(editor.entry);
1202 text_entry_destroy(editor.editor);
1203
1204 return 0;
1205}