blob: b34ef429ecf81c71fe6235922fff2a1b0b6784f0 [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 *
Bryce Harrington1f6b0d12015-06-10 22:48:59 -07005 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
Jan Arne Petersencba9e472012-06-21 21:52:19 +020011 *
Bryce Harrington1f6b0d12015-06-10 22:48:59 -070012 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
14 * Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
Jan Arne Petersencba9e472012-06-21 21:52:19 +020023 */
24
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010025#include "config.h"
26
Philipp Brüschweiler591cfca2012-07-11 22:25:29 +020027#include <assert.h>
Jussi Kukkonen649bbce2016-07-19 14:16:27 +030028#include <stdint.h>
Jan Arne Petersencba9e472012-06-21 21:52:19 +020029#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +020032#include <stdbool.h>
Manuel Bachmann22f34302015-03-30 01:57:44 +020033#include <unistd.h>
Jan Arne Petersencba9e472012-06-21 21:52:19 +020034
35#include <linux/input.h>
36#include <cairo.h>
37
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010038#include <pango/pangocairo.h>
39
Jon Cruz35b2eaa2015-06-15 15:37:08 -070040#include "shared/helpers.h"
Bryce Harringtone99e4bf2016-03-16 14:15:18 -070041#include "shared/xalloc.h"
Jan Arne Petersencba9e472012-06-21 21:52:19 +020042#include "window.h"
Jonas Ådahl3bcba342015-11-17 16:00:29 +080043#include "text-input-unstable-v1-client-protocol.h"
Jan Arne Petersencba9e472012-06-21 21:52:19 +020044
45struct text_entry {
46 struct widget *widget;
Jan Arne Petersene829adc2012-08-10 16:47:22 +020047 struct window *window;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020048 char *text;
49 int active;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +020050 uint32_t cursor;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +020051 uint32_t anchor;
Jan Arne Petersen46535312013-01-16 21:26:38 +010052 struct {
53 char *text;
54 int32_t cursor;
55 char *commit;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010056 PangoAttrList *attr_list;
Jan Arne Petersen46535312013-01-16 21:26:38 +010057 } preedit;
58 struct {
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010059 PangoAttrList *attr_list;
Jan Arne Petersen46535312013-01-16 21:26:38 +010060 int32_t cursor;
61 } preedit_info;
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +010062 struct {
63 int32_t cursor;
64 int32_t anchor;
Jan Arne Petersen919bc142013-04-18 16:47:34 +020065 uint32_t delete_index;
66 uint32_t delete_length;
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +020067 bool invalid_delete;
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +010068 } pending_commit;
Jonas Ådahl3bcba342015-11-17 16:00:29 +080069 struct zwp_text_input_v1 *text_input;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010070 PangoLayout *layout;
Jan Arne Petersencd997062012-11-18 19:06:44 +010071 struct {
72 xkb_mod_mask_t shift_mask;
73 } keysym;
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +010074 uint32_t serial;
Jan Arne Petersen00191c72013-04-18 16:47:33 +020075 uint32_t reset_serial;
Jan Arne Petersen0558a932013-01-16 21:26:45 +010076 uint32_t content_purpose;
Jan Arne Petersen61381972013-01-31 15:52:21 +010077 uint32_t click_to_show;
Jan Arne Petersen9d419132013-04-18 16:47:16 +020078 char *preferred_language;
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +020079 bool button_pressed;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020080};
81
82struct editor {
Jonas Ådahl3bcba342015-11-17 16:00:29 +080083 struct zwp_text_input_manager_v1 *text_input_manager;
Manuel Bachmann22f34302015-03-30 01:57:44 +020084 struct wl_data_source *selection;
85 char *selected_text;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020086 struct display *display;
87 struct window *window;
88 struct widget *widget;
89 struct text_entry *entry;
90 struct text_entry *editor;
Rob Bradford9d1d32b2012-11-18 19:06:49 +010091 struct text_entry *active_entry;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020092};
93
Jan Arne Petersen6345faa2012-11-05 03:26:39 +010094static const char *
Jan Arne Petersen6345faa2012-11-05 03:26:39 +010095utf8_end_char(const char *p)
96{
97 while ((*p & 0xc0) == 0x80)
98 p++;
99 return p;
100}
101
102static const char *
Jan Arne Petersen68516862013-04-18 16:47:42 +0200103utf8_prev_char(const char *s, const char *p)
104{
105 for (--p; p >= s; --p) {
106 if ((*p & 0xc0) != 0x80)
107 return p;
108 }
109 return NULL;
110}
111
112static const char *
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100113utf8_next_char(const char *p)
114{
115 if (*p != 0)
116 return utf8_end_char(++p);
117 return NULL;
118}
119
Manuel Bachmann8986c182014-04-18 12:50:14 +0200120static void
121move_up(const char *p, uint32_t *cursor)
122{
123 const char *posr, *posr_i;
124 char text[16];
125
126 xkb_keysym_to_utf8(XKB_KEY_Return, text, sizeof(text));
127
128 posr = strstr(p, text);
129 while (posr) {
130 if (*cursor > (unsigned)(posr-p)) {
131 posr_i = strstr(posr+1, text);
132 if (!posr_i || !(*cursor > (unsigned)(posr_i-p))) {
133 *cursor = posr-p;
134 break;
135 }
136 posr = posr_i;
137 } else {
138 break;
139 }
140 }
141}
142
143static void
144move_down(const char *p, uint32_t *cursor)
145{
146 const char *posr;
147 char text[16];
148
149 xkb_keysym_to_utf8(XKB_KEY_Return, text, sizeof(text));
150
151 posr = strstr(p, text);
152 while (posr) {
153 if (*cursor <= (unsigned)(posr-p)) {
154 *cursor = posr-p + 1;
155 break;
156 }
157 posr = strstr(posr+1, text);
158 }
159}
160
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200161static void text_entry_redraw_handler(struct widget *widget, void *data);
162static void text_entry_button_handler(struct widget *widget,
163 struct input *input, uint32_t time,
164 uint32_t button,
165 enum wl_pointer_button_state state, void *data);
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -0800166static void text_entry_touch_handler(struct widget *widget, struct input *input,
167 uint32_t serial, uint32_t time, int32_t id,
168 float tx, float ty, void *data);
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +0200169static int text_entry_motion_handler(struct widget *widget,
170 struct input *input, uint32_t time,
171 float x, float y, void *data);
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100172static void text_entry_insert_at_cursor(struct text_entry *entry, const char *text,
173 int32_t cursor, int32_t anchor);
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200174static void text_entry_set_preedit(struct text_entry *entry,
175 const char *preedit_text,
176 int preedit_cursor);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200177static void text_entry_delete_text(struct text_entry *entry,
178 uint32_t index, uint32_t length);
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200179static void text_entry_delete_selected_text(struct text_entry *entry);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100180static void text_entry_reset_preedit(struct text_entry *entry);
181static void text_entry_commit_and_reset(struct text_entry *entry);
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200182static void text_entry_get_cursor_rectangle(struct text_entry *entry, struct rectangle *rectangle);
183static void text_entry_update(struct text_entry *entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200184
185static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200186text_input_commit_string(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800187 struct zwp_text_input_v1 *text_input,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100188 uint32_t serial,
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100189 const char *text)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200190{
191 struct text_entry *entry = data;
192
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200193 if ((entry->serial - serial) > (entry->serial - entry->reset_serial)) {
194 fprintf(stderr, "Ignore commit. Serial: %u, Current: %u, Reset: %u\n",
195 serial, entry->serial, entry->reset_serial);
196 return;
197 }
198
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200199 if (entry->pending_commit.invalid_delete) {
200 fprintf(stderr, "Ignore commit. Invalid previous delete_surrounding event.\n");
201 memset(&entry->pending_commit, 0, sizeof entry->pending_commit);
202 return;
203 }
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100204
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200205 text_entry_reset_preedit(entry);
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200206
207 if (entry->pending_commit.delete_length) {
208 text_entry_delete_text(entry,
209 entry->pending_commit.delete_index,
210 entry->pending_commit.delete_length);
Jan Arne Petersena96953d2013-05-30 13:57:02 +0200211 } else {
212 text_entry_delete_selected_text(entry);
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200213 }
214
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100215 text_entry_insert_at_cursor(entry, text,
216 entry->pending_commit.cursor,
217 entry->pending_commit.anchor);
218
219 memset(&entry->pending_commit, 0, sizeof entry->pending_commit);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200220
221 widget_schedule_redraw(entry->widget);
222}
223
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200224static void
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200225clear_pending_preedit(struct text_entry *entry)
226{
227 memset(&entry->pending_commit, 0, sizeof entry->pending_commit);
228
229 pango_attr_list_unref(entry->preedit_info.attr_list);
230
231 entry->preedit_info.cursor = 0;
232 entry->preedit_info.attr_list = NULL;
233
234 memset(&entry->preedit_info, 0, sizeof entry->preedit_info);
235}
236
237static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200238text_input_preedit_string(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800239 struct zwp_text_input_v1 *text_input,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100240 uint32_t serial,
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200241 const char *text,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100242 const char *commit)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200243{
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200244 struct text_entry *entry = data;
245
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200246 if ((entry->serial - serial) > (entry->serial - entry->reset_serial)) {
247 fprintf(stderr, "Ignore preedit_string. Serial: %u, Current: %u, Reset: %u\n",
248 serial, entry->serial, entry->reset_serial);
249 clear_pending_preedit(entry);
250 return;
251 }
252
253 if (entry->pending_commit.invalid_delete) {
254 fprintf(stderr, "Ignore preedit_string. Invalid previous delete_surrounding event.\n");
255 clear_pending_preedit(entry);
256 return;
257 }
258
Jan Arne Petersena96953d2013-05-30 13:57:02 +0200259 if (entry->pending_commit.delete_length) {
260 text_entry_delete_text(entry,
261 entry->pending_commit.delete_index,
262 entry->pending_commit.delete_length);
263 } else {
264 text_entry_delete_selected_text(entry);
265 }
Jan Arne Petersena96953d2013-05-30 13:57:02 +0200266
Jan Arne Petersen46535312013-01-16 21:26:38 +0100267 text_entry_set_preedit(entry, text, entry->preedit_info.cursor);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100268 entry->preedit.commit = strdup(commit);
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200269 entry->preedit.attr_list = pango_attr_list_ref(entry->preedit_info.attr_list);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100270
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200271 clear_pending_preedit(entry);
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200272
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200273 text_entry_update(entry);
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200274
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200275 widget_schedule_redraw(entry->widget);
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200276}
277
278static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200279text_input_delete_surrounding_text(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800280 struct zwp_text_input_v1 *text_input,
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200281 int32_t index,
282 uint32_t length)
283{
284 struct text_entry *entry = data;
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200285 uint32_t text_length;
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200286
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200287 entry->pending_commit.delete_index = entry->cursor + index;
288 entry->pending_commit.delete_length = length;
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200289 entry->pending_commit.invalid_delete = false;
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200290
Jan Arne Petersen68516862013-04-18 16:47:42 +0200291 text_length = strlen(entry->text);
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200292
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200293 if (entry->pending_commit.delete_index > text_length ||
294 length > text_length ||
Jan Arne Petersen895a1282013-05-30 13:57:04 +0200295 entry->pending_commit.delete_index + length > text_length) {
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200296 fprintf(stderr, "delete_surrounding_text: Invalid index: %d," \
297 "length %u'; cursor: %u text length: %u\n", index, length, entry->cursor, text_length);
298 entry->pending_commit.invalid_delete = true;
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200299 return;
300 }
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200301}
302
303static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200304text_input_cursor_position(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800305 struct zwp_text_input_v1 *text_input,
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100306 int32_t index,
307 int32_t anchor)
308{
309 struct text_entry *entry = data;
310
311 entry->pending_commit.cursor = index;
312 entry->pending_commit.anchor = anchor;
313}
314
315static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200316text_input_preedit_styling(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800317 struct zwp_text_input_v1 *text_input,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100318 uint32_t index,
319 uint32_t length,
320 uint32_t style)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200321{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100322 struct text_entry *entry = data;
323 PangoAttribute *attr1 = NULL;
324 PangoAttribute *attr2 = NULL;
325
326 if (!entry->preedit_info.attr_list)
327 entry->preedit_info.attr_list = pango_attr_list_new();
328
329 switch (style) {
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800330 case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_DEFAULT:
331 case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_UNDERLINE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100332 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
333 break;
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800334 case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_INCORRECT:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100335 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_ERROR);
336 attr2 = pango_attr_underline_color_new(65535, 0, 0);
337 break;
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800338 case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_SELECTION:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100339 attr1 = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
340 attr2 = pango_attr_foreground_new(65535, 65535, 65535);
341 break;
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800342 case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_HIGHLIGHT:
343 case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_ACTIVE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100344 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
345 attr2 = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
346 break;
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800347 case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_INACTIVE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100348 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
349 attr2 = pango_attr_foreground_new(0.3 * 65535, 0.3 * 65535, 0.3 * 65535);
350 break;
351 }
352
353 if (attr1) {
354 attr1->start_index = entry->cursor + index;
355 attr1->end_index = entry->cursor + index + length;
356 pango_attr_list_insert(entry->preedit_info.attr_list, attr1);
357 }
358
359 if (attr2) {
360 attr2->start_index = entry->cursor + index;
361 attr2->end_index = entry->cursor + index + length;
362 pango_attr_list_insert(entry->preedit_info.attr_list, attr2);
363 }
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200364}
365
366static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200367text_input_preedit_cursor(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800368 struct zwp_text_input_v1 *text_input,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100369 int32_t index)
370{
371 struct text_entry *entry = data;
372
373 entry->preedit_info.cursor = index;
374}
375
376static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200377text_input_modifiers_map(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800378 struct zwp_text_input_v1 *text_input,
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100379 struct wl_array *map)
380{
Jan Arne Petersencd997062012-11-18 19:06:44 +0100381 struct text_entry *entry = data;
382
383 entry->keysym.shift_mask = keysym_modifiers_get_mask(map, "Shift");
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100384}
385
386static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200387text_input_keysym(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800388 struct zwp_text_input_v1 *text_input,
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100389 uint32_t serial,
390 uint32_t time,
391 uint32_t key,
392 uint32_t state,
393 uint32_t modifiers)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200394{
Jan Arne Petersen8aba11d2012-09-17 15:28:07 +0200395 struct text_entry *entry = data;
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100396 const char *new_char;
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200397
Jan Arne Petersencd997062012-11-18 19:06:44 +0100398 if (key == XKB_KEY_Left ||
399 key == XKB_KEY_Right) {
400 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
401 return;
402
403 if (key == XKB_KEY_Left)
404 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
405 else
406 new_char = utf8_next_char(entry->text + entry->cursor);
407
408 if (new_char != NULL) {
409 entry->cursor = new_char - entry->text;
Jan Arne Petersencd997062012-11-18 19:06:44 +0100410 }
411
Jan Arne Petersen68516862013-04-18 16:47:42 +0200412 if (!(modifiers & entry->keysym.shift_mask))
413 entry->anchor = entry->cursor;
414 widget_schedule_redraw(entry->widget);
415
Jan Arne Petersencd997062012-11-18 19:06:44 +0100416 return;
417 }
418
Manuel Bachmann8986c182014-04-18 12:50:14 +0200419 if (key == XKB_KEY_Up ||
420 key == XKB_KEY_Down) {
421 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
422 return;
423
424 if (key == XKB_KEY_Up)
425 move_up(entry->text, &entry->cursor);
426 else
427 move_down(entry->text, &entry->cursor);
428
429 if (!(modifiers & entry->keysym.shift_mask))
430 entry->anchor = entry->cursor;
431 widget_schedule_redraw(entry->widget);
432
433 return;
434 }
435
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100436 if (key == XKB_KEY_BackSpace) {
437 const char *start, *end;
438
Jan Arne Petersendfd34462013-04-18 16:47:26 +0200439 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
440 return;
441
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100442 text_entry_commit_and_reset(entry);
443
444 start = utf8_prev_char(entry->text, entry->text + entry->cursor);
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100445 if (start == NULL)
446 return;
447
Daiki Uenob08b3292013-06-28 18:59:44 +0900448 end = utf8_next_char(start);
449
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100450 text_entry_delete_text(entry,
451 start - entry->text,
452 end - start);
453
454 return;
455 }
456
Manuel Bachmann8986c182014-04-18 12:50:14 +0200457 if (key == XKB_KEY_Tab ||
458 key == XKB_KEY_KP_Enter ||
459 key == XKB_KEY_Return) {
460 char text[16];
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200461
Manuel Bachmann8986c182014-04-18 12:50:14 +0200462 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
463 return;
464
465 xkb_keysym_to_utf8(key, text, sizeof(text));
466
467 text_entry_insert_at_cursor(entry, text, 0, 0);
468
469 return;
470 }
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200471}
472
473static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200474text_input_enter(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800475 struct zwp_text_input_v1 *text_input,
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200476 struct wl_surface *surface)
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200477{
478 struct text_entry *entry = data;
479
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200480 if (surface != window_get_wl_surface(entry->window))
481 return;
482
Derek Foreman237a6842014-12-17 09:43:58 -0600483 entry->active++;
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200484
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200485 text_entry_update(entry);
486 entry->reset_serial = entry->serial;
487
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200488 widget_schedule_redraw(entry->widget);
489}
490
491static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200492text_input_leave(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800493 struct zwp_text_input_v1 *text_input)
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200494{
495 struct text_entry *entry = data;
496
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100497 text_entry_commit_and_reset(entry);
Derek Foreman237a6842014-12-17 09:43:58 -0600498 entry->active--;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100499
Derek Foreman237a6842014-12-17 09:43:58 -0600500 if (!entry->active)
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800501 zwp_text_input_v1_hide_input_panel(text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100502
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200503 widget_schedule_redraw(entry->widget);
504}
505
Jan Arne Petersen61381972013-01-31 15:52:21 +0100506static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200507text_input_input_panel_state(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800508 struct zwp_text_input_v1 *text_input,
Jan Arne Petersen61381972013-01-31 15:52:21 +0100509 uint32_t state)
510{
511}
512
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200513static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200514text_input_language(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800515 struct zwp_text_input_v1 *text_input,
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200516 uint32_t serial,
517 const char *language)
518{
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200519 fprintf(stderr, "input language is %s \n", language);
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200520}
521
522static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200523text_input_text_direction(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800524 struct zwp_text_input_v1 *text_input,
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200525 uint32_t serial,
526 uint32_t direction)
527{
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200528 struct text_entry *entry = data;
529 PangoContext *context = pango_layout_get_context(entry->layout);
530 PangoDirection pango_direction;
531
532
533 switch (direction) {
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800534 case ZWP_TEXT_INPUT_V1_TEXT_DIRECTION_LTR:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200535 pango_direction = PANGO_DIRECTION_LTR;
536 break;
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800537 case ZWP_TEXT_INPUT_V1_TEXT_DIRECTION_RTL:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200538 pango_direction = PANGO_DIRECTION_RTL;
539 break;
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800540 case ZWP_TEXT_INPUT_V1_TEXT_DIRECTION_AUTO:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200541 default:
542 pango_direction = PANGO_DIRECTION_NEUTRAL;
543 }
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200544
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200545 pango_context_set_base_dir(context, pango_direction);
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200546}
547
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800548static const struct zwp_text_input_v1_listener text_input_listener = {
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200549 text_input_enter,
550 text_input_leave,
551 text_input_modifiers_map,
552 text_input_input_panel_state,
553 text_input_preedit_string,
554 text_input_preedit_styling,
555 text_input_preedit_cursor,
556 text_input_commit_string,
557 text_input_cursor_position,
558 text_input_delete_surrounding_text,
559 text_input_keysym,
560 text_input_language,
561 text_input_text_direction
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200562};
563
Manuel Bachmann22f34302015-03-30 01:57:44 +0200564static void
565data_source_target(void *data,
566 struct wl_data_source *source, const char *mime_type)
567{
568}
569
570static void
571data_source_send(void *data,
572 struct wl_data_source *source,
573 const char *mime_type, int32_t fd)
574{
575 struct editor *editor = data;
576
Bryce Harrington7dd12ec2015-05-19 15:32:09 -0700577 if (write(fd, editor->selected_text, strlen(editor->selected_text) + 1) < 0)
578 fprintf(stderr, "write failed: %m\n");
Manuel Bachmann22f34302015-03-30 01:57:44 +0200579}
580
581static void
582data_source_cancelled(void *data, struct wl_data_source *source)
583{
584 wl_data_source_destroy(source);
585}
586
587static const struct wl_data_source_listener data_source_listener = {
588 data_source_target,
589 data_source_send,
590 data_source_cancelled
591};
592
593static void
594paste_func(void *buffer, size_t len,
595 int32_t x, int32_t y, void *data)
596{
597 struct editor *editor = data;
598 struct text_entry *entry = editor->active_entry;
599 char *pasted_text;
600
601 if (!entry)
602 return;
603
604 pasted_text = malloc(len + 1);
605 strncpy(pasted_text, buffer, len);
606 pasted_text[len] = '\0';
607
608 text_entry_insert_at_cursor(entry, pasted_text, 0, 0);
609
610 free(pasted_text);
611}
612
613static void
614editor_copy_cut(struct editor *editor, struct input *input, bool cut)
615{
616 struct text_entry *entry = editor->active_entry;
617
618 if (!entry)
619 return;
Michael Vetter2a18a522015-05-15 17:17:47 +0200620
Manuel Bachmann22f34302015-03-30 01:57:44 +0200621 if (entry->cursor != entry->anchor) {
622 int start_index = MIN(entry->cursor, entry->anchor);
623 int end_index = MAX(entry->cursor, entry->anchor);
624 int len = end_index - start_index;
625
626 editor->selected_text = realloc(editor->selected_text, len + 1);
627 strncpy(editor->selected_text, &entry->text[start_index], len);
628 editor->selected_text[len] = '\0';
629
630 if (cut)
631 text_entry_delete_text(entry, start_index, len);
632
633 editor->selection =
634 display_create_data_source(editor->display);
635 wl_data_source_offer(editor->selection,
636 "text/plain;charset=utf-8");
637 wl_data_source_add_listener(editor->selection,
638 &data_source_listener, editor);
639 input_set_selection(input, editor->selection,
640 display_get_serial(editor->display));
641 }
642}
643
644static void
645editor_paste(struct editor *editor, struct input *input)
646{
647 input_receive_selection_data(input,
648 "text/plain;charset=utf-8",
649 paste_func, editor);
650}
651
652static void
653menu_func(void *data, struct input *input, int index)
654{
655 struct window *window = data;
656 struct editor *editor = window_get_user_data(window);
657
658 fprintf(stderr, "picked entry %d\n", index);
659
660 switch (index) {
661 case 0:
662 editor_copy_cut(editor, input, true);
663 break;
664 case 1:
665 editor_copy_cut(editor, input, false);
666 break;
667 case 2:
668 editor_paste(editor, input);
669 break;
670 }
671}
672
673static void
674show_menu(struct editor *editor, struct input *input, uint32_t time)
675{
676 int32_t x, y;
677 static const char *entries[] = {
678 "Cut", "Copy", "Paste"
679 };
680
681 input_get_position(input, &x, &y);
682 window_show_menu(editor->display, input, time, editor->window,
683 x + 10, y + 20, menu_func,
684 entries, ARRAY_LENGTH(entries));
685}
686
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200687static struct text_entry*
688text_entry_create(struct editor *editor, const char *text)
689{
690 struct text_entry *entry;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200691
Ryo Munakata5e653ca2015-08-07 20:20:46 +0900692 entry = xzalloc(sizeof *entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200693
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200694 entry->widget = widget_add_widget(editor->widget, entry);
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200695 entry->window = editor->window;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200696 entry->text = strdup(text);
697 entry->active = 0;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200698 entry->cursor = strlen(text);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200699 entry->anchor = entry->cursor;
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800700 entry->text_input =
701 zwp_text_input_manager_v1_create_text_input(editor->text_input_manager);
702 zwp_text_input_v1_add_listener(entry->text_input,
703 &text_input_listener, entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200704
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200705 widget_set_redraw_handler(entry->widget, text_entry_redraw_handler);
706 widget_set_button_handler(entry->widget, text_entry_button_handler);
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +0200707 widget_set_motion_handler(entry->widget, text_entry_motion_handler);
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -0800708 widget_set_touch_down_handler(entry->widget, text_entry_touch_handler);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200709
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200710 return entry;
711}
712
713static void
714text_entry_destroy(struct text_entry *entry)
715{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200716 widget_destroy(entry->widget);
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800717 zwp_text_input_v1_destroy(entry->text_input);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100718 g_clear_object(&entry->layout);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200719 free(entry->text);
720 free(entry);
721}
722
723static void
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200724redraw_handler(struct widget *widget, void *data)
725{
726 struct editor *editor = data;
727 cairo_surface_t *surface;
728 struct rectangle allocation;
729 cairo_t *cr;
730
731 surface = window_get_surface(editor->window);
732 widget_get_allocation(editor->widget, &allocation);
733
734 cr = cairo_create(surface);
735 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
736 cairo_clip(cr);
737
738 cairo_translate(cr, allocation.x, allocation.y);
739
740 /* Draw background */
741 cairo_push_group(cr);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200742 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200743 cairo_set_source_rgba(cr, 1, 1, 1, 1);
744 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
745 cairo_fill(cr);
746
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200747 cairo_pop_group_to_source(cr);
748 cairo_paint(cr);
749
750 cairo_destroy(cr);
751 cairo_surface_destroy(surface);
752}
753
754static void
755text_entry_allocate(struct text_entry *entry, int32_t x, int32_t y,
756 int32_t width, int32_t height)
757{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200758 widget_set_allocation(entry->widget, x, y, width, height);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200759}
760
761static void
762resize_handler(struct widget *widget,
763 int32_t width, int32_t height, void *data)
764{
765 struct editor *editor = data;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200766 struct rectangle allocation;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200767
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200768 widget_get_allocation(editor->widget, &allocation);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200769
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200770 text_entry_allocate(editor->entry,
771 allocation.x + 20, allocation.y + 20,
772 width - 40, height / 2 - 40);
773 text_entry_allocate(editor->editor,
774 allocation.x + 20, allocation.y + height / 2 + 20,
775 width - 40, height / 2 - 40);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200776}
777
778static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200779text_entry_activate(struct text_entry *entry,
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200780 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200781{
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200782 struct wl_surface *surface = window_get_wl_surface(entry->window);
783
Jan Arne Petersen61381972013-01-31 15:52:21 +0100784 if (entry->click_to_show && entry->active) {
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800785 zwp_text_input_v1_show_input_panel(entry->text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100786
787 return;
788 }
789
790 if (!entry->click_to_show)
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800791 zwp_text_input_v1_show_input_panel(entry->text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100792
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800793 zwp_text_input_v1_activate(entry->text_input,
794 seat,
795 surface);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200796}
797
798static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200799text_entry_deactivate(struct text_entry *entry,
800 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200801{
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800802 zwp_text_input_v1_deactivate(entry->text_input,
803 seat);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200804}
805
806static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200807text_entry_update_layout(struct text_entry *entry)
808{
809 char *text;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100810 PangoAttrList *attr_list;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200811
Jan Arne Petersen68516862013-04-18 16:47:42 +0200812 assert(entry->cursor <= (strlen(entry->text) +
813 (entry->preedit.text ? strlen(entry->preedit.text) : 0)));
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200814
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100815 if (entry->preedit.text) {
Derek Foreman22044922014-11-20 15:42:35 -0600816 text = xmalloc(strlen(entry->text) + strlen(entry->preedit.text) + 1);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100817 strncpy(text, entry->text, entry->cursor);
818 strcpy(text + entry->cursor, entry->preedit.text);
819 strcpy(text + entry->cursor + strlen(entry->preedit.text),
820 entry->text + entry->cursor);
821 } else {
822 text = strdup(entry->text);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200823 }
824
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100825 if (entry->cursor != entry->anchor) {
826 int start_index = MIN(entry->cursor, entry->anchor);
827 int end_index = MAX(entry->cursor, entry->anchor);
828 PangoAttribute *attr;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200829
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100830 attr_list = pango_attr_list_copy(entry->preedit.attr_list);
831
832 if (!attr_list)
833 attr_list = pango_attr_list_new();
834
835 attr = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
836 attr->start_index = start_index;
837 attr->end_index = end_index;
838 pango_attr_list_insert(attr_list, attr);
839
840 attr = pango_attr_foreground_new(65535, 65535, 65535);
841 attr->start_index = start_index;
842 attr->end_index = end_index;
843 pango_attr_list_insert(attr_list, attr);
844 } else {
845 attr_list = pango_attr_list_ref(entry->preedit.attr_list);
846 }
847
848 if (entry->preedit.text && !entry->preedit.attr_list) {
849 PangoAttribute *attr;
850
851 if (!attr_list)
852 attr_list = pango_attr_list_new();
853
854 attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
855 attr->start_index = entry->cursor;
856 attr->end_index = entry->cursor + strlen(entry->preedit.text);
857 pango_attr_list_insert(attr_list, attr);
858 }
859
860 if (entry->layout) {
861 pango_layout_set_text(entry->layout, text, -1);
862 pango_layout_set_attributes(entry->layout, attr_list);
863 }
864
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200865 free(text);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100866 pango_attr_list_unref(attr_list);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200867}
868
869static void
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100870text_entry_update(struct text_entry *entry)
871{
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200872 struct rectangle cursor_rectangle;
873
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800874 zwp_text_input_v1_set_content_type(entry->text_input,
875 ZWP_TEXT_INPUT_V1_CONTENT_HINT_NONE,
876 entry->content_purpose);
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100877
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800878 zwp_text_input_v1_set_surrounding_text(entry->text_input,
879 entry->text,
880 entry->cursor,
881 entry->anchor);
Jan Arne Petersen0eabcaa2013-01-31 15:52:20 +0100882
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200883 if (entry->preferred_language)
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800884 zwp_text_input_v1_set_preferred_language(entry->text_input,
885 entry->preferred_language);
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200886
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200887 text_entry_get_cursor_rectangle(entry, &cursor_rectangle);
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800888 zwp_text_input_v1_set_cursor_rectangle(entry->text_input,
889 cursor_rectangle.x,
890 cursor_rectangle.y,
891 cursor_rectangle.width,
892 cursor_rectangle.height);
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200893
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800894 zwp_text_input_v1_commit_state(entry->text_input, ++entry->serial);
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100895}
896
897static void
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100898text_entry_insert_at_cursor(struct text_entry *entry, const char *text,
899 int32_t cursor, int32_t anchor)
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200900{
Derek Foreman22044922014-11-20 15:42:35 -0600901 char *new_text = xmalloc(strlen(entry->text) + strlen(text) + 1);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200902
903 strncpy(new_text, entry->text, entry->cursor);
904 strcpy(new_text + entry->cursor, text);
905 strcpy(new_text + entry->cursor + strlen(text),
906 entry->text + entry->cursor);
907
908 free(entry->text);
909 entry->text = new_text;
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100910 if (anchor >= 0)
911 entry->anchor = entry->cursor + strlen(text) + anchor;
912 else
913 entry->anchor = entry->cursor + 1 + anchor;
Jan Arne Petersen68516862013-04-18 16:47:42 +0200914
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100915 if (cursor >= 0)
916 entry->cursor += strlen(text) + cursor;
917 else
918 entry->cursor += 1 + cursor;
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200919
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200920 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100921
922 widget_schedule_redraw(entry->widget);
923
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100924 text_entry_update(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200925}
926
927static void
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100928text_entry_reset_preedit(struct text_entry *entry)
929{
930 entry->preedit.cursor = 0;
931
932 free(entry->preedit.text);
933 entry->preedit.text = NULL;
934
935 free(entry->preedit.commit);
936 entry->preedit.commit = NULL;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100937
938 pango_attr_list_unref(entry->preedit.attr_list);
939 entry->preedit.attr_list = NULL;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100940}
941
942static void
943text_entry_commit_and_reset(struct text_entry *entry)
944{
945 char *commit = NULL;
946
947 if (entry->preedit.commit)
948 commit = strdup(entry->preedit.commit);
949
950 text_entry_reset_preedit(entry);
951 if (commit) {
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100952 text_entry_insert_at_cursor(entry, commit, 0, 0);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100953 free(commit);
954 }
Jan Arne Petersen08015b62013-04-18 16:47:18 +0200955
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800956 zwp_text_input_v1_reset(entry->text_input);
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200957 text_entry_update(entry);
958 entry->reset_serial = entry->serial;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100959}
960
961static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200962text_entry_set_preedit(struct text_entry *entry,
963 const char *preedit_text,
964 int preedit_cursor)
965{
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100966 text_entry_reset_preedit(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200967
968 if (!preedit_text)
969 return;
970
Jan Arne Petersen46535312013-01-16 21:26:38 +0100971 entry->preedit.text = strdup(preedit_text);
972 entry->preedit.cursor = preedit_cursor;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200973
974 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100975
976 widget_schedule_redraw(entry->widget);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200977}
978
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100979static uint32_t
980text_entry_try_invoke_preedit_action(struct text_entry *entry,
981 int32_t x, int32_t y,
982 uint32_t button,
983 enum wl_pointer_button_state state)
984{
985 int index, trailing;
986 uint32_t cursor;
Jan Arne Petersen68516862013-04-18 16:47:42 +0200987 const char *text;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100988
989 if (!entry->preedit.text)
990 return 0;
991
992 pango_layout_xy_to_index(entry->layout,
993 x * PANGO_SCALE, y * PANGO_SCALE,
994 &index, &trailing);
Jan Arne Petersen68516862013-04-18 16:47:42 +0200995
996 text = pango_layout_get_text(entry->layout);
997 cursor = g_utf8_offset_to_pointer(text + index, trailing) - text;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100998
999 if (cursor < entry->cursor ||
1000 cursor > entry->cursor + strlen(entry->preedit.text)) {
1001 return 0;
1002 }
1003
1004 if (state == WL_POINTER_BUTTON_STATE_RELEASED)
Jonas Ådahl3bcba342015-11-17 16:00:29 +08001005 zwp_text_input_v1_invoke_action(entry->text_input,
1006 button,
1007 cursor - entry->cursor);
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001008
1009 return 1;
1010}
1011
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001012static bool
1013text_entry_has_preedit(struct text_entry *entry)
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001014{
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001015 return entry->preedit.text && (strlen(entry->preedit.text) > 0);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001016}
1017
1018static void
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001019text_entry_set_cursor_position(struct text_entry *entry,
1020 int32_t x, int32_t y,
1021 bool move_anchor)
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001022{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001023 int index, trailing;
Jan Arne Petersen68516862013-04-18 16:47:42 +02001024 const char *text;
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001025 uint32_t cursor;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001026
1027 pango_layout_xy_to_index(entry->layout,
1028 x * PANGO_SCALE, y * PANGO_SCALE,
1029 &index, &trailing);
Jan Arne Petersen68516862013-04-18 16:47:42 +02001030
1031 text = pango_layout_get_text(entry->layout);
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001032
1033 cursor = g_utf8_offset_to_pointer(text + index, trailing) - text;
1034
1035 if (move_anchor)
1036 entry->anchor = cursor;
1037
1038 if (text_entry_has_preedit(entry)) {
1039 text_entry_commit_and_reset(entry);
1040
1041 assert(!text_entry_has_preedit(entry));
1042 }
1043
1044 if (entry->cursor == cursor)
1045 return;
1046
1047 entry->cursor = cursor;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001048
1049 text_entry_update_layout(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001050
1051 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001052
Jan Arne Petersen0558a932013-01-16 21:26:45 +01001053 text_entry_update(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001054}
1055
1056static void
Jan Arne Petersene202bae2012-09-09 23:08:44 +02001057text_entry_delete_text(struct text_entry *entry,
1058 uint32_t index, uint32_t length)
1059{
Jan Arne Petersen68516862013-04-18 16:47:42 +02001060 uint32_t l;
1061
Jan Arne Petersen895a1282013-05-30 13:57:04 +02001062 assert(index <= strlen(entry->text));
1063 assert(index + length <= strlen(entry->text));
1064 assert(index + length >= length);
Jan Arne Petersen80ad1a92012-09-17 15:28:10 +02001065
Jan Arne Petersen68516862013-04-18 16:47:42 +02001066 l = strlen(entry->text + index + length);
1067 memmove(entry->text + index,
1068 entry->text + index + length,
1069 l + 1);
Jan Arne Petersene202bae2012-09-09 23:08:44 +02001070
Jan Arne Petersen9eaa8e52013-05-30 13:57:03 +02001071 if (entry->cursor > (index + length))
1072 entry->cursor -= length;
1073 else if (entry->cursor > index)
1074 entry->cursor = index;
1075
1076 entry->anchor = entry->cursor;
1077
Jan Arne Petersene202bae2012-09-09 23:08:44 +02001078 text_entry_update_layout(entry);
1079
1080 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001081
Jan Arne Petersen0558a932013-01-16 21:26:45 +01001082 text_entry_update(entry);
Jan Arne Petersene202bae2012-09-09 23:08:44 +02001083}
1084
1085static void
Jan Arne Petersene386dd22012-09-17 15:28:09 +02001086text_entry_delete_selected_text(struct text_entry *entry)
1087{
1088 uint32_t start_index = entry->anchor < entry->cursor ? entry->anchor : entry->cursor;
1089 uint32_t end_index = entry->anchor < entry->cursor ? entry->cursor : entry->anchor;
1090
1091 if (entry->anchor == entry->cursor)
1092 return;
1093
1094 text_entry_delete_text(entry, start_index, end_index - start_index);
1095
1096 entry->anchor = entry->cursor;
1097}
1098
1099static void
Jan Arne Petersenfe89e712013-04-18 16:47:27 +02001100text_entry_get_cursor_rectangle(struct text_entry *entry, struct rectangle *rectangle)
1101{
1102 struct rectangle allocation;
1103 PangoRectangle extents;
1104 PangoRectangle cursor_pos;
1105
1106 widget_get_allocation(entry->widget, &allocation);
1107
1108 if (entry->preedit.text && entry->preedit.cursor < 0) {
1109 rectangle->x = 0;
1110 rectangle->y = 0;
1111 rectangle->width = 0;
1112 rectangle->height = 0;
1113 return;
1114 }
1115
Jan Arne Petersen68516862013-04-18 16:47:42 +02001116
Jan Arne Petersenfe89e712013-04-18 16:47:27 +02001117 pango_layout_get_extents(entry->layout, &extents, NULL);
1118 pango_layout_get_cursor_pos(entry->layout,
1119 entry->cursor + entry->preedit.cursor,
1120 &cursor_pos, NULL);
1121
1122 rectangle->x = allocation.x + (allocation.height / 2) + PANGO_PIXELS(cursor_pos.x);
1123 rectangle->y = allocation.y + 10 + PANGO_PIXELS(cursor_pos.y);
1124 rectangle->width = PANGO_PIXELS(cursor_pos.width);
1125 rectangle->height = PANGO_PIXELS(cursor_pos.height);
1126}
1127
1128static void
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001129text_entry_draw_cursor(struct text_entry *entry, cairo_t *cr)
1130{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001131 PangoRectangle extents;
1132 PangoRectangle cursor_pos;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001133
Jan Arne Petersen46535312013-01-16 21:26:38 +01001134 if (entry->preedit.text && entry->preedit.cursor < 0)
1135 return;
1136
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001137 pango_layout_get_extents(entry->layout, &extents, NULL);
1138 pango_layout_get_cursor_pos(entry->layout,
1139 entry->cursor + entry->preedit.cursor,
1140 &cursor_pos, NULL);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001141
1142 cairo_set_line_width(cr, 1.0);
Peter Maatmanb9a23f42013-07-06 20:55:54 +02001143 cairo_move_to(cr, PANGO_PIXELS(cursor_pos.x), PANGO_PIXELS(cursor_pos.y));
1144 cairo_line_to(cr, PANGO_PIXELS(cursor_pos.x), PANGO_PIXELS(cursor_pos.y) + PANGO_PIXELS(cursor_pos.height));
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001145 cairo_stroke(cr);
1146}
1147
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001148static int
1149text_offset_left(struct rectangle *allocation)
1150{
1151 return 10;
1152}
1153
1154static int
1155text_offset_top(struct rectangle *allocation)
1156{
1157 return allocation->height / 2;
1158}
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +02001159
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +02001160static void
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001161text_entry_redraw_handler(struct widget *widget, void *data)
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001162{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001163 struct text_entry *entry = data;
1164 cairo_surface_t *surface;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001165 struct rectangle allocation;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001166 cairo_t *cr;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001167
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001168 surface = window_get_surface(entry->window);
1169 widget_get_allocation(entry->widget, &allocation);
1170
1171 cr = cairo_create(surface);
1172 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
1173 cairo_clip(cr);
1174
1175 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
1176
1177 cairo_push_group(cr);
1178 cairo_translate(cr, allocation.x, allocation.y);
1179
1180 cairo_set_source_rgba(cr, 1, 1, 1, 1);
1181 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
1182 cairo_fill(cr);
1183
1184 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
1185
1186 if (entry->active) {
1187 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
1188 cairo_set_line_width (cr, 3);
1189 cairo_set_source_rgba(cr, 0, 0, 1, 1.0);
1190 cairo_stroke(cr);
1191 }
1192
1193 cairo_set_source_rgba(cr, 0, 0, 0, 1);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001194
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001195 cairo_translate(cr,
1196 text_offset_left(&allocation),
1197 text_offset_top(&allocation));
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001198
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001199 if (!entry->layout)
1200 entry->layout = pango_cairo_create_layout(cr);
1201 else
1202 pango_cairo_update_layout(cr, entry->layout);
1203
1204 text_entry_update_layout(entry);
1205
1206 pango_cairo_show_layout(cr, entry->layout);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001207
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001208 text_entry_draw_cursor(entry, cr);
1209
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001210 cairo_pop_group_to_source(cr);
1211 cairo_paint(cr);
1212
1213 cairo_destroy(cr);
1214 cairo_surface_destroy(surface);
1215}
1216
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001217static int
1218text_entry_motion_handler(struct widget *widget,
1219 struct input *input, uint32_t time,
1220 float x, float y, void *data)
1221{
1222 struct text_entry *entry = data;
1223 struct rectangle allocation;
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001224 int tx, ty;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001225
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001226 if (!entry->button_pressed) {
1227 return CURSOR_IBEAM;
1228 }
1229
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001230 widget_get_allocation(entry->widget, &allocation);
1231
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001232 tx = x - allocation.x - text_offset_left(&allocation);
1233 ty = y - allocation.y - text_offset_top(&allocation);
1234
1235 text_entry_set_cursor_position(entry, tx, ty, false);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001236
1237 return CURSOR_IBEAM;
1238}
1239
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001240static void
1241text_entry_button_handler(struct widget *widget,
1242 struct input *input, uint32_t time,
1243 uint32_t button,
1244 enum wl_pointer_button_state state, void *data)
1245{
1246 struct text_entry *entry = data;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001247 struct rectangle allocation;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001248 struct editor *editor;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001249 int32_t x, y;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001250 uint32_t result;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001251
1252 widget_get_allocation(entry->widget, &allocation);
1253 input_get_position(input, &x, &y);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001254
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001255 x -= allocation.x + text_offset_left(&allocation);
1256 y -= allocation.y + text_offset_top(&allocation);
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001257
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001258 editor = window_get_user_data(entry->window);
1259
Manuel Bachmann22f34302015-03-30 01:57:44 +02001260 switch (button) {
1261 case BTN_LEFT:
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001262 entry->button_pressed = (state == WL_POINTER_BUTTON_STATE_PRESSED);
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001263 if (state == WL_POINTER_BUTTON_STATE_PRESSED)
1264 input_grab(input, entry->widget, button);
1265 else
1266 input_ungrab(input);
Manuel Bachmann22f34302015-03-30 01:57:44 +02001267 break;
1268 case BTN_RIGHT:
1269 if (state == WL_POINTER_BUTTON_STATE_PRESSED)
1270 show_menu(editor, input, time);
1271 break;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001272 }
1273
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001274 if (text_entry_has_preedit(entry)) {
1275 result = text_entry_try_invoke_preedit_action(entry, x, y, button, state);
1276
1277 if (result)
1278 return;
1279 }
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001280
Manuel Bachmann22f34302015-03-30 01:57:44 +02001281 if (state == WL_POINTER_BUTTON_STATE_PRESSED &&
1282 button == BTN_LEFT) {
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001283 struct wl_seat *seat = input_get_seat(input);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001284
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001285 text_entry_activate(entry, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001286 editor->active_entry = entry;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001287
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001288 text_entry_set_cursor_position(entry, x, y, true);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001289 }
1290}
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001291
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001292static void
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -08001293text_entry_touch_handler(struct widget *widget, struct input *input,
1294 uint32_t serial, uint32_t time, int32_t id,
1295 float tx, float ty, void *data)
1296{
1297 struct text_entry *entry = data;
1298 struct wl_seat *seat = input_get_seat(input);
1299 struct rectangle allocation;
1300 struct editor *editor;
1301 int32_t x, y;
1302
1303 widget_get_allocation(entry->widget, &allocation);
1304
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001305 x = tx - (allocation.x + text_offset_left(&allocation));
1306 y = ty - (allocation.y + text_offset_top(&allocation));
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -08001307
1308 editor = window_get_user_data(entry->window);
1309 text_entry_activate(entry, seat);
1310 editor->active_entry = entry;
1311
1312 text_entry_set_cursor_position(entry, x, y, true);
1313}
1314
1315static void
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001316editor_button_handler(struct widget *widget,
1317 struct input *input, uint32_t time,
1318 uint32_t button,
1319 enum wl_pointer_button_state state, void *data)
1320{
1321 struct editor *editor = data;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001322
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001323 if (button != BTN_LEFT) {
1324 return;
1325 }
Jan Arne Petersene829adc2012-08-10 16:47:22 +02001326
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001327 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
1328 struct wl_seat *seat = input_get_seat(input);
1329
Jan Arne Petersene829adc2012-08-10 16:47:22 +02001330 text_entry_deactivate(editor->entry, seat);
1331 text_entry_deactivate(editor->editor, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001332 editor->active_entry = NULL;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001333 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001334}
1335
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -08001336static void
1337editor_touch_handler(struct widget *widget, struct input *input,
1338 uint32_t serial, uint32_t time, int32_t id,
1339 float tx, float ty, void *data)
1340{
1341 struct editor *editor = data;
1342
1343 struct wl_seat *seat = input_get_seat(input);
1344
1345 text_entry_deactivate(editor->entry, seat);
1346 text_entry_deactivate(editor->editor, seat);
1347 editor->active_entry = NULL;
1348}
Kristian Høgsberg78858902014-01-01 23:57:42 -08001349
1350static void
1351keyboard_focus_handler(struct window *window,
1352 struct input *device, void *data)
1353{
1354 struct editor *editor = data;
1355
1356 window_schedule_redraw(editor->window);
1357}
1358
Manuel Bachmann22f34302015-03-30 01:57:44 +02001359static int
1360handle_bound_key(struct editor *editor,
1361 struct input *input, uint32_t sym, uint32_t time)
1362{
1363 switch (sym) {
1364 case XKB_KEY_X:
1365 editor_copy_cut(editor, input, true);
1366 return 1;
1367 case XKB_KEY_C:
1368 editor_copy_cut(editor, input, false);
1369 return 1;
1370 case XKB_KEY_V:
1371 editor_paste(editor, input);
1372 return 1;
1373 default:
1374 return 0;
1375 }
1376}
1377
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001378static void
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001379key_handler(struct window *window,
1380 struct input *input, uint32_t time,
1381 uint32_t key, uint32_t sym, enum wl_keyboard_key_state state,
1382 void *data)
1383{
1384 struct editor *editor = data;
1385 struct text_entry *entry;
Jan Arne Petersen68516862013-04-18 16:47:42 +02001386 const char *new_char;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001387 char text[16];
Manuel Bachmann22f34302015-03-30 01:57:44 +02001388 uint32_t modifiers;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001389
1390 if (!editor->active_entry)
1391 return;
1392
1393 entry = editor->active_entry;
1394
1395 if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
1396 return;
1397
Manuel Bachmann22f34302015-03-30 01:57:44 +02001398 modifiers = input_get_modifiers(input);
1399 if ((modifiers & MOD_CONTROL_MASK) &&
1400 (modifiers & MOD_SHIFT_MASK) &&
1401 handle_bound_key(editor, input, sym, time))
1402 return;
1403
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001404 switch (sym) {
1405 case XKB_KEY_BackSpace:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001406 text_entry_commit_and_reset(entry);
1407
Jan Arne Petersen68516862013-04-18 16:47:42 +02001408 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
1409 if (new_char != NULL)
1410 text_entry_delete_text(entry,
1411 new_char - entry->text,
1412 (entry->text + entry->cursor) - new_char);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001413 break;
1414 case XKB_KEY_Delete:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001415 text_entry_commit_and_reset(entry);
1416
Jan Arne Petersen68516862013-04-18 16:47:42 +02001417 new_char = utf8_next_char(entry->text + entry->cursor);
1418 if (new_char != NULL)
1419 text_entry_delete_text(entry,
1420 entry->cursor,
1421 new_char - (entry->text + entry->cursor));
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001422 break;
1423 case XKB_KEY_Left:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001424 text_entry_commit_and_reset(entry);
1425
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001426 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
1427 if (new_char != NULL) {
1428 entry->cursor = new_char - entry->text;
Rob Bradford70002832013-07-11 16:00:00 +01001429 if (!(input_get_modifiers(input) & MOD_SHIFT_MASK))
1430 entry->anchor = entry->cursor;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001431 widget_schedule_redraw(entry->widget);
1432 }
1433 break;
1434 case XKB_KEY_Right:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001435 text_entry_commit_and_reset(entry);
1436
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001437 new_char = utf8_next_char(entry->text + entry->cursor);
1438 if (new_char != NULL) {
1439 entry->cursor = new_char - entry->text;
Rob Bradford70002832013-07-11 16:00:00 +01001440 if (!(input_get_modifiers(input) & MOD_SHIFT_MASK))
1441 entry->anchor = entry->cursor;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001442 widget_schedule_redraw(entry->widget);
1443 }
1444 break;
Manuel Bachmann8986c182014-04-18 12:50:14 +02001445 case XKB_KEY_Up:
1446 text_entry_commit_and_reset(entry);
1447
1448 move_up(entry->text, &entry->cursor);
1449 if (!(input_get_modifiers(input) & MOD_SHIFT_MASK))
1450 entry->anchor = entry->cursor;
1451 widget_schedule_redraw(entry->widget);
1452 break;
1453 case XKB_KEY_Down:
1454 text_entry_commit_and_reset(entry);
1455
1456 move_down(entry->text, &entry->cursor);
1457 if (!(input_get_modifiers(input) & MOD_SHIFT_MASK))
1458 entry->anchor = entry->cursor;
1459 widget_schedule_redraw(entry->widget);
1460 break;
Peter Maatman08c38d42013-07-06 20:42:59 +02001461 case XKB_KEY_Escape:
1462 break;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001463 default:
1464 if (xkb_keysym_to_utf8(sym, text, sizeof(text)) <= 0)
1465 break;
1466
Peter Maatman08c38d42013-07-06 20:42:59 +02001467 text_entry_commit_and_reset(entry);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001468
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +01001469 text_entry_insert_at_cursor(entry, text, 0, 0);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001470 break;
1471 }
1472
1473 widget_schedule_redraw(entry->widget);
1474}
1475
1476static void
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001477global_handler(struct display *display, uint32_t name,
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001478 const char *interface, uint32_t version, void *data)
1479{
1480 struct editor *editor = data;
1481
Jonas Ådahl3bcba342015-11-17 16:00:29 +08001482 if (!strcmp(interface, "zwp_text_input_manager_v1")) {
Jan Arne Petersen78d00e42013-04-18 16:47:24 +02001483 editor->text_input_manager =
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001484 display_bind(display, name,
Jonas Ådahl3bcba342015-11-17 16:00:29 +08001485 &zwp_text_input_manager_v1_interface, 1);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001486 }
1487}
1488
1489int
1490main(int argc, char *argv[])
1491{
1492 struct editor editor;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001493 int i;
1494 uint32_t click_to_show = 0;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001495 const char *preferred_language = NULL;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001496
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001497 for (i = 1; i < argc; i++) {
Jan Arne Petersen61381972013-01-31 15:52:21 +01001498 if (strcmp("--click-to-show", argv[i]) == 0)
1499 click_to_show = 1;
Bill Spitzakbb0bb9c2014-08-08 12:59:58 -07001500 else if (strcmp("--preferred-language", argv[i]) == 0 &&
1501 i + 1 < argc) {
1502 preferred_language = argv[i + 1];
1503 i++;
1504 } else {
1505 printf("Usage: %s [OPTIONS]\n"
1506 " --click-to-show\n"
1507 " --preferred-language LANGUAGE\n",
1508 argv[0]);
1509 return 1;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001510 }
1511 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001512
Jan Arne Petersen25f6db52012-11-05 03:26:40 +01001513 memset(&editor, 0, sizeof editor);
1514
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001515#ifdef HAVE_PANGO
1516 g_type_init();
1517#endif
1518
Kristian Høgsberg4172f662013-02-20 15:27:49 -05001519 editor.display = display_create(&argc, argv);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001520 if (editor.display == NULL) {
1521 fprintf(stderr, "failed to create display: %m\n");
1522 return -1;
1523 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001524
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001525 display_set_user_data(editor.display, &editor);
1526 display_set_global_handler(editor.display, global_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001527
Olivier Blin30e1f3c2014-09-16 19:13:17 +02001528 if (editor.text_input_manager == NULL) {
1529 fprintf(stderr, "No text input manager global\n");
1530 return -1;
1531 }
1532
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001533 editor.window = window_create(editor.display);
Jason Ekstrandee7fefc2013-10-13 19:08:38 -05001534 editor.widget = window_frame_create(editor.window, &editor);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001535
1536 editor.entry = text_entry_create(&editor, "Entry");
Jan Arne Petersen61381972013-01-31 15:52:21 +01001537 editor.entry->click_to_show = click_to_show;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001538 if (preferred_language)
1539 editor.entry->preferred_language = strdup(preferred_language);
Jan Arne Petersen0558a932013-01-16 21:26:45 +01001540 editor.editor = text_entry_create(&editor, "Numeric");
Jonas Ådahl3bcba342015-11-17 16:00:29 +08001541 editor.editor->content_purpose = ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_NUMBER;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001542 editor.editor->click_to_show = click_to_show;
Manuel Bachmann22f34302015-03-30 01:57:44 +02001543 editor.selection = NULL;
1544 editor.selected_text = NULL;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001545
1546 window_set_title(editor.window, "Text Editor");
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001547 window_set_key_handler(editor.window, key_handler);
Kristian Høgsberg78858902014-01-01 23:57:42 -08001548 window_set_keyboard_focus_handler(editor.window,
1549 keyboard_focus_handler);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001550 window_set_user_data(editor.window, &editor);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001551
1552 widget_set_redraw_handler(editor.widget, redraw_handler);
1553 widget_set_resize_handler(editor.widget, resize_handler);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001554 widget_set_button_handler(editor.widget, editor_button_handler);
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -08001555 widget_set_touch_down_handler(editor.widget, editor_touch_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001556
1557 window_schedule_resize(editor.window, 500, 400);
1558
1559 display_run(editor.display);
1560
Manuel Bachmann22f34302015-03-30 01:57:44 +02001561 if (editor.selected_text)
1562 free(editor.selected_text);
1563 if (editor.selection)
1564 wl_data_source_destroy(editor.selection);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001565 text_entry_destroy(editor.entry);
1566 text_entry_destroy(editor.editor);
vivek31732f72014-05-15 18:58:16 +05301567 widget_destroy(editor.widget);
1568 window_destroy(editor.window);
1569 display_destroy(editor.display);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001570
1571 return 0;
1572}