blob: e61eda0467b443e493564f64effe8fe7eaefc08a [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;
59 } pending_commit;
Jan Arne Petersen78d00e42013-04-18 16:47:24 +020060 struct text_input *text_input;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010061 PangoLayout *layout;
Jan Arne Petersencd997062012-11-18 19:06:44 +010062 struct {
63 xkb_mod_mask_t shift_mask;
64 } keysym;
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +010065 uint32_t serial;
Jan Arne Petersen0558a932013-01-16 21:26:45 +010066 uint32_t content_purpose;
Jan Arne Petersen61381972013-01-31 15:52:21 +010067 uint32_t click_to_show;
Jan Arne Petersen9d419132013-04-18 16:47:16 +020068 char *preferred_language;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020069};
70
71struct editor {
Jan Arne Petersen78d00e42013-04-18 16:47:24 +020072 struct text_input_manager *text_input_manager;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020073 struct display *display;
74 struct window *window;
75 struct widget *widget;
76 struct text_entry *entry;
77 struct text_entry *editor;
Rob Bradford9d1d32b2012-11-18 19:06:49 +010078 struct text_entry *active_entry;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020079};
80
Jan Arne Petersen6345faa2012-11-05 03:26:39 +010081static const char *
82utf8_start_char(const char *text, const char *p)
83{
84 for (; p >= text; --p) {
85 if ((*p & 0xc0) != 0x80)
86 return p;
87 }
88 return NULL;
89}
90
91static const char *
92utf8_prev_char(const char *text, const char *p)
93{
94 if (p > text)
95 return utf8_start_char(text, --p);
96 return NULL;
97}
98
99static const char *
100utf8_end_char(const char *p)
101{
102 while ((*p & 0xc0) == 0x80)
103 p++;
104 return p;
105}
106
107static const char *
108utf8_next_char(const char *p)
109{
110 if (*p != 0)
111 return utf8_end_char(++p);
112 return NULL;
113}
114
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200115static void text_entry_redraw_handler(struct widget *widget, void *data);
116static void text_entry_button_handler(struct widget *widget,
117 struct input *input, uint32_t time,
118 uint32_t button,
119 enum wl_pointer_button_state state, void *data);
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100120static void text_entry_insert_at_cursor(struct text_entry *entry, const char *text,
121 int32_t cursor, int32_t anchor);
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200122static void text_entry_set_preedit(struct text_entry *entry,
123 const char *preedit_text,
124 int preedit_cursor);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200125static void text_entry_delete_text(struct text_entry *entry,
126 uint32_t index, uint32_t length);
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200127static void text_entry_delete_selected_text(struct text_entry *entry);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100128static void text_entry_reset_preedit(struct text_entry *entry);
129static void text_entry_commit_and_reset(struct text_entry *entry);
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200130static void text_entry_get_cursor_rectangle(struct text_entry *entry, struct rectangle *rectangle);
131static void text_entry_update(struct text_entry *entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200132
133static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200134text_input_commit_string(void *data,
135 struct text_input *text_input,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100136 uint32_t serial,
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100137 const char *text)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200138{
139 struct text_entry *entry = data;
140
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100141 text_entry_reset_preedit(entry);
142
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200143 text_entry_delete_selected_text(entry);
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100144 text_entry_insert_at_cursor(entry, text,
145 entry->pending_commit.cursor,
146 entry->pending_commit.anchor);
147
148 memset(&entry->pending_commit, 0, sizeof entry->pending_commit);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200149
150 widget_schedule_redraw(entry->widget);
151}
152
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200153static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200154text_input_preedit_string(void *data,
155 struct text_input *text_input,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100156 uint32_t serial,
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200157 const char *text,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100158 const char *commit)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200159{
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200160 struct text_entry *entry = data;
161
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200162 text_entry_delete_selected_text(entry);
Jan Arne Petersen46535312013-01-16 21:26:38 +0100163 text_entry_set_preedit(entry, text, entry->preedit_info.cursor);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100164 entry->preedit.commit = strdup(commit);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100165 entry->preedit.attr_list = entry->preedit_info.attr_list;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100166
167 entry->preedit_info.cursor = 0;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100168 entry->preedit_info.attr_list = NULL;
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200169
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200170 text_entry_update(entry);
171
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200172 widget_schedule_redraw(entry->widget);
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200173}
174
175static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200176text_input_delete_surrounding_text(void *data,
177 struct text_input *text_input,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100178 uint32_t serial,
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200179 int32_t index,
180 uint32_t length)
181{
182 struct text_entry *entry = data;
183 uint32_t cursor_index = index + entry->cursor;
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100184 const char *start, *end;
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200185
186 if (cursor_index > strlen(entry->text)) {
187 fprintf(stderr, "Invalid cursor index %d\n", index);
188 return;
189 }
190
191 if (cursor_index + length > strlen(entry->text)) {
192 fprintf(stderr, "Invalid length %d\n", length);
193 return;
194 }
195
196 if (length == 0)
197 return;
198
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100199 start = utf8_start_char(entry->text, entry->text + cursor_index);
200 end = utf8_end_char(entry->text + cursor_index + length);
201
202 text_entry_delete_text(entry,
203 start - entry->text,
204 end - start);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200205}
206
207static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200208text_input_cursor_position(void *data,
209 struct text_input *text_input,
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100210 uint32_t serial,
211 int32_t index,
212 int32_t anchor)
213{
214 struct text_entry *entry = data;
215
216 entry->pending_commit.cursor = index;
217 entry->pending_commit.anchor = anchor;
218}
219
220static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200221text_input_preedit_styling(void *data,
222 struct text_input *text_input,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100223 uint32_t serial,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100224 uint32_t index,
225 uint32_t length,
226 uint32_t style)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200227{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100228 struct text_entry *entry = data;
229 PangoAttribute *attr1 = NULL;
230 PangoAttribute *attr2 = NULL;
231
232 if (!entry->preedit_info.attr_list)
233 entry->preedit_info.attr_list = pango_attr_list_new();
234
235 switch (style) {
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200236 case TEXT_INPUT_PREEDIT_STYLE_DEFAULT:
237 case TEXT_INPUT_PREEDIT_STYLE_UNDERLINE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100238 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
239 break;
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200240 case TEXT_INPUT_PREEDIT_STYLE_INCORRECT:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100241 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_ERROR);
242 attr2 = pango_attr_underline_color_new(65535, 0, 0);
243 break;
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200244 case TEXT_INPUT_PREEDIT_STYLE_SELECTION:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100245 attr1 = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
246 attr2 = pango_attr_foreground_new(65535, 65535, 65535);
247 break;
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200248 case TEXT_INPUT_PREEDIT_STYLE_HIGHLIGHT:
249 case TEXT_INPUT_PREEDIT_STYLE_ACTIVE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100250 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
251 attr2 = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
252 break;
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200253 case TEXT_INPUT_PREEDIT_STYLE_INACTIVE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100254 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
255 attr2 = pango_attr_foreground_new(0.3 * 65535, 0.3 * 65535, 0.3 * 65535);
256 break;
257 }
258
259 if (attr1) {
260 attr1->start_index = entry->cursor + index;
261 attr1->end_index = entry->cursor + index + length;
262 pango_attr_list_insert(entry->preedit_info.attr_list, attr1);
263 }
264
265 if (attr2) {
266 attr2->start_index = entry->cursor + index;
267 attr2->end_index = entry->cursor + index + length;
268 pango_attr_list_insert(entry->preedit_info.attr_list, attr2);
269 }
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200270}
271
272static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200273text_input_preedit_cursor(void *data,
274 struct text_input *text_input,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100275 uint32_t serial,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100276 int32_t index)
277{
278 struct text_entry *entry = data;
279
280 entry->preedit_info.cursor = index;
281}
282
283static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200284text_input_modifiers_map(void *data,
285 struct text_input *text_input,
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100286 struct wl_array *map)
287{
Jan Arne Petersencd997062012-11-18 19:06:44 +0100288 struct text_entry *entry = data;
289
290 entry->keysym.shift_mask = keysym_modifiers_get_mask(map, "Shift");
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100291}
292
293static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200294text_input_keysym(void *data,
295 struct text_input *text_input,
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100296 uint32_t serial,
297 uint32_t time,
298 uint32_t key,
299 uint32_t state,
300 uint32_t modifiers)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200301{
Jan Arne Petersen8aba11d2012-09-17 15:28:07 +0200302 struct text_entry *entry = data;
Jan Arne Petersencd997062012-11-18 19:06:44 +0100303 const char *state_label = "release";
304 const char *key_label = "Unknown";
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100305 const char *new_char;
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200306
307 if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
308 state_label = "pressed";
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200309 }
310
Jan Arne Petersencd997062012-11-18 19:06:44 +0100311 if (key == XKB_KEY_Left ||
312 key == XKB_KEY_Right) {
313 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
314 return;
315
316 if (key == XKB_KEY_Left)
317 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
318 else
319 new_char = utf8_next_char(entry->text + entry->cursor);
320
321 if (new_char != NULL) {
322 entry->cursor = new_char - entry->text;
323 if (!(modifiers & entry->keysym.shift_mask))
324 entry->anchor = entry->cursor;
325 widget_schedule_redraw(entry->widget);
326 }
327
328 return;
329 }
330
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100331 if (key == XKB_KEY_BackSpace) {
332 const char *start, *end;
333
Jan Arne Petersendfd34462013-04-18 16:47:26 +0200334 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
335 return;
336
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100337 text_entry_commit_and_reset(entry);
338
339 start = utf8_prev_char(entry->text, entry->text + entry->cursor);
340
341 if (start == NULL)
342 return;
343
344 end = utf8_end_char(entry->text + entry->cursor);
345 text_entry_delete_text(entry,
346 start - entry->text,
347 end - start);
348
349 return;
350 }
351
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200352 switch (key) {
353 case XKB_KEY_Tab:
354 key_label = "Tab";
355 break;
356 case XKB_KEY_KP_Enter:
Jan Arne Petersencd997062012-11-18 19:06:44 +0100357 case XKB_KEY_Return:
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200358 key_label = "Enter";
359 break;
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200360 }
361
362 fprintf(stderr, "%s key was %s.\n", key_label, state_label);
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200363}
364
365static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200366text_input_enter(void *data,
367 struct text_input *text_input,
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200368 struct wl_surface *surface)
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200369{
370 struct text_entry *entry = data;
371
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200372 if (surface != window_get_wl_surface(entry->window))
373 return;
374
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200375 entry->active = 1;
376
377 widget_schedule_redraw(entry->widget);
378}
379
380static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200381text_input_leave(void *data,
382 struct text_input *text_input)
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200383{
384 struct text_entry *entry = data;
385
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100386 text_entry_commit_and_reset(entry);
387
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200388 entry->active = 0;
389
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200390 text_input_hide_input_panel(text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100391
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200392 widget_schedule_redraw(entry->widget);
393}
394
Jan Arne Petersen61381972013-01-31 15:52:21 +0100395static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200396text_input_input_panel_state(void *data,
397 struct text_input *text_input,
Jan Arne Petersen61381972013-01-31 15:52:21 +0100398 uint32_t state)
399{
400}
401
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200402static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200403text_input_language(void *data,
404 struct text_input *text_input,
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200405 uint32_t serial,
406 const char *language)
407{
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200408 fprintf(stderr, "input language is %s \n", language);
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200409}
410
411static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200412text_input_text_direction(void *data,
413 struct text_input *text_input,
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200414 uint32_t serial,
415 uint32_t direction)
416{
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200417 struct text_entry *entry = data;
418 PangoContext *context = pango_layout_get_context(entry->layout);
419 PangoDirection pango_direction;
420
421
422 switch (direction) {
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200423 case TEXT_INPUT_TEXT_DIRECTION_LTR:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200424 pango_direction = PANGO_DIRECTION_LTR;
425 break;
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200426 case TEXT_INPUT_TEXT_DIRECTION_RTL:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200427 pango_direction = PANGO_DIRECTION_RTL;
428 break;
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200429 case TEXT_INPUT_TEXT_DIRECTION_AUTO:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200430 default:
431 pango_direction = PANGO_DIRECTION_NEUTRAL;
432 }
433
434 pango_context_set_base_dir(context, pango_direction);
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200435}
436
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200437static const struct text_input_listener text_input_listener = {
438 text_input_enter,
439 text_input_leave,
440 text_input_modifiers_map,
441 text_input_input_panel_state,
442 text_input_preedit_string,
443 text_input_preedit_styling,
444 text_input_preedit_cursor,
445 text_input_commit_string,
446 text_input_cursor_position,
447 text_input_delete_surrounding_text,
448 text_input_keysym,
449 text_input_language,
450 text_input_text_direction
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200451};
452
453static struct text_entry*
454text_entry_create(struct editor *editor, const char *text)
455{
456 struct text_entry *entry;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200457
Jan Arne Petersencd997062012-11-18 19:06:44 +0100458 entry = calloc(1, sizeof *entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200459
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200460 entry->widget = widget_add_widget(editor->widget, entry);
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200461 entry->window = editor->window;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200462 entry->text = strdup(text);
463 entry->active = 0;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200464 entry->cursor = strlen(text);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200465 entry->anchor = entry->cursor;
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200466 entry->text_input = text_input_manager_create_text_input(editor->text_input_manager);
467 text_input_add_listener(entry->text_input, &text_input_listener, entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200468
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200469 widget_set_redraw_handler(entry->widget, text_entry_redraw_handler);
470 widget_set_button_handler(entry->widget, text_entry_button_handler);
471
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200472 return entry;
473}
474
475static void
476text_entry_destroy(struct text_entry *entry)
477{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200478 widget_destroy(entry->widget);
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200479 text_input_destroy(entry->text_input);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100480 g_clear_object(&entry->layout);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200481 free(entry->text);
482 free(entry);
483}
484
485static void
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200486redraw_handler(struct widget *widget, void *data)
487{
488 struct editor *editor = data;
489 cairo_surface_t *surface;
490 struct rectangle allocation;
491 cairo_t *cr;
492
493 surface = window_get_surface(editor->window);
494 widget_get_allocation(editor->widget, &allocation);
495
496 cr = cairo_create(surface);
497 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
498 cairo_clip(cr);
499
500 cairo_translate(cr, allocation.x, allocation.y);
501
502 /* Draw background */
503 cairo_push_group(cr);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200504 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200505 cairo_set_source_rgba(cr, 1, 1, 1, 1);
506 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
507 cairo_fill(cr);
508
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200509 cairo_pop_group_to_source(cr);
510 cairo_paint(cr);
511
512 cairo_destroy(cr);
513 cairo_surface_destroy(surface);
514}
515
516static void
517text_entry_allocate(struct text_entry *entry, int32_t x, int32_t y,
518 int32_t width, int32_t height)
519{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200520 widget_set_allocation(entry->widget, x, y, width, height);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200521}
522
523static void
524resize_handler(struct widget *widget,
525 int32_t width, int32_t height, void *data)
526{
527 struct editor *editor = data;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200528 struct rectangle allocation;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200529
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200530 widget_get_allocation(editor->widget, &allocation);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200531
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200532 text_entry_allocate(editor->entry,
533 allocation.x + 20, allocation.y + 20,
534 width - 40, height / 2 - 40);
535 text_entry_allocate(editor->editor,
536 allocation.x + 20, allocation.y + height / 2 + 20,
537 width - 40, height / 2 - 40);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200538}
539
540static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200541text_entry_activate(struct text_entry *entry,
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200542 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200543{
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200544 struct wl_surface *surface = window_get_wl_surface(entry->window);
545
Jan Arne Petersen61381972013-01-31 15:52:21 +0100546 if (entry->click_to_show && entry->active) {
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200547 text_input_show_input_panel(entry->text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100548
549 return;
550 }
551
552 if (!entry->click_to_show)
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200553 text_input_show_input_panel(entry->text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100554
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100555 entry->serial++;
556
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200557 text_input_activate(entry->text_input,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100558 entry->serial,
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200559 seat,
560 surface);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200561}
562
563static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200564text_entry_deactivate(struct text_entry *entry,
565 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200566{
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200567 text_input_deactivate(entry->text_input,
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200568 seat);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200569}
570
571static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200572text_entry_update_layout(struct text_entry *entry)
573{
574 char *text;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100575 PangoAttrList *attr_list;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200576
Philipp Brüschweiler237358b2012-10-02 11:06:51 +0200577 assert(((unsigned int)entry->cursor) <= strlen(entry->text) +
Jan Arne Petersen46535312013-01-16 21:26:38 +0100578 (entry->preedit.text ? strlen(entry->preedit.text) : 0));
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200579
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100580 if (entry->preedit.text) {
581 text = malloc(strlen(entry->text) + strlen(entry->preedit.text) + 1);
582 strncpy(text, entry->text, entry->cursor);
583 strcpy(text + entry->cursor, entry->preedit.text);
584 strcpy(text + entry->cursor + strlen(entry->preedit.text),
585 entry->text + entry->cursor);
586 } else {
587 text = strdup(entry->text);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200588 }
589
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100590 if (entry->cursor != entry->anchor) {
591 int start_index = MIN(entry->cursor, entry->anchor);
592 int end_index = MAX(entry->cursor, entry->anchor);
593 PangoAttribute *attr;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200594
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100595 attr_list = pango_attr_list_copy(entry->preedit.attr_list);
596
597 if (!attr_list)
598 attr_list = pango_attr_list_new();
599
600 attr = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
601 attr->start_index = start_index;
602 attr->end_index = end_index;
603 pango_attr_list_insert(attr_list, attr);
604
605 attr = pango_attr_foreground_new(65535, 65535, 65535);
606 attr->start_index = start_index;
607 attr->end_index = end_index;
608 pango_attr_list_insert(attr_list, attr);
609 } else {
610 attr_list = pango_attr_list_ref(entry->preedit.attr_list);
611 }
612
613 if (entry->preedit.text && !entry->preedit.attr_list) {
614 PangoAttribute *attr;
615
616 if (!attr_list)
617 attr_list = pango_attr_list_new();
618
619 attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
620 attr->start_index = entry->cursor;
621 attr->end_index = entry->cursor + strlen(entry->preedit.text);
622 pango_attr_list_insert(attr_list, attr);
623 }
624
625 if (entry->layout) {
626 pango_layout_set_text(entry->layout, text, -1);
627 pango_layout_set_attributes(entry->layout, attr_list);
628 }
629
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200630 free(text);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100631 pango_attr_list_unref(attr_list);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200632}
633
634static void
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100635text_entry_update(struct text_entry *entry)
636{
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200637 struct rectangle cursor_rectangle;
638
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200639 text_input_set_content_type(entry->text_input,
640 TEXT_INPUT_CONTENT_HINT_NONE,
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100641 entry->content_purpose);
642
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200643 text_input_set_surrounding_text(entry->text_input,
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100644 entry->text,
645 entry->cursor,
646 entry->anchor);
Jan Arne Petersen0eabcaa2013-01-31 15:52:20 +0100647
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200648 if (entry->preferred_language)
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200649 text_input_set_preferred_language(entry->text_input,
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200650 entry->preferred_language);
651
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200652 text_entry_get_cursor_rectangle(entry, &cursor_rectangle);
653 text_input_set_cursor_rectangle(entry->text_input, cursor_rectangle.x, cursor_rectangle.y,
654 cursor_rectangle.width, cursor_rectangle.height);
655
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200656 text_input_commit_state(entry->text_input);
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100657}
658
659static void
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100660text_entry_insert_at_cursor(struct text_entry *entry, const char *text,
661 int32_t cursor, int32_t anchor)
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200662{
663 char *new_text = malloc(strlen(entry->text) + strlen(text) + 1);
664
665 strncpy(new_text, entry->text, entry->cursor);
666 strcpy(new_text + entry->cursor, text);
667 strcpy(new_text + entry->cursor + strlen(text),
668 entry->text + entry->cursor);
669
670 free(entry->text);
671 entry->text = new_text;
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100672 if (anchor >= 0)
673 entry->anchor = entry->cursor + strlen(text) + anchor;
674 else
675 entry->anchor = entry->cursor + 1 + anchor;
676 if (cursor >= 0)
677 entry->cursor += strlen(text) + cursor;
678 else
679 entry->cursor += 1 + cursor;
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200680
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200681 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100682
683 widget_schedule_redraw(entry->widget);
684
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100685 text_entry_update(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200686}
687
688static void
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100689text_entry_reset_preedit(struct text_entry *entry)
690{
691 entry->preedit.cursor = 0;
692
693 free(entry->preedit.text);
694 entry->preedit.text = NULL;
695
696 free(entry->preedit.commit);
697 entry->preedit.commit = NULL;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100698
699 pango_attr_list_unref(entry->preedit.attr_list);
700 entry->preedit.attr_list = NULL;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100701}
702
703static void
704text_entry_commit_and_reset(struct text_entry *entry)
705{
706 char *commit = NULL;
707
708 if (entry->preedit.commit)
709 commit = strdup(entry->preedit.commit);
710
711 text_entry_reset_preedit(entry);
712 if (commit) {
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100713 text_entry_insert_at_cursor(entry, commit, 0, 0);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100714 free(commit);
715 }
Jan Arne Petersen08015b62013-04-18 16:47:18 +0200716
717 entry->serial++;
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200718 text_input_reset(entry->text_input, entry->serial);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100719}
720
721static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200722text_entry_set_preedit(struct text_entry *entry,
723 const char *preedit_text,
724 int preedit_cursor)
725{
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100726 text_entry_reset_preedit(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200727
728 if (!preedit_text)
729 return;
730
Jan Arne Petersen46535312013-01-16 21:26:38 +0100731 entry->preedit.text = strdup(preedit_text);
732 entry->preedit.cursor = preedit_cursor;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200733
734 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100735
736 widget_schedule_redraw(entry->widget);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200737}
738
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100739static uint32_t
740text_entry_try_invoke_preedit_action(struct text_entry *entry,
741 int32_t x, int32_t y,
742 uint32_t button,
743 enum wl_pointer_button_state state)
744{
745 int index, trailing;
746 uint32_t cursor;
747
748 if (!entry->preedit.text)
749 return 0;
750
751 pango_layout_xy_to_index(entry->layout,
752 x * PANGO_SCALE, y * PANGO_SCALE,
753 &index, &trailing);
754 cursor = index + trailing;
755
756 if (cursor < entry->cursor ||
757 cursor > entry->cursor + strlen(entry->preedit.text)) {
758 return 0;
759 }
760
761 if (state == WL_POINTER_BUTTON_STATE_RELEASED)
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200762 text_input_invoke_action(entry->text_input,
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100763 button,
764 cursor - entry->cursor);
765
766 return 1;
767}
768
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200769static void
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200770text_entry_set_cursor_position(struct text_entry *entry,
771 int32_t x, int32_t y)
772{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100773 int index, trailing;
774
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100775 text_entry_commit_and_reset(entry);
776
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100777 pango_layout_xy_to_index(entry->layout,
778 x * PANGO_SCALE, y * PANGO_SCALE,
779 &index, &trailing);
780 entry->cursor = index + trailing;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200781
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200782 text_entry_update_layout(entry);
783
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200784 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100785
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100786 text_entry_update(entry);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200787}
788
789static void
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200790text_entry_set_anchor_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
795 pango_layout_xy_to_index(entry->layout,
796 x * PANGO_SCALE, y * PANGO_SCALE,
797 &index, &trailing);
798 entry->anchor = index + trailing;
799
800 text_entry_update_layout(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200801
802 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100803
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100804 text_entry_update(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200805}
806
807static void
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200808text_entry_delete_text(struct text_entry *entry,
809 uint32_t index, uint32_t length)
810{
811 if (entry->cursor > index)
812 entry->cursor -= length;
813
Jan Arne Petersen80ad1a92012-09-17 15:28:10 +0200814 entry->anchor = entry->cursor;
815
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200816 entry->text[index] = '\0';
817 strcat(entry->text, entry->text + index + length);
818
819 text_entry_update_layout(entry);
820
821 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100822
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100823 text_entry_update(entry);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200824}
825
826static void
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200827text_entry_delete_selected_text(struct text_entry *entry)
828{
829 uint32_t start_index = entry->anchor < entry->cursor ? entry->anchor : entry->cursor;
830 uint32_t end_index = entry->anchor < entry->cursor ? entry->cursor : entry->anchor;
831
832 if (entry->anchor == entry->cursor)
833 return;
834
835 text_entry_delete_text(entry, start_index, end_index - start_index);
836
837 entry->anchor = entry->cursor;
838}
839
840static void
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200841text_entry_get_cursor_rectangle(struct text_entry *entry, struct rectangle *rectangle)
842{
843 struct rectangle allocation;
844 PangoRectangle extents;
845 PangoRectangle cursor_pos;
846
847 widget_get_allocation(entry->widget, &allocation);
848
849 if (entry->preedit.text && entry->preedit.cursor < 0) {
850 rectangle->x = 0;
851 rectangle->y = 0;
852 rectangle->width = 0;
853 rectangle->height = 0;
854 return;
855 }
856
857 pango_layout_get_extents(entry->layout, &extents, NULL);
858 pango_layout_get_cursor_pos(entry->layout,
859 entry->cursor + entry->preedit.cursor,
860 &cursor_pos, NULL);
861
862 rectangle->x = allocation.x + (allocation.height / 2) + PANGO_PIXELS(cursor_pos.x);
863 rectangle->y = allocation.y + 10 + PANGO_PIXELS(cursor_pos.y);
864 rectangle->width = PANGO_PIXELS(cursor_pos.width);
865 rectangle->height = PANGO_PIXELS(cursor_pos.height);
866}
867
868static void
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200869text_entry_draw_cursor(struct text_entry *entry, cairo_t *cr)
870{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100871 PangoRectangle extents;
872 PangoRectangle cursor_pos;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200873
Jan Arne Petersen46535312013-01-16 21:26:38 +0100874 if (entry->preedit.text && entry->preedit.cursor < 0)
875 return;
876
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100877 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);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200881
882 cairo_set_line_width(cr, 1.0);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100883 cairo_move_to(cr, PANGO_PIXELS(cursor_pos.x), PANGO_PIXELS(extents.height) + 2);
884 cairo_line_to(cr, PANGO_PIXELS(cursor_pos.x), - 2);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200885 cairo_stroke(cr);
886}
887
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200888static const int text_offset_left = 10;
889
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200890static void
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200891text_entry_redraw_handler(struct widget *widget, void *data)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200892{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200893 struct text_entry *entry = data;
894 cairo_surface_t *surface;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200895 struct rectangle allocation;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200896 cairo_t *cr;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200897
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200898 surface = window_get_surface(entry->window);
899 widget_get_allocation(entry->widget, &allocation);
900
901 cr = cairo_create(surface);
902 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
903 cairo_clip(cr);
904
905 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
906
907 cairo_push_group(cr);
908 cairo_translate(cr, allocation.x, allocation.y);
909
910 cairo_set_source_rgba(cr, 1, 1, 1, 1);
911 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
912 cairo_fill(cr);
913
914 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
915
916 if (entry->active) {
917 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
918 cairo_set_line_width (cr, 3);
919 cairo_set_source_rgba(cr, 0, 0, 1, 1.0);
920 cairo_stroke(cr);
921 }
922
923 cairo_set_source_rgba(cr, 0, 0, 0, 1);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200924
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200925 cairo_translate(cr, text_offset_left, allocation.height / 2);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200926
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100927 if (!entry->layout)
928 entry->layout = pango_cairo_create_layout(cr);
929 else
930 pango_cairo_update_layout(cr, entry->layout);
931
932 text_entry_update_layout(entry);
933
934 pango_cairo_show_layout(cr, entry->layout);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200935
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200936 text_entry_draw_cursor(entry, cr);
937
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200938 cairo_pop_group_to_source(cr);
939 cairo_paint(cr);
940
941 cairo_destroy(cr);
942 cairo_surface_destroy(surface);
943}
944
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200945static int
946text_entry_motion_handler(struct widget *widget,
947 struct input *input, uint32_t time,
948 float x, float y, void *data)
949{
950 struct text_entry *entry = data;
951 struct rectangle allocation;
952
953 widget_get_allocation(entry->widget, &allocation);
954
955 text_entry_set_cursor_position(entry,
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200956 x - allocation.x - text_offset_left,
957 y - allocation.y - text_offset_left);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200958
959 return CURSOR_IBEAM;
960}
961
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200962static void
963text_entry_button_handler(struct widget *widget,
964 struct input *input, uint32_t time,
965 uint32_t button,
966 enum wl_pointer_button_state state, void *data)
967{
968 struct text_entry *entry = data;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200969 struct rectangle allocation;
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100970 struct editor *editor;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200971 int32_t x, y;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100972 uint32_t result;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200973
974 widget_get_allocation(entry->widget, &allocation);
975 input_get_position(input, &x, &y);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200976
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100977 x -= allocation.x + text_offset_left;
978 y -= allocation.y + text_offset_left;
979
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100980 editor = window_get_user_data(entry->window);
981
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100982 result = text_entry_try_invoke_preedit_action(entry, x, y, button, state);
983
984 if (result)
985 return;
986
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200987 if (button != BTN_LEFT) {
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200988 return;
989 }
990
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100991 text_entry_set_cursor_position(entry, x, y);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200992
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200993 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
994 struct wl_seat *seat = input_get_seat(input);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200995
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200996 text_entry_activate(entry, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100997 editor->active_entry = entry;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200998
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100999 text_entry_set_anchor_position(entry, x, y);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001000
1001 widget_set_motion_handler(entry->widget, text_entry_motion_handler);
1002 } else {
1003 widget_set_motion_handler(entry->widget, NULL);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001004 }
1005}
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001006
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001007static void
1008editor_button_handler(struct widget *widget,
1009 struct input *input, uint32_t time,
1010 uint32_t button,
1011 enum wl_pointer_button_state state, void *data)
1012{
1013 struct editor *editor = data;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001014
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001015 if (button != BTN_LEFT) {
1016 return;
1017 }
Jan Arne Petersene829adc2012-08-10 16:47:22 +02001018
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001019 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
1020 struct wl_seat *seat = input_get_seat(input);
1021
Jan Arne Petersene829adc2012-08-10 16:47:22 +02001022 text_entry_deactivate(editor->entry, seat);
1023 text_entry_deactivate(editor->editor, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001024 editor->active_entry = NULL;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001025 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001026}
1027
1028static void
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001029key_handler(struct window *window,
1030 struct input *input, uint32_t time,
1031 uint32_t key, uint32_t sym, enum wl_keyboard_key_state state,
1032 void *data)
1033{
1034 struct editor *editor = data;
1035 struct text_entry *entry;
1036 const char *start, *end, *new_char;
1037 char text[16];
1038
1039 if (!editor->active_entry)
1040 return;
1041
1042 entry = editor->active_entry;
1043
1044 if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
1045 return;
1046
1047 switch (sym) {
1048 case XKB_KEY_BackSpace:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001049 text_entry_commit_and_reset(entry);
1050
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001051 start = utf8_prev_char(entry->text, entry->text + entry->cursor);
1052
1053 if (start == NULL)
1054 break;
1055
1056 end = utf8_end_char(entry->text + entry->cursor);
1057 text_entry_delete_text(entry,
1058 start - entry->text,
1059 end - start);
1060 break;
1061 case XKB_KEY_Delete:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001062 text_entry_commit_and_reset(entry);
1063
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001064 start = utf8_start_char(entry->text, entry->text + entry->cursor);
1065
1066 if (start == NULL)
1067 break;
1068
1069 end = utf8_next_char(start);
1070
1071 if (end == NULL)
1072 break;
1073
1074 text_entry_delete_text(entry,
1075 start - entry->text,
1076 end - start);
1077 break;
1078 case XKB_KEY_Left:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001079 text_entry_commit_and_reset(entry);
1080
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001081 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
1082 if (new_char != NULL) {
1083 entry->cursor = new_char - entry->text;
1084 entry->anchor = entry->cursor;
1085 widget_schedule_redraw(entry->widget);
1086 }
1087 break;
1088 case XKB_KEY_Right:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001089 text_entry_commit_and_reset(entry);
1090
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001091 new_char = utf8_next_char(entry->text + entry->cursor);
1092 if (new_char != NULL) {
1093 entry->cursor = new_char - entry->text;
1094 entry->anchor = entry->cursor;
1095 widget_schedule_redraw(entry->widget);
1096 }
1097 break;
1098 default:
1099 if (xkb_keysym_to_utf8(sym, text, sizeof(text)) <= 0)
1100 break;
1101
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001102 text_entry_commit_and_reset(entry);
1103
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +01001104 text_entry_insert_at_cursor(entry, text, 0, 0);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001105 break;
1106 }
1107
1108 widget_schedule_redraw(entry->widget);
1109}
1110
1111static void
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001112global_handler(struct display *display, uint32_t name,
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001113 const char *interface, uint32_t version, void *data)
1114{
1115 struct editor *editor = data;
1116
Jan Arne Petersen78d00e42013-04-18 16:47:24 +02001117 if (!strcmp(interface, "text_input_manager")) {
1118 editor->text_input_manager =
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001119 display_bind(display, name,
Jan Arne Petersen78d00e42013-04-18 16:47:24 +02001120 &text_input_manager_interface, 1);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001121 }
1122}
1123
1124int
1125main(int argc, char *argv[])
1126{
1127 struct editor editor;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001128 int i;
1129 uint32_t click_to_show = 0;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001130 const char *preferred_language = NULL;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001131
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001132 for (i = 1; i < argc; i++) {
Jan Arne Petersen61381972013-01-31 15:52:21 +01001133 if (strcmp("--click-to-show", argv[i]) == 0)
1134 click_to_show = 1;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001135 else if (strcmp("--preferred-language", argv[i]) == 0) {
1136 if (i + 1 < argc) {
1137 preferred_language = argv[i + 1];
1138 i++;
1139 }
1140 }
1141 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001142
Jan Arne Petersen25f6db52012-11-05 03:26:40 +01001143 memset(&editor, 0, sizeof editor);
1144
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001145#ifdef HAVE_PANGO
1146 g_type_init();
1147#endif
1148
Kristian Høgsberg4172f662013-02-20 15:27:49 -05001149 editor.display = display_create(&argc, argv);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001150 if (editor.display == NULL) {
1151 fprintf(stderr, "failed to create display: %m\n");
1152 return -1;
1153 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001154
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001155 display_set_user_data(editor.display, &editor);
1156 display_set_global_handler(editor.display, global_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001157
1158 editor.window = window_create(editor.display);
1159 editor.widget = frame_create(editor.window, &editor);
1160
1161 editor.entry = text_entry_create(&editor, "Entry");
Jan Arne Petersen61381972013-01-31 15:52:21 +01001162 editor.entry->click_to_show = click_to_show;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001163 if (preferred_language)
1164 editor.entry->preferred_language = strdup(preferred_language);
Jan Arne Petersen0558a932013-01-16 21:26:45 +01001165 editor.editor = text_entry_create(&editor, "Numeric");
Jan Arne Petersen78d00e42013-04-18 16:47:24 +02001166 editor.editor->content_purpose = TEXT_INPUT_CONTENT_PURPOSE_NUMBER;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001167 editor.editor->click_to_show = click_to_show;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001168
1169 window_set_title(editor.window, "Text Editor");
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001170 window_set_key_handler(editor.window, key_handler);
1171 window_set_user_data(editor.window, &editor);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001172
1173 widget_set_redraw_handler(editor.widget, redraw_handler);
1174 widget_set_resize_handler(editor.widget, resize_handler);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001175 widget_set_button_handler(editor.widget, editor_button_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001176
1177 window_schedule_resize(editor.window, 500, 400);
1178
1179 display_run(editor.display);
1180
1181 text_entry_destroy(editor.entry);
1182 text_entry_destroy(editor.editor);
1183
1184 return 0;
1185}