blob: 7c90ed9a1b754757b6aa4115c07037bd8678b433 [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;
Jan Arne Petersen919bc142013-04-18 16:47:34 +020059 uint32_t delete_index;
60 uint32_t delete_length;
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +010061 } pending_commit;
Jan Arne Petersen62ece762013-04-18 16:47:36 +020062 struct wl_text_input *text_input;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010063 PangoLayout *layout;
Jan Arne Petersencd997062012-11-18 19:06:44 +010064 struct {
65 xkb_mod_mask_t shift_mask;
66 } keysym;
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +010067 uint32_t serial;
Jan Arne Petersen00191c72013-04-18 16:47:33 +020068 uint32_t reset_serial;
Jan Arne Petersen0558a932013-01-16 21:26:45 +010069 uint32_t content_purpose;
Jan Arne Petersen61381972013-01-31 15:52:21 +010070 uint32_t click_to_show;
Jan Arne Petersen9d419132013-04-18 16:47:16 +020071 char *preferred_language;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020072};
73
74struct editor {
Jan Arne Petersen62ece762013-04-18 16:47:36 +020075 struct wl_text_input_manager *text_input_manager;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020076 struct display *display;
77 struct window *window;
78 struct widget *widget;
79 struct text_entry *entry;
80 struct text_entry *editor;
Rob Bradford9d1d32b2012-11-18 19:06:49 +010081 struct text_entry *active_entry;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020082};
83
Jan Arne Petersen6345faa2012-11-05 03:26:39 +010084static const char *
Jan Arne Petersen6345faa2012-11-05 03:26:39 +010085utf8_end_char(const char *p)
86{
87 while ((*p & 0xc0) == 0x80)
88 p++;
89 return p;
90}
91
92static const char *
Jan Arne Petersen68516862013-04-18 16:47:42 +020093utf8_prev_char(const char *s, const char *p)
94{
95 for (--p; p >= s; --p) {
96 if ((*p & 0xc0) != 0x80)
97 return p;
98 }
99 return NULL;
100}
101
102static const char *
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100103utf8_next_char(const char *p)
104{
105 if (*p != 0)
106 return utf8_end_char(++p);
107 return NULL;
108}
109
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200110static void text_entry_redraw_handler(struct widget *widget, void *data);
111static void text_entry_button_handler(struct widget *widget,
112 struct input *input, uint32_t time,
113 uint32_t button,
114 enum wl_pointer_button_state state, void *data);
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100115static void text_entry_insert_at_cursor(struct text_entry *entry, const char *text,
116 int32_t cursor, int32_t anchor);
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200117static void text_entry_set_preedit(struct text_entry *entry,
118 const char *preedit_text,
119 int preedit_cursor);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200120static void text_entry_delete_text(struct text_entry *entry,
121 uint32_t index, uint32_t length);
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200122static void text_entry_delete_selected_text(struct text_entry *entry);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100123static void text_entry_reset_preedit(struct text_entry *entry);
124static void text_entry_commit_and_reset(struct text_entry *entry);
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200125static void text_entry_get_cursor_rectangle(struct text_entry *entry, struct rectangle *rectangle);
126static void text_entry_update(struct text_entry *entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200127
128static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200129text_input_commit_string(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200130 struct wl_text_input *text_input,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100131 uint32_t serial,
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100132 const char *text)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200133{
134 struct text_entry *entry = data;
135
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200136 if ((entry->serial - serial) > (entry->serial - entry->reset_serial)) {
137 fprintf(stderr, "Ignore commit. Serial: %u, Current: %u, Reset: %u\n",
138 serial, entry->serial, entry->reset_serial);
139 return;
140 }
141
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100142 text_entry_reset_preedit(entry);
143
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200144 text_entry_delete_selected_text(entry);
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200145
146 if (entry->pending_commit.delete_length) {
147 text_entry_delete_text(entry,
148 entry->pending_commit.delete_index,
149 entry->pending_commit.delete_length);
150 }
151
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100152 text_entry_insert_at_cursor(entry, text,
153 entry->pending_commit.cursor,
154 entry->pending_commit.anchor);
155
156 memset(&entry->pending_commit, 0, sizeof entry->pending_commit);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200157
158 widget_schedule_redraw(entry->widget);
159}
160
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200161static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200162text_input_preedit_string(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200163 struct wl_text_input *text_input,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100164 uint32_t serial,
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200165 const char *text,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100166 const char *commit)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200167{
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200168 struct text_entry *entry = data;
169
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200170 text_entry_delete_selected_text(entry);
Jan Arne Petersen46535312013-01-16 21:26:38 +0100171 text_entry_set_preedit(entry, text, entry->preedit_info.cursor);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100172 entry->preedit.commit = strdup(commit);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100173 entry->preedit.attr_list = entry->preedit_info.attr_list;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100174
175 entry->preedit_info.cursor = 0;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100176 entry->preedit_info.attr_list = NULL;
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200177
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200178 text_entry_update(entry);
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200179
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200180 widget_schedule_redraw(entry->widget);
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200181}
182
183static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200184text_input_delete_surrounding_text(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200185 struct wl_text_input *text_input,
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200186 int32_t index,
187 uint32_t length)
188{
189 struct text_entry *entry = data;
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200190 uint32_t text_length;
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200191
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200192 entry->pending_commit.delete_index = entry->cursor + index;
193 entry->pending_commit.delete_length = length;
194
Jan Arne Petersen68516862013-04-18 16:47:42 +0200195 text_length = strlen(entry->text);
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200196
197 if (entry->pending_commit.delete_index > text_length) {
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200198 fprintf(stderr, "Invalid cursor index %d\n", index);
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200199 entry->pending_commit.delete_length = 0;
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200200 return;
201 }
202
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200203 if (entry->pending_commit.delete_index + length > text_length) {
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200204 fprintf(stderr, "Invalid length %d\n", length);
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200205 entry->pending_commit.delete_length = 0;
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200206 return;
207 }
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200208}
209
210static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200211text_input_cursor_position(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200212 struct wl_text_input *text_input,
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100213 int32_t index,
214 int32_t anchor)
215{
216 struct text_entry *entry = data;
217
218 entry->pending_commit.cursor = index;
219 entry->pending_commit.anchor = anchor;
220}
221
222static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200223text_input_preedit_styling(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200224 struct wl_text_input *text_input,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100225 uint32_t index,
226 uint32_t length,
227 uint32_t style)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200228{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100229 struct text_entry *entry = data;
230 PangoAttribute *attr1 = NULL;
231 PangoAttribute *attr2 = NULL;
232
233 if (!entry->preedit_info.attr_list)
234 entry->preedit_info.attr_list = pango_attr_list_new();
235
236 switch (style) {
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200237 case WL_TEXT_INPUT_PREEDIT_STYLE_DEFAULT:
238 case WL_TEXT_INPUT_PREEDIT_STYLE_UNDERLINE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100239 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
240 break;
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200241 case WL_TEXT_INPUT_PREEDIT_STYLE_INCORRECT:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100242 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_ERROR);
243 attr2 = pango_attr_underline_color_new(65535, 0, 0);
244 break;
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200245 case WL_TEXT_INPUT_PREEDIT_STYLE_SELECTION:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100246 attr1 = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
247 attr2 = pango_attr_foreground_new(65535, 65535, 65535);
248 break;
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200249 case WL_TEXT_INPUT_PREEDIT_STYLE_HIGHLIGHT:
250 case WL_TEXT_INPUT_PREEDIT_STYLE_ACTIVE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100251 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
252 attr2 = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
253 break;
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200254 case WL_TEXT_INPUT_PREEDIT_STYLE_INACTIVE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100255 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
256 attr2 = pango_attr_foreground_new(0.3 * 65535, 0.3 * 65535, 0.3 * 65535);
257 break;
258 }
259
260 if (attr1) {
261 attr1->start_index = entry->cursor + index;
262 attr1->end_index = entry->cursor + index + length;
263 pango_attr_list_insert(entry->preedit_info.attr_list, attr1);
264 }
265
266 if (attr2) {
267 attr2->start_index = entry->cursor + index;
268 attr2->end_index = entry->cursor + index + length;
269 pango_attr_list_insert(entry->preedit_info.attr_list, attr2);
270 }
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200271}
272
273static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200274text_input_preedit_cursor(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200275 struct wl_text_input *text_input,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100276 int32_t index)
277{
278 struct text_entry *entry = data;
279
280 entry->preedit_info.cursor = index;
281}
282
283static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200284text_input_modifiers_map(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200285 struct wl_text_input *text_input,
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100286 struct wl_array *map)
287{
Jan Arne Petersencd997062012-11-18 19:06:44 +0100288 struct text_entry *entry = data;
289
290 entry->keysym.shift_mask = keysym_modifiers_get_mask(map, "Shift");
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100291}
292
293static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200294text_input_keysym(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200295 struct wl_text_input *text_input,
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100296 uint32_t serial,
297 uint32_t time,
298 uint32_t key,
299 uint32_t state,
300 uint32_t modifiers)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200301{
Jan Arne Petersen8aba11d2012-09-17 15:28:07 +0200302 struct text_entry *entry = data;
Jan Arne Petersencd997062012-11-18 19:06:44 +0100303 const char *state_label = "release";
304 const char *key_label = "Unknown";
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100305 const char *new_char;
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200306
307 if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
308 state_label = "pressed";
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200309 }
310
Jan Arne Petersencd997062012-11-18 19:06:44 +0100311 if (key == XKB_KEY_Left ||
312 key == XKB_KEY_Right) {
313 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
314 return;
315
316 if (key == XKB_KEY_Left)
317 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
318 else
319 new_char = utf8_next_char(entry->text + entry->cursor);
320
321 if (new_char != NULL) {
322 entry->cursor = new_char - entry->text;
Jan Arne Petersencd997062012-11-18 19:06:44 +0100323 }
324
Jan Arne Petersen68516862013-04-18 16:47:42 +0200325 if (!(modifiers & entry->keysym.shift_mask))
326 entry->anchor = entry->cursor;
327 widget_schedule_redraw(entry->widget);
328
Jan Arne Petersencd997062012-11-18 19:06:44 +0100329 return;
330 }
331
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100332 if (key == XKB_KEY_BackSpace) {
333 const char *start, *end;
334
Jan Arne Petersendfd34462013-04-18 16:47:26 +0200335 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
336 return;
337
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100338 text_entry_commit_and_reset(entry);
339
340 start = utf8_prev_char(entry->text, entry->text + entry->cursor);
Jan Arne Petersen68516862013-04-18 16:47:42 +0200341 end = utf8_next_char(start);
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100342
343 if (start == NULL)
344 return;
345
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100346 text_entry_delete_text(entry,
347 start - entry->text,
348 end - start);
349
350 return;
351 }
352
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200353 switch (key) {
354 case XKB_KEY_Tab:
355 key_label = "Tab";
356 break;
357 case XKB_KEY_KP_Enter:
Jan Arne Petersencd997062012-11-18 19:06:44 +0100358 case XKB_KEY_Return:
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200359 key_label = "Enter";
360 break;
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200361 }
362
363 fprintf(stderr, "%s key was %s.\n", key_label, state_label);
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200364}
365
366static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200367text_input_enter(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200368 struct wl_text_input *text_input,
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200369 struct wl_surface *surface)
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200370{
371 struct text_entry *entry = data;
372
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200373 if (surface != window_get_wl_surface(entry->window))
374 return;
375
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200376 entry->active = 1;
377
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200378 text_entry_update(entry);
379 entry->reset_serial = entry->serial;
380
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200381 widget_schedule_redraw(entry->widget);
382}
383
384static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200385text_input_leave(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200386 struct wl_text_input *text_input)
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200387{
388 struct text_entry *entry = data;
389
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100390 text_entry_commit_and_reset(entry);
391
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200392 entry->active = 0;
393
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200394 wl_text_input_hide_input_panel(text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100395
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200396 widget_schedule_redraw(entry->widget);
397}
398
Jan Arne Petersen61381972013-01-31 15:52:21 +0100399static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200400text_input_input_panel_state(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200401 struct wl_text_input *text_input,
Jan Arne Petersen61381972013-01-31 15:52:21 +0100402 uint32_t state)
403{
404}
405
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200406static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200407text_input_language(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200408 struct wl_text_input *text_input,
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200409 uint32_t serial,
410 const char *language)
411{
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200412 fprintf(stderr, "input language is %s \n", language);
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200413}
414
415static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200416text_input_text_direction(void *data,
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200417 struct wl_text_input *text_input,
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200418 uint32_t serial,
419 uint32_t direction)
420{
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200421 struct text_entry *entry = data;
422 PangoContext *context = pango_layout_get_context(entry->layout);
423 PangoDirection pango_direction;
424
425
426 switch (direction) {
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200427 case WL_TEXT_INPUT_TEXT_DIRECTION_LTR:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200428 pango_direction = PANGO_DIRECTION_LTR;
429 break;
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200430 case WL_TEXT_INPUT_TEXT_DIRECTION_RTL:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200431 pango_direction = PANGO_DIRECTION_RTL;
432 break;
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200433 case WL_TEXT_INPUT_TEXT_DIRECTION_AUTO:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200434 default:
435 pango_direction = PANGO_DIRECTION_NEUTRAL;
436 }
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200437
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200438 pango_context_set_base_dir(context, pango_direction);
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200439}
440
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200441static const struct wl_text_input_listener text_input_listener = {
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200442 text_input_enter,
443 text_input_leave,
444 text_input_modifiers_map,
445 text_input_input_panel_state,
446 text_input_preedit_string,
447 text_input_preedit_styling,
448 text_input_preedit_cursor,
449 text_input_commit_string,
450 text_input_cursor_position,
451 text_input_delete_surrounding_text,
452 text_input_keysym,
453 text_input_language,
454 text_input_text_direction
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200455};
456
457static struct text_entry*
458text_entry_create(struct editor *editor, const char *text)
459{
460 struct text_entry *entry;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200461
Jan Arne Petersencd997062012-11-18 19:06:44 +0100462 entry = calloc(1, sizeof *entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200463
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200464 entry->widget = widget_add_widget(editor->widget, entry);
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200465 entry->window = editor->window;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200466 entry->text = strdup(text);
467 entry->active = 0;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200468 entry->cursor = strlen(text);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200469 entry->anchor = entry->cursor;
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200470 entry->text_input = wl_text_input_manager_create_text_input(editor->text_input_manager);
471 wl_text_input_add_listener(entry->text_input, &text_input_listener, entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200472
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200473 widget_set_redraw_handler(entry->widget, text_entry_redraw_handler);
474 widget_set_button_handler(entry->widget, text_entry_button_handler);
475
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200476 return entry;
477}
478
479static void
480text_entry_destroy(struct text_entry *entry)
481{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200482 widget_destroy(entry->widget);
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200483 wl_text_input_destroy(entry->text_input);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100484 g_clear_object(&entry->layout);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200485 free(entry->text);
486 free(entry);
487}
488
489static void
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200490redraw_handler(struct widget *widget, void *data)
491{
492 struct editor *editor = data;
493 cairo_surface_t *surface;
494 struct rectangle allocation;
495 cairo_t *cr;
496
497 surface = window_get_surface(editor->window);
498 widget_get_allocation(editor->widget, &allocation);
499
500 cr = cairo_create(surface);
501 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
502 cairo_clip(cr);
503
504 cairo_translate(cr, allocation.x, allocation.y);
505
506 /* Draw background */
507 cairo_push_group(cr);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200508 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200509 cairo_set_source_rgba(cr, 1, 1, 1, 1);
510 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
511 cairo_fill(cr);
512
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200513 cairo_pop_group_to_source(cr);
514 cairo_paint(cr);
515
516 cairo_destroy(cr);
517 cairo_surface_destroy(surface);
518}
519
520static void
521text_entry_allocate(struct text_entry *entry, int32_t x, int32_t y,
522 int32_t width, int32_t height)
523{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200524 widget_set_allocation(entry->widget, x, y, width, height);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200525}
526
527static void
528resize_handler(struct widget *widget,
529 int32_t width, int32_t height, void *data)
530{
531 struct editor *editor = data;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200532 struct rectangle allocation;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200533
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200534 widget_get_allocation(editor->widget, &allocation);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200535
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200536 text_entry_allocate(editor->entry,
537 allocation.x + 20, allocation.y + 20,
538 width - 40, height / 2 - 40);
539 text_entry_allocate(editor->editor,
540 allocation.x + 20, allocation.y + height / 2 + 20,
541 width - 40, height / 2 - 40);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200542}
543
544static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200545text_entry_activate(struct text_entry *entry,
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200546 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200547{
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200548 struct wl_surface *surface = window_get_wl_surface(entry->window);
549
Jan Arne Petersen61381972013-01-31 15:52:21 +0100550 if (entry->click_to_show && entry->active) {
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200551 wl_text_input_show_input_panel(entry->text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100552
553 return;
554 }
555
556 if (!entry->click_to_show)
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200557 wl_text_input_show_input_panel(entry->text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100558
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200559 wl_text_input_activate(entry->text_input,
560 seat,
561 surface);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200562}
563
564static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200565text_entry_deactivate(struct text_entry *entry,
566 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200567{
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200568 wl_text_input_deactivate(entry->text_input,
569 seat);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200570}
571
572static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200573text_entry_update_layout(struct text_entry *entry)
574{
575 char *text;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100576 PangoAttrList *attr_list;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200577
Jan Arne Petersen68516862013-04-18 16:47:42 +0200578 assert(entry->cursor <= (strlen(entry->text) +
579 (entry->preedit.text ? strlen(entry->preedit.text) : 0)));
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200580
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100581 if (entry->preedit.text) {
582 text = malloc(strlen(entry->text) + strlen(entry->preedit.text) + 1);
583 strncpy(text, entry->text, entry->cursor);
584 strcpy(text + entry->cursor, entry->preedit.text);
585 strcpy(text + entry->cursor + strlen(entry->preedit.text),
586 entry->text + entry->cursor);
587 } else {
588 text = strdup(entry->text);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200589 }
590
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100591 if (entry->cursor != entry->anchor) {
592 int start_index = MIN(entry->cursor, entry->anchor);
593 int end_index = MAX(entry->cursor, entry->anchor);
594 PangoAttribute *attr;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200595
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100596 attr_list = pango_attr_list_copy(entry->preedit.attr_list);
597
598 if (!attr_list)
599 attr_list = pango_attr_list_new();
600
601 attr = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
602 attr->start_index = start_index;
603 attr->end_index = end_index;
604 pango_attr_list_insert(attr_list, attr);
605
606 attr = pango_attr_foreground_new(65535, 65535, 65535);
607 attr->start_index = start_index;
608 attr->end_index = end_index;
609 pango_attr_list_insert(attr_list, attr);
610 } else {
611 attr_list = pango_attr_list_ref(entry->preedit.attr_list);
612 }
613
614 if (entry->preedit.text && !entry->preedit.attr_list) {
615 PangoAttribute *attr;
616
617 if (!attr_list)
618 attr_list = pango_attr_list_new();
619
620 attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
621 attr->start_index = entry->cursor;
622 attr->end_index = entry->cursor + strlen(entry->preedit.text);
623 pango_attr_list_insert(attr_list, attr);
624 }
625
626 if (entry->layout) {
627 pango_layout_set_text(entry->layout, text, -1);
628 pango_layout_set_attributes(entry->layout, attr_list);
629 }
630
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200631 free(text);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100632 pango_attr_list_unref(attr_list);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200633}
634
635static void
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100636text_entry_update(struct text_entry *entry)
637{
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200638 struct rectangle cursor_rectangle;
639
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200640 wl_text_input_set_content_type(entry->text_input,
641 WL_TEXT_INPUT_CONTENT_HINT_NONE,
642 entry->content_purpose);
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100643
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200644 wl_text_input_set_surrounding_text(entry->text_input,
645 entry->text,
646 entry->cursor,
647 entry->anchor);
Jan Arne Petersen0eabcaa2013-01-31 15:52:20 +0100648
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200649 if (entry->preferred_language)
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200650 wl_text_input_set_preferred_language(entry->text_input,
651 entry->preferred_language);
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200652
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200653 text_entry_get_cursor_rectangle(entry, &cursor_rectangle);
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200654 wl_text_input_set_cursor_rectangle(entry->text_input, cursor_rectangle.x, cursor_rectangle.y,
655 cursor_rectangle.width, cursor_rectangle.height);
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200656
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200657 wl_text_input_commit_state(entry->text_input, ++entry->serial);
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100658}
659
660static void
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100661text_entry_insert_at_cursor(struct text_entry *entry, const char *text,
662 int32_t cursor, int32_t anchor)
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200663{
664 char *new_text = malloc(strlen(entry->text) + strlen(text) + 1);
665
666 strncpy(new_text, entry->text, entry->cursor);
667 strcpy(new_text + entry->cursor, text);
668 strcpy(new_text + entry->cursor + strlen(text),
669 entry->text + entry->cursor);
670
671 free(entry->text);
672 entry->text = new_text;
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100673 if (anchor >= 0)
674 entry->anchor = entry->cursor + strlen(text) + anchor;
675 else
676 entry->anchor = entry->cursor + 1 + anchor;
Jan Arne Petersen68516862013-04-18 16:47:42 +0200677
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100678 if (cursor >= 0)
679 entry->cursor += strlen(text) + cursor;
680 else
681 entry->cursor += 1 + cursor;
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200682
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200683 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100684
685 widget_schedule_redraw(entry->widget);
686
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100687 text_entry_update(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200688}
689
690static void
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100691text_entry_reset_preedit(struct text_entry *entry)
692{
693 entry->preedit.cursor = 0;
694
695 free(entry->preedit.text);
696 entry->preedit.text = NULL;
697
698 free(entry->preedit.commit);
699 entry->preedit.commit = NULL;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100700
701 pango_attr_list_unref(entry->preedit.attr_list);
702 entry->preedit.attr_list = NULL;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100703}
704
705static void
706text_entry_commit_and_reset(struct text_entry *entry)
707{
708 char *commit = NULL;
709
710 if (entry->preedit.commit)
711 commit = strdup(entry->preedit.commit);
712
713 text_entry_reset_preedit(entry);
714 if (commit) {
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100715 text_entry_insert_at_cursor(entry, commit, 0, 0);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100716 free(commit);
717 }
Jan Arne Petersen08015b62013-04-18 16:47:18 +0200718
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200719 wl_text_input_reset(entry->text_input);
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200720 text_entry_update(entry);
721 entry->reset_serial = entry->serial;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100722}
723
724static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200725text_entry_set_preedit(struct text_entry *entry,
726 const char *preedit_text,
727 int preedit_cursor)
728{
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100729 text_entry_reset_preedit(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200730
731 if (!preedit_text)
732 return;
733
Jan Arne Petersen46535312013-01-16 21:26:38 +0100734 entry->preedit.text = strdup(preedit_text);
735 entry->preedit.cursor = preedit_cursor;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200736
737 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100738
739 widget_schedule_redraw(entry->widget);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200740}
741
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100742static uint32_t
743text_entry_try_invoke_preedit_action(struct text_entry *entry,
744 int32_t x, int32_t y,
745 uint32_t button,
746 enum wl_pointer_button_state state)
747{
748 int index, trailing;
749 uint32_t cursor;
Jan Arne Petersen68516862013-04-18 16:47:42 +0200750 const char *text;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100751
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);
Jan Arne Petersen68516862013-04-18 16:47:42 +0200758
759 text = pango_layout_get_text(entry->layout);
760 cursor = g_utf8_offset_to_pointer(text + index, trailing) - text;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100761
762 if (cursor < entry->cursor ||
763 cursor > entry->cursor + strlen(entry->preedit.text)) {
764 return 0;
765 }
766
767 if (state == WL_POINTER_BUTTON_STATE_RELEASED)
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200768 wl_text_input_invoke_action(entry->text_input,
769 button,
770 cursor - entry->cursor);
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100771
772 return 1;
773}
774
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200775static void
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200776text_entry_set_cursor_position(struct text_entry *entry,
777 int32_t x, int32_t y)
778{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100779 int index, trailing;
Jan Arne Petersen68516862013-04-18 16:47:42 +0200780 const char *text;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100781
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100782 text_entry_commit_and_reset(entry);
783
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100784 pango_layout_xy_to_index(entry->layout,
785 x * PANGO_SCALE, y * PANGO_SCALE,
786 &index, &trailing);
Jan Arne Petersen68516862013-04-18 16:47:42 +0200787
788 text = pango_layout_get_text(entry->layout);
789 entry->cursor = g_utf8_offset_to_pointer(text + index, trailing) - text;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200790
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200791 text_entry_update_layout(entry);
792
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200793 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100794
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100795 text_entry_update(entry);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200796}
797
798static void
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200799text_entry_set_anchor_position(struct text_entry *entry,
800 int32_t x, int32_t y)
801{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100802 int index, trailing;
Jan Arne Petersen68516862013-04-18 16:47:42 +0200803 const char *text;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100804
805 pango_layout_xy_to_index(entry->layout,
806 x * PANGO_SCALE, y * PANGO_SCALE,
807 &index, &trailing);
Jan Arne Petersen68516862013-04-18 16:47:42 +0200808
809 text = pango_layout_get_text(entry->layout);
810 entry->anchor = g_utf8_offset_to_pointer(text + index, trailing) - text;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100811
812 text_entry_update_layout(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200813
814 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100815
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100816 text_entry_update(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200817}
818
819static void
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200820text_entry_delete_text(struct text_entry *entry,
821 uint32_t index, uint32_t length)
822{
Jan Arne Petersen68516862013-04-18 16:47:42 +0200823 uint32_t l;
824
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200825 if (entry->cursor > index)
826 entry->cursor -= length;
827
Jan Arne Petersen80ad1a92012-09-17 15:28:10 +0200828 entry->anchor = entry->cursor;
829
Jan Arne Petersen68516862013-04-18 16:47:42 +0200830 l = strlen(entry->text + index + length);
831 memmove(entry->text + index,
832 entry->text + index + length,
833 l + 1);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200834
835 text_entry_update_layout(entry);
836
837 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100838
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100839 text_entry_update(entry);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200840}
841
842static void
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200843text_entry_delete_selected_text(struct text_entry *entry)
844{
845 uint32_t start_index = entry->anchor < entry->cursor ? entry->anchor : entry->cursor;
846 uint32_t end_index = entry->anchor < entry->cursor ? entry->cursor : entry->anchor;
847
848 if (entry->anchor == entry->cursor)
849 return;
850
851 text_entry_delete_text(entry, start_index, end_index - start_index);
852
853 entry->anchor = entry->cursor;
854}
855
856static void
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200857text_entry_get_cursor_rectangle(struct text_entry *entry, struct rectangle *rectangle)
858{
859 struct rectangle allocation;
860 PangoRectangle extents;
861 PangoRectangle cursor_pos;
862
863 widget_get_allocation(entry->widget, &allocation);
864
865 if (entry->preedit.text && entry->preedit.cursor < 0) {
866 rectangle->x = 0;
867 rectangle->y = 0;
868 rectangle->width = 0;
869 rectangle->height = 0;
870 return;
871 }
872
Jan Arne Petersen68516862013-04-18 16:47:42 +0200873
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200874 pango_layout_get_extents(entry->layout, &extents, NULL);
875 pango_layout_get_cursor_pos(entry->layout,
876 entry->cursor + entry->preedit.cursor,
877 &cursor_pos, NULL);
878
879 rectangle->x = allocation.x + (allocation.height / 2) + PANGO_PIXELS(cursor_pos.x);
880 rectangle->y = allocation.y + 10 + PANGO_PIXELS(cursor_pos.y);
881 rectangle->width = PANGO_PIXELS(cursor_pos.width);
882 rectangle->height = PANGO_PIXELS(cursor_pos.height);
883}
884
885static void
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200886text_entry_draw_cursor(struct text_entry *entry, cairo_t *cr)
887{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100888 PangoRectangle extents;
889 PangoRectangle cursor_pos;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200890
Jan Arne Petersen46535312013-01-16 21:26:38 +0100891 if (entry->preedit.text && entry->preedit.cursor < 0)
892 return;
893
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100894 pango_layout_get_extents(entry->layout, &extents, NULL);
895 pango_layout_get_cursor_pos(entry->layout,
896 entry->cursor + entry->preedit.cursor,
897 &cursor_pos, NULL);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200898
899 cairo_set_line_width(cr, 1.0);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100900 cairo_move_to(cr, PANGO_PIXELS(cursor_pos.x), PANGO_PIXELS(extents.height) + 2);
901 cairo_line_to(cr, PANGO_PIXELS(cursor_pos.x), - 2);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200902 cairo_stroke(cr);
903}
904
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200905static const int text_offset_left = 10;
906
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200907static void
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200908text_entry_redraw_handler(struct widget *widget, void *data)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200909{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200910 struct text_entry *entry = data;
911 cairo_surface_t *surface;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200912 struct rectangle allocation;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200913 cairo_t *cr;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200914
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200915 surface = window_get_surface(entry->window);
916 widget_get_allocation(entry->widget, &allocation);
917
918 cr = cairo_create(surface);
919 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
920 cairo_clip(cr);
921
922 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
923
924 cairo_push_group(cr);
925 cairo_translate(cr, allocation.x, allocation.y);
926
927 cairo_set_source_rgba(cr, 1, 1, 1, 1);
928 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
929 cairo_fill(cr);
930
931 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
932
933 if (entry->active) {
934 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
935 cairo_set_line_width (cr, 3);
936 cairo_set_source_rgba(cr, 0, 0, 1, 1.0);
937 cairo_stroke(cr);
938 }
939
940 cairo_set_source_rgba(cr, 0, 0, 0, 1);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200941
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200942 cairo_translate(cr, text_offset_left, allocation.height / 2);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200943
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100944 if (!entry->layout)
945 entry->layout = pango_cairo_create_layout(cr);
946 else
947 pango_cairo_update_layout(cr, entry->layout);
948
949 text_entry_update_layout(entry);
950
951 pango_cairo_show_layout(cr, entry->layout);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200952
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200953 text_entry_draw_cursor(entry, cr);
954
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200955 cairo_pop_group_to_source(cr);
956 cairo_paint(cr);
957
958 cairo_destroy(cr);
959 cairo_surface_destroy(surface);
960}
961
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200962static int
963text_entry_motion_handler(struct widget *widget,
964 struct input *input, uint32_t time,
965 float x, float y, void *data)
966{
967 struct text_entry *entry = data;
968 struct rectangle allocation;
969
970 widget_get_allocation(entry->widget, &allocation);
971
972 text_entry_set_cursor_position(entry,
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +0200973 x - allocation.x - text_offset_left,
974 y - allocation.y - text_offset_left);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200975
976 return CURSOR_IBEAM;
977}
978
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200979static void
980text_entry_button_handler(struct widget *widget,
981 struct input *input, uint32_t time,
982 uint32_t button,
983 enum wl_pointer_button_state state, void *data)
984{
985 struct text_entry *entry = data;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200986 struct rectangle allocation;
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100987 struct editor *editor;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200988 int32_t x, y;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100989 uint32_t result;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200990
991 widget_get_allocation(entry->widget, &allocation);
992 input_get_position(input, &x, &y);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200993
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100994 x -= allocation.x + text_offset_left;
995 y -= allocation.y + text_offset_left;
996
Rob Bradford9d1d32b2012-11-18 19:06:49 +0100997 editor = window_get_user_data(entry->window);
998
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100999 result = text_entry_try_invoke_preedit_action(entry, x, y, button, state);
1000
1001 if (result)
1002 return;
1003
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001004 if (button != BTN_LEFT) {
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001005 return;
1006 }
1007
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001008 text_entry_set_cursor_position(entry, x, y);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001009
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001010 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
1011 struct wl_seat *seat = input_get_seat(input);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001012
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001013 text_entry_activate(entry, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001014 editor->active_entry = entry;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001015
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001016 text_entry_set_anchor_position(entry, x, y);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001017
1018 widget_set_motion_handler(entry->widget, text_entry_motion_handler);
1019 } else {
1020 widget_set_motion_handler(entry->widget, NULL);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001021 }
1022}
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001023
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001024static void
1025editor_button_handler(struct widget *widget,
1026 struct input *input, uint32_t time,
1027 uint32_t button,
1028 enum wl_pointer_button_state state, void *data)
1029{
1030 struct editor *editor = data;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001031
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001032 if (button != BTN_LEFT) {
1033 return;
1034 }
Jan Arne Petersene829adc2012-08-10 16:47:22 +02001035
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001036 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
1037 struct wl_seat *seat = input_get_seat(input);
1038
Jan Arne Petersene829adc2012-08-10 16:47:22 +02001039 text_entry_deactivate(editor->entry, seat);
1040 text_entry_deactivate(editor->editor, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001041 editor->active_entry = NULL;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001042 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001043}
1044
1045static void
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001046key_handler(struct window *window,
1047 struct input *input, uint32_t time,
1048 uint32_t key, uint32_t sym, enum wl_keyboard_key_state state,
1049 void *data)
1050{
1051 struct editor *editor = data;
1052 struct text_entry *entry;
Jan Arne Petersen68516862013-04-18 16:47:42 +02001053 const char *new_char;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001054 char text[16];
1055
1056 if (!editor->active_entry)
1057 return;
1058
1059 entry = editor->active_entry;
1060
1061 if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
1062 return;
1063
1064 switch (sym) {
1065 case XKB_KEY_BackSpace:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001066 text_entry_commit_and_reset(entry);
1067
Jan Arne Petersen68516862013-04-18 16:47:42 +02001068 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
1069 if (new_char != NULL)
1070 text_entry_delete_text(entry,
1071 new_char - entry->text,
1072 (entry->text + entry->cursor) - new_char);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001073 break;
1074 case XKB_KEY_Delete:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001075 text_entry_commit_and_reset(entry);
1076
Jan Arne Petersen68516862013-04-18 16:47:42 +02001077 new_char = utf8_next_char(entry->text + entry->cursor);
1078 if (new_char != NULL)
1079 text_entry_delete_text(entry,
1080 entry->cursor,
1081 new_char - (entry->text + entry->cursor));
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001082 break;
1083 case XKB_KEY_Left:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001084 text_entry_commit_and_reset(entry);
1085
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001086 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
1087 if (new_char != NULL) {
1088 entry->cursor = new_char - entry->text;
1089 entry->anchor = entry->cursor;
1090 widget_schedule_redraw(entry->widget);
1091 }
1092 break;
1093 case XKB_KEY_Right:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001094 text_entry_commit_and_reset(entry);
1095
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001096 new_char = utf8_next_char(entry->text + entry->cursor);
1097 if (new_char != NULL) {
1098 entry->cursor = new_char - entry->text;
1099 entry->anchor = entry->cursor;
1100 widget_schedule_redraw(entry->widget);
1101 }
1102 break;
1103 default:
1104 if (xkb_keysym_to_utf8(sym, text, sizeof(text)) <= 0)
1105 break;
1106
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001107 text_entry_commit_and_reset(entry);
1108
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +01001109 text_entry_insert_at_cursor(entry, text, 0, 0);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001110 break;
1111 }
1112
1113 widget_schedule_redraw(entry->widget);
1114}
1115
1116static void
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001117global_handler(struct display *display, uint32_t name,
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001118 const char *interface, uint32_t version, void *data)
1119{
1120 struct editor *editor = data;
1121
Jan Arne Petersen62ece762013-04-18 16:47:36 +02001122 if (!strcmp(interface, "wl_text_input_manager")) {
Jan Arne Petersen78d00e42013-04-18 16:47:24 +02001123 editor->text_input_manager =
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001124 display_bind(display, name,
Jan Arne Petersen62ece762013-04-18 16:47:36 +02001125 &wl_text_input_manager_interface, 1);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001126 }
1127}
1128
1129int
1130main(int argc, char *argv[])
1131{
1132 struct editor editor;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001133 int i;
1134 uint32_t click_to_show = 0;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001135 const char *preferred_language = NULL;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001136
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001137 for (i = 1; i < argc; i++) {
Jan Arne Petersen61381972013-01-31 15:52:21 +01001138 if (strcmp("--click-to-show", argv[i]) == 0)
1139 click_to_show = 1;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001140 else if (strcmp("--preferred-language", argv[i]) == 0) {
1141 if (i + 1 < argc) {
1142 preferred_language = argv[i + 1];
1143 i++;
1144 }
1145 }
1146 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001147
Jan Arne Petersen25f6db52012-11-05 03:26:40 +01001148 memset(&editor, 0, sizeof editor);
1149
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001150#ifdef HAVE_PANGO
1151 g_type_init();
1152#endif
1153
Kristian Høgsberg4172f662013-02-20 15:27:49 -05001154 editor.display = display_create(&argc, argv);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001155 if (editor.display == NULL) {
1156 fprintf(stderr, "failed to create display: %m\n");
1157 return -1;
1158 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001159
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001160 display_set_user_data(editor.display, &editor);
1161 display_set_global_handler(editor.display, global_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001162
1163 editor.window = window_create(editor.display);
1164 editor.widget = frame_create(editor.window, &editor);
1165
1166 editor.entry = text_entry_create(&editor, "Entry");
Jan Arne Petersen61381972013-01-31 15:52:21 +01001167 editor.entry->click_to_show = click_to_show;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001168 if (preferred_language)
1169 editor.entry->preferred_language = strdup(preferred_language);
Jan Arne Petersen0558a932013-01-16 21:26:45 +01001170 editor.editor = text_entry_create(&editor, "Numeric");
Jan Arne Petersen62ece762013-04-18 16:47:36 +02001171 editor.editor->content_purpose = WL_TEXT_INPUT_CONTENT_PURPOSE_NUMBER;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001172 editor.editor->click_to_show = click_to_show;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001173
1174 window_set_title(editor.window, "Text Editor");
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001175 window_set_key_handler(editor.window, key_handler);
1176 window_set_user_data(editor.window, &editor);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001177
1178 widget_set_redraw_handler(editor.widget, redraw_handler);
1179 widget_set_resize_handler(editor.widget, resize_handler);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001180 widget_set_button_handler(editor.widget, editor_button_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001181
1182 window_schedule_resize(editor.window, 500, 400);
1183
1184 display_run(editor.display);
1185
1186 text_entry_destroy(editor.entry);
1187 text_entry_destroy(editor.editor);
1188
1189 return 0;
1190}