blob: 77764e253097355b76817ac2bce59d19d04d36fa [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
Philipp Brüschweiler591cfca2012-07-11 22:25:29 +020024#include <assert.h>
Jan Arne Petersencba9e472012-06-21 21:52:19 +020025#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28
29#include <linux/input.h>
30#include <cairo.h>
31
32#include "window.h"
33#include "text-client-protocol.h"
34
Jan Arne Petersenb9eb02c2012-09-09 23:08:35 +020035static const char *font_name = "sans-serif";
36static int font_size = 14;
37
38struct text_layout {
39 cairo_glyph_t *glyphs;
40 int num_glyphs;
41 cairo_text_cluster_t *clusters;
42 int num_clusters;
43 cairo_text_cluster_flags_t cluster_flags;
44 cairo_scaled_font_t *font;
45};
46
Jan Arne Petersencba9e472012-06-21 21:52:19 +020047struct text_entry {
48 struct widget *widget;
Jan Arne Petersene829adc2012-08-10 16:47:22 +020049 struct window *window;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020050 char *text;
51 int active;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +020052 uint32_t cursor;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +020053 uint32_t anchor;
Jan Arne Petersen46535312013-01-16 21:26:38 +010054 struct {
55 char *text;
56 int32_t cursor;
57 char *commit;
58 } preedit;
59 struct {
60 int32_t cursor;
61 } preedit_info;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020062 struct text_model *model;
Jan Arne Petersenb9eb02c2012-09-09 23:08:35 +020063 struct text_layout *layout;
Jan Arne Petersencd997062012-11-18 19:06:44 +010064 struct {
65 xkb_mod_mask_t shift_mask;
66 } keysym;
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +010067 uint32_t serial;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020068};
69
70struct editor {
Jan Arne Petersen51963742012-08-10 16:47:20 +020071 struct text_model_factory *text_model_factory;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020072 struct display *display;
73 struct window *window;
74 struct widget *widget;
75 struct text_entry *entry;
76 struct text_entry *editor;
Rob Bradford9d1d32b2012-11-18 19:06:49 +010077 struct text_entry *active_entry;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020078};
79
Jan Arne Petersen6345faa2012-11-05 03:26:39 +010080static const char *
81utf8_start_char(const char *text, const char *p)
82{
83 for (; p >= text; --p) {
84 if ((*p & 0xc0) != 0x80)
85 return p;
86 }
87 return NULL;
88}
89
90static const char *
91utf8_prev_char(const char *text, const char *p)
92{
93 if (p > text)
94 return utf8_start_char(text, --p);
95 return NULL;
96}
97
98static const char *
99utf8_end_char(const char *p)
100{
101 while ((*p & 0xc0) == 0x80)
102 p++;
103 return p;
104}
105
106static const char *
107utf8_next_char(const char *p)
108{
109 if (*p != 0)
110 return utf8_end_char(++p);
111 return NULL;
112}
113
Jan Arne Petersenb9eb02c2012-09-09 23:08:35 +0200114static struct text_layout *
115text_layout_create(void)
116{
117 struct text_layout *layout;
118 cairo_surface_t *surface;
119 cairo_t *cr;
120
121 layout = malloc(sizeof *layout);
122 if (!layout)
123 return NULL;
124
125 layout->glyphs = NULL;
126 layout->num_glyphs = 0;
127
128 layout->clusters = NULL;
129 layout->num_clusters = 0;
130
131 surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0);
132 cr = cairo_create(surface);
133 cairo_set_font_size(cr, font_size);
134 cairo_select_font_face(cr, font_name, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
135 layout->font = cairo_get_scaled_font(cr);
136 cairo_scaled_font_reference(layout->font);
137
138 cairo_destroy(cr);
139 cairo_surface_destroy(surface);
140
141 return layout;
142}
143
144static void
145text_layout_destroy(struct text_layout *layout)
146{
147 if (layout->glyphs)
148 cairo_glyph_free(layout->glyphs);
149
150 if (layout->clusters)
151 cairo_text_cluster_free(layout->clusters);
152
153 cairo_scaled_font_destroy(layout->font);
154
155 free(layout);
156}
157
158static void
159text_layout_set_text(struct text_layout *layout,
160 const char *text)
161{
162 if (layout->glyphs)
163 cairo_glyph_free(layout->glyphs);
164
165 if (layout->clusters)
166 cairo_text_cluster_free(layout->clusters);
167
168 layout->glyphs = NULL;
169 layout->num_glyphs = 0;
170 layout->clusters = NULL;
171 layout->num_clusters = 0;
172
173 cairo_scaled_font_text_to_glyphs(layout->font, 0, 0, text, -1,
174 &layout->glyphs, &layout->num_glyphs,
175 &layout->clusters, &layout->num_clusters,
176 &layout->cluster_flags);
177}
178
179static void
180text_layout_draw(struct text_layout *layout, cairo_t *cr)
181{
182 cairo_save(cr);
183 cairo_set_scaled_font(cr, layout->font);
184 cairo_show_glyphs(cr, layout->glyphs, layout->num_glyphs);
185 cairo_restore(cr);
186}
187
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200188static void
189text_layout_extents(struct text_layout *layout, cairo_text_extents_t *extents)
190{
191 cairo_scaled_font_glyph_extents(layout->font,
192 layout->glyphs, layout->num_glyphs,
193 extents);
194}
195
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100196static uint32_t
197bytes_from_glyphs(struct text_layout *layout, uint32_t index)
198{
199 int i;
200 uint32_t glyphs = 0, bytes = 0;
201
202 for (i = 0; i < layout->num_clusters && glyphs < index; i++) {
203 bytes += layout->clusters[i].num_bytes;
204 glyphs += layout->clusters[i].num_glyphs;
205 }
206
207 return bytes;
208}
209
210static uint32_t
211glyphs_from_bytes(struct text_layout *layout, uint32_t index)
212{
213 int i;
214 uint32_t glyphs = 0, bytes = 0;
215
216 for (i = 0; i < layout->num_clusters && bytes < index; i++) {
217 bytes += layout->clusters[i].num_bytes;
218 glyphs += layout->clusters[i].num_glyphs;
219 }
220
221 return glyphs;
222}
223
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200224static int
225text_layout_xy_to_index(struct text_layout *layout, double x, double y)
226{
227 cairo_text_extents_t extents;
228 int i;
Philipp Brüschweiler70f83672012-10-02 11:06:54 +0200229 double d;
230
231 if (layout->num_glyphs == 0)
232 return 0;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200233
234 cairo_scaled_font_glyph_extents(layout->font,
235 layout->glyphs, layout->num_glyphs,
236 &extents);
237
Philipp Brüschweiler70f83672012-10-02 11:06:54 +0200238 if (x < 0)
239 return 0;
240
241 for (i = 0; i < layout->num_glyphs - 1; ++i) {
242 d = layout->glyphs[i + 1].x - layout->glyphs[i].x;
243 if (x < layout->glyphs[i].x + d/2)
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100244 return bytes_from_glyphs(layout, i);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200245 }
246
Philipp Brüschweiler70f83672012-10-02 11:06:54 +0200247 d = extents.width - layout->glyphs[layout->num_glyphs - 1].x;
248 if (x < layout->glyphs[layout->num_glyphs - 1].x + d/2)
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100249 return bytes_from_glyphs(layout, layout->num_glyphs - 1);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200250
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100251 return bytes_from_glyphs(layout, layout->num_glyphs);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200252}
253
254static void
255text_layout_index_to_pos(struct text_layout *layout, uint32_t index, cairo_rectangle_t *pos)
256{
257 cairo_text_extents_t extents;
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100258 int glyph_index = glyphs_from_bytes(layout, index);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200259
260 if (!pos)
261 return;
262
263 cairo_scaled_font_glyph_extents(layout->font,
264 layout->glyphs, layout->num_glyphs,
265 &extents);
266
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100267 if (glyph_index >= layout->num_glyphs) {
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200268 pos->x = extents.x_advance;
269 pos->y = layout->num_glyphs ? layout->glyphs[layout->num_glyphs - 1].y : 0;
270 pos->width = 1;
271 pos->height = extents.height;
272 return;
273 }
274
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100275 pos->x = layout->glyphs[glyph_index].x;
276 pos->y = layout->glyphs[glyph_index].y;
277 pos->width = glyph_index < layout->num_glyphs - 1 ? layout->glyphs[glyph_index + 1].x : extents.x_advance - pos->x;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200278 pos->height = extents.height;
279}
280
281static void
282text_layout_get_cursor_pos(struct text_layout *layout, int index, cairo_rectangle_t *pos)
283{
284 text_layout_index_to_pos(layout, index, pos);
285 pos->width = 1;
286}
Jan Arne Petersenb9eb02c2012-09-09 23:08:35 +0200287
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200288static void text_entry_redraw_handler(struct widget *widget, void *data);
289static void text_entry_button_handler(struct widget *widget,
290 struct input *input, uint32_t time,
291 uint32_t button,
292 enum wl_pointer_button_state state, void *data);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200293static void text_entry_insert_at_cursor(struct text_entry *entry, const char *text);
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200294static void text_entry_set_preedit(struct text_entry *entry,
295 const char *preedit_text,
296 int preedit_cursor);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200297static void text_entry_delete_text(struct text_entry *entry,
298 uint32_t index, uint32_t length);
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200299static void text_entry_delete_selected_text(struct text_entry *entry);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100300static void text_entry_reset_preedit(struct text_entry *entry);
301static void text_entry_commit_and_reset(struct text_entry *entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200302
303static void
304text_model_commit_string(void *data,
305 struct text_model *text_model,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100306 uint32_t serial,
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200307 const char *text,
308 uint32_t index)
309{
310 struct text_entry *entry = data;
311
John Kåre Alsaker011a1ce2012-10-12 12:25:06 +0200312 if (index > strlen(text))
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200313 fprintf(stderr, "Invalid cursor index %d\n", index);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200314
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100315 text_entry_reset_preedit(entry);
316
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200317 text_entry_delete_selected_text(entry);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200318 text_entry_insert_at_cursor(entry, text);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200319
320 widget_schedule_redraw(entry->widget);
321}
322
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200323static void
324text_model_preedit_string(void *data,
325 struct text_model *text_model,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100326 uint32_t serial,
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200327 const char *text,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100328 const char *commit)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200329{
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200330 struct text_entry *entry = data;
331
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200332 text_entry_delete_selected_text(entry);
Jan Arne Petersen46535312013-01-16 21:26:38 +0100333 text_entry_set_preedit(entry, text, entry->preedit_info.cursor);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100334 entry->preedit.commit = strdup(commit);
335
336 entry->preedit_info.cursor = 0;
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200337
338 widget_schedule_redraw(entry->widget);
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200339}
340
341static void
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200342text_model_delete_surrounding_text(void *data,
343 struct text_model *text_model,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100344 uint32_t serial,
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200345 int32_t index,
346 uint32_t length)
347{
348 struct text_entry *entry = data;
349 uint32_t cursor_index = index + entry->cursor;
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100350 const char *start, *end;
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200351
352 if (cursor_index > strlen(entry->text)) {
353 fprintf(stderr, "Invalid cursor index %d\n", index);
354 return;
355 }
356
357 if (cursor_index + length > strlen(entry->text)) {
358 fprintf(stderr, "Invalid length %d\n", length);
359 return;
360 }
361
362 if (length == 0)
363 return;
364
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100365 start = utf8_start_char(entry->text, entry->text + cursor_index);
366 end = utf8_end_char(entry->text + cursor_index + length);
367
368 text_entry_delete_text(entry,
369 start - entry->text,
370 end - start);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200371}
372
373static void
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200374text_model_preedit_styling(void *data,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100375 struct text_model *text_model,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100376 uint32_t serial,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100377 uint32_t index,
378 uint32_t length,
379 uint32_t style)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200380{
381}
382
383static void
Jan Arne Petersen46535312013-01-16 21:26:38 +0100384text_model_preedit_cursor(void *data,
385 struct text_model *text_model,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100386 uint32_t serial,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100387 int32_t index)
388{
389 struct text_entry *entry = data;
390
391 entry->preedit_info.cursor = index;
392}
393
394static void
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100395text_model_modifiers_map(void *data,
396 struct text_model *text_model,
397 struct wl_array *map)
398{
Jan Arne Petersencd997062012-11-18 19:06:44 +0100399 struct text_entry *entry = data;
400
401 entry->keysym.shift_mask = keysym_modifiers_get_mask(map, "Shift");
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100402}
403
404static void
405text_model_keysym(void *data,
406 struct text_model *text_model,
407 uint32_t serial,
408 uint32_t time,
409 uint32_t key,
410 uint32_t state,
411 uint32_t modifiers)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200412{
Jan Arne Petersen8aba11d2012-09-17 15:28:07 +0200413 struct text_entry *entry = data;
Jan Arne Petersencd997062012-11-18 19:06:44 +0100414 const char *state_label = "release";
415 const char *key_label = "Unknown";
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100416 const char *new_char;
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200417
418 if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
419 state_label = "pressed";
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200420 }
421
Jan Arne Petersencd997062012-11-18 19:06:44 +0100422 if (key == XKB_KEY_Left ||
423 key == XKB_KEY_Right) {
424 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
425 return;
426
427 if (key == XKB_KEY_Left)
428 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
429 else
430 new_char = utf8_next_char(entry->text + entry->cursor);
431
432 if (new_char != NULL) {
433 entry->cursor = new_char - entry->text;
434 if (!(modifiers & entry->keysym.shift_mask))
435 entry->anchor = entry->cursor;
436 widget_schedule_redraw(entry->widget);
437 }
438
439 return;
440 }
441
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200442 switch (key) {
443 case XKB_KEY_Tab:
444 key_label = "Tab";
445 break;
446 case XKB_KEY_KP_Enter:
Jan Arne Petersencd997062012-11-18 19:06:44 +0100447 case XKB_KEY_Return:
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200448 key_label = "Enter";
449 break;
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200450 }
451
452 fprintf(stderr, "%s key was %s.\n", key_label, state_label);
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200453}
454
455static void
456text_model_selection_replacement(void *data,
457 struct text_model *text_model)
458{
459}
460
461static void
462text_model_direction(void *data,
463 struct text_model *text_model)
464{
465}
466
467static void
468text_model_locale(void *data,
469 struct text_model *text_model)
470{
471}
472
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200473static void
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200474text_model_enter(void *data,
475 struct text_model *text_model,
476 struct wl_surface *surface)
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200477{
478 struct text_entry *entry = data;
479
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200480 if (surface != window_get_wl_surface(entry->window))
481 return;
482
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200483 entry->active = 1;
484
485 widget_schedule_redraw(entry->widget);
486}
487
488static void
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200489text_model_leave(void *data,
490 struct text_model *text_model)
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200491{
492 struct text_entry *entry = data;
493
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100494 text_entry_commit_and_reset(entry);
495
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200496 entry->active = 0;
497
498 widget_schedule_redraw(entry->widget);
499}
500
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200501static const struct text_model_listener text_model_listener = {
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200502 text_model_commit_string,
503 text_model_preedit_string,
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200504 text_model_delete_surrounding_text,
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200505 text_model_preedit_styling,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100506 text_model_preedit_cursor,
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100507 text_model_modifiers_map,
508 text_model_keysym,
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200509 text_model_selection_replacement,
510 text_model_direction,
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200511 text_model_locale,
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200512 text_model_enter,
513 text_model_leave
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200514};
515
516static struct text_entry*
517text_entry_create(struct editor *editor, const char *text)
518{
519 struct text_entry *entry;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200520
Jan Arne Petersencd997062012-11-18 19:06:44 +0100521 entry = calloc(1, sizeof *entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200522
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200523 entry->widget = widget_add_widget(editor->widget, entry);
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200524 entry->window = editor->window;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200525 entry->text = strdup(text);
526 entry->active = 0;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200527 entry->cursor = strlen(text);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200528 entry->anchor = entry->cursor;
Jan Arne Petersen4c265182012-09-09 23:08:30 +0200529 entry->model = text_model_factory_create_text_model(editor->text_model_factory);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200530 text_model_add_listener(entry->model, &text_model_listener, entry);
531
Jan Arne Petersenb9eb02c2012-09-09 23:08:35 +0200532 entry->layout = text_layout_create();
533 text_layout_set_text(entry->layout, entry->text);
534
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200535 widget_set_redraw_handler(entry->widget, text_entry_redraw_handler);
536 widget_set_button_handler(entry->widget, text_entry_button_handler);
537
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200538 return entry;
539}
540
541static void
542text_entry_destroy(struct text_entry *entry)
543{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200544 widget_destroy(entry->widget);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200545 text_model_destroy(entry->model);
Jan Arne Petersenb9eb02c2012-09-09 23:08:35 +0200546 text_layout_destroy(entry->layout);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200547 free(entry->text);
548 free(entry);
549}
550
551static void
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200552redraw_handler(struct widget *widget, void *data)
553{
554 struct editor *editor = data;
555 cairo_surface_t *surface;
556 struct rectangle allocation;
557 cairo_t *cr;
558
559 surface = window_get_surface(editor->window);
560 widget_get_allocation(editor->widget, &allocation);
561
562 cr = cairo_create(surface);
563 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
564 cairo_clip(cr);
565
566 cairo_translate(cr, allocation.x, allocation.y);
567
568 /* Draw background */
569 cairo_push_group(cr);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200570 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200571 cairo_set_source_rgba(cr, 1, 1, 1, 1);
572 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
573 cairo_fill(cr);
574
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200575 cairo_pop_group_to_source(cr);
576 cairo_paint(cr);
577
578 cairo_destroy(cr);
579 cairo_surface_destroy(surface);
580}
581
582static void
583text_entry_allocate(struct text_entry *entry, int32_t x, int32_t y,
584 int32_t width, int32_t height)
585{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200586 widget_set_allocation(entry->widget, x, y, width, height);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200587}
588
589static void
590resize_handler(struct widget *widget,
591 int32_t width, int32_t height, void *data)
592{
593 struct editor *editor = data;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200594 struct rectangle allocation;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200595
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200596 widget_get_allocation(editor->widget, &allocation);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200597
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200598 text_entry_allocate(editor->entry,
599 allocation.x + 20, allocation.y + 20,
600 width - 40, height / 2 - 40);
601 text_entry_allocate(editor->editor,
602 allocation.x + 20, allocation.y + height / 2 + 20,
603 width - 40, height / 2 - 40);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200604}
605
606static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200607text_entry_activate(struct text_entry *entry,
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200608 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200609{
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200610 struct wl_surface *surface = window_get_wl_surface(entry->window);
611
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100612 entry->serial++;
613
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200614 text_model_activate(entry->model,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100615 entry->serial,
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200616 seat,
617 surface);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200618}
619
620static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200621text_entry_deactivate(struct text_entry *entry,
622 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200623{
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200624 text_model_deactivate(entry->model,
625 seat);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200626}
627
628static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200629text_entry_update_layout(struct text_entry *entry)
630{
631 char *text;
632
Philipp Brüschweiler237358b2012-10-02 11:06:51 +0200633 assert(((unsigned int)entry->cursor) <= strlen(entry->text) +
Jan Arne Petersen46535312013-01-16 21:26:38 +0100634 (entry->preedit.text ? strlen(entry->preedit.text) : 0));
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200635
Jan Arne Petersen46535312013-01-16 21:26:38 +0100636 if (!entry->preedit.text) {
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200637 text_layout_set_text(entry->layout, entry->text);
638 return;
639 }
640
Jan Arne Petersen46535312013-01-16 21:26:38 +0100641 text = malloc(strlen(entry->text) + strlen(entry->preedit.text) + 1);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200642 strncpy(text, entry->text, entry->cursor);
Jan Arne Petersen46535312013-01-16 21:26:38 +0100643 strcpy(text + entry->cursor, entry->preedit.text);
644 strcpy(text + entry->cursor + strlen(entry->preedit.text),
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200645 entry->text + entry->cursor);
646
647 text_layout_set_text(entry->layout, text);
648 free(text);
649
650 widget_schedule_redraw(entry->widget);
Jan Arne Petersencb08f4d2012-09-09 23:08:40 +0200651
652 text_model_set_surrounding_text(entry->model,
653 entry->text,
654 entry->cursor,
655 entry->anchor);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200656}
657
658static void
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200659text_entry_insert_at_cursor(struct text_entry *entry, const char *text)
660{
661 char *new_text = malloc(strlen(entry->text) + strlen(text) + 1);
662
663 strncpy(new_text, entry->text, entry->cursor);
664 strcpy(new_text + entry->cursor, text);
665 strcpy(new_text + entry->cursor + strlen(text),
666 entry->text + entry->cursor);
667
668 free(entry->text);
669 entry->text = new_text;
670 entry->cursor += strlen(text);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200671 entry->anchor += strlen(text);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200672
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200673 text_entry_update_layout(entry);
674}
675
676static void
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100677text_entry_reset_preedit(struct text_entry *entry)
678{
679 entry->preedit.cursor = 0;
680
681 free(entry->preedit.text);
682 entry->preedit.text = NULL;
683
684 free(entry->preedit.commit);
685 entry->preedit.commit = NULL;
686}
687
688static void
689text_entry_commit_and_reset(struct text_entry *entry)
690{
691 char *commit = NULL;
692
693 if (entry->preedit.commit)
694 commit = strdup(entry->preedit.commit);
695
696 text_entry_reset_preedit(entry);
697 if (commit) {
698 text_entry_insert_at_cursor(entry, commit);
699 free(commit);
700 }
701}
702
703static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200704text_entry_set_preedit(struct text_entry *entry,
705 const char *preedit_text,
706 int preedit_cursor)
707{
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100708 text_entry_reset_preedit(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200709
710 if (!preedit_text)
711 return;
712
Jan Arne Petersen46535312013-01-16 21:26:38 +0100713 entry->preedit.text = strdup(preedit_text);
714 entry->preedit.cursor = preedit_cursor;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200715
716 text_entry_update_layout(entry);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200717}
718
719static void
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200720text_entry_set_cursor_position(struct text_entry *entry,
721 int32_t x, int32_t y)
722{
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100723 text_entry_commit_and_reset(entry);
724
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200725 entry->cursor = text_layout_xy_to_index(entry->layout, x, y);
726
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100727 entry->serial++;
728
729 text_model_reset(entry->model, entry->serial);
Jan Arne Petersenc1e481e2012-09-09 23:08:46 +0200730
Jan Arne Petersen46535312013-01-16 21:26:38 +0100731 if (entry->preedit.cursor > 0 &&
732 entry->cursor >= (uint32_t)entry->preedit.cursor) {
733 entry->cursor -= entry->preedit.cursor;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200734 }
735
736 text_entry_update_layout(entry);
737
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200738 widget_schedule_redraw(entry->widget);
739}
740
741static void
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200742text_entry_set_anchor_position(struct text_entry *entry,
743 int32_t x, int32_t y)
744{
745 entry->anchor = text_layout_xy_to_index(entry->layout, x, y);
746
747 widget_schedule_redraw(entry->widget);
748}
749
750static void
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200751text_entry_delete_text(struct text_entry *entry,
752 uint32_t index, uint32_t length)
753{
754 if (entry->cursor > index)
755 entry->cursor -= length;
756
Jan Arne Petersen80ad1a92012-09-17 15:28:10 +0200757 entry->anchor = entry->cursor;
758
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200759 entry->text[index] = '\0';
760 strcat(entry->text, entry->text + index + length);
761
762 text_entry_update_layout(entry);
763
764 widget_schedule_redraw(entry->widget);
765}
766
767static void
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200768text_entry_delete_selected_text(struct text_entry *entry)
769{
770 uint32_t start_index = entry->anchor < entry->cursor ? entry->anchor : entry->cursor;
771 uint32_t end_index = entry->anchor < entry->cursor ? entry->cursor : entry->anchor;
772
773 if (entry->anchor == entry->cursor)
774 return;
775
776 text_entry_delete_text(entry, start_index, end_index - start_index);
777
778 entry->anchor = entry->cursor;
779}
780
781static void
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200782text_entry_draw_selection(struct text_entry *entry, cairo_t *cr)
783{
784 cairo_text_extents_t extents;
785 uint32_t start_index = entry->anchor < entry->cursor ? entry->anchor : entry->cursor;
786 uint32_t end_index = entry->anchor < entry->cursor ? entry->cursor : entry->anchor;
787 cairo_rectangle_t start;
788 cairo_rectangle_t end;
789
790 if (entry->anchor == entry->cursor)
791 return;
792
793 text_layout_extents(entry->layout, &extents);
794
795 text_layout_index_to_pos(entry->layout, start_index, &start);
796 text_layout_index_to_pos(entry->layout, end_index, &end);
797
798 cairo_save (cr);
799
Philipp Brüschweilerb8911dc2012-10-02 11:06:52 +0200800 cairo_set_source_rgba(cr, 0.3, 0.3, 1.0, 0.5);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200801 cairo_rectangle(cr,
802 start.x, extents.y_bearing + extents.height + 2,
803 end.x - start.x, -extents.height - 4);
804 cairo_fill(cr);
805
806 cairo_rectangle(cr,
807 start.x, extents.y_bearing + extents.height,
808 end.x - start.x, -extents.height);
809 cairo_clip(cr);
810 cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
811 text_layout_draw(entry->layout, cr);
812
813 cairo_restore (cr);
814}
815
816static void
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200817text_entry_draw_cursor(struct text_entry *entry, cairo_t *cr)
818{
819 cairo_text_extents_t extents;
820 cairo_rectangle_t cursor_pos;
821
Jan Arne Petersen46535312013-01-16 21:26:38 +0100822 if (entry->preedit.text && entry->preedit.cursor < 0)
823 return;
824
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200825 text_layout_extents(entry->layout, &extents);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200826 text_layout_get_cursor_pos(entry->layout,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100827 entry->cursor + entry->preedit.cursor,
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200828 &cursor_pos);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200829
830 cairo_set_line_width(cr, 1.0);
831 cairo_move_to(cr, cursor_pos.x, extents.y_bearing + extents.height + 2);
832 cairo_line_to(cr, cursor_pos.x, extents.y_bearing - 2);
833 cairo_stroke(cr);
834}
835
836static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200837text_entry_draw_preedit(struct text_entry *entry, cairo_t *cr)
838{
839 cairo_text_extents_t extents;
840 cairo_rectangle_t start;
841 cairo_rectangle_t end;
842
Jan Arne Petersen46535312013-01-16 21:26:38 +0100843 if (!entry->preedit.text)
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200844 return;
845
846 text_layout_extents(entry->layout, &extents);
847
848 text_layout_index_to_pos(entry->layout, entry->cursor, &start);
849 text_layout_index_to_pos(entry->layout,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100850 entry->cursor + strlen(entry->preedit.text),
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200851 &end);
852
853 cairo_save (cr);
854
855 cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
856 cairo_rectangle(cr,
857 start.x, 0,
858 end.x - start.x, 1);
859 cairo_fill(cr);
860
861 cairo_restore (cr);
862}
863
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200864static const int text_offset_left = 10;
865
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200866static void
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200867text_entry_redraw_handler(struct widget *widget, void *data)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200868{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200869 struct text_entry *entry = data;
870 cairo_surface_t *surface;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200871 struct rectangle allocation;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200872 cairo_t *cr;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200873
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200874 surface = window_get_surface(entry->window);
875 widget_get_allocation(entry->widget, &allocation);
876
877 cr = cairo_create(surface);
878 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
879 cairo_clip(cr);
880
881 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
882
883 cairo_push_group(cr);
884 cairo_translate(cr, allocation.x, allocation.y);
885
886 cairo_set_source_rgba(cr, 1, 1, 1, 1);
887 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
888 cairo_fill(cr);
889
890 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
891
892 if (entry->active) {
893 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
894 cairo_set_line_width (cr, 3);
895 cairo_set_source_rgba(cr, 0, 0, 1, 1.0);
896 cairo_stroke(cr);
897 }
898
899 cairo_set_source_rgba(cr, 0, 0, 0, 1);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200900
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200901 cairo_translate(cr, text_offset_left, allocation.height / 2);
Jan Arne Petersenb9eb02c2012-09-09 23:08:35 +0200902 text_layout_draw(entry->layout, cr);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200903
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200904 text_entry_draw_selection(entry, cr);
905
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200906 text_entry_draw_cursor(entry, cr);
907
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200908 text_entry_draw_preedit(entry, cr);
909
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200910 cairo_pop_group_to_source(cr);
911 cairo_paint(cr);
912
913 cairo_destroy(cr);
914 cairo_surface_destroy(surface);
915}
916
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200917static int
918text_entry_motion_handler(struct widget *widget,
919 struct input *input, uint32_t time,
920 float x, float y, void *data)
921{
922 struct text_entry *entry = data;
923 struct rectangle allocation;
924
925 widget_get_allocation(entry->widget, &allocation);
926
927 text_entry_set_cursor_position(entry,
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200928 x - allocation.x - text_offset_left,
929 y - allocation.y - text_offset_left);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200930
931 return CURSOR_IBEAM;
932}
933
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200934static void
935text_entry_button_handler(struct widget *widget,
936 struct input *input, uint32_t time,
937 uint32_t button,
938 enum wl_pointer_button_state state, void *data)
939{
940 struct text_entry *entry = data;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200941 struct rectangle allocation;
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100942 struct editor *editor;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200943 int32_t x, y;
944
945 widget_get_allocation(entry->widget, &allocation);
946 input_get_position(input, &x, &y);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200947
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100948 editor = window_get_user_data(entry->window);
949
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200950 if (button != BTN_LEFT) {
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200951 return;
952 }
953
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200954 text_entry_set_cursor_position(entry,
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200955 x - allocation.x - text_offset_left,
956 y - allocation.y - text_offset_left);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200957
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200958 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
959 struct wl_seat *seat = input_get_seat(input);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200960
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200961 text_entry_activate(entry, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100962 editor->active_entry = entry;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200963
964 text_entry_set_anchor_position(entry,
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200965 x - allocation.x - text_offset_left,
966 y - allocation.y - text_offset_left);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200967
968 widget_set_motion_handler(entry->widget, text_entry_motion_handler);
969 } else {
970 widget_set_motion_handler(entry->widget, NULL);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200971 }
972}
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200973
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200974static void
975editor_button_handler(struct widget *widget,
976 struct input *input, uint32_t time,
977 uint32_t button,
978 enum wl_pointer_button_state state, void *data)
979{
980 struct editor *editor = data;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200981
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200982 if (button != BTN_LEFT) {
983 return;
984 }
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200985
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200986 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
987 struct wl_seat *seat = input_get_seat(input);
988
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200989 text_entry_deactivate(editor->entry, seat);
990 text_entry_deactivate(editor->editor, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100991 editor->active_entry = NULL;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200992 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200993}
994
995static void
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100996key_handler(struct window *window,
997 struct input *input, uint32_t time,
998 uint32_t key, uint32_t sym, enum wl_keyboard_key_state state,
999 void *data)
1000{
1001 struct editor *editor = data;
1002 struct text_entry *entry;
1003 const char *start, *end, *new_char;
1004 char text[16];
1005
1006 if (!editor->active_entry)
1007 return;
1008
1009 entry = editor->active_entry;
1010
1011 if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
1012 return;
1013
1014 switch (sym) {
1015 case XKB_KEY_BackSpace:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001016 text_entry_commit_and_reset(entry);
1017
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001018 start = utf8_prev_char(entry->text, entry->text + entry->cursor);
1019
1020 if (start == NULL)
1021 break;
1022
1023 end = utf8_end_char(entry->text + entry->cursor);
1024 text_entry_delete_text(entry,
1025 start - entry->text,
1026 end - start);
1027 break;
1028 case XKB_KEY_Delete:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001029 text_entry_commit_and_reset(entry);
1030
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001031 start = utf8_start_char(entry->text, entry->text + entry->cursor);
1032
1033 if (start == NULL)
1034 break;
1035
1036 end = utf8_next_char(start);
1037
1038 if (end == NULL)
1039 break;
1040
1041 text_entry_delete_text(entry,
1042 start - entry->text,
1043 end - start);
1044 break;
1045 case XKB_KEY_Left:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001046 text_entry_commit_and_reset(entry);
1047
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001048 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
1049 if (new_char != NULL) {
1050 entry->cursor = new_char - entry->text;
1051 entry->anchor = entry->cursor;
1052 widget_schedule_redraw(entry->widget);
1053 }
1054 break;
1055 case XKB_KEY_Right:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001056 text_entry_commit_and_reset(entry);
1057
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001058 new_char = utf8_next_char(entry->text + entry->cursor);
1059 if (new_char != NULL) {
1060 entry->cursor = new_char - entry->text;
1061 entry->anchor = entry->cursor;
1062 widget_schedule_redraw(entry->widget);
1063 }
1064 break;
1065 default:
1066 if (xkb_keysym_to_utf8(sym, text, sizeof(text)) <= 0)
1067 break;
1068
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001069 text_entry_commit_and_reset(entry);
1070
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001071 text_entry_insert_at_cursor(entry, text);
1072 break;
1073 }
1074
1075 widget_schedule_redraw(entry->widget);
1076}
1077
1078static void
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001079global_handler(struct display *display, uint32_t name,
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001080 const char *interface, uint32_t version, void *data)
1081{
1082 struct editor *editor = data;
1083
Jan Arne Petersen51963742012-08-10 16:47:20 +02001084 if (!strcmp(interface, "text_model_factory")) {
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001085 editor->text_model_factory =
1086 display_bind(display, name,
1087 &text_model_factory_interface, 1);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001088 }
1089}
1090
1091int
1092main(int argc, char *argv[])
1093{
1094 struct editor editor;
1095
Jan Arne Petersen25f6db52012-11-05 03:26:40 +01001096 memset(&editor, 0, sizeof editor);
1097
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001098 editor.display = display_create(argc, argv);
1099 if (editor.display == NULL) {
1100 fprintf(stderr, "failed to create display: %m\n");
1101 return -1;
1102 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001103
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001104 display_set_user_data(editor.display, &editor);
1105 display_set_global_handler(editor.display, global_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001106
1107 editor.window = window_create(editor.display);
1108 editor.widget = frame_create(editor.window, &editor);
1109
1110 editor.entry = text_entry_create(&editor, "Entry");
1111 editor.editor = text_entry_create(&editor, "Editor");
1112
1113 window_set_title(editor.window, "Text Editor");
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001114 window_set_key_handler(editor.window, key_handler);
1115 window_set_user_data(editor.window, &editor);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001116
1117 widget_set_redraw_handler(editor.widget, redraw_handler);
1118 widget_set_resize_handler(editor.widget, resize_handler);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001119 widget_set_button_handler(editor.widget, editor_button_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001120
1121 window_schedule_resize(editor.window, 500, 400);
1122
1123 display_run(editor.display);
1124
1125 text_entry_destroy(editor.entry);
1126 text_entry_destroy(editor.editor);
1127
1128 return 0;
1129}