blob: a830ead50498c47e714958eb1c9102bac9ece3d5 [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 Petersencba9e472012-06-21 21:52:19 +020056 struct text_model *model;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010057 PangoLayout *layout;
Jan Arne Petersencd997062012-11-18 19:06:44 +010058 struct {
59 xkb_mod_mask_t shift_mask;
60 } keysym;
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +010061 uint32_t serial;
Jan Arne Petersen0558a932013-01-16 21:26:45 +010062 uint32_t content_purpose;
Jan Arne Petersen61381972013-01-31 15:52:21 +010063 uint32_t click_to_show;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020064};
65
66struct editor {
Jan Arne Petersen51963742012-08-10 16:47:20 +020067 struct text_model_factory *text_model_factory;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020068 struct display *display;
69 struct window *window;
70 struct widget *widget;
71 struct text_entry *entry;
72 struct text_entry *editor;
Rob Bradford9d1d32b2012-11-18 19:06:49 +010073 struct text_entry *active_entry;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020074};
75
Jan Arne Petersen6345faa2012-11-05 03:26:39 +010076static const char *
77utf8_start_char(const char *text, const char *p)
78{
79 for (; p >= text; --p) {
80 if ((*p & 0xc0) != 0x80)
81 return p;
82 }
83 return NULL;
84}
85
86static const char *
87utf8_prev_char(const char *text, const char *p)
88{
89 if (p > text)
90 return utf8_start_char(text, --p);
91 return NULL;
92}
93
94static const char *
95utf8_end_char(const char *p)
96{
97 while ((*p & 0xc0) == 0x80)
98 p++;
99 return p;
100}
101
102static const char *
103utf8_next_char(const char *p)
104{
105 if (*p != 0)
106 return utf8_end_char(++p);
107 return NULL;
108}
109
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200110static void text_entry_redraw_handler(struct widget *widget, void *data);
111static void text_entry_button_handler(struct widget *widget,
112 struct input *input, uint32_t time,
113 uint32_t button,
114 enum wl_pointer_button_state state, void *data);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200115static void text_entry_insert_at_cursor(struct text_entry *entry, const char *text);
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200116static void text_entry_set_preedit(struct text_entry *entry,
117 const char *preedit_text,
118 int preedit_cursor);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200119static void text_entry_delete_text(struct text_entry *entry,
120 uint32_t index, uint32_t length);
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200121static void text_entry_delete_selected_text(struct text_entry *entry);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100122static void text_entry_reset_preedit(struct text_entry *entry);
123static void text_entry_commit_and_reset(struct text_entry *entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200124
125static void
126text_model_commit_string(void *data,
127 struct text_model *text_model,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100128 uint32_t serial,
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200129 const char *text,
130 uint32_t index)
131{
132 struct text_entry *entry = data;
133
John Kåre Alsaker011a1ce2012-10-12 12:25:06 +0200134 if (index > strlen(text))
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200135 fprintf(stderr, "Invalid cursor index %d\n", index);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200136
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100137 text_entry_reset_preedit(entry);
138
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200139 text_entry_delete_selected_text(entry);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200140 text_entry_insert_at_cursor(entry, text);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200141
142 widget_schedule_redraw(entry->widget);
143}
144
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200145static void
146text_model_preedit_string(void *data,
147 struct text_model *text_model,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100148 uint32_t serial,
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200149 const char *text,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100150 const char *commit)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200151{
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200152 struct text_entry *entry = data;
153
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200154 text_entry_delete_selected_text(entry);
Jan Arne Petersen46535312013-01-16 21:26:38 +0100155 text_entry_set_preedit(entry, text, entry->preedit_info.cursor);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100156 entry->preedit.commit = strdup(commit);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100157 entry->preedit.attr_list = entry->preedit_info.attr_list;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100158
159 entry->preedit_info.cursor = 0;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100160 entry->preedit_info.attr_list = NULL;
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200161
162 widget_schedule_redraw(entry->widget);
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200163}
164
165static void
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200166text_model_delete_surrounding_text(void *data,
167 struct text_model *text_model,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100168 uint32_t serial,
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200169 int32_t index,
170 uint32_t length)
171{
172 struct text_entry *entry = data;
173 uint32_t cursor_index = index + entry->cursor;
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100174 const char *start, *end;
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200175
176 if (cursor_index > strlen(entry->text)) {
177 fprintf(stderr, "Invalid cursor index %d\n", index);
178 return;
179 }
180
181 if (cursor_index + length > strlen(entry->text)) {
182 fprintf(stderr, "Invalid length %d\n", length);
183 return;
184 }
185
186 if (length == 0)
187 return;
188
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100189 start = utf8_start_char(entry->text, entry->text + cursor_index);
190 end = utf8_end_char(entry->text + cursor_index + length);
191
192 text_entry_delete_text(entry,
193 start - entry->text,
194 end - start);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200195}
196
197static void
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200198text_model_preedit_styling(void *data,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100199 struct text_model *text_model,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100200 uint32_t serial,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100201 uint32_t index,
202 uint32_t length,
203 uint32_t style)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200204{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100205 struct text_entry *entry = data;
206 PangoAttribute *attr1 = NULL;
207 PangoAttribute *attr2 = NULL;
208
209 if (!entry->preedit_info.attr_list)
210 entry->preedit_info.attr_list = pango_attr_list_new();
211
212 switch (style) {
213 case TEXT_MODEL_PREEDIT_STYLE_DEFAULT:
214 case TEXT_MODEL_PREEDIT_STYLE_UNDERLINE:
215 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
216 break;
217 case TEXT_MODEL_PREEDIT_STYLE_INCORRECT:
218 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_ERROR);
219 attr2 = pango_attr_underline_color_new(65535, 0, 0);
220 break;
221 case TEXT_MODEL_PREEDIT_STYLE_SELECTION:
222 attr1 = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
223 attr2 = pango_attr_foreground_new(65535, 65535, 65535);
224 break;
225 case TEXT_MODEL_PREEDIT_STYLE_HIGHLIGHT:
226 case TEXT_MODEL_PREEDIT_STYLE_ACTIVE:
227 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
228 attr2 = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
229 break;
230 case TEXT_MODEL_PREEDIT_STYLE_INACTIVE:
231 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
232 attr2 = pango_attr_foreground_new(0.3 * 65535, 0.3 * 65535, 0.3 * 65535);
233 break;
234 }
235
236 if (attr1) {
237 attr1->start_index = entry->cursor + index;
238 attr1->end_index = entry->cursor + index + length;
239 pango_attr_list_insert(entry->preedit_info.attr_list, attr1);
240 }
241
242 if (attr2) {
243 attr2->start_index = entry->cursor + index;
244 attr2->end_index = entry->cursor + index + length;
245 pango_attr_list_insert(entry->preedit_info.attr_list, attr2);
246 }
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200247}
248
249static void
Jan Arne Petersen46535312013-01-16 21:26:38 +0100250text_model_preedit_cursor(void *data,
251 struct text_model *text_model,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100252 uint32_t serial,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100253 int32_t index)
254{
255 struct text_entry *entry = data;
256
257 entry->preedit_info.cursor = index;
258}
259
260static void
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100261text_model_modifiers_map(void *data,
262 struct text_model *text_model,
263 struct wl_array *map)
264{
Jan Arne Petersencd997062012-11-18 19:06:44 +0100265 struct text_entry *entry = data;
266
267 entry->keysym.shift_mask = keysym_modifiers_get_mask(map, "Shift");
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100268}
269
270static void
271text_model_keysym(void *data,
272 struct text_model *text_model,
273 uint32_t serial,
274 uint32_t time,
275 uint32_t key,
276 uint32_t state,
277 uint32_t modifiers)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200278{
Jan Arne Petersen8aba11d2012-09-17 15:28:07 +0200279 struct text_entry *entry = data;
Jan Arne Petersencd997062012-11-18 19:06:44 +0100280 const char *state_label = "release";
281 const char *key_label = "Unknown";
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100282 const char *new_char;
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200283
284 if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
285 state_label = "pressed";
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200286 }
287
Jan Arne Petersencd997062012-11-18 19:06:44 +0100288 if (key == XKB_KEY_Left ||
289 key == XKB_KEY_Right) {
290 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
291 return;
292
293 if (key == XKB_KEY_Left)
294 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
295 else
296 new_char = utf8_next_char(entry->text + entry->cursor);
297
298 if (new_char != NULL) {
299 entry->cursor = new_char - entry->text;
300 if (!(modifiers & entry->keysym.shift_mask))
301 entry->anchor = entry->cursor;
302 widget_schedule_redraw(entry->widget);
303 }
304
305 return;
306 }
307
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100308 if (key == XKB_KEY_BackSpace) {
309 const char *start, *end;
310
311 text_entry_commit_and_reset(entry);
312
313 start = utf8_prev_char(entry->text, entry->text + entry->cursor);
314
315 if (start == NULL)
316 return;
317
318 end = utf8_end_char(entry->text + entry->cursor);
319 text_entry_delete_text(entry,
320 start - entry->text,
321 end - start);
322
323 return;
324 }
325
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200326 switch (key) {
327 case XKB_KEY_Tab:
328 key_label = "Tab";
329 break;
330 case XKB_KEY_KP_Enter:
Jan Arne Petersencd997062012-11-18 19:06:44 +0100331 case XKB_KEY_Return:
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200332 key_label = "Enter";
333 break;
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200334 }
335
336 fprintf(stderr, "%s key was %s.\n", key_label, state_label);
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200337}
338
339static void
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200340text_model_enter(void *data,
341 struct text_model *text_model,
342 struct wl_surface *surface)
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200343{
344 struct text_entry *entry = data;
345
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200346 if (surface != window_get_wl_surface(entry->window))
347 return;
348
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200349 entry->active = 1;
350
351 widget_schedule_redraw(entry->widget);
352}
353
354static void
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200355text_model_leave(void *data,
356 struct text_model *text_model)
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200357{
358 struct text_entry *entry = data;
359
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100360 text_entry_commit_and_reset(entry);
361
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200362 entry->active = 0;
363
Jan Arne Petersen61381972013-01-31 15:52:21 +0100364 text_model_hide_input_panel(text_model);
365
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200366 widget_schedule_redraw(entry->widget);
367}
368
Jan Arne Petersen61381972013-01-31 15:52:21 +0100369static void
370text_model_input_panel_state(void *data,
371 struct text_model *text_model,
372 uint32_t state)
373{
374}
375
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200376static const struct text_model_listener text_model_listener = {
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200377 text_model_commit_string,
378 text_model_preedit_string,
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200379 text_model_delete_surrounding_text,
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200380 text_model_preedit_styling,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100381 text_model_preedit_cursor,
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100382 text_model_modifiers_map,
383 text_model_keysym,
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200384 text_model_enter,
Jan Arne Petersen61381972013-01-31 15:52:21 +0100385 text_model_leave,
386 text_model_input_panel_state
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200387};
388
389static struct text_entry*
390text_entry_create(struct editor *editor, const char *text)
391{
392 struct text_entry *entry;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200393
Jan Arne Petersencd997062012-11-18 19:06:44 +0100394 entry = calloc(1, sizeof *entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200395
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200396 entry->widget = widget_add_widget(editor->widget, entry);
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200397 entry->window = editor->window;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200398 entry->text = strdup(text);
399 entry->active = 0;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200400 entry->cursor = strlen(text);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200401 entry->anchor = entry->cursor;
Jan Arne Petersen4c265182012-09-09 23:08:30 +0200402 entry->model = text_model_factory_create_text_model(editor->text_model_factory);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200403 text_model_add_listener(entry->model, &text_model_listener, entry);
404
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200405 widget_set_redraw_handler(entry->widget, text_entry_redraw_handler);
406 widget_set_button_handler(entry->widget, text_entry_button_handler);
407
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200408 return entry;
409}
410
411static void
412text_entry_destroy(struct text_entry *entry)
413{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200414 widget_destroy(entry->widget);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200415 text_model_destroy(entry->model);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100416 g_clear_object(&entry->layout);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200417 free(entry->text);
418 free(entry);
419}
420
421static void
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200422redraw_handler(struct widget *widget, void *data)
423{
424 struct editor *editor = data;
425 cairo_surface_t *surface;
426 struct rectangle allocation;
427 cairo_t *cr;
428
429 surface = window_get_surface(editor->window);
430 widget_get_allocation(editor->widget, &allocation);
431
432 cr = cairo_create(surface);
433 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
434 cairo_clip(cr);
435
436 cairo_translate(cr, allocation.x, allocation.y);
437
438 /* Draw background */
439 cairo_push_group(cr);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200440 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200441 cairo_set_source_rgba(cr, 1, 1, 1, 1);
442 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
443 cairo_fill(cr);
444
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200445 cairo_pop_group_to_source(cr);
446 cairo_paint(cr);
447
448 cairo_destroy(cr);
449 cairo_surface_destroy(surface);
450}
451
452static void
453text_entry_allocate(struct text_entry *entry, int32_t x, int32_t y,
454 int32_t width, int32_t height)
455{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200456 widget_set_allocation(entry->widget, x, y, width, height);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200457}
458
459static void
460resize_handler(struct widget *widget,
461 int32_t width, int32_t height, void *data)
462{
463 struct editor *editor = data;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200464 struct rectangle allocation;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200465
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200466 widget_get_allocation(editor->widget, &allocation);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200467
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200468 text_entry_allocate(editor->entry,
469 allocation.x + 20, allocation.y + 20,
470 width - 40, height / 2 - 40);
471 text_entry_allocate(editor->editor,
472 allocation.x + 20, allocation.y + height / 2 + 20,
473 width - 40, height / 2 - 40);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200474}
475
476static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200477text_entry_activate(struct text_entry *entry,
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200478 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200479{
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200480 struct wl_surface *surface = window_get_wl_surface(entry->window);
481
Jan Arne Petersen61381972013-01-31 15:52:21 +0100482 if (entry->click_to_show && entry->active) {
483 text_model_show_input_panel(entry->model);
484
485 return;
486 }
487
488 if (!entry->click_to_show)
489 text_model_show_input_panel(entry->model);
490
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100491 entry->serial++;
492
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200493 text_model_activate(entry->model,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100494 entry->serial,
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200495 seat,
496 surface);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200497}
498
499static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200500text_entry_deactivate(struct text_entry *entry,
501 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200502{
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200503 text_model_deactivate(entry->model,
504 seat);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200505}
506
507static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200508text_entry_update_layout(struct text_entry *entry)
509{
510 char *text;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100511 PangoAttrList *attr_list;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200512
Philipp Brüschweiler237358b2012-10-02 11:06:51 +0200513 assert(((unsigned int)entry->cursor) <= strlen(entry->text) +
Jan Arne Petersen46535312013-01-16 21:26:38 +0100514 (entry->preedit.text ? strlen(entry->preedit.text) : 0));
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200515
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100516 if (entry->preedit.text) {
517 text = malloc(strlen(entry->text) + strlen(entry->preedit.text) + 1);
518 strncpy(text, entry->text, entry->cursor);
519 strcpy(text + entry->cursor, entry->preedit.text);
520 strcpy(text + entry->cursor + strlen(entry->preedit.text),
521 entry->text + entry->cursor);
522 } else {
523 text = strdup(entry->text);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200524 }
525
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100526 if (entry->cursor != entry->anchor) {
527 int start_index = MIN(entry->cursor, entry->anchor);
528 int end_index = MAX(entry->cursor, entry->anchor);
529 PangoAttribute *attr;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200530
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100531 attr_list = pango_attr_list_copy(entry->preedit.attr_list);
532
533 if (!attr_list)
534 attr_list = pango_attr_list_new();
535
536 attr = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
537 attr->start_index = start_index;
538 attr->end_index = end_index;
539 pango_attr_list_insert(attr_list, attr);
540
541 attr = pango_attr_foreground_new(65535, 65535, 65535);
542 attr->start_index = start_index;
543 attr->end_index = end_index;
544 pango_attr_list_insert(attr_list, attr);
545 } else {
546 attr_list = pango_attr_list_ref(entry->preedit.attr_list);
547 }
548
549 if (entry->preedit.text && !entry->preedit.attr_list) {
550 PangoAttribute *attr;
551
552 if (!attr_list)
553 attr_list = pango_attr_list_new();
554
555 attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
556 attr->start_index = entry->cursor;
557 attr->end_index = entry->cursor + strlen(entry->preedit.text);
558 pango_attr_list_insert(attr_list, attr);
559 }
560
561 if (entry->layout) {
562 pango_layout_set_text(entry->layout, text, -1);
563 pango_layout_set_attributes(entry->layout, attr_list);
564 }
565
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200566 free(text);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100567 pango_attr_list_unref(attr_list);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200568}
569
570static void
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100571text_entry_update(struct text_entry *entry)
572{
573 text_model_set_content_type(entry->model,
574 TEXT_MODEL_CONTENT_HINT_NONE,
575 entry->content_purpose);
576
577 text_model_set_surrounding_text(entry->model,
578 entry->text,
579 entry->cursor,
580 entry->anchor);
Jan Arne Petersen0eabcaa2013-01-31 15:52:20 +0100581
582 text_model_commit(entry->model);
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100583}
584
585static void
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200586text_entry_insert_at_cursor(struct text_entry *entry, const char *text)
587{
588 char *new_text = malloc(strlen(entry->text) + strlen(text) + 1);
589
590 strncpy(new_text, entry->text, entry->cursor);
591 strcpy(new_text + entry->cursor, text);
592 strcpy(new_text + entry->cursor + strlen(text),
593 entry->text + entry->cursor);
594
595 free(entry->text);
596 entry->text = new_text;
597 entry->cursor += strlen(text);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200598 entry->anchor += strlen(text);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200599
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200600 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100601
602 widget_schedule_redraw(entry->widget);
603
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100604 text_entry_update(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200605}
606
607static void
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100608text_entry_reset_preedit(struct text_entry *entry)
609{
610 entry->preedit.cursor = 0;
611
612 free(entry->preedit.text);
613 entry->preedit.text = NULL;
614
615 free(entry->preedit.commit);
616 entry->preedit.commit = NULL;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100617
618 pango_attr_list_unref(entry->preedit.attr_list);
619 entry->preedit.attr_list = NULL;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100620}
621
622static void
623text_entry_commit_and_reset(struct text_entry *entry)
624{
625 char *commit = NULL;
626
627 if (entry->preedit.commit)
628 commit = strdup(entry->preedit.commit);
629
630 text_entry_reset_preedit(entry);
631 if (commit) {
632 text_entry_insert_at_cursor(entry, commit);
633 free(commit);
634 }
635}
636
637static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200638text_entry_set_preedit(struct text_entry *entry,
639 const char *preedit_text,
640 int preedit_cursor)
641{
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100642 text_entry_reset_preedit(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200643
644 if (!preedit_text)
645 return;
646
Jan Arne Petersen46535312013-01-16 21:26:38 +0100647 entry->preedit.text = strdup(preedit_text);
648 entry->preedit.cursor = preedit_cursor;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200649
650 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100651
652 widget_schedule_redraw(entry->widget);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200653}
654
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100655static uint32_t
656text_entry_try_invoke_preedit_action(struct text_entry *entry,
657 int32_t x, int32_t y,
658 uint32_t button,
659 enum wl_pointer_button_state state)
660{
661 int index, trailing;
662 uint32_t cursor;
663
664 if (!entry->preedit.text)
665 return 0;
666
667 pango_layout_xy_to_index(entry->layout,
668 x * PANGO_SCALE, y * PANGO_SCALE,
669 &index, &trailing);
670 cursor = index + trailing;
671
672 if (cursor < entry->cursor ||
673 cursor > entry->cursor + strlen(entry->preedit.text)) {
674 return 0;
675 }
676
677 if (state == WL_POINTER_BUTTON_STATE_RELEASED)
678 text_model_invoke_action(entry->model,
679 button,
680 cursor - entry->cursor);
681
682 return 1;
683}
684
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200685static void
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200686text_entry_set_cursor_position(struct text_entry *entry,
687 int32_t x, int32_t y)
688{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100689 int index, trailing;
690
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100691 text_entry_commit_and_reset(entry);
692
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100693 pango_layout_xy_to_index(entry->layout,
694 x * PANGO_SCALE, y * PANGO_SCALE,
695 &index, &trailing);
696 entry->cursor = index + trailing;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200697
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100698 entry->serial++;
699
700 text_model_reset(entry->model, entry->serial);
Jan Arne Petersenc1e481e2012-09-09 23:08:46 +0200701
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200702 text_entry_update_layout(entry);
703
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200704 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100705
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100706 text_entry_update(entry);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200707}
708
709static void
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200710text_entry_set_anchor_position(struct text_entry *entry,
711 int32_t x, int32_t y)
712{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100713 int index, trailing;
714
715 pango_layout_xy_to_index(entry->layout,
716 x * PANGO_SCALE, y * PANGO_SCALE,
717 &index, &trailing);
718 entry->anchor = index + trailing;
719
720 text_entry_update_layout(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200721
722 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100723
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100724 text_entry_update(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200725}
726
727static void
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200728text_entry_delete_text(struct text_entry *entry,
729 uint32_t index, uint32_t length)
730{
731 if (entry->cursor > index)
732 entry->cursor -= length;
733
Jan Arne Petersen80ad1a92012-09-17 15:28:10 +0200734 entry->anchor = entry->cursor;
735
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200736 entry->text[index] = '\0';
737 strcat(entry->text, entry->text + index + length);
738
739 text_entry_update_layout(entry);
740
741 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100742
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100743 text_entry_update(entry);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200744}
745
746static void
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200747text_entry_delete_selected_text(struct text_entry *entry)
748{
749 uint32_t start_index = entry->anchor < entry->cursor ? entry->anchor : entry->cursor;
750 uint32_t end_index = entry->anchor < entry->cursor ? entry->cursor : entry->anchor;
751
752 if (entry->anchor == entry->cursor)
753 return;
754
755 text_entry_delete_text(entry, start_index, end_index - start_index);
756
757 entry->anchor = entry->cursor;
758}
759
760static void
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200761text_entry_draw_cursor(struct text_entry *entry, cairo_t *cr)
762{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100763 PangoRectangle extents;
764 PangoRectangle cursor_pos;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200765
Jan Arne Petersen46535312013-01-16 21:26:38 +0100766 if (entry->preedit.text && entry->preedit.cursor < 0)
767 return;
768
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100769 pango_layout_get_extents(entry->layout, &extents, NULL);
770 pango_layout_get_cursor_pos(entry->layout,
771 entry->cursor + entry->preedit.cursor,
772 &cursor_pos, NULL);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200773
774 cairo_set_line_width(cr, 1.0);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100775 cairo_move_to(cr, PANGO_PIXELS(cursor_pos.x), PANGO_PIXELS(extents.height) + 2);
776 cairo_line_to(cr, PANGO_PIXELS(cursor_pos.x), - 2);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200777 cairo_stroke(cr);
778}
779
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200780static const int text_offset_left = 10;
781
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200782static void
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200783text_entry_redraw_handler(struct widget *widget, void *data)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200784{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200785 struct text_entry *entry = data;
786 cairo_surface_t *surface;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200787 struct rectangle allocation;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200788 cairo_t *cr;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200789
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200790 surface = window_get_surface(entry->window);
791 widget_get_allocation(entry->widget, &allocation);
792
793 cr = cairo_create(surface);
794 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
795 cairo_clip(cr);
796
797 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
798
799 cairo_push_group(cr);
800 cairo_translate(cr, allocation.x, allocation.y);
801
802 cairo_set_source_rgba(cr, 1, 1, 1, 1);
803 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
804 cairo_fill(cr);
805
806 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
807
808 if (entry->active) {
809 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
810 cairo_set_line_width (cr, 3);
811 cairo_set_source_rgba(cr, 0, 0, 1, 1.0);
812 cairo_stroke(cr);
813 }
814
815 cairo_set_source_rgba(cr, 0, 0, 0, 1);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200816
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200817 cairo_translate(cr, text_offset_left, allocation.height / 2);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200818
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100819 if (!entry->layout)
820 entry->layout = pango_cairo_create_layout(cr);
821 else
822 pango_cairo_update_layout(cr, entry->layout);
823
824 text_entry_update_layout(entry);
825
826 pango_cairo_show_layout(cr, entry->layout);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200827
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200828 text_entry_draw_cursor(entry, cr);
829
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200830 cairo_pop_group_to_source(cr);
831 cairo_paint(cr);
832
833 cairo_destroy(cr);
834 cairo_surface_destroy(surface);
835}
836
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200837static int
838text_entry_motion_handler(struct widget *widget,
839 struct input *input, uint32_t time,
840 float x, float y, void *data)
841{
842 struct text_entry *entry = data;
843 struct rectangle allocation;
844
845 widget_get_allocation(entry->widget, &allocation);
846
847 text_entry_set_cursor_position(entry,
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200848 x - allocation.x - text_offset_left,
849 y - allocation.y - text_offset_left);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200850
851 return CURSOR_IBEAM;
852}
853
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200854static void
855text_entry_button_handler(struct widget *widget,
856 struct input *input, uint32_t time,
857 uint32_t button,
858 enum wl_pointer_button_state state, void *data)
859{
860 struct text_entry *entry = data;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200861 struct rectangle allocation;
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100862 struct editor *editor;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200863 int32_t x, y;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100864 uint32_t result;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200865
866 widget_get_allocation(entry->widget, &allocation);
867 input_get_position(input, &x, &y);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200868
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100869 x -= allocation.x + text_offset_left;
870 y -= allocation.y + text_offset_left;
871
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100872 editor = window_get_user_data(entry->window);
873
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100874 result = text_entry_try_invoke_preedit_action(entry, x, y, button, state);
875
876 if (result)
877 return;
878
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200879 if (button != BTN_LEFT) {
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200880 return;
881 }
882
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100883 text_entry_set_cursor_position(entry, x, y);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200884
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200885 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
886 struct wl_seat *seat = input_get_seat(input);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200887
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200888 text_entry_activate(entry, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100889 editor->active_entry = entry;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200890
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100891 text_entry_set_anchor_position(entry, x, y);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200892
893 widget_set_motion_handler(entry->widget, text_entry_motion_handler);
894 } else {
895 widget_set_motion_handler(entry->widget, NULL);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200896 }
897}
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200898
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200899static void
900editor_button_handler(struct widget *widget,
901 struct input *input, uint32_t time,
902 uint32_t button,
903 enum wl_pointer_button_state state, void *data)
904{
905 struct editor *editor = data;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200906
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200907 if (button != BTN_LEFT) {
908 return;
909 }
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200910
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200911 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
912 struct wl_seat *seat = input_get_seat(input);
913
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200914 text_entry_deactivate(editor->entry, seat);
915 text_entry_deactivate(editor->editor, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100916 editor->active_entry = NULL;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200917 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200918}
919
920static void
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100921key_handler(struct window *window,
922 struct input *input, uint32_t time,
923 uint32_t key, uint32_t sym, enum wl_keyboard_key_state state,
924 void *data)
925{
926 struct editor *editor = data;
927 struct text_entry *entry;
928 const char *start, *end, *new_char;
929 char text[16];
930
931 if (!editor->active_entry)
932 return;
933
934 entry = editor->active_entry;
935
936 if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
937 return;
938
939 switch (sym) {
940 case XKB_KEY_BackSpace:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100941 text_entry_commit_and_reset(entry);
942
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100943 start = utf8_prev_char(entry->text, entry->text + entry->cursor);
944
945 if (start == NULL)
946 break;
947
948 end = utf8_end_char(entry->text + entry->cursor);
949 text_entry_delete_text(entry,
950 start - entry->text,
951 end - start);
952 break;
953 case XKB_KEY_Delete:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100954 text_entry_commit_and_reset(entry);
955
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100956 start = utf8_start_char(entry->text, entry->text + entry->cursor);
957
958 if (start == NULL)
959 break;
960
961 end = utf8_next_char(start);
962
963 if (end == NULL)
964 break;
965
966 text_entry_delete_text(entry,
967 start - entry->text,
968 end - start);
969 break;
970 case XKB_KEY_Left:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100971 text_entry_commit_and_reset(entry);
972
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100973 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
974 if (new_char != NULL) {
975 entry->cursor = new_char - entry->text;
976 entry->anchor = entry->cursor;
977 widget_schedule_redraw(entry->widget);
978 }
979 break;
980 case XKB_KEY_Right:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100981 text_entry_commit_and_reset(entry);
982
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100983 new_char = utf8_next_char(entry->text + entry->cursor);
984 if (new_char != NULL) {
985 entry->cursor = new_char - entry->text;
986 entry->anchor = entry->cursor;
987 widget_schedule_redraw(entry->widget);
988 }
989 break;
990 default:
991 if (xkb_keysym_to_utf8(sym, text, sizeof(text)) <= 0)
992 break;
993
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100994 text_entry_commit_and_reset(entry);
995
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100996 text_entry_insert_at_cursor(entry, text);
997 break;
998 }
999
1000 widget_schedule_redraw(entry->widget);
1001}
1002
1003static void
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001004global_handler(struct display *display, uint32_t name,
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001005 const char *interface, uint32_t version, void *data)
1006{
1007 struct editor *editor = data;
1008
Jan Arne Petersen51963742012-08-10 16:47:20 +02001009 if (!strcmp(interface, "text_model_factory")) {
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001010 editor->text_model_factory =
1011 display_bind(display, name,
1012 &text_model_factory_interface, 1);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001013 }
1014}
1015
1016int
1017main(int argc, char *argv[])
1018{
1019 struct editor editor;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001020 int i;
1021 uint32_t click_to_show = 0;
1022
1023 for (i = 1; i < argc; i++)
1024 if (strcmp("--click-to-show", argv[i]) == 0)
1025 click_to_show = 1;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001026
Jan Arne Petersen25f6db52012-11-05 03:26:40 +01001027 memset(&editor, 0, sizeof editor);
1028
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001029#ifdef HAVE_PANGO
1030 g_type_init();
1031#endif
1032
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001033 editor.display = display_create(argc, argv);
1034 if (editor.display == NULL) {
1035 fprintf(stderr, "failed to create display: %m\n");
1036 return -1;
1037 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001038
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001039 display_set_user_data(editor.display, &editor);
1040 display_set_global_handler(editor.display, global_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001041
1042 editor.window = window_create(editor.display);
1043 editor.widget = frame_create(editor.window, &editor);
1044
1045 editor.entry = text_entry_create(&editor, "Entry");
Jan Arne Petersen61381972013-01-31 15:52:21 +01001046 editor.entry->click_to_show = click_to_show;
Jan Arne Petersen0558a932013-01-16 21:26:45 +01001047 editor.editor = text_entry_create(&editor, "Numeric");
1048 editor.editor->content_purpose = TEXT_MODEL_CONTENT_PURPOSE_NUMBER;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001049 editor.editor->click_to_show = click_to_show;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001050
1051 window_set_title(editor.window, "Text Editor");
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001052 window_set_key_handler(editor.window, key_handler);
1053 window_set_user_data(editor.window, &editor);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001054
1055 widget_set_redraw_handler(editor.widget, redraw_handler);
1056 widget_set_resize_handler(editor.widget, resize_handler);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001057 widget_set_button_handler(editor.widget, editor_button_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001058
1059 window_schedule_resize(editor.window, 500, 400);
1060
1061 display_run(editor.display);
1062
1063 text_entry_destroy(editor.entry);
1064 text_entry_destroy(editor.editor);
1065
1066 return 0;
1067}