blob: 58c69119e217948cfe8446989322972ec066a2b7 [file] [log] [blame]
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001/*
2 * Copyright © 2012 Openismus GmbH
Jan Arne Petersen4c265182012-09-09 23:08:30 +02003 * Copyright © 2012 Intel Corporation
Jan Arne Petersencba9e472012-06-21 21:52:19 +02004 *
5 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the copyright holders not be used in
10 * advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. The copyright holders make
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
14 *
15 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 */
23
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010024#include "config.h"
25
Philipp Brüschweiler591cfca2012-07-11 22:25:29 +020026#include <assert.h>
Jan Arne Petersencba9e472012-06-21 21:52:19 +020027#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30
31#include <linux/input.h>
32#include <cairo.h>
33
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010034#include <pango/pangocairo.h>
35
Jan Arne Petersencba9e472012-06-21 21:52:19 +020036#include "window.h"
37#include "text-client-protocol.h"
38
39struct text_entry {
40 struct widget *widget;
Jan Arne Petersene829adc2012-08-10 16:47:22 +020041 struct window *window;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020042 char *text;
43 int active;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +020044 uint32_t cursor;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +020045 uint32_t anchor;
Jan Arne Petersen46535312013-01-16 21:26:38 +010046 struct {
47 char *text;
48 int32_t cursor;
49 char *commit;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010050 PangoAttrList *attr_list;
Jan Arne Petersen46535312013-01-16 21:26:38 +010051 } preedit;
52 struct {
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010053 PangoAttrList *attr_list;
Jan Arne Petersen46535312013-01-16 21:26:38 +010054 int32_t cursor;
55 } preedit_info;
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +010056 struct {
57 int32_t cursor;
58 int32_t anchor;
59 } pending_commit;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020060 struct text_model *model;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010061 PangoLayout *layout;
Jan Arne Petersencd997062012-11-18 19:06:44 +010062 struct {
63 xkb_mod_mask_t shift_mask;
64 } keysym;
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +010065 uint32_t serial;
Jan Arne Petersen0558a932013-01-16 21:26:45 +010066 uint32_t content_purpose;
Jan Arne Petersen61381972013-01-31 15:52:21 +010067 uint32_t click_to_show;
Jan Arne Petersen9d419132013-04-18 16:47:16 +020068 char *preferred_language;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020069};
70
71struct editor {
Jan Arne Petersen51963742012-08-10 16:47:20 +020072 struct text_model_factory *text_model_factory;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020073 struct display *display;
74 struct window *window;
75 struct widget *widget;
76 struct text_entry *entry;
77 struct text_entry *editor;
Rob Bradford9d1d32b2012-11-18 19:06:49 +010078 struct text_entry *active_entry;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020079};
80
Jan Arne Petersen6345faa2012-11-05 03:26:39 +010081static const char *
82utf8_start_char(const char *text, const char *p)
83{
84 for (; p >= text; --p) {
85 if ((*p & 0xc0) != 0x80)
86 return p;
87 }
88 return NULL;
89}
90
91static const char *
92utf8_prev_char(const char *text, const char *p)
93{
94 if (p > text)
95 return utf8_start_char(text, --p);
96 return NULL;
97}
98
99static const char *
100utf8_end_char(const char *p)
101{
102 while ((*p & 0xc0) == 0x80)
103 p++;
104 return p;
105}
106
107static const char *
108utf8_next_char(const char *p)
109{
110 if (*p != 0)
111 return utf8_end_char(++p);
112 return NULL;
113}
114
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200115static void text_entry_redraw_handler(struct widget *widget, void *data);
116static void text_entry_button_handler(struct widget *widget,
117 struct input *input, uint32_t time,
118 uint32_t button,
119 enum wl_pointer_button_state state, void *data);
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100120static void text_entry_insert_at_cursor(struct text_entry *entry, const char *text,
121 int32_t cursor, int32_t anchor);
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200122static void text_entry_set_preedit(struct text_entry *entry,
123 const char *preedit_text,
124 int preedit_cursor);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200125static void text_entry_delete_text(struct text_entry *entry,
126 uint32_t index, uint32_t length);
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200127static void text_entry_delete_selected_text(struct text_entry *entry);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100128static void text_entry_reset_preedit(struct text_entry *entry);
129static void text_entry_commit_and_reset(struct text_entry *entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200130
131static void
132text_model_commit_string(void *data,
133 struct text_model *text_model,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100134 uint32_t serial,
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100135 const char *text)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200136{
137 struct text_entry *entry = data;
138
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100139 text_entry_reset_preedit(entry);
140
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200141 text_entry_delete_selected_text(entry);
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100142 text_entry_insert_at_cursor(entry, text,
143 entry->pending_commit.cursor,
144 entry->pending_commit.anchor);
145
146 memset(&entry->pending_commit, 0, sizeof entry->pending_commit);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200147
148 widget_schedule_redraw(entry->widget);
149}
150
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200151static void
152text_model_preedit_string(void *data,
153 struct text_model *text_model,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100154 uint32_t serial,
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200155 const char *text,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100156 const char *commit)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200157{
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200158 struct text_entry *entry = data;
159
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200160 text_entry_delete_selected_text(entry);
Jan Arne Petersen46535312013-01-16 21:26:38 +0100161 text_entry_set_preedit(entry, text, entry->preedit_info.cursor);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100162 entry->preedit.commit = strdup(commit);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100163 entry->preedit.attr_list = entry->preedit_info.attr_list;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100164
165 entry->preedit_info.cursor = 0;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100166 entry->preedit_info.attr_list = NULL;
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200167
168 widget_schedule_redraw(entry->widget);
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200169}
170
171static void
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200172text_model_delete_surrounding_text(void *data,
173 struct text_model *text_model,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100174 uint32_t serial,
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200175 int32_t index,
176 uint32_t length)
177{
178 struct text_entry *entry = data;
179 uint32_t cursor_index = index + entry->cursor;
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100180 const char *start, *end;
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200181
182 if (cursor_index > strlen(entry->text)) {
183 fprintf(stderr, "Invalid cursor index %d\n", index);
184 return;
185 }
186
187 if (cursor_index + length > strlen(entry->text)) {
188 fprintf(stderr, "Invalid length %d\n", length);
189 return;
190 }
191
192 if (length == 0)
193 return;
194
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100195 start = utf8_start_char(entry->text, entry->text + cursor_index);
196 end = utf8_end_char(entry->text + cursor_index + length);
197
198 text_entry_delete_text(entry,
199 start - entry->text,
200 end - start);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200201}
202
203static void
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100204text_model_cursor_position(void *data,
205 struct text_model *text_model,
206 uint32_t serial,
207 int32_t index,
208 int32_t anchor)
209{
210 struct text_entry *entry = data;
211
212 entry->pending_commit.cursor = index;
213 entry->pending_commit.anchor = anchor;
214}
215
216static void
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200217text_model_preedit_styling(void *data,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100218 struct text_model *text_model,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100219 uint32_t serial,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100220 uint32_t index,
221 uint32_t length,
222 uint32_t style)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200223{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100224 struct text_entry *entry = data;
225 PangoAttribute *attr1 = NULL;
226 PangoAttribute *attr2 = NULL;
227
228 if (!entry->preedit_info.attr_list)
229 entry->preedit_info.attr_list = pango_attr_list_new();
230
231 switch (style) {
232 case TEXT_MODEL_PREEDIT_STYLE_DEFAULT:
233 case TEXT_MODEL_PREEDIT_STYLE_UNDERLINE:
234 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
235 break;
236 case TEXT_MODEL_PREEDIT_STYLE_INCORRECT:
237 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_ERROR);
238 attr2 = pango_attr_underline_color_new(65535, 0, 0);
239 break;
240 case TEXT_MODEL_PREEDIT_STYLE_SELECTION:
241 attr1 = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
242 attr2 = pango_attr_foreground_new(65535, 65535, 65535);
243 break;
244 case TEXT_MODEL_PREEDIT_STYLE_HIGHLIGHT:
245 case TEXT_MODEL_PREEDIT_STYLE_ACTIVE:
246 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
247 attr2 = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
248 break;
249 case TEXT_MODEL_PREEDIT_STYLE_INACTIVE:
250 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
251 attr2 = pango_attr_foreground_new(0.3 * 65535, 0.3 * 65535, 0.3 * 65535);
252 break;
253 }
254
255 if (attr1) {
256 attr1->start_index = entry->cursor + index;
257 attr1->end_index = entry->cursor + index + length;
258 pango_attr_list_insert(entry->preedit_info.attr_list, attr1);
259 }
260
261 if (attr2) {
262 attr2->start_index = entry->cursor + index;
263 attr2->end_index = entry->cursor + index + length;
264 pango_attr_list_insert(entry->preedit_info.attr_list, attr2);
265 }
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200266}
267
268static void
Jan Arne Petersen46535312013-01-16 21:26:38 +0100269text_model_preedit_cursor(void *data,
270 struct text_model *text_model,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100271 uint32_t serial,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100272 int32_t index)
273{
274 struct text_entry *entry = data;
275
276 entry->preedit_info.cursor = index;
277}
278
279static void
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100280text_model_modifiers_map(void *data,
281 struct text_model *text_model,
282 struct wl_array *map)
283{
Jan Arne Petersencd997062012-11-18 19:06:44 +0100284 struct text_entry *entry = data;
285
286 entry->keysym.shift_mask = keysym_modifiers_get_mask(map, "Shift");
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100287}
288
289static void
290text_model_keysym(void *data,
291 struct text_model *text_model,
292 uint32_t serial,
293 uint32_t time,
294 uint32_t key,
295 uint32_t state,
296 uint32_t modifiers)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200297{
Jan Arne Petersen8aba11d2012-09-17 15:28:07 +0200298 struct text_entry *entry = data;
Jan Arne Petersencd997062012-11-18 19:06:44 +0100299 const char *state_label = "release";
300 const char *key_label = "Unknown";
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100301 const char *new_char;
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200302
303 if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
304 state_label = "pressed";
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200305 }
306
Jan Arne Petersencd997062012-11-18 19:06:44 +0100307 if (key == XKB_KEY_Left ||
308 key == XKB_KEY_Right) {
309 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
310 return;
311
312 if (key == XKB_KEY_Left)
313 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
314 else
315 new_char = utf8_next_char(entry->text + entry->cursor);
316
317 if (new_char != NULL) {
318 entry->cursor = new_char - entry->text;
319 if (!(modifiers & entry->keysym.shift_mask))
320 entry->anchor = entry->cursor;
321 widget_schedule_redraw(entry->widget);
322 }
323
324 return;
325 }
326
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100327 if (key == XKB_KEY_BackSpace) {
328 const char *start, *end;
329
330 text_entry_commit_and_reset(entry);
331
332 start = utf8_prev_char(entry->text, entry->text + entry->cursor);
333
334 if (start == NULL)
335 return;
336
337 end = utf8_end_char(entry->text + entry->cursor);
338 text_entry_delete_text(entry,
339 start - entry->text,
340 end - start);
341
342 return;
343 }
344
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200345 switch (key) {
346 case XKB_KEY_Tab:
347 key_label = "Tab";
348 break;
349 case XKB_KEY_KP_Enter:
Jan Arne Petersencd997062012-11-18 19:06:44 +0100350 case XKB_KEY_Return:
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200351 key_label = "Enter";
352 break;
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200353 }
354
355 fprintf(stderr, "%s key was %s.\n", key_label, state_label);
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200356}
357
358static void
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200359text_model_enter(void *data,
360 struct text_model *text_model,
361 struct wl_surface *surface)
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200362{
363 struct text_entry *entry = data;
364
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200365 if (surface != window_get_wl_surface(entry->window))
366 return;
367
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200368 entry->active = 1;
369
370 widget_schedule_redraw(entry->widget);
371}
372
373static void
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200374text_model_leave(void *data,
375 struct text_model *text_model)
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200376{
377 struct text_entry *entry = data;
378
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100379 text_entry_commit_and_reset(entry);
380
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200381 entry->active = 0;
382
Jan Arne Petersen61381972013-01-31 15:52:21 +0100383 text_model_hide_input_panel(text_model);
384
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200385 widget_schedule_redraw(entry->widget);
386}
387
Jan Arne Petersen61381972013-01-31 15:52:21 +0100388static void
389text_model_input_panel_state(void *data,
390 struct text_model *text_model,
391 uint32_t state)
392{
393}
394
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200395static void
396text_model_language(void *data,
397 struct text_model *text_model,
398 uint32_t serial,
399 const char *language)
400{
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200401 fprintf(stderr, "input language is %s \n", language);
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200402}
403
404static void
405text_model_text_direction(void *data,
406 struct text_model *text_model,
407 uint32_t serial,
408 uint32_t direction)
409{
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200410 struct text_entry *entry = data;
411 PangoContext *context = pango_layout_get_context(entry->layout);
412 PangoDirection pango_direction;
413
414
415 switch (direction) {
416 case TEXT_MODEL_TEXT_DIRECTION_LTR:
417 pango_direction = PANGO_DIRECTION_LTR;
418 break;
419 case TEXT_MODEL_TEXT_DIRECTION_RTL:
420 pango_direction = PANGO_DIRECTION_RTL;
421 break;
422 case TEXT_MODEL_TEXT_DIRECTION_AUTO:
423 default:
424 pango_direction = PANGO_DIRECTION_NEUTRAL;
425 }
426
427 pango_context_set_base_dir(context, pango_direction);
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200428}
429
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200430static const struct text_model_listener text_model_listener = {
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200431 text_model_commit_string,
432 text_model_preedit_string,
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200433 text_model_delete_surrounding_text,
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100434 text_model_cursor_position,
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200435 text_model_preedit_styling,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100436 text_model_preedit_cursor,
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100437 text_model_modifiers_map,
438 text_model_keysym,
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200439 text_model_enter,
Jan Arne Petersen61381972013-01-31 15:52:21 +0100440 text_model_leave,
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200441 text_model_input_panel_state,
442 text_model_language,
443 text_model_text_direction
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200444};
445
446static struct text_entry*
447text_entry_create(struct editor *editor, const char *text)
448{
449 struct text_entry *entry;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200450
Jan Arne Petersencd997062012-11-18 19:06:44 +0100451 entry = calloc(1, sizeof *entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200452
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200453 entry->widget = widget_add_widget(editor->widget, entry);
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200454 entry->window = editor->window;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200455 entry->text = strdup(text);
456 entry->active = 0;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200457 entry->cursor = strlen(text);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200458 entry->anchor = entry->cursor;
Jan Arne Petersen4c265182012-09-09 23:08:30 +0200459 entry->model = text_model_factory_create_text_model(editor->text_model_factory);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200460 text_model_add_listener(entry->model, &text_model_listener, entry);
461
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200462 widget_set_redraw_handler(entry->widget, text_entry_redraw_handler);
463 widget_set_button_handler(entry->widget, text_entry_button_handler);
464
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200465 return entry;
466}
467
468static void
469text_entry_destroy(struct text_entry *entry)
470{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200471 widget_destroy(entry->widget);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200472 text_model_destroy(entry->model);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100473 g_clear_object(&entry->layout);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200474 free(entry->text);
475 free(entry);
476}
477
478static void
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200479redraw_handler(struct widget *widget, void *data)
480{
481 struct editor *editor = data;
482 cairo_surface_t *surface;
483 struct rectangle allocation;
484 cairo_t *cr;
485
486 surface = window_get_surface(editor->window);
487 widget_get_allocation(editor->widget, &allocation);
488
489 cr = cairo_create(surface);
490 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
491 cairo_clip(cr);
492
493 cairo_translate(cr, allocation.x, allocation.y);
494
495 /* Draw background */
496 cairo_push_group(cr);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200497 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200498 cairo_set_source_rgba(cr, 1, 1, 1, 1);
499 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
500 cairo_fill(cr);
501
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200502 cairo_pop_group_to_source(cr);
503 cairo_paint(cr);
504
505 cairo_destroy(cr);
506 cairo_surface_destroy(surface);
507}
508
509static void
510text_entry_allocate(struct text_entry *entry, int32_t x, int32_t y,
511 int32_t width, int32_t height)
512{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200513 widget_set_allocation(entry->widget, x, y, width, height);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200514}
515
516static void
517resize_handler(struct widget *widget,
518 int32_t width, int32_t height, void *data)
519{
520 struct editor *editor = data;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200521 struct rectangle allocation;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200522
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200523 widget_get_allocation(editor->widget, &allocation);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200524
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200525 text_entry_allocate(editor->entry,
526 allocation.x + 20, allocation.y + 20,
527 width - 40, height / 2 - 40);
528 text_entry_allocate(editor->editor,
529 allocation.x + 20, allocation.y + height / 2 + 20,
530 width - 40, height / 2 - 40);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200531}
532
533static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200534text_entry_activate(struct text_entry *entry,
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200535 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200536{
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200537 struct wl_surface *surface = window_get_wl_surface(entry->window);
538
Jan Arne Petersen61381972013-01-31 15:52:21 +0100539 if (entry->click_to_show && entry->active) {
540 text_model_show_input_panel(entry->model);
541
542 return;
543 }
544
545 if (!entry->click_to_show)
546 text_model_show_input_panel(entry->model);
547
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100548 entry->serial++;
549
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200550 text_model_activate(entry->model,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100551 entry->serial,
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200552 seat,
553 surface);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200554}
555
556static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200557text_entry_deactivate(struct text_entry *entry,
558 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200559{
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200560 text_model_deactivate(entry->model,
561 seat);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200562}
563
564static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200565text_entry_update_layout(struct text_entry *entry)
566{
567 char *text;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100568 PangoAttrList *attr_list;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200569
Philipp Brüschweiler237358b2012-10-02 11:06:51 +0200570 assert(((unsigned int)entry->cursor) <= strlen(entry->text) +
Jan Arne Petersen46535312013-01-16 21:26:38 +0100571 (entry->preedit.text ? strlen(entry->preedit.text) : 0));
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200572
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100573 if (entry->preedit.text) {
574 text = malloc(strlen(entry->text) + strlen(entry->preedit.text) + 1);
575 strncpy(text, entry->text, entry->cursor);
576 strcpy(text + entry->cursor, entry->preedit.text);
577 strcpy(text + entry->cursor + strlen(entry->preedit.text),
578 entry->text + entry->cursor);
579 } else {
580 text = strdup(entry->text);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200581 }
582
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100583 if (entry->cursor != entry->anchor) {
584 int start_index = MIN(entry->cursor, entry->anchor);
585 int end_index = MAX(entry->cursor, entry->anchor);
586 PangoAttribute *attr;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200587
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100588 attr_list = pango_attr_list_copy(entry->preedit.attr_list);
589
590 if (!attr_list)
591 attr_list = pango_attr_list_new();
592
593 attr = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
594 attr->start_index = start_index;
595 attr->end_index = end_index;
596 pango_attr_list_insert(attr_list, attr);
597
598 attr = pango_attr_foreground_new(65535, 65535, 65535);
599 attr->start_index = start_index;
600 attr->end_index = end_index;
601 pango_attr_list_insert(attr_list, attr);
602 } else {
603 attr_list = pango_attr_list_ref(entry->preedit.attr_list);
604 }
605
606 if (entry->preedit.text && !entry->preedit.attr_list) {
607 PangoAttribute *attr;
608
609 if (!attr_list)
610 attr_list = pango_attr_list_new();
611
612 attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
613 attr->start_index = entry->cursor;
614 attr->end_index = entry->cursor + strlen(entry->preedit.text);
615 pango_attr_list_insert(attr_list, attr);
616 }
617
618 if (entry->layout) {
619 pango_layout_set_text(entry->layout, text, -1);
620 pango_layout_set_attributes(entry->layout, attr_list);
621 }
622
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200623 free(text);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100624 pango_attr_list_unref(attr_list);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200625}
626
627static void
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100628text_entry_update(struct text_entry *entry)
629{
630 text_model_set_content_type(entry->model,
631 TEXT_MODEL_CONTENT_HINT_NONE,
632 entry->content_purpose);
633
634 text_model_set_surrounding_text(entry->model,
635 entry->text,
636 entry->cursor,
637 entry->anchor);
Jan Arne Petersen0eabcaa2013-01-31 15:52:20 +0100638
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200639 if (entry->preferred_language)
640 text_model_set_preferred_language(entry->model,
641 entry->preferred_language);
642
Jan Arne Petersen0eabcaa2013-01-31 15:52:20 +0100643 text_model_commit(entry->model);
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100644}
645
646static void
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100647text_entry_insert_at_cursor(struct text_entry *entry, const char *text,
648 int32_t cursor, int32_t anchor)
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200649{
650 char *new_text = malloc(strlen(entry->text) + strlen(text) + 1);
651
652 strncpy(new_text, entry->text, entry->cursor);
653 strcpy(new_text + entry->cursor, text);
654 strcpy(new_text + entry->cursor + strlen(text),
655 entry->text + entry->cursor);
656
657 free(entry->text);
658 entry->text = new_text;
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100659 if (anchor >= 0)
660 entry->anchor = entry->cursor + strlen(text) + anchor;
661 else
662 entry->anchor = entry->cursor + 1 + anchor;
663 if (cursor >= 0)
664 entry->cursor += strlen(text) + cursor;
665 else
666 entry->cursor += 1 + cursor;
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200667
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200668 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100669
670 widget_schedule_redraw(entry->widget);
671
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100672 text_entry_update(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200673}
674
675static void
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100676text_entry_reset_preedit(struct text_entry *entry)
677{
678 entry->preedit.cursor = 0;
679
680 free(entry->preedit.text);
681 entry->preedit.text = NULL;
682
683 free(entry->preedit.commit);
684 entry->preedit.commit = NULL;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100685
686 pango_attr_list_unref(entry->preedit.attr_list);
687 entry->preedit.attr_list = NULL;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100688}
689
690static void
691text_entry_commit_and_reset(struct text_entry *entry)
692{
693 char *commit = NULL;
694
695 if (entry->preedit.commit)
696 commit = strdup(entry->preedit.commit);
697
698 text_entry_reset_preedit(entry);
699 if (commit) {
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100700 text_entry_insert_at_cursor(entry, commit, 0, 0);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100701 free(commit);
702 }
703}
704
705static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200706text_entry_set_preedit(struct text_entry *entry,
707 const char *preedit_text,
708 int preedit_cursor)
709{
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100710 text_entry_reset_preedit(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200711
712 if (!preedit_text)
713 return;
714
Jan Arne Petersen46535312013-01-16 21:26:38 +0100715 entry->preedit.text = strdup(preedit_text);
716 entry->preedit.cursor = preedit_cursor;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200717
718 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100719
720 widget_schedule_redraw(entry->widget);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200721}
722
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100723static uint32_t
724text_entry_try_invoke_preedit_action(struct text_entry *entry,
725 int32_t x, int32_t y,
726 uint32_t button,
727 enum wl_pointer_button_state state)
728{
729 int index, trailing;
730 uint32_t cursor;
731
732 if (!entry->preedit.text)
733 return 0;
734
735 pango_layout_xy_to_index(entry->layout,
736 x * PANGO_SCALE, y * PANGO_SCALE,
737 &index, &trailing);
738 cursor = index + trailing;
739
740 if (cursor < entry->cursor ||
741 cursor > entry->cursor + strlen(entry->preedit.text)) {
742 return 0;
743 }
744
745 if (state == WL_POINTER_BUTTON_STATE_RELEASED)
746 text_model_invoke_action(entry->model,
747 button,
748 cursor - entry->cursor);
749
750 return 1;
751}
752
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200753static void
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200754text_entry_set_cursor_position(struct text_entry *entry,
755 int32_t x, int32_t y)
756{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100757 int index, trailing;
758
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100759 text_entry_commit_and_reset(entry);
760
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100761 pango_layout_xy_to_index(entry->layout,
762 x * PANGO_SCALE, y * PANGO_SCALE,
763 &index, &trailing);
764 entry->cursor = index + trailing;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200765
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100766 entry->serial++;
767
768 text_model_reset(entry->model, entry->serial);
Jan Arne Petersenc1e481e2012-09-09 23:08:46 +0200769
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200770 text_entry_update_layout(entry);
771
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200772 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100773
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100774 text_entry_update(entry);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200775}
776
777static void
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200778text_entry_set_anchor_position(struct text_entry *entry,
779 int32_t x, int32_t y)
780{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100781 int index, trailing;
782
783 pango_layout_xy_to_index(entry->layout,
784 x * PANGO_SCALE, y * PANGO_SCALE,
785 &index, &trailing);
786 entry->anchor = index + trailing;
787
788 text_entry_update_layout(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200789
790 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100791
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100792 text_entry_update(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200793}
794
795static void
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200796text_entry_delete_text(struct text_entry *entry,
797 uint32_t index, uint32_t length)
798{
799 if (entry->cursor > index)
800 entry->cursor -= length;
801
Jan Arne Petersen80ad1a92012-09-17 15:28:10 +0200802 entry->anchor = entry->cursor;
803
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200804 entry->text[index] = '\0';
805 strcat(entry->text, entry->text + index + length);
806
807 text_entry_update_layout(entry);
808
809 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100810
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100811 text_entry_update(entry);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200812}
813
814static void
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200815text_entry_delete_selected_text(struct text_entry *entry)
816{
817 uint32_t start_index = entry->anchor < entry->cursor ? entry->anchor : entry->cursor;
818 uint32_t end_index = entry->anchor < entry->cursor ? entry->cursor : entry->anchor;
819
820 if (entry->anchor == entry->cursor)
821 return;
822
823 text_entry_delete_text(entry, start_index, end_index - start_index);
824
825 entry->anchor = entry->cursor;
826}
827
828static void
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200829text_entry_draw_cursor(struct text_entry *entry, cairo_t *cr)
830{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100831 PangoRectangle extents;
832 PangoRectangle cursor_pos;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200833
Jan Arne Petersen46535312013-01-16 21:26:38 +0100834 if (entry->preedit.text && entry->preedit.cursor < 0)
835 return;
836
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100837 pango_layout_get_extents(entry->layout, &extents, NULL);
838 pango_layout_get_cursor_pos(entry->layout,
839 entry->cursor + entry->preedit.cursor,
840 &cursor_pos, NULL);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200841
842 cairo_set_line_width(cr, 1.0);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100843 cairo_move_to(cr, PANGO_PIXELS(cursor_pos.x), PANGO_PIXELS(extents.height) + 2);
844 cairo_line_to(cr, PANGO_PIXELS(cursor_pos.x), - 2);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200845 cairo_stroke(cr);
846}
847
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200848static const int text_offset_left = 10;
849
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200850static void
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200851text_entry_redraw_handler(struct widget *widget, void *data)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200852{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200853 struct text_entry *entry = data;
854 cairo_surface_t *surface;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200855 struct rectangle allocation;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200856 cairo_t *cr;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200857
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200858 surface = window_get_surface(entry->window);
859 widget_get_allocation(entry->widget, &allocation);
860
861 cr = cairo_create(surface);
862 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
863 cairo_clip(cr);
864
865 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
866
867 cairo_push_group(cr);
868 cairo_translate(cr, allocation.x, allocation.y);
869
870 cairo_set_source_rgba(cr, 1, 1, 1, 1);
871 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
872 cairo_fill(cr);
873
874 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
875
876 if (entry->active) {
877 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
878 cairo_set_line_width (cr, 3);
879 cairo_set_source_rgba(cr, 0, 0, 1, 1.0);
880 cairo_stroke(cr);
881 }
882
883 cairo_set_source_rgba(cr, 0, 0, 0, 1);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200884
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200885 cairo_translate(cr, text_offset_left, allocation.height / 2);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200886
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100887 if (!entry->layout)
888 entry->layout = pango_cairo_create_layout(cr);
889 else
890 pango_cairo_update_layout(cr, entry->layout);
891
892 text_entry_update_layout(entry);
893
894 pango_cairo_show_layout(cr, entry->layout);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200895
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200896 text_entry_draw_cursor(entry, cr);
897
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200898 cairo_pop_group_to_source(cr);
899 cairo_paint(cr);
900
901 cairo_destroy(cr);
902 cairo_surface_destroy(surface);
903}
904
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200905static int
906text_entry_motion_handler(struct widget *widget,
907 struct input *input, uint32_t time,
908 float x, float y, void *data)
909{
910 struct text_entry *entry = data;
911 struct rectangle allocation;
912
913 widget_get_allocation(entry->widget, &allocation);
914
915 text_entry_set_cursor_position(entry,
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200916 x - allocation.x - text_offset_left,
917 y - allocation.y - text_offset_left);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200918
919 return CURSOR_IBEAM;
920}
921
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200922static void
923text_entry_button_handler(struct widget *widget,
924 struct input *input, uint32_t time,
925 uint32_t button,
926 enum wl_pointer_button_state state, void *data)
927{
928 struct text_entry *entry = data;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200929 struct rectangle allocation;
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100930 struct editor *editor;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200931 int32_t x, y;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100932 uint32_t result;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200933
934 widget_get_allocation(entry->widget, &allocation);
935 input_get_position(input, &x, &y);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200936
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100937 x -= allocation.x + text_offset_left;
938 y -= allocation.y + text_offset_left;
939
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100940 editor = window_get_user_data(entry->window);
941
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100942 result = text_entry_try_invoke_preedit_action(entry, x, y, button, state);
943
944 if (result)
945 return;
946
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200947 if (button != BTN_LEFT) {
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200948 return;
949 }
950
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100951 text_entry_set_cursor_position(entry, x, y);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200952
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200953 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
954 struct wl_seat *seat = input_get_seat(input);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200955
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200956 text_entry_activate(entry, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100957 editor->active_entry = entry;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200958
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100959 text_entry_set_anchor_position(entry, x, y);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200960
961 widget_set_motion_handler(entry->widget, text_entry_motion_handler);
962 } else {
963 widget_set_motion_handler(entry->widget, NULL);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200964 }
965}
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200966
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200967static void
968editor_button_handler(struct widget *widget,
969 struct input *input, uint32_t time,
970 uint32_t button,
971 enum wl_pointer_button_state state, void *data)
972{
973 struct editor *editor = data;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200974
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200975 if (button != BTN_LEFT) {
976 return;
977 }
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200978
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200979 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
980 struct wl_seat *seat = input_get_seat(input);
981
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200982 text_entry_deactivate(editor->entry, seat);
983 text_entry_deactivate(editor->editor, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100984 editor->active_entry = NULL;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200985 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200986}
987
988static void
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100989key_handler(struct window *window,
990 struct input *input, uint32_t time,
991 uint32_t key, uint32_t sym, enum wl_keyboard_key_state state,
992 void *data)
993{
994 struct editor *editor = data;
995 struct text_entry *entry;
996 const char *start, *end, *new_char;
997 char text[16];
998
999 if (!editor->active_entry)
1000 return;
1001
1002 entry = editor->active_entry;
1003
1004 if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
1005 return;
1006
1007 switch (sym) {
1008 case XKB_KEY_BackSpace:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001009 text_entry_commit_and_reset(entry);
1010
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001011 start = utf8_prev_char(entry->text, entry->text + entry->cursor);
1012
1013 if (start == NULL)
1014 break;
1015
1016 end = utf8_end_char(entry->text + entry->cursor);
1017 text_entry_delete_text(entry,
1018 start - entry->text,
1019 end - start);
1020 break;
1021 case XKB_KEY_Delete:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001022 text_entry_commit_and_reset(entry);
1023
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001024 start = utf8_start_char(entry->text, entry->text + entry->cursor);
1025
1026 if (start == NULL)
1027 break;
1028
1029 end = utf8_next_char(start);
1030
1031 if (end == NULL)
1032 break;
1033
1034 text_entry_delete_text(entry,
1035 start - entry->text,
1036 end - start);
1037 break;
1038 case XKB_KEY_Left:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001039 text_entry_commit_and_reset(entry);
1040
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001041 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
1042 if (new_char != NULL) {
1043 entry->cursor = new_char - entry->text;
1044 entry->anchor = entry->cursor;
1045 widget_schedule_redraw(entry->widget);
1046 }
1047 break;
1048 case XKB_KEY_Right:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001049 text_entry_commit_and_reset(entry);
1050
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001051 new_char = utf8_next_char(entry->text + entry->cursor);
1052 if (new_char != NULL) {
1053 entry->cursor = new_char - entry->text;
1054 entry->anchor = entry->cursor;
1055 widget_schedule_redraw(entry->widget);
1056 }
1057 break;
1058 default:
1059 if (xkb_keysym_to_utf8(sym, text, sizeof(text)) <= 0)
1060 break;
1061
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001062 text_entry_commit_and_reset(entry);
1063
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +01001064 text_entry_insert_at_cursor(entry, text, 0, 0);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001065 break;
1066 }
1067
1068 widget_schedule_redraw(entry->widget);
1069}
1070
1071static void
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001072global_handler(struct display *display, uint32_t name,
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001073 const char *interface, uint32_t version, void *data)
1074{
1075 struct editor *editor = data;
1076
Jan Arne Petersen51963742012-08-10 16:47:20 +02001077 if (!strcmp(interface, "text_model_factory")) {
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001078 editor->text_model_factory =
1079 display_bind(display, name,
1080 &text_model_factory_interface, 1);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001081 }
1082}
1083
1084int
1085main(int argc, char *argv[])
1086{
1087 struct editor editor;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001088 int i;
1089 uint32_t click_to_show = 0;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001090 const char *preferred_language = NULL;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001091
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001092 for (i = 1; i < argc; i++) {
Jan Arne Petersen61381972013-01-31 15:52:21 +01001093 if (strcmp("--click-to-show", argv[i]) == 0)
1094 click_to_show = 1;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001095 else if (strcmp("--preferred-language", argv[i]) == 0) {
1096 if (i + 1 < argc) {
1097 preferred_language = argv[i + 1];
1098 i++;
1099 }
1100 }
1101 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001102
Jan Arne Petersen25f6db52012-11-05 03:26:40 +01001103 memset(&editor, 0, sizeof editor);
1104
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001105#ifdef HAVE_PANGO
1106 g_type_init();
1107#endif
1108
Kristian Høgsberg4172f662013-02-20 15:27:49 -05001109 editor.display = display_create(&argc, argv);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001110 if (editor.display == NULL) {
1111 fprintf(stderr, "failed to create display: %m\n");
1112 return -1;
1113 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001114
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001115 display_set_user_data(editor.display, &editor);
1116 display_set_global_handler(editor.display, global_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001117
1118 editor.window = window_create(editor.display);
1119 editor.widget = frame_create(editor.window, &editor);
1120
1121 editor.entry = text_entry_create(&editor, "Entry");
Jan Arne Petersen61381972013-01-31 15:52:21 +01001122 editor.entry->click_to_show = click_to_show;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001123 if (preferred_language)
1124 editor.entry->preferred_language = strdup(preferred_language);
Jan Arne Petersen0558a932013-01-16 21:26:45 +01001125 editor.editor = text_entry_create(&editor, "Numeric");
1126 editor.editor->content_purpose = TEXT_MODEL_CONTENT_PURPOSE_NUMBER;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001127 editor.editor->click_to_show = click_to_show;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001128
1129 window_set_title(editor.window, "Text Editor");
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001130 window_set_key_handler(editor.window, key_handler);
1131 window_set_user_data(editor.window, &editor);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001132
1133 widget_set_redraw_handler(editor.widget, redraw_handler);
1134 widget_set_resize_handler(editor.widget, resize_handler);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001135 widget_set_button_handler(editor.widget, editor_button_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001136
1137 window_schedule_resize(editor.window, 500, 400);
1138
1139 display_run(editor.display);
1140
1141 text_entry_destroy(editor.entry);
1142 text_entry_destroy(editor.editor);
1143
1144 return 0;
1145}