blob: ef1dd283fbbc297eb955309969e095f01c57df5e [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 Petersencba9e472012-06-21 21:52:19 +020062};
63
64struct editor {
Jan Arne Petersen51963742012-08-10 16:47:20 +020065 struct text_model_factory *text_model_factory;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020066 struct display *display;
67 struct window *window;
68 struct widget *widget;
69 struct text_entry *entry;
70 struct text_entry *editor;
Rob Bradford9d1d32b2012-11-18 19:06:49 +010071 struct text_entry *active_entry;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020072};
73
Jan Arne Petersen6345faa2012-11-05 03:26:39 +010074static const char *
75utf8_start_char(const char *text, const char *p)
76{
77 for (; p >= text; --p) {
78 if ((*p & 0xc0) != 0x80)
79 return p;
80 }
81 return NULL;
82}
83
84static const char *
85utf8_prev_char(const char *text, const char *p)
86{
87 if (p > text)
88 return utf8_start_char(text, --p);
89 return NULL;
90}
91
92static const char *
93utf8_end_char(const char *p)
94{
95 while ((*p & 0xc0) == 0x80)
96 p++;
97 return p;
98}
99
100static const char *
101utf8_next_char(const char *p)
102{
103 if (*p != 0)
104 return utf8_end_char(++p);
105 return NULL;
106}
107
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200108static void text_entry_redraw_handler(struct widget *widget, void *data);
109static void text_entry_button_handler(struct widget *widget,
110 struct input *input, uint32_t time,
111 uint32_t button,
112 enum wl_pointer_button_state state, void *data);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200113static void text_entry_insert_at_cursor(struct text_entry *entry, const char *text);
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200114static void text_entry_set_preedit(struct text_entry *entry,
115 const char *preedit_text,
116 int preedit_cursor);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200117static void text_entry_delete_text(struct text_entry *entry,
118 uint32_t index, uint32_t length);
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200119static void text_entry_delete_selected_text(struct text_entry *entry);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100120static void text_entry_reset_preedit(struct text_entry *entry);
121static void text_entry_commit_and_reset(struct text_entry *entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200122
123static void
124text_model_commit_string(void *data,
125 struct text_model *text_model,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100126 uint32_t serial,
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200127 const char *text,
128 uint32_t index)
129{
130 struct text_entry *entry = data;
131
John Kåre Alsaker011a1ce2012-10-12 12:25:06 +0200132 if (index > strlen(text))
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200133 fprintf(stderr, "Invalid cursor index %d\n", index);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200134
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100135 text_entry_reset_preedit(entry);
136
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200137 text_entry_delete_selected_text(entry);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200138 text_entry_insert_at_cursor(entry, text);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200139
140 widget_schedule_redraw(entry->widget);
141}
142
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200143static void
144text_model_preedit_string(void *data,
145 struct text_model *text_model,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100146 uint32_t serial,
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200147 const char *text,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100148 const char *commit)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200149{
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200150 struct text_entry *entry = data;
151
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200152 text_entry_delete_selected_text(entry);
Jan Arne Petersen46535312013-01-16 21:26:38 +0100153 text_entry_set_preedit(entry, text, entry->preedit_info.cursor);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100154 entry->preedit.commit = strdup(commit);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100155 entry->preedit.attr_list = entry->preedit_info.attr_list;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100156
157 entry->preedit_info.cursor = 0;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100158 entry->preedit_info.attr_list = NULL;
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200159
160 widget_schedule_redraw(entry->widget);
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200161}
162
163static void
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200164text_model_delete_surrounding_text(void *data,
165 struct text_model *text_model,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100166 uint32_t serial,
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200167 int32_t index,
168 uint32_t length)
169{
170 struct text_entry *entry = data;
171 uint32_t cursor_index = index + entry->cursor;
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100172 const char *start, *end;
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200173
174 if (cursor_index > strlen(entry->text)) {
175 fprintf(stderr, "Invalid cursor index %d\n", index);
176 return;
177 }
178
179 if (cursor_index + length > strlen(entry->text)) {
180 fprintf(stderr, "Invalid length %d\n", length);
181 return;
182 }
183
184 if (length == 0)
185 return;
186
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100187 start = utf8_start_char(entry->text, entry->text + cursor_index);
188 end = utf8_end_char(entry->text + cursor_index + length);
189
190 text_entry_delete_text(entry,
191 start - entry->text,
192 end - start);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200193}
194
195static void
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200196text_model_preedit_styling(void *data,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100197 struct text_model *text_model,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100198 uint32_t serial,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100199 uint32_t index,
200 uint32_t length,
201 uint32_t style)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200202{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100203 struct text_entry *entry = data;
204 PangoAttribute *attr1 = NULL;
205 PangoAttribute *attr2 = NULL;
206
207 if (!entry->preedit_info.attr_list)
208 entry->preedit_info.attr_list = pango_attr_list_new();
209
210 switch (style) {
211 case TEXT_MODEL_PREEDIT_STYLE_DEFAULT:
212 case TEXT_MODEL_PREEDIT_STYLE_UNDERLINE:
213 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
214 break;
215 case TEXT_MODEL_PREEDIT_STYLE_INCORRECT:
216 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_ERROR);
217 attr2 = pango_attr_underline_color_new(65535, 0, 0);
218 break;
219 case TEXT_MODEL_PREEDIT_STYLE_SELECTION:
220 attr1 = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
221 attr2 = pango_attr_foreground_new(65535, 65535, 65535);
222 break;
223 case TEXT_MODEL_PREEDIT_STYLE_HIGHLIGHT:
224 case TEXT_MODEL_PREEDIT_STYLE_ACTIVE:
225 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
226 attr2 = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
227 break;
228 case TEXT_MODEL_PREEDIT_STYLE_INACTIVE:
229 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
230 attr2 = pango_attr_foreground_new(0.3 * 65535, 0.3 * 65535, 0.3 * 65535);
231 break;
232 }
233
234 if (attr1) {
235 attr1->start_index = entry->cursor + index;
236 attr1->end_index = entry->cursor + index + length;
237 pango_attr_list_insert(entry->preedit_info.attr_list, attr1);
238 }
239
240 if (attr2) {
241 attr2->start_index = entry->cursor + index;
242 attr2->end_index = entry->cursor + index + length;
243 pango_attr_list_insert(entry->preedit_info.attr_list, attr2);
244 }
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200245}
246
247static void
Jan Arne Petersen46535312013-01-16 21:26:38 +0100248text_model_preedit_cursor(void *data,
249 struct text_model *text_model,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100250 uint32_t serial,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100251 int32_t index)
252{
253 struct text_entry *entry = data;
254
255 entry->preedit_info.cursor = index;
256}
257
258static void
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100259text_model_modifiers_map(void *data,
260 struct text_model *text_model,
261 struct wl_array *map)
262{
Jan Arne Petersencd997062012-11-18 19:06:44 +0100263 struct text_entry *entry = data;
264
265 entry->keysym.shift_mask = keysym_modifiers_get_mask(map, "Shift");
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100266}
267
268static void
269text_model_keysym(void *data,
270 struct text_model *text_model,
271 uint32_t serial,
272 uint32_t time,
273 uint32_t key,
274 uint32_t state,
275 uint32_t modifiers)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200276{
Jan Arne Petersen8aba11d2012-09-17 15:28:07 +0200277 struct text_entry *entry = data;
Jan Arne Petersencd997062012-11-18 19:06:44 +0100278 const char *state_label = "release";
279 const char *key_label = "Unknown";
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100280 const char *new_char;
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200281
282 if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
283 state_label = "pressed";
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200284 }
285
Jan Arne Petersencd997062012-11-18 19:06:44 +0100286 if (key == XKB_KEY_Left ||
287 key == XKB_KEY_Right) {
288 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
289 return;
290
291 if (key == XKB_KEY_Left)
292 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
293 else
294 new_char = utf8_next_char(entry->text + entry->cursor);
295
296 if (new_char != NULL) {
297 entry->cursor = new_char - entry->text;
298 if (!(modifiers & entry->keysym.shift_mask))
299 entry->anchor = entry->cursor;
300 widget_schedule_redraw(entry->widget);
301 }
302
303 return;
304 }
305
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200306 switch (key) {
307 case XKB_KEY_Tab:
308 key_label = "Tab";
309 break;
310 case XKB_KEY_KP_Enter:
Jan Arne Petersencd997062012-11-18 19:06:44 +0100311 case XKB_KEY_Return:
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200312 key_label = "Enter";
313 break;
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200314 }
315
316 fprintf(stderr, "%s key was %s.\n", key_label, state_label);
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200317}
318
319static void
320text_model_selection_replacement(void *data,
321 struct text_model *text_model)
322{
323}
324
325static void
326text_model_direction(void *data,
327 struct text_model *text_model)
328{
329}
330
331static void
332text_model_locale(void *data,
333 struct text_model *text_model)
334{
335}
336
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200337static void
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200338text_model_enter(void *data,
339 struct text_model *text_model,
340 struct wl_surface *surface)
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200341{
342 struct text_entry *entry = data;
343
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200344 if (surface != window_get_wl_surface(entry->window))
345 return;
346
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200347 entry->active = 1;
348
349 widget_schedule_redraw(entry->widget);
350}
351
352static void
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200353text_model_leave(void *data,
354 struct text_model *text_model)
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200355{
356 struct text_entry *entry = data;
357
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100358 text_entry_commit_and_reset(entry);
359
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200360 entry->active = 0;
361
362 widget_schedule_redraw(entry->widget);
363}
364
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200365static const struct text_model_listener text_model_listener = {
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200366 text_model_commit_string,
367 text_model_preedit_string,
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200368 text_model_delete_surrounding_text,
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200369 text_model_preedit_styling,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100370 text_model_preedit_cursor,
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100371 text_model_modifiers_map,
372 text_model_keysym,
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200373 text_model_selection_replacement,
374 text_model_direction,
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200375 text_model_locale,
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200376 text_model_enter,
377 text_model_leave
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200378};
379
380static struct text_entry*
381text_entry_create(struct editor *editor, const char *text)
382{
383 struct text_entry *entry;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200384
Jan Arne Petersencd997062012-11-18 19:06:44 +0100385 entry = calloc(1, sizeof *entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200386
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200387 entry->widget = widget_add_widget(editor->widget, entry);
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200388 entry->window = editor->window;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200389 entry->text = strdup(text);
390 entry->active = 0;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200391 entry->cursor = strlen(text);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200392 entry->anchor = entry->cursor;
Jan Arne Petersen4c265182012-09-09 23:08:30 +0200393 entry->model = text_model_factory_create_text_model(editor->text_model_factory);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200394 text_model_add_listener(entry->model, &text_model_listener, entry);
395
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200396 widget_set_redraw_handler(entry->widget, text_entry_redraw_handler);
397 widget_set_button_handler(entry->widget, text_entry_button_handler);
398
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200399 return entry;
400}
401
402static void
403text_entry_destroy(struct text_entry *entry)
404{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200405 widget_destroy(entry->widget);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200406 text_model_destroy(entry->model);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100407 g_clear_object(&entry->layout);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200408 free(entry->text);
409 free(entry);
410}
411
412static void
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200413redraw_handler(struct widget *widget, void *data)
414{
415 struct editor *editor = data;
416 cairo_surface_t *surface;
417 struct rectangle allocation;
418 cairo_t *cr;
419
420 surface = window_get_surface(editor->window);
421 widget_get_allocation(editor->widget, &allocation);
422
423 cr = cairo_create(surface);
424 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
425 cairo_clip(cr);
426
427 cairo_translate(cr, allocation.x, allocation.y);
428
429 /* Draw background */
430 cairo_push_group(cr);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200431 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200432 cairo_set_source_rgba(cr, 1, 1, 1, 1);
433 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
434 cairo_fill(cr);
435
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200436 cairo_pop_group_to_source(cr);
437 cairo_paint(cr);
438
439 cairo_destroy(cr);
440 cairo_surface_destroy(surface);
441}
442
443static void
444text_entry_allocate(struct text_entry *entry, int32_t x, int32_t y,
445 int32_t width, int32_t height)
446{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200447 widget_set_allocation(entry->widget, x, y, width, height);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200448}
449
450static void
451resize_handler(struct widget *widget,
452 int32_t width, int32_t height, void *data)
453{
454 struct editor *editor = data;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200455 struct rectangle allocation;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200456
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200457 widget_get_allocation(editor->widget, &allocation);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200458
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200459 text_entry_allocate(editor->entry,
460 allocation.x + 20, allocation.y + 20,
461 width - 40, height / 2 - 40);
462 text_entry_allocate(editor->editor,
463 allocation.x + 20, allocation.y + height / 2 + 20,
464 width - 40, height / 2 - 40);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200465}
466
467static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200468text_entry_activate(struct text_entry *entry,
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200469 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200470{
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200471 struct wl_surface *surface = window_get_wl_surface(entry->window);
472
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100473 entry->serial++;
474
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200475 text_model_activate(entry->model,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100476 entry->serial,
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200477 seat,
478 surface);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200479}
480
481static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200482text_entry_deactivate(struct text_entry *entry,
483 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200484{
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200485 text_model_deactivate(entry->model,
486 seat);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200487}
488
489static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200490text_entry_update_layout(struct text_entry *entry)
491{
492 char *text;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100493 PangoAttrList *attr_list;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200494
Philipp Brüschweiler237358b2012-10-02 11:06:51 +0200495 assert(((unsigned int)entry->cursor) <= strlen(entry->text) +
Jan Arne Petersen46535312013-01-16 21:26:38 +0100496 (entry->preedit.text ? strlen(entry->preedit.text) : 0));
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200497
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100498 if (entry->preedit.text) {
499 text = malloc(strlen(entry->text) + strlen(entry->preedit.text) + 1);
500 strncpy(text, entry->text, entry->cursor);
501 strcpy(text + entry->cursor, entry->preedit.text);
502 strcpy(text + entry->cursor + strlen(entry->preedit.text),
503 entry->text + entry->cursor);
504 } else {
505 text = strdup(entry->text);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200506 }
507
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100508 if (entry->cursor != entry->anchor) {
509 int start_index = MIN(entry->cursor, entry->anchor);
510 int end_index = MAX(entry->cursor, entry->anchor);
511 PangoAttribute *attr;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200512
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100513 attr_list = pango_attr_list_copy(entry->preedit.attr_list);
514
515 if (!attr_list)
516 attr_list = pango_attr_list_new();
517
518 attr = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
519 attr->start_index = start_index;
520 attr->end_index = end_index;
521 pango_attr_list_insert(attr_list, attr);
522
523 attr = pango_attr_foreground_new(65535, 65535, 65535);
524 attr->start_index = start_index;
525 attr->end_index = end_index;
526 pango_attr_list_insert(attr_list, attr);
527 } else {
528 attr_list = pango_attr_list_ref(entry->preedit.attr_list);
529 }
530
531 if (entry->preedit.text && !entry->preedit.attr_list) {
532 PangoAttribute *attr;
533
534 if (!attr_list)
535 attr_list = pango_attr_list_new();
536
537 attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
538 attr->start_index = entry->cursor;
539 attr->end_index = entry->cursor + strlen(entry->preedit.text);
540 pango_attr_list_insert(attr_list, attr);
541 }
542
543 if (entry->layout) {
544 pango_layout_set_text(entry->layout, text, -1);
545 pango_layout_set_attributes(entry->layout, attr_list);
546 }
547
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200548 free(text);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100549 pango_attr_list_unref(attr_list);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200550}
551
552static void
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200553text_entry_insert_at_cursor(struct text_entry *entry, const char *text)
554{
555 char *new_text = malloc(strlen(entry->text) + strlen(text) + 1);
556
557 strncpy(new_text, entry->text, entry->cursor);
558 strcpy(new_text + entry->cursor, text);
559 strcpy(new_text + entry->cursor + strlen(text),
560 entry->text + entry->cursor);
561
562 free(entry->text);
563 entry->text = new_text;
564 entry->cursor += strlen(text);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200565 entry->anchor += strlen(text);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200566
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200567 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100568
569 widget_schedule_redraw(entry->widget);
570
571 text_model_set_surrounding_text(entry->model,
572 entry->text,
573 entry->cursor,
574 entry->anchor);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200575}
576
577static void
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100578text_entry_reset_preedit(struct text_entry *entry)
579{
580 entry->preedit.cursor = 0;
581
582 free(entry->preedit.text);
583 entry->preedit.text = NULL;
584
585 free(entry->preedit.commit);
586 entry->preedit.commit = NULL;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100587
588 pango_attr_list_unref(entry->preedit.attr_list);
589 entry->preedit.attr_list = NULL;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100590}
591
592static void
593text_entry_commit_and_reset(struct text_entry *entry)
594{
595 char *commit = NULL;
596
597 if (entry->preedit.commit)
598 commit = strdup(entry->preedit.commit);
599
600 text_entry_reset_preedit(entry);
601 if (commit) {
602 text_entry_insert_at_cursor(entry, commit);
603 free(commit);
604 }
605}
606
607static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200608text_entry_set_preedit(struct text_entry *entry,
609 const char *preedit_text,
610 int preedit_cursor)
611{
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100612 text_entry_reset_preedit(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200613
614 if (!preedit_text)
615 return;
616
Jan Arne Petersen46535312013-01-16 21:26:38 +0100617 entry->preedit.text = strdup(preedit_text);
618 entry->preedit.cursor = preedit_cursor;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200619
620 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100621
622 widget_schedule_redraw(entry->widget);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200623}
624
625static void
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200626text_entry_set_cursor_position(struct text_entry *entry,
627 int32_t x, int32_t y)
628{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100629 int index, trailing;
630
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100631 text_entry_commit_and_reset(entry);
632
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100633 pango_layout_xy_to_index(entry->layout,
634 x * PANGO_SCALE, y * PANGO_SCALE,
635 &index, &trailing);
636 entry->cursor = index + trailing;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200637
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100638 entry->serial++;
639
640 text_model_reset(entry->model, entry->serial);
Jan Arne Petersenc1e481e2012-09-09 23:08:46 +0200641
Jan Arne Petersen46535312013-01-16 21:26:38 +0100642 if (entry->preedit.cursor > 0 &&
643 entry->cursor >= (uint32_t)entry->preedit.cursor) {
644 entry->cursor -= entry->preedit.cursor;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200645 }
646
647 text_entry_update_layout(entry);
648
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200649 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100650
651 text_model_set_surrounding_text(entry->model,
652 entry->text,
653 entry->cursor,
654 entry->anchor);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200655}
656
657static void
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200658text_entry_set_anchor_position(struct text_entry *entry,
659 int32_t x, int32_t y)
660{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100661 int index, trailing;
662
663 pango_layout_xy_to_index(entry->layout,
664 x * PANGO_SCALE, y * PANGO_SCALE,
665 &index, &trailing);
666 entry->anchor = index + trailing;
667
668 text_entry_update_layout(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200669
670 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100671
672 text_model_set_surrounding_text(entry->model,
673 entry->text,
674 entry->cursor,
675 entry->anchor);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200676}
677
678static void
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200679text_entry_delete_text(struct text_entry *entry,
680 uint32_t index, uint32_t length)
681{
682 if (entry->cursor > index)
683 entry->cursor -= length;
684
Jan Arne Petersen80ad1a92012-09-17 15:28:10 +0200685 entry->anchor = entry->cursor;
686
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200687 entry->text[index] = '\0';
688 strcat(entry->text, entry->text + index + length);
689
690 text_entry_update_layout(entry);
691
692 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100693
694 text_model_set_surrounding_text(entry->model,
695 entry->text,
696 entry->cursor,
697 entry->anchor);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200698}
699
700static void
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200701text_entry_delete_selected_text(struct text_entry *entry)
702{
703 uint32_t start_index = entry->anchor < entry->cursor ? entry->anchor : entry->cursor;
704 uint32_t end_index = entry->anchor < entry->cursor ? entry->cursor : entry->anchor;
705
706 if (entry->anchor == entry->cursor)
707 return;
708
709 text_entry_delete_text(entry, start_index, end_index - start_index);
710
711 entry->anchor = entry->cursor;
712}
713
714static void
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200715text_entry_draw_cursor(struct text_entry *entry, cairo_t *cr)
716{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100717 PangoRectangle extents;
718 PangoRectangle cursor_pos;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200719
Jan Arne Petersen46535312013-01-16 21:26:38 +0100720 if (entry->preedit.text && entry->preedit.cursor < 0)
721 return;
722
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100723 pango_layout_get_extents(entry->layout, &extents, NULL);
724 pango_layout_get_cursor_pos(entry->layout,
725 entry->cursor + entry->preedit.cursor,
726 &cursor_pos, NULL);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200727
728 cairo_set_line_width(cr, 1.0);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100729 cairo_move_to(cr, PANGO_PIXELS(cursor_pos.x), PANGO_PIXELS(extents.height) + 2);
730 cairo_line_to(cr, PANGO_PIXELS(cursor_pos.x), - 2);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200731 cairo_stroke(cr);
732}
733
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200734static const int text_offset_left = 10;
735
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200736static void
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200737text_entry_redraw_handler(struct widget *widget, void *data)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200738{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200739 struct text_entry *entry = data;
740 cairo_surface_t *surface;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200741 struct rectangle allocation;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200742 cairo_t *cr;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200743
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200744 surface = window_get_surface(entry->window);
745 widget_get_allocation(entry->widget, &allocation);
746
747 cr = cairo_create(surface);
748 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
749 cairo_clip(cr);
750
751 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
752
753 cairo_push_group(cr);
754 cairo_translate(cr, allocation.x, allocation.y);
755
756 cairo_set_source_rgba(cr, 1, 1, 1, 1);
757 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
758 cairo_fill(cr);
759
760 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
761
762 if (entry->active) {
763 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
764 cairo_set_line_width (cr, 3);
765 cairo_set_source_rgba(cr, 0, 0, 1, 1.0);
766 cairo_stroke(cr);
767 }
768
769 cairo_set_source_rgba(cr, 0, 0, 0, 1);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200770
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200771 cairo_translate(cr, text_offset_left, allocation.height / 2);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200772
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100773 if (!entry->layout)
774 entry->layout = pango_cairo_create_layout(cr);
775 else
776 pango_cairo_update_layout(cr, entry->layout);
777
778 text_entry_update_layout(entry);
779
780 pango_cairo_show_layout(cr, entry->layout);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200781
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200782 text_entry_draw_cursor(entry, cr);
783
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200784 cairo_pop_group_to_source(cr);
785 cairo_paint(cr);
786
787 cairo_destroy(cr);
788 cairo_surface_destroy(surface);
789}
790
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200791static int
792text_entry_motion_handler(struct widget *widget,
793 struct input *input, uint32_t time,
794 float x, float y, void *data)
795{
796 struct text_entry *entry = data;
797 struct rectangle allocation;
798
799 widget_get_allocation(entry->widget, &allocation);
800
801 text_entry_set_cursor_position(entry,
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200802 x - allocation.x - text_offset_left,
803 y - allocation.y - text_offset_left);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200804
805 return CURSOR_IBEAM;
806}
807
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200808static void
809text_entry_button_handler(struct widget *widget,
810 struct input *input, uint32_t time,
811 uint32_t button,
812 enum wl_pointer_button_state state, void *data)
813{
814 struct text_entry *entry = data;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200815 struct rectangle allocation;
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100816 struct editor *editor;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200817 int32_t x, y;
818
819 widget_get_allocation(entry->widget, &allocation);
820 input_get_position(input, &x, &y);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200821
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100822 editor = window_get_user_data(entry->window);
823
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200824 if (button != BTN_LEFT) {
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200825 return;
826 }
827
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200828 text_entry_set_cursor_position(entry,
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200829 x - allocation.x - text_offset_left,
830 y - allocation.y - text_offset_left);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200831
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200832 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
833 struct wl_seat *seat = input_get_seat(input);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200834
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200835 text_entry_activate(entry, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100836 editor->active_entry = entry;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200837
838 text_entry_set_anchor_position(entry,
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200839 x - allocation.x - text_offset_left,
840 y - allocation.y - text_offset_left);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200841
842 widget_set_motion_handler(entry->widget, text_entry_motion_handler);
843 } else {
844 widget_set_motion_handler(entry->widget, NULL);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200845 }
846}
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200847
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200848static void
849editor_button_handler(struct widget *widget,
850 struct input *input, uint32_t time,
851 uint32_t button,
852 enum wl_pointer_button_state state, void *data)
853{
854 struct editor *editor = data;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200855
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200856 if (button != BTN_LEFT) {
857 return;
858 }
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200859
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200860 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
861 struct wl_seat *seat = input_get_seat(input);
862
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200863 text_entry_deactivate(editor->entry, seat);
864 text_entry_deactivate(editor->editor, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100865 editor->active_entry = NULL;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200866 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200867}
868
869static void
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100870key_handler(struct window *window,
871 struct input *input, uint32_t time,
872 uint32_t key, uint32_t sym, enum wl_keyboard_key_state state,
873 void *data)
874{
875 struct editor *editor = data;
876 struct text_entry *entry;
877 const char *start, *end, *new_char;
878 char text[16];
879
880 if (!editor->active_entry)
881 return;
882
883 entry = editor->active_entry;
884
885 if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
886 return;
887
888 switch (sym) {
889 case XKB_KEY_BackSpace:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100890 text_entry_commit_and_reset(entry);
891
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100892 start = utf8_prev_char(entry->text, entry->text + entry->cursor);
893
894 if (start == NULL)
895 break;
896
897 end = utf8_end_char(entry->text + entry->cursor);
898 text_entry_delete_text(entry,
899 start - entry->text,
900 end - start);
901 break;
902 case XKB_KEY_Delete:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100903 text_entry_commit_and_reset(entry);
904
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100905 start = utf8_start_char(entry->text, entry->text + entry->cursor);
906
907 if (start == NULL)
908 break;
909
910 end = utf8_next_char(start);
911
912 if (end == NULL)
913 break;
914
915 text_entry_delete_text(entry,
916 start - entry->text,
917 end - start);
918 break;
919 case XKB_KEY_Left:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100920 text_entry_commit_and_reset(entry);
921
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100922 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
923 if (new_char != NULL) {
924 entry->cursor = new_char - entry->text;
925 entry->anchor = entry->cursor;
926 widget_schedule_redraw(entry->widget);
927 }
928 break;
929 case XKB_KEY_Right:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100930 text_entry_commit_and_reset(entry);
931
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100932 new_char = utf8_next_char(entry->text + entry->cursor);
933 if (new_char != NULL) {
934 entry->cursor = new_char - entry->text;
935 entry->anchor = entry->cursor;
936 widget_schedule_redraw(entry->widget);
937 }
938 break;
939 default:
940 if (xkb_keysym_to_utf8(sym, text, sizeof(text)) <= 0)
941 break;
942
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100943 text_entry_commit_and_reset(entry);
944
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100945 text_entry_insert_at_cursor(entry, text);
946 break;
947 }
948
949 widget_schedule_redraw(entry->widget);
950}
951
952static void
Kristian Høgsbergfa80e112012-10-10 21:34:26 -0400953global_handler(struct display *display, uint32_t name,
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200954 const char *interface, uint32_t version, void *data)
955{
956 struct editor *editor = data;
957
Jan Arne Petersen51963742012-08-10 16:47:20 +0200958 if (!strcmp(interface, "text_model_factory")) {
Kristian Høgsbergfa80e112012-10-10 21:34:26 -0400959 editor->text_model_factory =
960 display_bind(display, name,
961 &text_model_factory_interface, 1);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200962 }
963}
964
965int
966main(int argc, char *argv[])
967{
968 struct editor editor;
969
Jan Arne Petersen25f6db52012-11-05 03:26:40 +0100970 memset(&editor, 0, sizeof editor);
971
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100972#ifdef HAVE_PANGO
973 g_type_init();
974#endif
975
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200976 editor.display = display_create(argc, argv);
977 if (editor.display == NULL) {
978 fprintf(stderr, "failed to create display: %m\n");
979 return -1;
980 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200981
Kristian Høgsbergfa80e112012-10-10 21:34:26 -0400982 display_set_user_data(editor.display, &editor);
983 display_set_global_handler(editor.display, global_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200984
985 editor.window = window_create(editor.display);
986 editor.widget = frame_create(editor.window, &editor);
987
988 editor.entry = text_entry_create(&editor, "Entry");
989 editor.editor = text_entry_create(&editor, "Editor");
990
991 window_set_title(editor.window, "Text Editor");
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100992 window_set_key_handler(editor.window, key_handler);
993 window_set_user_data(editor.window, &editor);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200994
995 widget_set_redraw_handler(editor.widget, redraw_handler);
996 widget_set_resize_handler(editor.widget, resize_handler);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200997 widget_set_button_handler(editor.widget, editor_button_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200998
999 window_schedule_resize(editor.window, 500, 400);
1000
1001 display_run(editor.display);
1002
1003 text_entry_destroy(editor.entry);
1004 text_entry_destroy(editor.editor);
1005
1006 return 0;
1007}