blob: 027b562fdd71e0576fe18a6e661e16bed4b58c80 [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 Petersen78d00e42013-04-18 16:47:24 +020060 struct text_input *text_input;
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 Petersen78d00e42013-04-18 16:47:24 +020072 struct text_input_manager *text_input_manager;
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
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200132text_input_commit_string(void *data,
133 struct text_input *text_input,
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
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200152text_input_preedit_string(void *data,
153 struct text_input *text_input,
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 Petersen78d00e42013-04-18 16:47:24 +0200172text_input_delete_surrounding_text(void *data,
173 struct text_input *text_input,
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 Petersen78d00e42013-04-18 16:47:24 +0200204text_input_cursor_position(void *data,
205 struct text_input *text_input,
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100206 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 Petersen78d00e42013-04-18 16:47:24 +0200217text_input_preedit_styling(void *data,
218 struct text_input *text_input,
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) {
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200232 case TEXT_INPUT_PREEDIT_STYLE_DEFAULT:
233 case TEXT_INPUT_PREEDIT_STYLE_UNDERLINE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100234 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
235 break;
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200236 case TEXT_INPUT_PREEDIT_STYLE_INCORRECT:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100237 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_ERROR);
238 attr2 = pango_attr_underline_color_new(65535, 0, 0);
239 break;
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200240 case TEXT_INPUT_PREEDIT_STYLE_SELECTION:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100241 attr1 = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
242 attr2 = pango_attr_foreground_new(65535, 65535, 65535);
243 break;
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200244 case TEXT_INPUT_PREEDIT_STYLE_HIGHLIGHT:
245 case TEXT_INPUT_PREEDIT_STYLE_ACTIVE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100246 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
247 attr2 = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
248 break;
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200249 case TEXT_INPUT_PREEDIT_STYLE_INACTIVE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100250 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 Petersen78d00e42013-04-18 16:47:24 +0200269text_input_preedit_cursor(void *data,
270 struct text_input *text_input,
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 Petersen78d00e42013-04-18 16:47:24 +0200280text_input_modifiers_map(void *data,
281 struct text_input *text_input,
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100282 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
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200290text_input_keysym(void *data,
291 struct text_input *text_input,
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100292 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 Petersen78d00e42013-04-18 16:47:24 +0200359text_input_enter(void *data,
360 struct text_input *text_input,
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200361 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 Petersen78d00e42013-04-18 16:47:24 +0200374text_input_leave(void *data,
375 struct text_input *text_input)
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 Petersen78d00e42013-04-18 16:47:24 +0200383 text_input_hide_input_panel(text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100384
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
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200389text_input_input_panel_state(void *data,
390 struct text_input *text_input,
Jan Arne Petersen61381972013-01-31 15:52:21 +0100391 uint32_t state)
392{
393}
394
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200395static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200396text_input_language(void *data,
397 struct text_input *text_input,
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200398 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
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200405text_input_text_direction(void *data,
406 struct text_input *text_input,
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200407 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) {
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200416 case TEXT_INPUT_TEXT_DIRECTION_LTR:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200417 pango_direction = PANGO_DIRECTION_LTR;
418 break;
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200419 case TEXT_INPUT_TEXT_DIRECTION_RTL:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200420 pango_direction = PANGO_DIRECTION_RTL;
421 break;
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200422 case TEXT_INPUT_TEXT_DIRECTION_AUTO:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200423 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 Petersen78d00e42013-04-18 16:47:24 +0200430static const struct text_input_listener text_input_listener = {
431 text_input_enter,
432 text_input_leave,
433 text_input_modifiers_map,
434 text_input_input_panel_state,
435 text_input_preedit_string,
436 text_input_preedit_styling,
437 text_input_preedit_cursor,
438 text_input_commit_string,
439 text_input_cursor_position,
440 text_input_delete_surrounding_text,
441 text_input_keysym,
442 text_input_language,
443 text_input_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 Petersen78d00e42013-04-18 16:47:24 +0200459 entry->text_input = text_input_manager_create_text_input(editor->text_input_manager);
460 text_input_add_listener(entry->text_input, &text_input_listener, entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200461
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 Petersen78d00e42013-04-18 16:47:24 +0200472 text_input_destroy(entry->text_input);
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) {
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200540 text_input_show_input_panel(entry->text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100541
542 return;
543 }
544
545 if (!entry->click_to_show)
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200546 text_input_show_input_panel(entry->text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100547
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100548 entry->serial++;
549
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200550 text_input_activate(entry->text_input,
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 Petersen78d00e42013-04-18 16:47:24 +0200560 text_input_deactivate(entry->text_input,
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200561 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{
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200630 text_input_set_content_type(entry->text_input,
631 TEXT_INPUT_CONTENT_HINT_NONE,
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100632 entry->content_purpose);
633
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200634 text_input_set_surrounding_text(entry->text_input,
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100635 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)
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200640 text_input_set_preferred_language(entry->text_input,
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200641 entry->preferred_language);
642
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200643 text_input_commit_state(entry->text_input);
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 }
Jan Arne Petersen08015b62013-04-18 16:47:18 +0200703
704 entry->serial++;
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200705 text_input_reset(entry->text_input, entry->serial);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100706}
707
708static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200709text_entry_set_preedit(struct text_entry *entry,
710 const char *preedit_text,
711 int preedit_cursor)
712{
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100713 text_entry_reset_preedit(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200714
715 if (!preedit_text)
716 return;
717
Jan Arne Petersen46535312013-01-16 21:26:38 +0100718 entry->preedit.text = strdup(preedit_text);
719 entry->preedit.cursor = preedit_cursor;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200720
721 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100722
723 widget_schedule_redraw(entry->widget);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200724}
725
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100726static uint32_t
727text_entry_try_invoke_preedit_action(struct text_entry *entry,
728 int32_t x, int32_t y,
729 uint32_t button,
730 enum wl_pointer_button_state state)
731{
732 int index, trailing;
733 uint32_t cursor;
734
735 if (!entry->preedit.text)
736 return 0;
737
738 pango_layout_xy_to_index(entry->layout,
739 x * PANGO_SCALE, y * PANGO_SCALE,
740 &index, &trailing);
741 cursor = index + trailing;
742
743 if (cursor < entry->cursor ||
744 cursor > entry->cursor + strlen(entry->preedit.text)) {
745 return 0;
746 }
747
748 if (state == WL_POINTER_BUTTON_STATE_RELEASED)
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200749 text_input_invoke_action(entry->text_input,
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100750 button,
751 cursor - entry->cursor);
752
753 return 1;
754}
755
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200756static void
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200757text_entry_set_cursor_position(struct text_entry *entry,
758 int32_t x, int32_t y)
759{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100760 int index, trailing;
761
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100762 text_entry_commit_and_reset(entry);
763
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100764 pango_layout_xy_to_index(entry->layout,
765 x * PANGO_SCALE, y * PANGO_SCALE,
766 &index, &trailing);
767 entry->cursor = index + trailing;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200768
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200769 text_entry_update_layout(entry);
770
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200771 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100772
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100773 text_entry_update(entry);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200774}
775
776static void
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200777text_entry_set_anchor_position(struct text_entry *entry,
778 int32_t x, int32_t y)
779{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100780 int index, trailing;
781
782 pango_layout_xy_to_index(entry->layout,
783 x * PANGO_SCALE, y * PANGO_SCALE,
784 &index, &trailing);
785 entry->anchor = index + trailing;
786
787 text_entry_update_layout(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200788
789 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100790
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100791 text_entry_update(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200792}
793
794static void
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200795text_entry_delete_text(struct text_entry *entry,
796 uint32_t index, uint32_t length)
797{
798 if (entry->cursor > index)
799 entry->cursor -= length;
800
Jan Arne Petersen80ad1a92012-09-17 15:28:10 +0200801 entry->anchor = entry->cursor;
802
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200803 entry->text[index] = '\0';
804 strcat(entry->text, entry->text + index + length);
805
806 text_entry_update_layout(entry);
807
808 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100809
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100810 text_entry_update(entry);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200811}
812
813static void
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200814text_entry_delete_selected_text(struct text_entry *entry)
815{
816 uint32_t start_index = entry->anchor < entry->cursor ? entry->anchor : entry->cursor;
817 uint32_t end_index = entry->anchor < entry->cursor ? entry->cursor : entry->anchor;
818
819 if (entry->anchor == entry->cursor)
820 return;
821
822 text_entry_delete_text(entry, start_index, end_index - start_index);
823
824 entry->anchor = entry->cursor;
825}
826
827static void
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200828text_entry_draw_cursor(struct text_entry *entry, cairo_t *cr)
829{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100830 PangoRectangle extents;
831 PangoRectangle cursor_pos;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200832
Jan Arne Petersen46535312013-01-16 21:26:38 +0100833 if (entry->preedit.text && entry->preedit.cursor < 0)
834 return;
835
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100836 pango_layout_get_extents(entry->layout, &extents, NULL);
837 pango_layout_get_cursor_pos(entry->layout,
838 entry->cursor + entry->preedit.cursor,
839 &cursor_pos, NULL);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200840
841 cairo_set_line_width(cr, 1.0);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100842 cairo_move_to(cr, PANGO_PIXELS(cursor_pos.x), PANGO_PIXELS(extents.height) + 2);
843 cairo_line_to(cr, PANGO_PIXELS(cursor_pos.x), - 2);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200844 cairo_stroke(cr);
845}
846
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200847static const int text_offset_left = 10;
848
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200849static void
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200850text_entry_redraw_handler(struct widget *widget, void *data)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200851{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200852 struct text_entry *entry = data;
853 cairo_surface_t *surface;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200854 struct rectangle allocation;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200855 cairo_t *cr;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200856
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200857 surface = window_get_surface(entry->window);
858 widget_get_allocation(entry->widget, &allocation);
859
860 cr = cairo_create(surface);
861 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
862 cairo_clip(cr);
863
864 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
865
866 cairo_push_group(cr);
867 cairo_translate(cr, allocation.x, allocation.y);
868
869 cairo_set_source_rgba(cr, 1, 1, 1, 1);
870 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
871 cairo_fill(cr);
872
873 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
874
875 if (entry->active) {
876 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
877 cairo_set_line_width (cr, 3);
878 cairo_set_source_rgba(cr, 0, 0, 1, 1.0);
879 cairo_stroke(cr);
880 }
881
882 cairo_set_source_rgba(cr, 0, 0, 0, 1);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200883
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200884 cairo_translate(cr, text_offset_left, allocation.height / 2);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200885
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100886 if (!entry->layout)
887 entry->layout = pango_cairo_create_layout(cr);
888 else
889 pango_cairo_update_layout(cr, entry->layout);
890
891 text_entry_update_layout(entry);
892
893 pango_cairo_show_layout(cr, entry->layout);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200894
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200895 text_entry_draw_cursor(entry, cr);
896
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200897 cairo_pop_group_to_source(cr);
898 cairo_paint(cr);
899
900 cairo_destroy(cr);
901 cairo_surface_destroy(surface);
902}
903
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200904static int
905text_entry_motion_handler(struct widget *widget,
906 struct input *input, uint32_t time,
907 float x, float y, void *data)
908{
909 struct text_entry *entry = data;
910 struct rectangle allocation;
911
912 widget_get_allocation(entry->widget, &allocation);
913
914 text_entry_set_cursor_position(entry,
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200915 x - allocation.x - text_offset_left,
916 y - allocation.y - text_offset_left);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200917
918 return CURSOR_IBEAM;
919}
920
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200921static void
922text_entry_button_handler(struct widget *widget,
923 struct input *input, uint32_t time,
924 uint32_t button,
925 enum wl_pointer_button_state state, void *data)
926{
927 struct text_entry *entry = data;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200928 struct rectangle allocation;
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100929 struct editor *editor;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200930 int32_t x, y;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100931 uint32_t result;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200932
933 widget_get_allocation(entry->widget, &allocation);
934 input_get_position(input, &x, &y);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200935
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100936 x -= allocation.x + text_offset_left;
937 y -= allocation.y + text_offset_left;
938
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100939 editor = window_get_user_data(entry->window);
940
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100941 result = text_entry_try_invoke_preedit_action(entry, x, y, button, state);
942
943 if (result)
944 return;
945
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200946 if (button != BTN_LEFT) {
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200947 return;
948 }
949
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100950 text_entry_set_cursor_position(entry, x, y);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200951
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200952 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
953 struct wl_seat *seat = input_get_seat(input);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200954
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200955 text_entry_activate(entry, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100956 editor->active_entry = entry;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200957
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100958 text_entry_set_anchor_position(entry, x, y);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200959
960 widget_set_motion_handler(entry->widget, text_entry_motion_handler);
961 } else {
962 widget_set_motion_handler(entry->widget, NULL);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200963 }
964}
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200965
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200966static void
967editor_button_handler(struct widget *widget,
968 struct input *input, uint32_t time,
969 uint32_t button,
970 enum wl_pointer_button_state state, void *data)
971{
972 struct editor *editor = data;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200973
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200974 if (button != BTN_LEFT) {
975 return;
976 }
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200977
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200978 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
979 struct wl_seat *seat = input_get_seat(input);
980
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200981 text_entry_deactivate(editor->entry, seat);
982 text_entry_deactivate(editor->editor, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100983 editor->active_entry = NULL;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200984 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200985}
986
987static void
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100988key_handler(struct window *window,
989 struct input *input, uint32_t time,
990 uint32_t key, uint32_t sym, enum wl_keyboard_key_state state,
991 void *data)
992{
993 struct editor *editor = data;
994 struct text_entry *entry;
995 const char *start, *end, *new_char;
996 char text[16];
997
998 if (!editor->active_entry)
999 return;
1000
1001 entry = editor->active_entry;
1002
1003 if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
1004 return;
1005
1006 switch (sym) {
1007 case XKB_KEY_BackSpace:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001008 text_entry_commit_and_reset(entry);
1009
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001010 start = utf8_prev_char(entry->text, entry->text + entry->cursor);
1011
1012 if (start == NULL)
1013 break;
1014
1015 end = utf8_end_char(entry->text + entry->cursor);
1016 text_entry_delete_text(entry,
1017 start - entry->text,
1018 end - start);
1019 break;
1020 case XKB_KEY_Delete:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001021 text_entry_commit_and_reset(entry);
1022
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001023 start = utf8_start_char(entry->text, entry->text + entry->cursor);
1024
1025 if (start == NULL)
1026 break;
1027
1028 end = utf8_next_char(start);
1029
1030 if (end == NULL)
1031 break;
1032
1033 text_entry_delete_text(entry,
1034 start - entry->text,
1035 end - start);
1036 break;
1037 case XKB_KEY_Left:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001038 text_entry_commit_and_reset(entry);
1039
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001040 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
1041 if (new_char != NULL) {
1042 entry->cursor = new_char - entry->text;
1043 entry->anchor = entry->cursor;
1044 widget_schedule_redraw(entry->widget);
1045 }
1046 break;
1047 case XKB_KEY_Right:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001048 text_entry_commit_and_reset(entry);
1049
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001050 new_char = utf8_next_char(entry->text + entry->cursor);
1051 if (new_char != NULL) {
1052 entry->cursor = new_char - entry->text;
1053 entry->anchor = entry->cursor;
1054 widget_schedule_redraw(entry->widget);
1055 }
1056 break;
1057 default:
1058 if (xkb_keysym_to_utf8(sym, text, sizeof(text)) <= 0)
1059 break;
1060
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001061 text_entry_commit_and_reset(entry);
1062
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +01001063 text_entry_insert_at_cursor(entry, text, 0, 0);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001064 break;
1065 }
1066
1067 widget_schedule_redraw(entry->widget);
1068}
1069
1070static void
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001071global_handler(struct display *display, uint32_t name,
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001072 const char *interface, uint32_t version, void *data)
1073{
1074 struct editor *editor = data;
1075
Jan Arne Petersen78d00e42013-04-18 16:47:24 +02001076 if (!strcmp(interface, "text_input_manager")) {
1077 editor->text_input_manager =
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001078 display_bind(display, name,
Jan Arne Petersen78d00e42013-04-18 16:47:24 +02001079 &text_input_manager_interface, 1);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001080 }
1081}
1082
1083int
1084main(int argc, char *argv[])
1085{
1086 struct editor editor;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001087 int i;
1088 uint32_t click_to_show = 0;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001089 const char *preferred_language = NULL;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001090
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001091 for (i = 1; i < argc; i++) {
Jan Arne Petersen61381972013-01-31 15:52:21 +01001092 if (strcmp("--click-to-show", argv[i]) == 0)
1093 click_to_show = 1;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001094 else if (strcmp("--preferred-language", argv[i]) == 0) {
1095 if (i + 1 < argc) {
1096 preferred_language = argv[i + 1];
1097 i++;
1098 }
1099 }
1100 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001101
Jan Arne Petersen25f6db52012-11-05 03:26:40 +01001102 memset(&editor, 0, sizeof editor);
1103
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001104#ifdef HAVE_PANGO
1105 g_type_init();
1106#endif
1107
Kristian Høgsberg4172f662013-02-20 15:27:49 -05001108 editor.display = display_create(&argc, argv);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001109 if (editor.display == NULL) {
1110 fprintf(stderr, "failed to create display: %m\n");
1111 return -1;
1112 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001113
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001114 display_set_user_data(editor.display, &editor);
1115 display_set_global_handler(editor.display, global_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001116
1117 editor.window = window_create(editor.display);
1118 editor.widget = frame_create(editor.window, &editor);
1119
1120 editor.entry = text_entry_create(&editor, "Entry");
Jan Arne Petersen61381972013-01-31 15:52:21 +01001121 editor.entry->click_to_show = click_to_show;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001122 if (preferred_language)
1123 editor.entry->preferred_language = strdup(preferred_language);
Jan Arne Petersen0558a932013-01-16 21:26:45 +01001124 editor.editor = text_entry_create(&editor, "Numeric");
Jan Arne Petersen78d00e42013-04-18 16:47:24 +02001125 editor.editor->content_purpose = TEXT_INPUT_CONTENT_PURPOSE_NUMBER;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001126 editor.editor->click_to_show = click_to_show;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001127
1128 window_set_title(editor.window, "Text Editor");
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001129 window_set_key_handler(editor.window, key_handler);
1130 window_set_user_data(editor.window, &editor);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001131
1132 widget_set_redraw_handler(editor.widget, redraw_handler);
1133 widget_set_resize_handler(editor.widget, resize_handler);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001134 widget_set_button_handler(editor.widget, editor_button_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001135
1136 window_schedule_resize(editor.window, 500, 400);
1137
1138 display_run(editor.display);
1139
1140 text_entry_destroy(editor.entry);
1141 text_entry_destroy(editor.editor);
1142
1143 return 0;
1144}