blob: c40815ac74406eebc7a26a9d94b212bff8be0c3c [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 Petersen00191c72013-04-18 16:47:33 +020066 uint32_t reset_serial;
Jan Arne Petersen0558a932013-01-16 21:26:45 +010067 uint32_t content_purpose;
Jan Arne Petersen61381972013-01-31 15:52:21 +010068 uint32_t click_to_show;
Jan Arne Petersen9d419132013-04-18 16:47:16 +020069 char *preferred_language;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020070};
71
72struct editor {
Jan Arne Petersen78d00e42013-04-18 16:47:24 +020073 struct text_input_manager *text_input_manager;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020074 struct display *display;
75 struct window *window;
76 struct widget *widget;
77 struct text_entry *entry;
78 struct text_entry *editor;
Rob Bradford9d1d32b2012-11-18 19:06:49 +010079 struct text_entry *active_entry;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020080};
81
Jan Arne Petersen6345faa2012-11-05 03:26:39 +010082static const char *
83utf8_start_char(const char *text, const char *p)
84{
85 for (; p >= text; --p) {
86 if ((*p & 0xc0) != 0x80)
87 return p;
88 }
89 return NULL;
90}
91
92static const char *
93utf8_prev_char(const char *text, const char *p)
94{
95 if (p > text)
96 return utf8_start_char(text, --p);
97 return NULL;
98}
99
100static const char *
101utf8_end_char(const char *p)
102{
103 while ((*p & 0xc0) == 0x80)
104 p++;
105 return p;
106}
107
108static const char *
109utf8_next_char(const char *p)
110{
111 if (*p != 0)
112 return utf8_end_char(++p);
113 return NULL;
114}
115
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200116static void text_entry_redraw_handler(struct widget *widget, void *data);
117static void text_entry_button_handler(struct widget *widget,
118 struct input *input, uint32_t time,
119 uint32_t button,
120 enum wl_pointer_button_state state, void *data);
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100121static void text_entry_insert_at_cursor(struct text_entry *entry, const char *text,
122 int32_t cursor, int32_t anchor);
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200123static void text_entry_set_preedit(struct text_entry *entry,
124 const char *preedit_text,
125 int preedit_cursor);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200126static void text_entry_delete_text(struct text_entry *entry,
127 uint32_t index, uint32_t length);
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200128static void text_entry_delete_selected_text(struct text_entry *entry);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100129static void text_entry_reset_preedit(struct text_entry *entry);
130static void text_entry_commit_and_reset(struct text_entry *entry);
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200131static void text_entry_get_cursor_rectangle(struct text_entry *entry, struct rectangle *rectangle);
132static void text_entry_update(struct text_entry *entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200133
134static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200135text_input_commit_string(void *data,
136 struct text_input *text_input,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100137 uint32_t serial,
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100138 const char *text)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200139{
140 struct text_entry *entry = data;
141
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200142 if ((entry->serial - serial) > (entry->serial - entry->reset_serial)) {
143 fprintf(stderr, "Ignore commit. Serial: %u, Current: %u, Reset: %u\n",
144 serial, entry->serial, entry->reset_serial);
145 return;
146 }
147
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100148 text_entry_reset_preedit(entry);
149
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200150 text_entry_delete_selected_text(entry);
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100151 text_entry_insert_at_cursor(entry, text,
152 entry->pending_commit.cursor,
153 entry->pending_commit.anchor);
154
155 memset(&entry->pending_commit, 0, sizeof entry->pending_commit);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200156
157 widget_schedule_redraw(entry->widget);
158}
159
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200160static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200161text_input_preedit_string(void *data,
162 struct text_input *text_input,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100163 uint32_t serial,
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200164 const char *text,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100165 const char *commit)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200166{
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200167 struct text_entry *entry = data;
168
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200169 text_entry_delete_selected_text(entry);
Jan Arne Petersen46535312013-01-16 21:26:38 +0100170 text_entry_set_preedit(entry, text, entry->preedit_info.cursor);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100171 entry->preedit.commit = strdup(commit);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100172 entry->preedit.attr_list = entry->preedit_info.attr_list;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100173
174 entry->preedit_info.cursor = 0;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100175 entry->preedit_info.attr_list = NULL;
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200176
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200177 text_entry_update(entry);
178
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200179 widget_schedule_redraw(entry->widget);
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200180}
181
182static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200183text_input_delete_surrounding_text(void *data,
184 struct text_input *text_input,
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200185 int32_t index,
186 uint32_t length)
187{
188 struct text_entry *entry = data;
189 uint32_t cursor_index = index + entry->cursor;
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100190 const char *start, *end;
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200191
192 if (cursor_index > strlen(entry->text)) {
193 fprintf(stderr, "Invalid cursor index %d\n", index);
194 return;
195 }
196
197 if (cursor_index + length > strlen(entry->text)) {
198 fprintf(stderr, "Invalid length %d\n", length);
199 return;
200 }
201
202 if (length == 0)
203 return;
204
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100205 start = utf8_start_char(entry->text, entry->text + cursor_index);
206 end = utf8_end_char(entry->text + cursor_index + length);
207
208 text_entry_delete_text(entry,
209 start - entry->text,
210 end - start);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200211}
212
213static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200214text_input_cursor_position(void *data,
215 struct text_input *text_input,
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100216 int32_t index,
217 int32_t anchor)
218{
219 struct text_entry *entry = data;
220
221 entry->pending_commit.cursor = index;
222 entry->pending_commit.anchor = anchor;
223}
224
225static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200226text_input_preedit_styling(void *data,
227 struct text_input *text_input,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100228 uint32_t index,
229 uint32_t length,
230 uint32_t style)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200231{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100232 struct text_entry *entry = data;
233 PangoAttribute *attr1 = NULL;
234 PangoAttribute *attr2 = NULL;
235
236 if (!entry->preedit_info.attr_list)
237 entry->preedit_info.attr_list = pango_attr_list_new();
238
239 switch (style) {
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200240 case TEXT_INPUT_PREEDIT_STYLE_DEFAULT:
241 case TEXT_INPUT_PREEDIT_STYLE_UNDERLINE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100242 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
243 break;
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200244 case TEXT_INPUT_PREEDIT_STYLE_INCORRECT:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100245 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_ERROR);
246 attr2 = pango_attr_underline_color_new(65535, 0, 0);
247 break;
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200248 case TEXT_INPUT_PREEDIT_STYLE_SELECTION:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100249 attr1 = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
250 attr2 = pango_attr_foreground_new(65535, 65535, 65535);
251 break;
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200252 case TEXT_INPUT_PREEDIT_STYLE_HIGHLIGHT:
253 case TEXT_INPUT_PREEDIT_STYLE_ACTIVE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100254 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
255 attr2 = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
256 break;
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200257 case TEXT_INPUT_PREEDIT_STYLE_INACTIVE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100258 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
259 attr2 = pango_attr_foreground_new(0.3 * 65535, 0.3 * 65535, 0.3 * 65535);
260 break;
261 }
262
263 if (attr1) {
264 attr1->start_index = entry->cursor + index;
265 attr1->end_index = entry->cursor + index + length;
266 pango_attr_list_insert(entry->preedit_info.attr_list, attr1);
267 }
268
269 if (attr2) {
270 attr2->start_index = entry->cursor + index;
271 attr2->end_index = entry->cursor + index + length;
272 pango_attr_list_insert(entry->preedit_info.attr_list, attr2);
273 }
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200274}
275
276static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200277text_input_preedit_cursor(void *data,
278 struct text_input *text_input,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100279 int32_t index)
280{
281 struct text_entry *entry = data;
282
283 entry->preedit_info.cursor = index;
284}
285
286static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200287text_input_modifiers_map(void *data,
288 struct text_input *text_input,
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100289 struct wl_array *map)
290{
Jan Arne Petersencd997062012-11-18 19:06:44 +0100291 struct text_entry *entry = data;
292
293 entry->keysym.shift_mask = keysym_modifiers_get_mask(map, "Shift");
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100294}
295
296static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200297text_input_keysym(void *data,
298 struct text_input *text_input,
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100299 uint32_t serial,
300 uint32_t time,
301 uint32_t key,
302 uint32_t state,
303 uint32_t modifiers)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200304{
Jan Arne Petersen8aba11d2012-09-17 15:28:07 +0200305 struct text_entry *entry = data;
Jan Arne Petersencd997062012-11-18 19:06:44 +0100306 const char *state_label = "release";
307 const char *key_label = "Unknown";
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100308 const char *new_char;
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200309
310 if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
311 state_label = "pressed";
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200312 }
313
Jan Arne Petersencd997062012-11-18 19:06:44 +0100314 if (key == XKB_KEY_Left ||
315 key == XKB_KEY_Right) {
316 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
317 return;
318
319 if (key == XKB_KEY_Left)
320 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
321 else
322 new_char = utf8_next_char(entry->text + entry->cursor);
323
324 if (new_char != NULL) {
325 entry->cursor = new_char - entry->text;
326 if (!(modifiers & entry->keysym.shift_mask))
327 entry->anchor = entry->cursor;
328 widget_schedule_redraw(entry->widget);
329 }
330
331 return;
332 }
333
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100334 if (key == XKB_KEY_BackSpace) {
335 const char *start, *end;
336
Jan Arne Petersendfd34462013-04-18 16:47:26 +0200337 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
338 return;
339
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100340 text_entry_commit_and_reset(entry);
341
342 start = utf8_prev_char(entry->text, entry->text + entry->cursor);
343
344 if (start == NULL)
345 return;
346
347 end = utf8_end_char(entry->text + entry->cursor);
348 text_entry_delete_text(entry,
349 start - entry->text,
350 end - start);
351
352 return;
353 }
354
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200355 switch (key) {
356 case XKB_KEY_Tab:
357 key_label = "Tab";
358 break;
359 case XKB_KEY_KP_Enter:
Jan Arne Petersencd997062012-11-18 19:06:44 +0100360 case XKB_KEY_Return:
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200361 key_label = "Enter";
362 break;
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200363 }
364
365 fprintf(stderr, "%s key was %s.\n", key_label, state_label);
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200366}
367
368static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200369text_input_enter(void *data,
370 struct text_input *text_input,
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200371 struct wl_surface *surface)
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200372{
373 struct text_entry *entry = data;
374
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200375 if (surface != window_get_wl_surface(entry->window))
376 return;
377
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200378 entry->active = 1;
379
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200380 text_entry_update(entry);
381 entry->reset_serial = entry->serial;
382
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200383 widget_schedule_redraw(entry->widget);
384}
385
386static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200387text_input_leave(void *data,
388 struct text_input *text_input)
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200389{
390 struct text_entry *entry = data;
391
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100392 text_entry_commit_and_reset(entry);
393
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200394 entry->active = 0;
395
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200396 text_input_hide_input_panel(text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100397
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200398 widget_schedule_redraw(entry->widget);
399}
400
Jan Arne Petersen61381972013-01-31 15:52:21 +0100401static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200402text_input_input_panel_state(void *data,
403 struct text_input *text_input,
Jan Arne Petersen61381972013-01-31 15:52:21 +0100404 uint32_t state)
405{
406}
407
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200408static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200409text_input_language(void *data,
410 struct text_input *text_input,
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200411 uint32_t serial,
412 const char *language)
413{
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200414 fprintf(stderr, "input language is %s \n", language);
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200415}
416
417static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200418text_input_text_direction(void *data,
419 struct text_input *text_input,
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200420 uint32_t serial,
421 uint32_t direction)
422{
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200423 struct text_entry *entry = data;
424 PangoContext *context = pango_layout_get_context(entry->layout);
425 PangoDirection pango_direction;
426
427
428 switch (direction) {
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200429 case TEXT_INPUT_TEXT_DIRECTION_LTR:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200430 pango_direction = PANGO_DIRECTION_LTR;
431 break;
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200432 case TEXT_INPUT_TEXT_DIRECTION_RTL:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200433 pango_direction = PANGO_DIRECTION_RTL;
434 break;
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200435 case TEXT_INPUT_TEXT_DIRECTION_AUTO:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200436 default:
437 pango_direction = PANGO_DIRECTION_NEUTRAL;
438 }
439
440 pango_context_set_base_dir(context, pango_direction);
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200441}
442
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200443static const struct text_input_listener text_input_listener = {
444 text_input_enter,
445 text_input_leave,
446 text_input_modifiers_map,
447 text_input_input_panel_state,
448 text_input_preedit_string,
449 text_input_preedit_styling,
450 text_input_preedit_cursor,
451 text_input_commit_string,
452 text_input_cursor_position,
453 text_input_delete_surrounding_text,
454 text_input_keysym,
455 text_input_language,
456 text_input_text_direction
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200457};
458
459static struct text_entry*
460text_entry_create(struct editor *editor, const char *text)
461{
462 struct text_entry *entry;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200463
Jan Arne Petersencd997062012-11-18 19:06:44 +0100464 entry = calloc(1, sizeof *entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200465
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200466 entry->widget = widget_add_widget(editor->widget, entry);
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200467 entry->window = editor->window;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200468 entry->text = strdup(text);
469 entry->active = 0;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200470 entry->cursor = strlen(text);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200471 entry->anchor = entry->cursor;
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200472 entry->text_input = text_input_manager_create_text_input(editor->text_input_manager);
473 text_input_add_listener(entry->text_input, &text_input_listener, entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200474
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200475 widget_set_redraw_handler(entry->widget, text_entry_redraw_handler);
476 widget_set_button_handler(entry->widget, text_entry_button_handler);
477
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200478 return entry;
479}
480
481static void
482text_entry_destroy(struct text_entry *entry)
483{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200484 widget_destroy(entry->widget);
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200485 text_input_destroy(entry->text_input);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100486 g_clear_object(&entry->layout);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200487 free(entry->text);
488 free(entry);
489}
490
491static void
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200492redraw_handler(struct widget *widget, void *data)
493{
494 struct editor *editor = data;
495 cairo_surface_t *surface;
496 struct rectangle allocation;
497 cairo_t *cr;
498
499 surface = window_get_surface(editor->window);
500 widget_get_allocation(editor->widget, &allocation);
501
502 cr = cairo_create(surface);
503 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
504 cairo_clip(cr);
505
506 cairo_translate(cr, allocation.x, allocation.y);
507
508 /* Draw background */
509 cairo_push_group(cr);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200510 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200511 cairo_set_source_rgba(cr, 1, 1, 1, 1);
512 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
513 cairo_fill(cr);
514
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200515 cairo_pop_group_to_source(cr);
516 cairo_paint(cr);
517
518 cairo_destroy(cr);
519 cairo_surface_destroy(surface);
520}
521
522static void
523text_entry_allocate(struct text_entry *entry, int32_t x, int32_t y,
524 int32_t width, int32_t height)
525{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200526 widget_set_allocation(entry->widget, x, y, width, height);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200527}
528
529static void
530resize_handler(struct widget *widget,
531 int32_t width, int32_t height, void *data)
532{
533 struct editor *editor = data;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200534 struct rectangle allocation;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200535
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200536 widget_get_allocation(editor->widget, &allocation);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200537
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200538 text_entry_allocate(editor->entry,
539 allocation.x + 20, allocation.y + 20,
540 width - 40, height / 2 - 40);
541 text_entry_allocate(editor->editor,
542 allocation.x + 20, allocation.y + height / 2 + 20,
543 width - 40, height / 2 - 40);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200544}
545
546static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200547text_entry_activate(struct text_entry *entry,
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200548 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200549{
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200550 struct wl_surface *surface = window_get_wl_surface(entry->window);
551
Jan Arne Petersen61381972013-01-31 15:52:21 +0100552 if (entry->click_to_show && entry->active) {
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200553 text_input_show_input_panel(entry->text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100554
555 return;
556 }
557
558 if (!entry->click_to_show)
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200559 text_input_show_input_panel(entry->text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100560
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200561 text_input_activate(entry->text_input,
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200562 seat,
563 surface);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200564}
565
566static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200567text_entry_deactivate(struct text_entry *entry,
568 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200569{
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200570 text_input_deactivate(entry->text_input,
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200571 seat);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200572}
573
574static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200575text_entry_update_layout(struct text_entry *entry)
576{
577 char *text;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100578 PangoAttrList *attr_list;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200579
Philipp Brüschweiler237358b2012-10-02 11:06:51 +0200580 assert(((unsigned int)entry->cursor) <= strlen(entry->text) +
Jan Arne Petersen46535312013-01-16 21:26:38 +0100581 (entry->preedit.text ? strlen(entry->preedit.text) : 0));
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200582
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100583 if (entry->preedit.text) {
584 text = malloc(strlen(entry->text) + strlen(entry->preedit.text) + 1);
585 strncpy(text, entry->text, entry->cursor);
586 strcpy(text + entry->cursor, entry->preedit.text);
587 strcpy(text + entry->cursor + strlen(entry->preedit.text),
588 entry->text + entry->cursor);
589 } else {
590 text = strdup(entry->text);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200591 }
592
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100593 if (entry->cursor != entry->anchor) {
594 int start_index = MIN(entry->cursor, entry->anchor);
595 int end_index = MAX(entry->cursor, entry->anchor);
596 PangoAttribute *attr;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200597
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100598 attr_list = pango_attr_list_copy(entry->preedit.attr_list);
599
600 if (!attr_list)
601 attr_list = pango_attr_list_new();
602
603 attr = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
604 attr->start_index = start_index;
605 attr->end_index = end_index;
606 pango_attr_list_insert(attr_list, attr);
607
608 attr = pango_attr_foreground_new(65535, 65535, 65535);
609 attr->start_index = start_index;
610 attr->end_index = end_index;
611 pango_attr_list_insert(attr_list, attr);
612 } else {
613 attr_list = pango_attr_list_ref(entry->preedit.attr_list);
614 }
615
616 if (entry->preedit.text && !entry->preedit.attr_list) {
617 PangoAttribute *attr;
618
619 if (!attr_list)
620 attr_list = pango_attr_list_new();
621
622 attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
623 attr->start_index = entry->cursor;
624 attr->end_index = entry->cursor + strlen(entry->preedit.text);
625 pango_attr_list_insert(attr_list, attr);
626 }
627
628 if (entry->layout) {
629 pango_layout_set_text(entry->layout, text, -1);
630 pango_layout_set_attributes(entry->layout, attr_list);
631 }
632
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200633 free(text);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100634 pango_attr_list_unref(attr_list);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200635}
636
637static void
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100638text_entry_update(struct text_entry *entry)
639{
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200640 struct rectangle cursor_rectangle;
641
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200642 text_input_set_content_type(entry->text_input,
643 TEXT_INPUT_CONTENT_HINT_NONE,
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100644 entry->content_purpose);
645
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200646 text_input_set_surrounding_text(entry->text_input,
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100647 entry->text,
648 entry->cursor,
649 entry->anchor);
Jan Arne Petersen0eabcaa2013-01-31 15:52:20 +0100650
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200651 if (entry->preferred_language)
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200652 text_input_set_preferred_language(entry->text_input,
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200653 entry->preferred_language);
654
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200655 text_entry_get_cursor_rectangle(entry, &cursor_rectangle);
656 text_input_set_cursor_rectangle(entry->text_input, cursor_rectangle.x, cursor_rectangle.y,
657 cursor_rectangle.width, cursor_rectangle.height);
658
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200659 text_input_commit_state(entry->text_input, ++entry->serial);
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100660}
661
662static void
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100663text_entry_insert_at_cursor(struct text_entry *entry, const char *text,
664 int32_t cursor, int32_t anchor)
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200665{
666 char *new_text = malloc(strlen(entry->text) + strlen(text) + 1);
667
668 strncpy(new_text, entry->text, entry->cursor);
669 strcpy(new_text + entry->cursor, text);
670 strcpy(new_text + entry->cursor + strlen(text),
671 entry->text + entry->cursor);
672
673 free(entry->text);
674 entry->text = new_text;
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100675 if (anchor >= 0)
676 entry->anchor = entry->cursor + strlen(text) + anchor;
677 else
678 entry->anchor = entry->cursor + 1 + anchor;
679 if (cursor >= 0)
680 entry->cursor += strlen(text) + cursor;
681 else
682 entry->cursor += 1 + cursor;
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200683
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200684 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100685
686 widget_schedule_redraw(entry->widget);
687
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100688 text_entry_update(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200689}
690
691static void
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100692text_entry_reset_preedit(struct text_entry *entry)
693{
694 entry->preedit.cursor = 0;
695
696 free(entry->preedit.text);
697 entry->preedit.text = NULL;
698
699 free(entry->preedit.commit);
700 entry->preedit.commit = NULL;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100701
702 pango_attr_list_unref(entry->preedit.attr_list);
703 entry->preedit.attr_list = NULL;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100704}
705
706static void
707text_entry_commit_and_reset(struct text_entry *entry)
708{
709 char *commit = NULL;
710
711 if (entry->preedit.commit)
712 commit = strdup(entry->preedit.commit);
713
714 text_entry_reset_preedit(entry);
715 if (commit) {
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100716 text_entry_insert_at_cursor(entry, commit, 0, 0);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100717 free(commit);
718 }
Jan Arne Petersen08015b62013-04-18 16:47:18 +0200719
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200720 text_input_reset(entry->text_input);
721 text_entry_update(entry);
722 entry->reset_serial = entry->serial;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100723}
724
725static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200726text_entry_set_preedit(struct text_entry *entry,
727 const char *preedit_text,
728 int preedit_cursor)
729{
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100730 text_entry_reset_preedit(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200731
732 if (!preedit_text)
733 return;
734
Jan Arne Petersen46535312013-01-16 21:26:38 +0100735 entry->preedit.text = strdup(preedit_text);
736 entry->preedit.cursor = preedit_cursor;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200737
738 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100739
740 widget_schedule_redraw(entry->widget);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200741}
742
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100743static uint32_t
744text_entry_try_invoke_preedit_action(struct text_entry *entry,
745 int32_t x, int32_t y,
746 uint32_t button,
747 enum wl_pointer_button_state state)
748{
749 int index, trailing;
750 uint32_t cursor;
751
752 if (!entry->preedit.text)
753 return 0;
754
755 pango_layout_xy_to_index(entry->layout,
756 x * PANGO_SCALE, y * PANGO_SCALE,
757 &index, &trailing);
758 cursor = index + trailing;
759
760 if (cursor < entry->cursor ||
761 cursor > entry->cursor + strlen(entry->preedit.text)) {
762 return 0;
763 }
764
765 if (state == WL_POINTER_BUTTON_STATE_RELEASED)
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200766 text_input_invoke_action(entry->text_input,
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100767 button,
768 cursor - entry->cursor);
769
770 return 1;
771}
772
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200773static void
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200774text_entry_set_cursor_position(struct text_entry *entry,
775 int32_t x, int32_t y)
776{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100777 int index, trailing;
778
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100779 text_entry_commit_and_reset(entry);
780
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100781 pango_layout_xy_to_index(entry->layout,
782 x * PANGO_SCALE, y * PANGO_SCALE,
783 &index, &trailing);
784 entry->cursor = index + trailing;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200785
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200786 text_entry_update_layout(entry);
787
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200788 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100789
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100790 text_entry_update(entry);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200791}
792
793static void
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200794text_entry_set_anchor_position(struct text_entry *entry,
795 int32_t x, int32_t y)
796{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100797 int index, trailing;
798
799 pango_layout_xy_to_index(entry->layout,
800 x * PANGO_SCALE, y * PANGO_SCALE,
801 &index, &trailing);
802 entry->anchor = index + trailing;
803
804 text_entry_update_layout(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200805
806 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100807
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100808 text_entry_update(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200809}
810
811static void
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200812text_entry_delete_text(struct text_entry *entry,
813 uint32_t index, uint32_t length)
814{
815 if (entry->cursor > index)
816 entry->cursor -= length;
817
Jan Arne Petersen80ad1a92012-09-17 15:28:10 +0200818 entry->anchor = entry->cursor;
819
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200820 entry->text[index] = '\0';
821 strcat(entry->text, entry->text + index + length);
822
823 text_entry_update_layout(entry);
824
825 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100826
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100827 text_entry_update(entry);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200828}
829
830static void
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200831text_entry_delete_selected_text(struct text_entry *entry)
832{
833 uint32_t start_index = entry->anchor < entry->cursor ? entry->anchor : entry->cursor;
834 uint32_t end_index = entry->anchor < entry->cursor ? entry->cursor : entry->anchor;
835
836 if (entry->anchor == entry->cursor)
837 return;
838
839 text_entry_delete_text(entry, start_index, end_index - start_index);
840
841 entry->anchor = entry->cursor;
842}
843
844static void
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200845text_entry_get_cursor_rectangle(struct text_entry *entry, struct rectangle *rectangle)
846{
847 struct rectangle allocation;
848 PangoRectangle extents;
849 PangoRectangle cursor_pos;
850
851 widget_get_allocation(entry->widget, &allocation);
852
853 if (entry->preedit.text && entry->preedit.cursor < 0) {
854 rectangle->x = 0;
855 rectangle->y = 0;
856 rectangle->width = 0;
857 rectangle->height = 0;
858 return;
859 }
860
861 pango_layout_get_extents(entry->layout, &extents, NULL);
862 pango_layout_get_cursor_pos(entry->layout,
863 entry->cursor + entry->preedit.cursor,
864 &cursor_pos, NULL);
865
866 rectangle->x = allocation.x + (allocation.height / 2) + PANGO_PIXELS(cursor_pos.x);
867 rectangle->y = allocation.y + 10 + PANGO_PIXELS(cursor_pos.y);
868 rectangle->width = PANGO_PIXELS(cursor_pos.width);
869 rectangle->height = PANGO_PIXELS(cursor_pos.height);
870}
871
872static void
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200873text_entry_draw_cursor(struct text_entry *entry, cairo_t *cr)
874{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100875 PangoRectangle extents;
876 PangoRectangle cursor_pos;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200877
Jan Arne Petersen46535312013-01-16 21:26:38 +0100878 if (entry->preedit.text && entry->preedit.cursor < 0)
879 return;
880
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100881 pango_layout_get_extents(entry->layout, &extents, NULL);
882 pango_layout_get_cursor_pos(entry->layout,
883 entry->cursor + entry->preedit.cursor,
884 &cursor_pos, NULL);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200885
886 cairo_set_line_width(cr, 1.0);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100887 cairo_move_to(cr, PANGO_PIXELS(cursor_pos.x), PANGO_PIXELS(extents.height) + 2);
888 cairo_line_to(cr, PANGO_PIXELS(cursor_pos.x), - 2);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200889 cairo_stroke(cr);
890}
891
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200892static const int text_offset_left = 10;
893
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200894static void
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200895text_entry_redraw_handler(struct widget *widget, void *data)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200896{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200897 struct text_entry *entry = data;
898 cairo_surface_t *surface;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200899 struct rectangle allocation;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200900 cairo_t *cr;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200901
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200902 surface = window_get_surface(entry->window);
903 widget_get_allocation(entry->widget, &allocation);
904
905 cr = cairo_create(surface);
906 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
907 cairo_clip(cr);
908
909 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
910
911 cairo_push_group(cr);
912 cairo_translate(cr, allocation.x, allocation.y);
913
914 cairo_set_source_rgba(cr, 1, 1, 1, 1);
915 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
916 cairo_fill(cr);
917
918 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
919
920 if (entry->active) {
921 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
922 cairo_set_line_width (cr, 3);
923 cairo_set_source_rgba(cr, 0, 0, 1, 1.0);
924 cairo_stroke(cr);
925 }
926
927 cairo_set_source_rgba(cr, 0, 0, 0, 1);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200928
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200929 cairo_translate(cr, text_offset_left, allocation.height / 2);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200930
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100931 if (!entry->layout)
932 entry->layout = pango_cairo_create_layout(cr);
933 else
934 pango_cairo_update_layout(cr, entry->layout);
935
936 text_entry_update_layout(entry);
937
938 pango_cairo_show_layout(cr, entry->layout);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200939
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200940 text_entry_draw_cursor(entry, cr);
941
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200942 cairo_pop_group_to_source(cr);
943 cairo_paint(cr);
944
945 cairo_destroy(cr);
946 cairo_surface_destroy(surface);
947}
948
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200949static int
950text_entry_motion_handler(struct widget *widget,
951 struct input *input, uint32_t time,
952 float x, float y, void *data)
953{
954 struct text_entry *entry = data;
955 struct rectangle allocation;
956
957 widget_get_allocation(entry->widget, &allocation);
958
959 text_entry_set_cursor_position(entry,
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200960 x - allocation.x - text_offset_left,
961 y - allocation.y - text_offset_left);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200962
963 return CURSOR_IBEAM;
964}
965
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200966static void
967text_entry_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 text_entry *entry = data;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200973 struct rectangle allocation;
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100974 struct editor *editor;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200975 int32_t x, y;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100976 uint32_t result;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200977
978 widget_get_allocation(entry->widget, &allocation);
979 input_get_position(input, &x, &y);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200980
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100981 x -= allocation.x + text_offset_left;
982 y -= allocation.y + text_offset_left;
983
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100984 editor = window_get_user_data(entry->window);
985
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100986 result = text_entry_try_invoke_preedit_action(entry, x, y, button, state);
987
988 if (result)
989 return;
990
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200991 if (button != BTN_LEFT) {
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200992 return;
993 }
994
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100995 text_entry_set_cursor_position(entry, x, y);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200996
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200997 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
998 struct wl_seat *seat = input_get_seat(input);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200999
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001000 text_entry_activate(entry, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001001 editor->active_entry = entry;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001002
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001003 text_entry_set_anchor_position(entry, x, y);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001004
1005 widget_set_motion_handler(entry->widget, text_entry_motion_handler);
1006 } else {
1007 widget_set_motion_handler(entry->widget, NULL);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001008 }
1009}
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001010
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001011static void
1012editor_button_handler(struct widget *widget,
1013 struct input *input, uint32_t time,
1014 uint32_t button,
1015 enum wl_pointer_button_state state, void *data)
1016{
1017 struct editor *editor = data;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001018
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001019 if (button != BTN_LEFT) {
1020 return;
1021 }
Jan Arne Petersene829adc2012-08-10 16:47:22 +02001022
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001023 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
1024 struct wl_seat *seat = input_get_seat(input);
1025
Jan Arne Petersene829adc2012-08-10 16:47:22 +02001026 text_entry_deactivate(editor->entry, seat);
1027 text_entry_deactivate(editor->editor, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001028 editor->active_entry = NULL;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001029 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001030}
1031
1032static void
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001033key_handler(struct window *window,
1034 struct input *input, uint32_t time,
1035 uint32_t key, uint32_t sym, enum wl_keyboard_key_state state,
1036 void *data)
1037{
1038 struct editor *editor = data;
1039 struct text_entry *entry;
1040 const char *start, *end, *new_char;
1041 char text[16];
1042
1043 if (!editor->active_entry)
1044 return;
1045
1046 entry = editor->active_entry;
1047
1048 if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
1049 return;
1050
1051 switch (sym) {
1052 case XKB_KEY_BackSpace:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001053 text_entry_commit_and_reset(entry);
1054
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001055 start = utf8_prev_char(entry->text, entry->text + entry->cursor);
1056
1057 if (start == NULL)
1058 break;
1059
1060 end = utf8_end_char(entry->text + entry->cursor);
1061 text_entry_delete_text(entry,
1062 start - entry->text,
1063 end - start);
1064 break;
1065 case XKB_KEY_Delete:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001066 text_entry_commit_and_reset(entry);
1067
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001068 start = utf8_start_char(entry->text, entry->text + entry->cursor);
1069
1070 if (start == NULL)
1071 break;
1072
1073 end = utf8_next_char(start);
1074
1075 if (end == NULL)
1076 break;
1077
1078 text_entry_delete_text(entry,
1079 start - entry->text,
1080 end - start);
1081 break;
1082 case XKB_KEY_Left:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001083 text_entry_commit_and_reset(entry);
1084
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001085 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
1086 if (new_char != NULL) {
1087 entry->cursor = new_char - entry->text;
1088 entry->anchor = entry->cursor;
1089 widget_schedule_redraw(entry->widget);
1090 }
1091 break;
1092 case XKB_KEY_Right:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001093 text_entry_commit_and_reset(entry);
1094
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001095 new_char = utf8_next_char(entry->text + entry->cursor);
1096 if (new_char != NULL) {
1097 entry->cursor = new_char - entry->text;
1098 entry->anchor = entry->cursor;
1099 widget_schedule_redraw(entry->widget);
1100 }
1101 break;
1102 default:
1103 if (xkb_keysym_to_utf8(sym, text, sizeof(text)) <= 0)
1104 break;
1105
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001106 text_entry_commit_and_reset(entry);
1107
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +01001108 text_entry_insert_at_cursor(entry, text, 0, 0);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001109 break;
1110 }
1111
1112 widget_schedule_redraw(entry->widget);
1113}
1114
1115static void
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001116global_handler(struct display *display, uint32_t name,
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001117 const char *interface, uint32_t version, void *data)
1118{
1119 struct editor *editor = data;
1120
Jan Arne Petersen78d00e42013-04-18 16:47:24 +02001121 if (!strcmp(interface, "text_input_manager")) {
1122 editor->text_input_manager =
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001123 display_bind(display, name,
Jan Arne Petersen78d00e42013-04-18 16:47:24 +02001124 &text_input_manager_interface, 1);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001125 }
1126}
1127
1128int
1129main(int argc, char *argv[])
1130{
1131 struct editor editor;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001132 int i;
1133 uint32_t click_to_show = 0;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001134 const char *preferred_language = NULL;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001135
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001136 for (i = 1; i < argc; i++) {
Jan Arne Petersen61381972013-01-31 15:52:21 +01001137 if (strcmp("--click-to-show", argv[i]) == 0)
1138 click_to_show = 1;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001139 else if (strcmp("--preferred-language", argv[i]) == 0) {
1140 if (i + 1 < argc) {
1141 preferred_language = argv[i + 1];
1142 i++;
1143 }
1144 }
1145 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001146
Jan Arne Petersen25f6db52012-11-05 03:26:40 +01001147 memset(&editor, 0, sizeof editor);
1148
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001149#ifdef HAVE_PANGO
1150 g_type_init();
1151#endif
1152
Kristian Høgsberg4172f662013-02-20 15:27:49 -05001153 editor.display = display_create(&argc, argv);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001154 if (editor.display == NULL) {
1155 fprintf(stderr, "failed to create display: %m\n");
1156 return -1;
1157 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001158
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001159 display_set_user_data(editor.display, &editor);
1160 display_set_global_handler(editor.display, global_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001161
1162 editor.window = window_create(editor.display);
1163 editor.widget = frame_create(editor.window, &editor);
1164
1165 editor.entry = text_entry_create(&editor, "Entry");
Jan Arne Petersen61381972013-01-31 15:52:21 +01001166 editor.entry->click_to_show = click_to_show;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001167 if (preferred_language)
1168 editor.entry->preferred_language = strdup(preferred_language);
Jan Arne Petersen0558a932013-01-16 21:26:45 +01001169 editor.editor = text_entry_create(&editor, "Numeric");
Jan Arne Petersen78d00e42013-04-18 16:47:24 +02001170 editor.editor->content_purpose = TEXT_INPUT_CONTENT_PURPOSE_NUMBER;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001171 editor.editor->click_to_show = click_to_show;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001172
1173 window_set_title(editor.window, "Text Editor");
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001174 window_set_key_handler(editor.window, key_handler);
1175 window_set_user_data(editor.window, &editor);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001176
1177 widget_set_redraw_handler(editor.widget, redraw_handler);
1178 widget_set_resize_handler(editor.widget, resize_handler);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001179 widget_set_button_handler(editor.widget, editor_button_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001180
1181 window_schedule_resize(editor.window, 500, 400);
1182
1183 display_run(editor.display);
1184
1185 text_entry_destroy(editor.entry);
1186 text_entry_destroy(editor.editor);
1187
1188 return 0;
1189}