text: Add delete_surrounding_text to protocol
[profile/ivi/weston.git] / clients / editor.c
1 /*
2  * Copyright © 2012 Openismus GmbH
3  * Copyright © 2012 Intel Corporation
4  *
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
24 #include <assert.h>
25 #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
35 static const char *font_name = "sans-serif";
36 static int font_size = 14;
37
38 struct 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
47 struct text_entry {
48         struct widget *widget;
49         struct window *window;
50         char *text;
51         int active;
52         uint32_t cursor;
53         uint32_t anchor;
54         char *preedit_text;
55         uint32_t preedit_cursor;
56         struct text_model *model;
57         struct text_layout *layout;
58 };
59
60 struct editor {
61         struct text_model_factory *text_model_factory;
62         struct display *display;
63         struct window *window;
64         struct widget *widget;
65         struct text_entry *entry;
66         struct text_entry *editor;
67 };
68
69 static struct text_layout *
70 text_layout_create(void)
71 {
72         struct text_layout *layout;
73         cairo_surface_t *surface;
74         cairo_t *cr;
75
76         layout = malloc(sizeof *layout);
77         if (!layout)
78                 return NULL;
79
80         layout->glyphs = NULL;
81         layout->num_glyphs = 0;
82
83         layout->clusters = NULL;
84         layout->num_clusters = 0;
85
86         surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 0, 0);
87         cr = cairo_create(surface);
88         cairo_set_font_size(cr, font_size);
89         cairo_select_font_face(cr, font_name, CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
90         layout->font = cairo_get_scaled_font(cr);
91         cairo_scaled_font_reference(layout->font);
92
93         cairo_destroy(cr);
94         cairo_surface_destroy(surface);
95
96         return layout;
97 }
98
99 static void
100 text_layout_destroy(struct text_layout *layout)
101 {
102         if (layout->glyphs)
103                 cairo_glyph_free(layout->glyphs);
104
105         if (layout->clusters)
106                 cairo_text_cluster_free(layout->clusters);
107
108         cairo_scaled_font_destroy(layout->font);
109
110         free(layout);
111 }
112
113 static void
114 text_layout_set_text(struct text_layout *layout,
115                      const char *text)
116 {
117         if (layout->glyphs)
118                 cairo_glyph_free(layout->glyphs);
119
120         if (layout->clusters)
121                 cairo_text_cluster_free(layout->clusters);
122
123         layout->glyphs = NULL;
124         layout->num_glyphs = 0;
125         layout->clusters = NULL;
126         layout->num_clusters = 0;
127
128         cairo_scaled_font_text_to_glyphs(layout->font, 0, 0, text, -1,
129                                          &layout->glyphs, &layout->num_glyphs,
130                                          &layout->clusters, &layout->num_clusters,
131                                          &layout->cluster_flags);
132 }
133
134 static void
135 text_layout_draw(struct text_layout *layout, cairo_t *cr)
136 {
137         cairo_save(cr);
138         cairo_set_scaled_font(cr, layout->font);
139         cairo_show_glyphs(cr, layout->glyphs, layout->num_glyphs);
140         cairo_restore(cr);
141 }
142
143 static void
144 text_layout_extents(struct text_layout *layout, cairo_text_extents_t *extents)
145 {
146         cairo_scaled_font_glyph_extents(layout->font,
147                                         layout->glyphs, layout->num_glyphs,
148                                         extents);
149 }
150
151 static int
152 text_layout_xy_to_index(struct text_layout *layout, double x, double y)
153 {
154         cairo_text_extents_t extents;
155         int i;
156
157         cairo_scaled_font_glyph_extents(layout->font,
158                                         layout->glyphs, layout->num_glyphs,
159                                         &extents);
160
161         for (i = 1; i < layout->num_glyphs; i++) {
162                 if (layout->glyphs[i].x >= x) {
163                         return i - 1;
164                 }
165         }
166
167         if (x >= layout->glyphs[layout->num_glyphs - 1].x && x < extents.width)
168                 return layout->num_glyphs - 1;
169
170         return layout->num_glyphs;
171 }
172
173 static void
174 text_layout_index_to_pos(struct text_layout *layout, uint32_t index, cairo_rectangle_t *pos)
175 {
176         cairo_text_extents_t extents;
177
178         if (!pos)
179                 return;
180
181         cairo_scaled_font_glyph_extents(layout->font,
182                                         layout->glyphs, layout->num_glyphs,
183                                         &extents);
184
185         if ((int)index >= layout->num_glyphs) {
186                 pos->x = extents.x_advance;
187                 pos->y = layout->num_glyphs ? layout->glyphs[layout->num_glyphs - 1].y : 0;
188                 pos->width = 1;
189                 pos->height = extents.height;
190                 return;
191         }
192
193         pos->x = layout->glyphs[index].x;
194         pos->y = layout->glyphs[index].y;
195         pos->width = (int)index < layout->num_glyphs - 1 ? layout->glyphs[index + 1].x : extents.x_advance - pos->x;
196         pos->height = extents.height;
197 }
198
199 static void
200 text_layout_get_cursor_pos(struct text_layout *layout, int index, cairo_rectangle_t *pos)
201 {
202         text_layout_index_to_pos(layout, index, pos);
203         pos->width = 1;
204 }
205
206 static void text_entry_redraw_handler(struct widget *widget, void *data);
207 static void text_entry_button_handler(struct widget *widget,
208                                       struct input *input, uint32_t time,
209                                       uint32_t button,
210                                       enum wl_pointer_button_state state, void *data);
211 static void text_entry_insert_at_cursor(struct text_entry *entry, const char *text);
212 static void text_entry_set_preedit(struct text_entry *entry,
213                                    const char *preedit_text,
214                                    int preedit_cursor);
215 static void text_entry_delete_text(struct text_entry *entry,
216                                    uint32_t index, uint32_t length);
217
218 static void
219 text_model_commit_string(void *data,
220                          struct text_model *text_model,
221                          const char *text,
222                          uint32_t index)
223 {
224         struct text_entry *entry = data;
225
226         if (index > strlen(text)) {
227                 fprintf(stderr, "Invalid cursor index %d\n", index);
228                 index = strlen(text);
229         }
230
231         text_entry_insert_at_cursor(entry, text);
232
233         widget_schedule_redraw(entry->widget);
234 }
235
236 static void
237 text_model_preedit_string(void *data,
238                           struct text_model *text_model,
239                           const char *text,
240                           uint32_t index)
241 {
242         struct text_entry *entry = data;
243
244         if (index > strlen(text)) {
245                 fprintf(stderr, "Invalid cursor index %d\n", index);
246                 index = strlen(text);
247         }
248
249         text_entry_set_preedit(entry, text, index);
250
251         widget_schedule_redraw(entry->widget);
252 }
253
254 static void
255 text_model_delete_surrounding_text(void *data,
256                                    struct text_model *text_model,
257                                    int32_t index,
258                                    uint32_t length)
259 {
260         struct text_entry *entry = data;
261         uint32_t cursor_index = index + entry->cursor;
262
263         if (cursor_index > strlen(entry->text)) {
264                 fprintf(stderr, "Invalid cursor index %d\n", index);
265                 return;
266         }
267
268         if (cursor_index + length > strlen(entry->text)) {
269                 fprintf(stderr, "Invalid length %d\n", length);
270                 return;
271         }
272
273         if (length == 0)
274                 return;
275
276         text_entry_delete_text(entry, cursor_index, length);
277 }
278
279 static void
280 text_model_preedit_styling(void *data,
281                            struct text_model *text_model)
282 {
283 }
284
285 static void
286 text_model_key(void *data,
287                struct text_model *text_model)
288 {
289 }
290
291 static void
292 text_model_selection_replacement(void *data,
293                                  struct text_model *text_model)
294 {
295 }
296
297 static void
298 text_model_direction(void *data,
299                      struct text_model *text_model)
300 {
301 }
302
303 static void
304 text_model_locale(void *data,
305                   struct text_model *text_model)
306 {
307 }
308
309 static void
310 text_model_activated(void *data,
311                      struct text_model *text_model)
312 {
313         struct text_entry *entry = data;
314
315         entry->active = 1;
316
317         widget_schedule_redraw(entry->widget);
318 }
319
320 static void
321 text_model_deactivated(void *data,
322                        struct text_model *text_model)
323 {
324         struct text_entry *entry = data;
325
326         entry->active = 0;
327
328         widget_schedule_redraw(entry->widget);
329 }
330
331 static const struct text_model_listener text_model_listener = {
332         text_model_commit_string,
333         text_model_preedit_string,
334         text_model_delete_surrounding_text,
335         text_model_preedit_styling,
336         text_model_key,
337         text_model_selection_replacement,
338         text_model_direction,
339         text_model_locale,
340         text_model_activated,
341         text_model_deactivated
342 };
343
344 static struct text_entry*
345 text_entry_create(struct editor *editor, const char *text)
346 {
347         struct text_entry *entry;
348
349         entry = malloc(sizeof *entry);
350
351         entry->widget = widget_add_widget(editor->widget, entry);
352         entry->window = editor->window;
353         entry->text = strdup(text);
354         entry->active = 0;
355         entry->cursor = strlen(text);
356         entry->anchor = entry->cursor;
357         entry->preedit_text = NULL;
358         entry->preedit_cursor = 0;
359         entry->model = text_model_factory_create_text_model(editor->text_model_factory);
360         text_model_add_listener(entry->model, &text_model_listener, entry);
361
362         entry->layout = text_layout_create();
363         text_layout_set_text(entry->layout, entry->text);
364
365         widget_set_redraw_handler(entry->widget, text_entry_redraw_handler);
366         widget_set_button_handler(entry->widget, text_entry_button_handler);
367
368         return entry;
369 }
370
371 static void
372 text_entry_destroy(struct text_entry *entry)
373 {
374         widget_destroy(entry->widget);
375         text_model_destroy(entry->model);
376         text_layout_destroy(entry->layout);
377         free(entry->text);
378         free(entry);
379 }
380
381 static void
382 redraw_handler(struct widget *widget, void *data)
383 {
384         struct editor *editor = data;
385         cairo_surface_t *surface;
386         struct rectangle allocation;
387         cairo_t *cr;
388
389         surface = window_get_surface(editor->window);
390         widget_get_allocation(editor->widget, &allocation);
391
392         cr = cairo_create(surface);
393         cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
394         cairo_clip(cr);
395
396         cairo_translate(cr, allocation.x, allocation.y);
397
398         /* Draw background */
399         cairo_push_group(cr);
400         cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
401         cairo_set_source_rgba(cr, 1, 1, 1, 1);
402         cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
403         cairo_fill(cr);
404
405         cairo_pop_group_to_source(cr);
406         cairo_paint(cr);
407
408         cairo_destroy(cr);
409         cairo_surface_destroy(surface);
410 }
411
412 static void
413 text_entry_allocate(struct text_entry *entry, int32_t x, int32_t y,
414                     int32_t width, int32_t height)
415 {
416         widget_set_allocation(entry->widget, x, y, width, height);
417 }
418
419 static void
420 resize_handler(struct widget *widget,
421                int32_t width, int32_t height, void *data)
422 {
423         struct editor *editor = data;
424         struct rectangle allocation;
425
426         widget_get_allocation(editor->widget, &allocation);
427
428         text_entry_allocate(editor->entry,
429                             allocation.x + 20, allocation.y + 20,
430                             width - 40, height / 2 - 40);
431         text_entry_allocate(editor->editor,
432                             allocation.x + 20, allocation.y + height / 2 + 20,
433                             width - 40, height / 2 - 40);
434 }
435
436 static void
437 text_entry_activate(struct text_entry *entry,
438                     struct wl_seat *seat)
439 {
440         struct wl_surface *surface = window_get_wl_surface(entry->window);
441
442         text_model_activate(entry->model,
443                             seat,
444                             surface);
445 }
446
447 static void
448 text_entry_deactivate(struct text_entry *entry,
449                       struct wl_seat *seat)
450 {
451         text_model_deactivate(entry->model,
452                               seat);
453 }
454
455 static void
456 text_entry_update_layout(struct text_entry *entry)
457 {
458         char *text;
459
460         assert(((unsigned int)entry->cursor) <= strlen(entry->text));
461
462         if (!entry->preedit_text) {
463                 text_layout_set_text(entry->layout, entry->text);
464                 return;
465         }
466
467         text = malloc(strlen(entry->text) + strlen(entry->preedit_text) + 1);
468         strncpy(text, entry->text, entry->cursor);
469         strcpy(text + entry->cursor, entry->preedit_text);
470         strcpy(text + entry->cursor + strlen(entry->preedit_text),
471                entry->text + entry->cursor);
472
473         text_layout_set_text(entry->layout, text);
474         free(text);
475
476         widget_schedule_redraw(entry->widget);
477
478         text_model_set_surrounding_text(entry->model,
479                                         entry->text,
480                                         entry->cursor,
481                                         entry->anchor);
482 }
483
484 static void
485 text_entry_insert_at_cursor(struct text_entry *entry, const char *text)
486 {
487         char *new_text = malloc(strlen(entry->text) + strlen(text) + 1);
488
489         strncpy(new_text, entry->text, entry->cursor);
490         strcpy(new_text + entry->cursor, text);
491         strcpy(new_text + entry->cursor + strlen(text),
492                entry->text + entry->cursor);
493
494         free(entry->text);
495         entry->text = new_text;
496         entry->cursor += strlen(text);
497         entry->anchor += strlen(text);
498
499         text_entry_update_layout(entry);
500 }
501
502 static void
503 text_entry_set_preedit(struct text_entry *entry,
504                        const char *preedit_text,
505                        int preedit_cursor)
506 {
507         if (entry->preedit_text) {
508                 free(entry->preedit_text);
509                 entry->preedit_text = NULL;
510                 entry->preedit_cursor = 0;
511         }
512
513         if (!preedit_text)
514                 return;
515
516         entry->preedit_text = strdup(preedit_text);
517         entry->preedit_cursor = preedit_cursor;
518
519         text_entry_update_layout(entry);
520 }
521
522 static void
523 text_entry_set_cursor_position(struct text_entry *entry,
524                                int32_t x, int32_t y)
525 {
526         entry->cursor = text_layout_xy_to_index(entry->layout, x, y);
527
528         if (entry->cursor >= entry->preedit_cursor) {
529                 entry->cursor -= entry->preedit_cursor;
530         }
531
532         text_entry_update_layout(entry);
533
534         widget_schedule_redraw(entry->widget);
535 }
536
537 static void
538 text_entry_set_anchor_position(struct text_entry *entry,
539                                int32_t x, int32_t y)
540 {
541         entry->anchor = text_layout_xy_to_index(entry->layout, x, y);
542
543         widget_schedule_redraw(entry->widget);
544 }
545
546 static void
547 text_entry_delete_text(struct text_entry *entry,
548                        uint32_t index, uint32_t length)
549 {
550         if (entry->cursor > index)
551                 entry->cursor -= length;
552
553         entry->text[index] = '\0';
554         strcat(entry->text, entry->text + index + length);
555
556         text_entry_update_layout(entry);
557
558         widget_schedule_redraw(entry->widget);
559 }
560
561 static void
562 text_entry_draw_selection(struct text_entry *entry, cairo_t *cr)
563 {
564         cairo_text_extents_t extents;
565         uint32_t start_index = entry->anchor < entry->cursor ? entry->anchor : entry->cursor;
566         uint32_t end_index = entry->anchor < entry->cursor ? entry->cursor : entry->anchor;
567         cairo_rectangle_t start;
568         cairo_rectangle_t end;
569
570         if (entry->anchor == entry->cursor)
571                 return;
572
573         text_layout_extents(entry->layout, &extents);
574
575         text_layout_index_to_pos(entry->layout, start_index, &start);
576         text_layout_index_to_pos(entry->layout, end_index, &end);
577
578         cairo_save (cr);
579
580         cairo_set_source_rgba(cr, 0.0, 0.0, 1.0, 1.0);
581         cairo_rectangle(cr,
582                         start.x, extents.y_bearing + extents.height + 2,
583                         end.x - start.x, -extents.height - 4);
584         cairo_fill(cr);
585
586         cairo_rectangle(cr,
587                         start.x, extents.y_bearing + extents.height,
588                         end.x - start.x, -extents.height);
589         cairo_clip(cr);
590         cairo_set_source_rgba(cr, 1.0, 1.0, 1.0, 1.0);
591         text_layout_draw(entry->layout, cr);
592
593         cairo_restore (cr);
594 }
595
596 static void
597 text_entry_draw_cursor(struct text_entry *entry, cairo_t *cr)
598 {
599         cairo_text_extents_t extents;
600         cairo_rectangle_t cursor_pos;
601
602         text_layout_extents(entry->layout, &extents);
603         text_layout_get_cursor_pos(entry->layout,
604                                    entry->cursor + entry->preedit_cursor,
605                                    &cursor_pos);
606
607         cairo_set_line_width(cr, 1.0);
608         cairo_move_to(cr, cursor_pos.x, extents.y_bearing + extents.height + 2);
609         cairo_line_to(cr, cursor_pos.x, extents.y_bearing - 2);
610         cairo_stroke(cr);
611 }
612
613 static void
614 text_entry_draw_preedit(struct text_entry *entry, cairo_t *cr)
615 {
616         cairo_text_extents_t extents;
617         cairo_rectangle_t start;
618         cairo_rectangle_t end;
619
620         if (!entry->preedit_text)
621                 return;
622
623         text_layout_extents(entry->layout, &extents);
624
625         text_layout_index_to_pos(entry->layout, entry->cursor, &start);
626         text_layout_index_to_pos(entry->layout,
627                                  entry->cursor + strlen(entry->preedit_text),
628                                  &end);
629
630         cairo_save (cr);
631
632         cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
633         cairo_rectangle(cr,
634                         start.x, 0,
635                         end.x - start.x, 1);
636         cairo_fill(cr);
637
638         cairo_restore (cr);
639 }
640
641 static void
642 text_entry_redraw_handler(struct widget *widget, void *data)
643 {
644         struct text_entry *entry = data;
645         cairo_surface_t *surface;
646         struct rectangle allocation;
647         cairo_t *cr;
648
649         surface = window_get_surface(entry->window);
650         widget_get_allocation(entry->widget, &allocation);
651
652         cr = cairo_create(surface);
653         cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
654         cairo_clip(cr);
655
656         cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
657
658         cairo_push_group(cr);
659         cairo_translate(cr, allocation.x, allocation.y);
660
661         cairo_set_source_rgba(cr, 1, 1, 1, 1);
662         cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
663         cairo_fill(cr);
664
665         cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
666
667         if (entry->active) {
668                 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
669                 cairo_set_line_width (cr, 3);
670                 cairo_set_source_rgba(cr, 0, 0, 1, 1.0);
671                 cairo_stroke(cr);
672         }
673
674         cairo_set_source_rgba(cr, 0, 0, 0, 1);
675
676         cairo_translate(cr, 10, allocation.height / 2);
677         text_layout_draw(entry->layout, cr);
678
679         text_entry_draw_selection(entry, cr);
680
681         text_entry_draw_cursor(entry, cr);
682
683         text_entry_draw_preedit(entry, cr);
684
685         cairo_pop_group_to_source(cr);
686         cairo_paint(cr);
687
688         cairo_destroy(cr);
689         cairo_surface_destroy(surface);
690 }
691
692 static int
693 text_entry_motion_handler(struct widget *widget,
694                           struct input *input, uint32_t time,
695                           float x, float y, void *data)
696 {
697         struct text_entry *entry = data;
698         struct rectangle allocation;
699
700         widget_get_allocation(entry->widget, &allocation);
701
702         text_entry_set_cursor_position(entry,
703                                        x - allocation.x,
704                                        y - allocation.y);
705
706         return CURSOR_IBEAM;
707 }
708
709 static void
710 text_entry_button_handler(struct widget *widget,
711                           struct input *input, uint32_t time,
712                           uint32_t button,
713                           enum wl_pointer_button_state state, void *data)
714 {
715         struct text_entry *entry = data;
716         struct rectangle allocation;
717         int32_t x, y;
718
719         widget_get_allocation(entry->widget, &allocation);
720         input_get_position(input, &x, &y);
721
722         if (button != BTN_LEFT) {
723                 return;
724         }
725
726         text_entry_set_cursor_position(entry,
727                                        x - allocation.x,
728                                        y - allocation.y);
729
730         if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
731                 struct wl_seat *seat = input_get_seat(input);
732
733                 text_entry_activate(entry, seat);
734
735                 text_entry_set_anchor_position(entry,
736                                                x - allocation.x,
737                                                y - allocation.y);
738
739                 widget_set_motion_handler(entry->widget, text_entry_motion_handler);
740         } else {
741                 widget_set_motion_handler(entry->widget, NULL);
742         }
743 }
744
745 static void
746 editor_button_handler(struct widget *widget,
747                       struct input *input, uint32_t time,
748                       uint32_t button,
749                       enum wl_pointer_button_state state, void *data)
750 {
751         struct editor *editor = data;
752
753         if (button != BTN_LEFT) {
754                 return;
755         }
756
757         if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
758                 struct wl_seat *seat = input_get_seat(input);
759
760                 text_entry_deactivate(editor->entry, seat);
761                 text_entry_deactivate(editor->editor, seat);
762         }
763 }
764
765 static void
766 global_handler(struct wl_display *display, uint32_t id,
767                const char *interface, uint32_t version, void *data)
768 {
769         struct editor *editor = data;
770
771         if (!strcmp(interface, "text_model_factory")) {
772                 editor->text_model_factory = wl_display_bind(display, id,
773                                                              &text_model_factory_interface);
774         }
775 }
776
777 int
778 main(int argc, char *argv[])
779 {
780         struct editor editor;
781
782         editor.display = display_create(argc, argv);
783         if (editor.display == NULL) {
784                 fprintf(stderr, "failed to create display: %m\n");
785                 return -1;
786         }
787         wl_display_add_global_listener(display_get_display(editor.display),
788                                        global_handler, &editor);
789
790
791         editor.window = window_create(editor.display);
792         editor.widget = frame_create(editor.window, &editor);
793
794         editor.entry = text_entry_create(&editor, "Entry");
795         editor.editor = text_entry_create(&editor, "Editor");
796         text_entry_set_preedit(editor.editor, "preedit", strlen("preedit"));
797
798         window_set_title(editor.window, "Text Editor");
799
800         widget_set_redraw_handler(editor.widget, redraw_handler);
801         widget_set_resize_handler(editor.widget, resize_handler);
802         widget_set_button_handler(editor.widget, editor_button_handler);
803
804         window_schedule_resize(editor.window, 500, 400);
805
806         display_run(editor.display);
807
808         text_entry_destroy(editor.entry);
809         text_entry_destroy(editor.editor);
810
811         return 0;
812 }