blob: 30bf555cf9d1329aa59b8dca047fa7c670a4b663 [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");
Derek Foreman2af7e202016-07-07 10:52:17 -0500579
580 close(fd);
Manuel Bachmann22f34302015-03-30 01:57:44 +0200581}
582
583static void
584data_source_cancelled(void *data, struct wl_data_source *source)
585{
586 wl_data_source_destroy(source);
587}
588
589static const struct wl_data_source_listener data_source_listener = {
590 data_source_target,
591 data_source_send,
592 data_source_cancelled
593};
594
595static void
596paste_func(void *buffer, size_t len,
597 int32_t x, int32_t y, void *data)
598{
599 struct editor *editor = data;
600 struct text_entry *entry = editor->active_entry;
601 char *pasted_text;
602
603 if (!entry)
604 return;
605
606 pasted_text = malloc(len + 1);
607 strncpy(pasted_text, buffer, len);
608 pasted_text[len] = '\0';
609
610 text_entry_insert_at_cursor(entry, pasted_text, 0, 0);
611
612 free(pasted_text);
613}
614
615static void
616editor_copy_cut(struct editor *editor, struct input *input, bool cut)
617{
618 struct text_entry *entry = editor->active_entry;
619
620 if (!entry)
621 return;
Michael Vetter2a18a522015-05-15 17:17:47 +0200622
Manuel Bachmann22f34302015-03-30 01:57:44 +0200623 if (entry->cursor != entry->anchor) {
624 int start_index = MIN(entry->cursor, entry->anchor);
625 int end_index = MAX(entry->cursor, entry->anchor);
626 int len = end_index - start_index;
627
628 editor->selected_text = realloc(editor->selected_text, len + 1);
629 strncpy(editor->selected_text, &entry->text[start_index], len);
630 editor->selected_text[len] = '\0';
631
632 if (cut)
633 text_entry_delete_text(entry, start_index, len);
634
635 editor->selection =
636 display_create_data_source(editor->display);
637 wl_data_source_offer(editor->selection,
638 "text/plain;charset=utf-8");
639 wl_data_source_add_listener(editor->selection,
640 &data_source_listener, editor);
641 input_set_selection(input, editor->selection,
642 display_get_serial(editor->display));
643 }
644}
645
646static void
647editor_paste(struct editor *editor, struct input *input)
648{
649 input_receive_selection_data(input,
650 "text/plain;charset=utf-8",
651 paste_func, editor);
652}
653
654static void
655menu_func(void *data, struct input *input, int index)
656{
657 struct window *window = data;
658 struct editor *editor = window_get_user_data(window);
659
660 fprintf(stderr, "picked entry %d\n", index);
661
662 switch (index) {
663 case 0:
664 editor_copy_cut(editor, input, true);
665 break;
666 case 1:
667 editor_copy_cut(editor, input, false);
668 break;
669 case 2:
670 editor_paste(editor, input);
671 break;
672 }
673}
674
675static void
676show_menu(struct editor *editor, struct input *input, uint32_t time)
677{
678 int32_t x, y;
679 static const char *entries[] = {
680 "Cut", "Copy", "Paste"
681 };
682
683 input_get_position(input, &x, &y);
684 window_show_menu(editor->display, input, time, editor->window,
685 x + 10, y + 20, menu_func,
686 entries, ARRAY_LENGTH(entries));
687}
688
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200689static struct text_entry*
690text_entry_create(struct editor *editor, const char *text)
691{
692 struct text_entry *entry;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200693
Ryo Munakata5e653ca2015-08-07 20:20:46 +0900694 entry = xzalloc(sizeof *entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200695
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200696 entry->widget = widget_add_widget(editor->widget, entry);
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200697 entry->window = editor->window;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200698 entry->text = strdup(text);
699 entry->active = 0;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200700 entry->cursor = strlen(text);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200701 entry->anchor = entry->cursor;
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800702 entry->text_input =
703 zwp_text_input_manager_v1_create_text_input(editor->text_input_manager);
704 zwp_text_input_v1_add_listener(entry->text_input,
705 &text_input_listener, entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200706
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200707 widget_set_redraw_handler(entry->widget, text_entry_redraw_handler);
708 widget_set_button_handler(entry->widget, text_entry_button_handler);
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +0200709 widget_set_motion_handler(entry->widget, text_entry_motion_handler);
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -0800710 widget_set_touch_down_handler(entry->widget, text_entry_touch_handler);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200711
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200712 return entry;
713}
714
715static void
716text_entry_destroy(struct text_entry *entry)
717{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200718 widget_destroy(entry->widget);
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800719 zwp_text_input_v1_destroy(entry->text_input);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100720 g_clear_object(&entry->layout);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200721 free(entry->text);
Silvan Jegene31d95f2016-11-17 21:43:06 +0100722 free(entry->preferred_language);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200723 free(entry);
724}
725
726static void
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200727redraw_handler(struct widget *widget, void *data)
728{
729 struct editor *editor = data;
730 cairo_surface_t *surface;
731 struct rectangle allocation;
732 cairo_t *cr;
733
734 surface = window_get_surface(editor->window);
735 widget_get_allocation(editor->widget, &allocation);
736
737 cr = cairo_create(surface);
738 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
739 cairo_clip(cr);
740
741 cairo_translate(cr, allocation.x, allocation.y);
742
743 /* Draw background */
744 cairo_push_group(cr);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200745 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200746 cairo_set_source_rgba(cr, 1, 1, 1, 1);
747 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
748 cairo_fill(cr);
749
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200750 cairo_pop_group_to_source(cr);
751 cairo_paint(cr);
752
753 cairo_destroy(cr);
754 cairo_surface_destroy(surface);
755}
756
757static void
758text_entry_allocate(struct text_entry *entry, int32_t x, int32_t y,
759 int32_t width, int32_t height)
760{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200761 widget_set_allocation(entry->widget, x, y, width, height);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200762}
763
764static void
765resize_handler(struct widget *widget,
766 int32_t width, int32_t height, void *data)
767{
768 struct editor *editor = data;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200769 struct rectangle allocation;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200770
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200771 widget_get_allocation(editor->widget, &allocation);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200772
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200773 text_entry_allocate(editor->entry,
774 allocation.x + 20, allocation.y + 20,
775 width - 40, height / 2 - 40);
776 text_entry_allocate(editor->editor,
777 allocation.x + 20, allocation.y + height / 2 + 20,
778 width - 40, height / 2 - 40);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200779}
780
781static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200782text_entry_activate(struct text_entry *entry,
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200783 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200784{
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200785 struct wl_surface *surface = window_get_wl_surface(entry->window);
786
Jan Arne Petersen61381972013-01-31 15:52:21 +0100787 if (entry->click_to_show && entry->active) {
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800788 zwp_text_input_v1_show_input_panel(entry->text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100789
790 return;
791 }
792
793 if (!entry->click_to_show)
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800794 zwp_text_input_v1_show_input_panel(entry->text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100795
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800796 zwp_text_input_v1_activate(entry->text_input,
797 seat,
798 surface);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200799}
800
801static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200802text_entry_deactivate(struct text_entry *entry,
803 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200804{
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800805 zwp_text_input_v1_deactivate(entry->text_input,
806 seat);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200807}
808
809static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200810text_entry_update_layout(struct text_entry *entry)
811{
812 char *text;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100813 PangoAttrList *attr_list;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200814
Jan Arne Petersen68516862013-04-18 16:47:42 +0200815 assert(entry->cursor <= (strlen(entry->text) +
816 (entry->preedit.text ? strlen(entry->preedit.text) : 0)));
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200817
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100818 if (entry->preedit.text) {
Derek Foreman22044922014-11-20 15:42:35 -0600819 text = xmalloc(strlen(entry->text) + strlen(entry->preedit.text) + 1);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100820 strncpy(text, entry->text, entry->cursor);
821 strcpy(text + entry->cursor, entry->preedit.text);
822 strcpy(text + entry->cursor + strlen(entry->preedit.text),
823 entry->text + entry->cursor);
824 } else {
825 text = strdup(entry->text);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200826 }
827
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100828 if (entry->cursor != entry->anchor) {
829 int start_index = MIN(entry->cursor, entry->anchor);
830 int end_index = MAX(entry->cursor, entry->anchor);
831 PangoAttribute *attr;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200832
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100833 attr_list = pango_attr_list_copy(entry->preedit.attr_list);
834
835 if (!attr_list)
836 attr_list = pango_attr_list_new();
837
838 attr = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
839 attr->start_index = start_index;
840 attr->end_index = end_index;
841 pango_attr_list_insert(attr_list, attr);
842
843 attr = pango_attr_foreground_new(65535, 65535, 65535);
844 attr->start_index = start_index;
845 attr->end_index = end_index;
846 pango_attr_list_insert(attr_list, attr);
847 } else {
848 attr_list = pango_attr_list_ref(entry->preedit.attr_list);
849 }
850
851 if (entry->preedit.text && !entry->preedit.attr_list) {
852 PangoAttribute *attr;
853
854 if (!attr_list)
855 attr_list = pango_attr_list_new();
856
857 attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
858 attr->start_index = entry->cursor;
859 attr->end_index = entry->cursor + strlen(entry->preedit.text);
860 pango_attr_list_insert(attr_list, attr);
861 }
862
863 if (entry->layout) {
864 pango_layout_set_text(entry->layout, text, -1);
865 pango_layout_set_attributes(entry->layout, attr_list);
866 }
867
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200868 free(text);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100869 pango_attr_list_unref(attr_list);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200870}
871
872static void
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100873text_entry_update(struct text_entry *entry)
874{
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200875 struct rectangle cursor_rectangle;
876
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800877 zwp_text_input_v1_set_content_type(entry->text_input,
878 ZWP_TEXT_INPUT_V1_CONTENT_HINT_NONE,
879 entry->content_purpose);
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100880
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800881 zwp_text_input_v1_set_surrounding_text(entry->text_input,
882 entry->text,
883 entry->cursor,
884 entry->anchor);
Jan Arne Petersen0eabcaa2013-01-31 15:52:20 +0100885
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200886 if (entry->preferred_language)
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800887 zwp_text_input_v1_set_preferred_language(entry->text_input,
888 entry->preferred_language);
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200889
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200890 text_entry_get_cursor_rectangle(entry, &cursor_rectangle);
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800891 zwp_text_input_v1_set_cursor_rectangle(entry->text_input,
892 cursor_rectangle.x,
893 cursor_rectangle.y,
894 cursor_rectangle.width,
895 cursor_rectangle.height);
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200896
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800897 zwp_text_input_v1_commit_state(entry->text_input, ++entry->serial);
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100898}
899
900static void
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100901text_entry_insert_at_cursor(struct text_entry *entry, const char *text,
902 int32_t cursor, int32_t anchor)
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200903{
Derek Foreman22044922014-11-20 15:42:35 -0600904 char *new_text = xmalloc(strlen(entry->text) + strlen(text) + 1);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200905
906 strncpy(new_text, entry->text, entry->cursor);
907 strcpy(new_text + entry->cursor, text);
908 strcpy(new_text + entry->cursor + strlen(text),
909 entry->text + entry->cursor);
910
911 free(entry->text);
912 entry->text = new_text;
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100913 if (anchor >= 0)
914 entry->anchor = entry->cursor + strlen(text) + anchor;
915 else
916 entry->anchor = entry->cursor + 1 + anchor;
Jan Arne Petersen68516862013-04-18 16:47:42 +0200917
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100918 if (cursor >= 0)
919 entry->cursor += strlen(text) + cursor;
920 else
921 entry->cursor += 1 + cursor;
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200922
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200923 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100924
925 widget_schedule_redraw(entry->widget);
926
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100927 text_entry_update(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200928}
929
930static void
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100931text_entry_reset_preedit(struct text_entry *entry)
932{
933 entry->preedit.cursor = 0;
934
935 free(entry->preedit.text);
936 entry->preedit.text = NULL;
937
938 free(entry->preedit.commit);
939 entry->preedit.commit = NULL;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100940
941 pango_attr_list_unref(entry->preedit.attr_list);
942 entry->preedit.attr_list = NULL;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100943}
944
945static void
946text_entry_commit_and_reset(struct text_entry *entry)
947{
948 char *commit = NULL;
949
950 if (entry->preedit.commit)
951 commit = strdup(entry->preedit.commit);
952
953 text_entry_reset_preedit(entry);
954 if (commit) {
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100955 text_entry_insert_at_cursor(entry, commit, 0, 0);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100956 free(commit);
957 }
Jan Arne Petersen08015b62013-04-18 16:47:18 +0200958
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800959 zwp_text_input_v1_reset(entry->text_input);
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200960 text_entry_update(entry);
961 entry->reset_serial = entry->serial;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100962}
963
964static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200965text_entry_set_preedit(struct text_entry *entry,
966 const char *preedit_text,
967 int preedit_cursor)
968{
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100969 text_entry_reset_preedit(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200970
971 if (!preedit_text)
972 return;
973
Jan Arne Petersen46535312013-01-16 21:26:38 +0100974 entry->preedit.text = strdup(preedit_text);
975 entry->preedit.cursor = preedit_cursor;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200976
977 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100978
979 widget_schedule_redraw(entry->widget);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200980}
981
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100982static uint32_t
983text_entry_try_invoke_preedit_action(struct text_entry *entry,
984 int32_t x, int32_t y,
985 uint32_t button,
986 enum wl_pointer_button_state state)
987{
988 int index, trailing;
989 uint32_t cursor;
Jan Arne Petersen68516862013-04-18 16:47:42 +0200990 const char *text;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100991
992 if (!entry->preedit.text)
993 return 0;
994
995 pango_layout_xy_to_index(entry->layout,
996 x * PANGO_SCALE, y * PANGO_SCALE,
997 &index, &trailing);
Jan Arne Petersen68516862013-04-18 16:47:42 +0200998
999 text = pango_layout_get_text(entry->layout);
1000 cursor = g_utf8_offset_to_pointer(text + index, trailing) - text;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001001
1002 if (cursor < entry->cursor ||
1003 cursor > entry->cursor + strlen(entry->preedit.text)) {
1004 return 0;
1005 }
1006
1007 if (state == WL_POINTER_BUTTON_STATE_RELEASED)
Jonas Ådahl3bcba342015-11-17 16:00:29 +08001008 zwp_text_input_v1_invoke_action(entry->text_input,
1009 button,
1010 cursor - entry->cursor);
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001011
1012 return 1;
1013}
1014
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001015static bool
1016text_entry_has_preedit(struct text_entry *entry)
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001017{
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001018 return entry->preedit.text && (strlen(entry->preedit.text) > 0);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001019}
1020
1021static void
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001022text_entry_set_cursor_position(struct text_entry *entry,
1023 int32_t x, int32_t y,
1024 bool move_anchor)
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001025{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001026 int index, trailing;
Jan Arne Petersen68516862013-04-18 16:47:42 +02001027 const char *text;
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001028 uint32_t cursor;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001029
1030 pango_layout_xy_to_index(entry->layout,
1031 x * PANGO_SCALE, y * PANGO_SCALE,
1032 &index, &trailing);
Jan Arne Petersen68516862013-04-18 16:47:42 +02001033
1034 text = pango_layout_get_text(entry->layout);
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001035
1036 cursor = g_utf8_offset_to_pointer(text + index, trailing) - text;
1037
1038 if (move_anchor)
1039 entry->anchor = cursor;
1040
1041 if (text_entry_has_preedit(entry)) {
1042 text_entry_commit_and_reset(entry);
1043
1044 assert(!text_entry_has_preedit(entry));
1045 }
1046
1047 if (entry->cursor == cursor)
1048 return;
1049
1050 entry->cursor = cursor;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001051
1052 text_entry_update_layout(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001053
1054 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001055
Jan Arne Petersen0558a932013-01-16 21:26:45 +01001056 text_entry_update(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001057}
1058
1059static void
Jan Arne Petersene202bae2012-09-09 23:08:44 +02001060text_entry_delete_text(struct text_entry *entry,
1061 uint32_t index, uint32_t length)
1062{
Jan Arne Petersen68516862013-04-18 16:47:42 +02001063 uint32_t l;
1064
Jan Arne Petersen895a1282013-05-30 13:57:04 +02001065 assert(index <= strlen(entry->text));
1066 assert(index + length <= strlen(entry->text));
1067 assert(index + length >= length);
Jan Arne Petersen80ad1a92012-09-17 15:28:10 +02001068
Jan Arne Petersen68516862013-04-18 16:47:42 +02001069 l = strlen(entry->text + index + length);
1070 memmove(entry->text + index,
1071 entry->text + index + length,
1072 l + 1);
Jan Arne Petersene202bae2012-09-09 23:08:44 +02001073
Jan Arne Petersen9eaa8e52013-05-30 13:57:03 +02001074 if (entry->cursor > (index + length))
1075 entry->cursor -= length;
1076 else if (entry->cursor > index)
1077 entry->cursor = index;
1078
1079 entry->anchor = entry->cursor;
1080
Jan Arne Petersene202bae2012-09-09 23:08:44 +02001081 text_entry_update_layout(entry);
1082
1083 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001084
Jan Arne Petersen0558a932013-01-16 21:26:45 +01001085 text_entry_update(entry);
Jan Arne Petersene202bae2012-09-09 23:08:44 +02001086}
1087
1088static void
Jan Arne Petersene386dd22012-09-17 15:28:09 +02001089text_entry_delete_selected_text(struct text_entry *entry)
1090{
1091 uint32_t start_index = entry->anchor < entry->cursor ? entry->anchor : entry->cursor;
1092 uint32_t end_index = entry->anchor < entry->cursor ? entry->cursor : entry->anchor;
1093
1094 if (entry->anchor == entry->cursor)
1095 return;
1096
1097 text_entry_delete_text(entry, start_index, end_index - start_index);
1098
1099 entry->anchor = entry->cursor;
1100}
1101
1102static void
Jan Arne Petersenfe89e712013-04-18 16:47:27 +02001103text_entry_get_cursor_rectangle(struct text_entry *entry, struct rectangle *rectangle)
1104{
1105 struct rectangle allocation;
1106 PangoRectangle extents;
1107 PangoRectangle cursor_pos;
1108
1109 widget_get_allocation(entry->widget, &allocation);
1110
1111 if (entry->preedit.text && entry->preedit.cursor < 0) {
1112 rectangle->x = 0;
1113 rectangle->y = 0;
1114 rectangle->width = 0;
1115 rectangle->height = 0;
1116 return;
1117 }
1118
Jan Arne Petersen68516862013-04-18 16:47:42 +02001119
Jan Arne Petersenfe89e712013-04-18 16:47:27 +02001120 pango_layout_get_extents(entry->layout, &extents, NULL);
1121 pango_layout_get_cursor_pos(entry->layout,
1122 entry->cursor + entry->preedit.cursor,
1123 &cursor_pos, NULL);
1124
1125 rectangle->x = allocation.x + (allocation.height / 2) + PANGO_PIXELS(cursor_pos.x);
1126 rectangle->y = allocation.y + 10 + PANGO_PIXELS(cursor_pos.y);
1127 rectangle->width = PANGO_PIXELS(cursor_pos.width);
1128 rectangle->height = PANGO_PIXELS(cursor_pos.height);
1129}
1130
1131static void
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001132text_entry_draw_cursor(struct text_entry *entry, cairo_t *cr)
1133{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001134 PangoRectangle extents;
1135 PangoRectangle cursor_pos;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001136
Jan Arne Petersen46535312013-01-16 21:26:38 +01001137 if (entry->preedit.text && entry->preedit.cursor < 0)
1138 return;
1139
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001140 pango_layout_get_extents(entry->layout, &extents, NULL);
1141 pango_layout_get_cursor_pos(entry->layout,
1142 entry->cursor + entry->preedit.cursor,
1143 &cursor_pos, NULL);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001144
1145 cairo_set_line_width(cr, 1.0);
Peter Maatmanb9a23f42013-07-06 20:55:54 +02001146 cairo_move_to(cr, PANGO_PIXELS(cursor_pos.x), PANGO_PIXELS(cursor_pos.y));
1147 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 +02001148 cairo_stroke(cr);
1149}
1150
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001151static int
1152text_offset_left(struct rectangle *allocation)
1153{
1154 return 10;
1155}
1156
1157static int
1158text_offset_top(struct rectangle *allocation)
1159{
1160 return allocation->height / 2;
1161}
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +02001162
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +02001163static void
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001164text_entry_redraw_handler(struct widget *widget, void *data)
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001165{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001166 struct text_entry *entry = data;
1167 cairo_surface_t *surface;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001168 struct rectangle allocation;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001169 cairo_t *cr;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001170
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001171 surface = window_get_surface(entry->window);
1172 widget_get_allocation(entry->widget, &allocation);
1173
1174 cr = cairo_create(surface);
1175 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
1176 cairo_clip(cr);
1177
1178 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
1179
1180 cairo_push_group(cr);
1181 cairo_translate(cr, allocation.x, allocation.y);
1182
1183 cairo_set_source_rgba(cr, 1, 1, 1, 1);
1184 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
1185 cairo_fill(cr);
1186
1187 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
1188
1189 if (entry->active) {
1190 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
1191 cairo_set_line_width (cr, 3);
1192 cairo_set_source_rgba(cr, 0, 0, 1, 1.0);
1193 cairo_stroke(cr);
1194 }
1195
1196 cairo_set_source_rgba(cr, 0, 0, 0, 1);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001197
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001198 cairo_translate(cr,
1199 text_offset_left(&allocation),
1200 text_offset_top(&allocation));
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001201
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001202 if (!entry->layout)
1203 entry->layout = pango_cairo_create_layout(cr);
1204 else
1205 pango_cairo_update_layout(cr, entry->layout);
1206
1207 text_entry_update_layout(entry);
1208
1209 pango_cairo_show_layout(cr, entry->layout);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001210
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001211 text_entry_draw_cursor(entry, cr);
1212
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001213 cairo_pop_group_to_source(cr);
1214 cairo_paint(cr);
1215
1216 cairo_destroy(cr);
1217 cairo_surface_destroy(surface);
1218}
1219
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001220static int
1221text_entry_motion_handler(struct widget *widget,
1222 struct input *input, uint32_t time,
1223 float x, float y, void *data)
1224{
1225 struct text_entry *entry = data;
1226 struct rectangle allocation;
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001227 int tx, ty;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001228
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001229 if (!entry->button_pressed) {
1230 return CURSOR_IBEAM;
1231 }
1232
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001233 widget_get_allocation(entry->widget, &allocation);
1234
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001235 tx = x - allocation.x - text_offset_left(&allocation);
1236 ty = y - allocation.y - text_offset_top(&allocation);
1237
1238 text_entry_set_cursor_position(entry, tx, ty, false);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001239
1240 return CURSOR_IBEAM;
1241}
1242
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001243static void
1244text_entry_button_handler(struct widget *widget,
1245 struct input *input, uint32_t time,
1246 uint32_t button,
1247 enum wl_pointer_button_state state, void *data)
1248{
1249 struct text_entry *entry = data;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001250 struct rectangle allocation;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001251 struct editor *editor;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001252 int32_t x, y;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001253 uint32_t result;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001254
1255 widget_get_allocation(entry->widget, &allocation);
1256 input_get_position(input, &x, &y);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001257
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001258 x -= allocation.x + text_offset_left(&allocation);
1259 y -= allocation.y + text_offset_top(&allocation);
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001260
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001261 editor = window_get_user_data(entry->window);
1262
Manuel Bachmann22f34302015-03-30 01:57:44 +02001263 switch (button) {
1264 case BTN_LEFT:
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001265 entry->button_pressed = (state == WL_POINTER_BUTTON_STATE_PRESSED);
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001266 if (state == WL_POINTER_BUTTON_STATE_PRESSED)
1267 input_grab(input, entry->widget, button);
1268 else
1269 input_ungrab(input);
Manuel Bachmann22f34302015-03-30 01:57:44 +02001270 break;
1271 case BTN_RIGHT:
1272 if (state == WL_POINTER_BUTTON_STATE_PRESSED)
1273 show_menu(editor, input, time);
1274 break;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001275 }
1276
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001277 if (text_entry_has_preedit(entry)) {
1278 result = text_entry_try_invoke_preedit_action(entry, x, y, button, state);
1279
1280 if (result)
1281 return;
1282 }
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001283
Manuel Bachmann22f34302015-03-30 01:57:44 +02001284 if (state == WL_POINTER_BUTTON_STATE_PRESSED &&
1285 button == BTN_LEFT) {
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001286 struct wl_seat *seat = input_get_seat(input);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001287
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001288 text_entry_activate(entry, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001289 editor->active_entry = entry;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001290
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001291 text_entry_set_cursor_position(entry, x, y, true);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001292 }
1293}
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001294
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001295static void
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -08001296text_entry_touch_handler(struct widget *widget, struct input *input,
1297 uint32_t serial, uint32_t time, int32_t id,
1298 float tx, float ty, void *data)
1299{
1300 struct text_entry *entry = data;
1301 struct wl_seat *seat = input_get_seat(input);
1302 struct rectangle allocation;
1303 struct editor *editor;
1304 int32_t x, y;
1305
1306 widget_get_allocation(entry->widget, &allocation);
1307
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001308 x = tx - (allocation.x + text_offset_left(&allocation));
1309 y = ty - (allocation.y + text_offset_top(&allocation));
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -08001310
1311 editor = window_get_user_data(entry->window);
1312 text_entry_activate(entry, seat);
1313 editor->active_entry = entry;
1314
1315 text_entry_set_cursor_position(entry, x, y, true);
1316}
1317
1318static void
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001319editor_button_handler(struct widget *widget,
1320 struct input *input, uint32_t time,
1321 uint32_t button,
1322 enum wl_pointer_button_state state, void *data)
1323{
1324 struct editor *editor = data;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001325
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001326 if (button != BTN_LEFT) {
1327 return;
1328 }
Jan Arne Petersene829adc2012-08-10 16:47:22 +02001329
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001330 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
1331 struct wl_seat *seat = input_get_seat(input);
1332
Jan Arne Petersene829adc2012-08-10 16:47:22 +02001333 text_entry_deactivate(editor->entry, seat);
1334 text_entry_deactivate(editor->editor, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001335 editor->active_entry = NULL;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001336 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001337}
1338
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -08001339static void
1340editor_touch_handler(struct widget *widget, struct input *input,
1341 uint32_t serial, uint32_t time, int32_t id,
1342 float tx, float ty, void *data)
1343{
1344 struct editor *editor = data;
1345
1346 struct wl_seat *seat = input_get_seat(input);
1347
1348 text_entry_deactivate(editor->entry, seat);
1349 text_entry_deactivate(editor->editor, seat);
1350 editor->active_entry = NULL;
1351}
Kristian Høgsberg78858902014-01-01 23:57:42 -08001352
1353static void
1354keyboard_focus_handler(struct window *window,
1355 struct input *device, void *data)
1356{
1357 struct editor *editor = data;
1358
1359 window_schedule_redraw(editor->window);
1360}
1361
Manuel Bachmann22f34302015-03-30 01:57:44 +02001362static int
1363handle_bound_key(struct editor *editor,
1364 struct input *input, uint32_t sym, uint32_t time)
1365{
1366 switch (sym) {
1367 case XKB_KEY_X:
1368 editor_copy_cut(editor, input, true);
1369 return 1;
1370 case XKB_KEY_C:
1371 editor_copy_cut(editor, input, false);
1372 return 1;
1373 case XKB_KEY_V:
1374 editor_paste(editor, input);
1375 return 1;
1376 default:
1377 return 0;
1378 }
1379}
1380
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001381static void
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001382key_handler(struct window *window,
1383 struct input *input, uint32_t time,
1384 uint32_t key, uint32_t sym, enum wl_keyboard_key_state state,
1385 void *data)
1386{
1387 struct editor *editor = data;
1388 struct text_entry *entry;
Jan Arne Petersen68516862013-04-18 16:47:42 +02001389 const char *new_char;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001390 char text[16];
Manuel Bachmann22f34302015-03-30 01:57:44 +02001391 uint32_t modifiers;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001392
1393 if (!editor->active_entry)
1394 return;
1395
1396 entry = editor->active_entry;
1397
1398 if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
1399 return;
1400
Manuel Bachmann22f34302015-03-30 01:57:44 +02001401 modifiers = input_get_modifiers(input);
1402 if ((modifiers & MOD_CONTROL_MASK) &&
1403 (modifiers & MOD_SHIFT_MASK) &&
1404 handle_bound_key(editor, input, sym, time))
1405 return;
1406
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001407 switch (sym) {
1408 case XKB_KEY_BackSpace:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001409 text_entry_commit_and_reset(entry);
1410
Jan Arne Petersen68516862013-04-18 16:47:42 +02001411 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
1412 if (new_char != NULL)
1413 text_entry_delete_text(entry,
1414 new_char - entry->text,
1415 (entry->text + entry->cursor) - new_char);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001416 break;
1417 case XKB_KEY_Delete:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001418 text_entry_commit_and_reset(entry);
1419
Jan Arne Petersen68516862013-04-18 16:47:42 +02001420 new_char = utf8_next_char(entry->text + entry->cursor);
1421 if (new_char != NULL)
1422 text_entry_delete_text(entry,
1423 entry->cursor,
1424 new_char - (entry->text + entry->cursor));
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001425 break;
1426 case XKB_KEY_Left:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001427 text_entry_commit_and_reset(entry);
1428
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001429 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
1430 if (new_char != NULL) {
1431 entry->cursor = new_char - entry->text;
Rob Bradford70002832013-07-11 16:00:00 +01001432 if (!(input_get_modifiers(input) & MOD_SHIFT_MASK))
1433 entry->anchor = entry->cursor;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001434 widget_schedule_redraw(entry->widget);
1435 }
1436 break;
1437 case XKB_KEY_Right:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001438 text_entry_commit_and_reset(entry);
1439
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001440 new_char = utf8_next_char(entry->text + entry->cursor);
1441 if (new_char != NULL) {
1442 entry->cursor = new_char - entry->text;
Rob Bradford70002832013-07-11 16:00:00 +01001443 if (!(input_get_modifiers(input) & MOD_SHIFT_MASK))
1444 entry->anchor = entry->cursor;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001445 widget_schedule_redraw(entry->widget);
1446 }
1447 break;
Manuel Bachmann8986c182014-04-18 12:50:14 +02001448 case XKB_KEY_Up:
1449 text_entry_commit_and_reset(entry);
1450
1451 move_up(entry->text, &entry->cursor);
1452 if (!(input_get_modifiers(input) & MOD_SHIFT_MASK))
1453 entry->anchor = entry->cursor;
1454 widget_schedule_redraw(entry->widget);
1455 break;
1456 case XKB_KEY_Down:
1457 text_entry_commit_and_reset(entry);
1458
1459 move_down(entry->text, &entry->cursor);
1460 if (!(input_get_modifiers(input) & MOD_SHIFT_MASK))
1461 entry->anchor = entry->cursor;
1462 widget_schedule_redraw(entry->widget);
1463 break;
Peter Maatman08c38d42013-07-06 20:42:59 +02001464 case XKB_KEY_Escape:
1465 break;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001466 default:
1467 if (xkb_keysym_to_utf8(sym, text, sizeof(text)) <= 0)
1468 break;
1469
Peter Maatman08c38d42013-07-06 20:42:59 +02001470 text_entry_commit_and_reset(entry);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001471
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +01001472 text_entry_insert_at_cursor(entry, text, 0, 0);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001473 break;
1474 }
1475
1476 widget_schedule_redraw(entry->widget);
1477}
1478
1479static void
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001480global_handler(struct display *display, uint32_t name,
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001481 const char *interface, uint32_t version, void *data)
1482{
1483 struct editor *editor = data;
1484
Jonas Ådahl3bcba342015-11-17 16:00:29 +08001485 if (!strcmp(interface, "zwp_text_input_manager_v1")) {
Jan Arne Petersen78d00e42013-04-18 16:47:24 +02001486 editor->text_input_manager =
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001487 display_bind(display, name,
Jonas Ådahl3bcba342015-11-17 16:00:29 +08001488 &zwp_text_input_manager_v1_interface, 1);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001489 }
1490}
1491
1492int
1493main(int argc, char *argv[])
1494{
1495 struct editor editor;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001496 int i;
1497 uint32_t click_to_show = 0;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001498 const char *preferred_language = NULL;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001499
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001500 for (i = 1; i < argc; i++) {
Jan Arne Petersen61381972013-01-31 15:52:21 +01001501 if (strcmp("--click-to-show", argv[i]) == 0)
1502 click_to_show = 1;
Bill Spitzakbb0bb9c2014-08-08 12:59:58 -07001503 else if (strcmp("--preferred-language", argv[i]) == 0 &&
1504 i + 1 < argc) {
1505 preferred_language = argv[i + 1];
1506 i++;
1507 } else {
1508 printf("Usage: %s [OPTIONS]\n"
1509 " --click-to-show\n"
1510 " --preferred-language LANGUAGE\n",
1511 argv[0]);
1512 return 1;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001513 }
1514 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001515
Jan Arne Petersen25f6db52012-11-05 03:26:40 +01001516 memset(&editor, 0, sizeof editor);
1517
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001518#ifdef HAVE_PANGO
1519 g_type_init();
1520#endif
1521
Kristian Høgsberg4172f662013-02-20 15:27:49 -05001522 editor.display = display_create(&argc, argv);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001523 if (editor.display == NULL) {
1524 fprintf(stderr, "failed to create display: %m\n");
1525 return -1;
1526 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001527
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001528 display_set_user_data(editor.display, &editor);
1529 display_set_global_handler(editor.display, global_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001530
Olivier Blin30e1f3c2014-09-16 19:13:17 +02001531 if (editor.text_input_manager == NULL) {
1532 fprintf(stderr, "No text input manager global\n");
1533 return -1;
1534 }
1535
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001536 editor.window = window_create(editor.display);
Jason Ekstrandee7fefc2013-10-13 19:08:38 -05001537 editor.widget = window_frame_create(editor.window, &editor);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001538
1539 editor.entry = text_entry_create(&editor, "Entry");
Jan Arne Petersen61381972013-01-31 15:52:21 +01001540 editor.entry->click_to_show = click_to_show;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001541 if (preferred_language)
1542 editor.entry->preferred_language = strdup(preferred_language);
Jan Arne Petersen0558a932013-01-16 21:26:45 +01001543 editor.editor = text_entry_create(&editor, "Numeric");
Jonas Ådahl3bcba342015-11-17 16:00:29 +08001544 editor.editor->content_purpose = ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_NUMBER;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001545 editor.editor->click_to_show = click_to_show;
Manuel Bachmann22f34302015-03-30 01:57:44 +02001546 editor.selection = NULL;
1547 editor.selected_text = NULL;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001548
1549 window_set_title(editor.window, "Text Editor");
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001550 window_set_key_handler(editor.window, key_handler);
Kristian Høgsberg78858902014-01-01 23:57:42 -08001551 window_set_keyboard_focus_handler(editor.window,
1552 keyboard_focus_handler);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001553 window_set_user_data(editor.window, &editor);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001554
1555 widget_set_redraw_handler(editor.widget, redraw_handler);
1556 widget_set_resize_handler(editor.widget, resize_handler);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001557 widget_set_button_handler(editor.widget, editor_button_handler);
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -08001558 widget_set_touch_down_handler(editor.widget, editor_touch_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001559
1560 window_schedule_resize(editor.window, 500, 400);
1561
1562 display_run(editor.display);
1563
Manuel Bachmann22f34302015-03-30 01:57:44 +02001564 if (editor.selected_text)
1565 free(editor.selected_text);
1566 if (editor.selection)
1567 wl_data_source_destroy(editor.selection);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001568 text_entry_destroy(editor.entry);
1569 text_entry_destroy(editor.editor);
vivek31732f72014-05-15 18:58:16 +05301570 widget_destroy(editor.widget);
1571 window_destroy(editor.window);
1572 display_destroy(editor.display);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001573
1574 return 0;
1575}