blob: 6805d8a8eb569553d561da6f66fee61dc6c93a41 [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);
722 free(entry);
723}
724
725static void
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200726redraw_handler(struct widget *widget, void *data)
727{
728 struct editor *editor = data;
729 cairo_surface_t *surface;
730 struct rectangle allocation;
731 cairo_t *cr;
732
733 surface = window_get_surface(editor->window);
734 widget_get_allocation(editor->widget, &allocation);
735
736 cr = cairo_create(surface);
737 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
738 cairo_clip(cr);
739
740 cairo_translate(cr, allocation.x, allocation.y);
741
742 /* Draw background */
743 cairo_push_group(cr);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200744 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200745 cairo_set_source_rgba(cr, 1, 1, 1, 1);
746 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
747 cairo_fill(cr);
748
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200749 cairo_pop_group_to_source(cr);
750 cairo_paint(cr);
751
752 cairo_destroy(cr);
753 cairo_surface_destroy(surface);
754}
755
756static void
757text_entry_allocate(struct text_entry *entry, int32_t x, int32_t y,
758 int32_t width, int32_t height)
759{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200760 widget_set_allocation(entry->widget, x, y, width, height);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200761}
762
763static void
764resize_handler(struct widget *widget,
765 int32_t width, int32_t height, void *data)
766{
767 struct editor *editor = data;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200768 struct rectangle allocation;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200769
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200770 widget_get_allocation(editor->widget, &allocation);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200771
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200772 text_entry_allocate(editor->entry,
773 allocation.x + 20, allocation.y + 20,
774 width - 40, height / 2 - 40);
775 text_entry_allocate(editor->editor,
776 allocation.x + 20, allocation.y + height / 2 + 20,
777 width - 40, height / 2 - 40);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200778}
779
780static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200781text_entry_activate(struct text_entry *entry,
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200782 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200783{
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200784 struct wl_surface *surface = window_get_wl_surface(entry->window);
785
Jan Arne Petersen61381972013-01-31 15:52:21 +0100786 if (entry->click_to_show && entry->active) {
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800787 zwp_text_input_v1_show_input_panel(entry->text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100788
789 return;
790 }
791
792 if (!entry->click_to_show)
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800793 zwp_text_input_v1_show_input_panel(entry->text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100794
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800795 zwp_text_input_v1_activate(entry->text_input,
796 seat,
797 surface);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200798}
799
800static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200801text_entry_deactivate(struct text_entry *entry,
802 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200803{
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800804 zwp_text_input_v1_deactivate(entry->text_input,
805 seat);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200806}
807
808static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200809text_entry_update_layout(struct text_entry *entry)
810{
811 char *text;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100812 PangoAttrList *attr_list;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200813
Jan Arne Petersen68516862013-04-18 16:47:42 +0200814 assert(entry->cursor <= (strlen(entry->text) +
815 (entry->preedit.text ? strlen(entry->preedit.text) : 0)));
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200816
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100817 if (entry->preedit.text) {
Derek Foreman22044922014-11-20 15:42:35 -0600818 text = xmalloc(strlen(entry->text) + strlen(entry->preedit.text) + 1);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100819 strncpy(text, entry->text, entry->cursor);
820 strcpy(text + entry->cursor, entry->preedit.text);
821 strcpy(text + entry->cursor + strlen(entry->preedit.text),
822 entry->text + entry->cursor);
823 } else {
824 text = strdup(entry->text);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200825 }
826
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100827 if (entry->cursor != entry->anchor) {
828 int start_index = MIN(entry->cursor, entry->anchor);
829 int end_index = MAX(entry->cursor, entry->anchor);
830 PangoAttribute *attr;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200831
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100832 attr_list = pango_attr_list_copy(entry->preedit.attr_list);
833
834 if (!attr_list)
835 attr_list = pango_attr_list_new();
836
837 attr = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
838 attr->start_index = start_index;
839 attr->end_index = end_index;
840 pango_attr_list_insert(attr_list, attr);
841
842 attr = pango_attr_foreground_new(65535, 65535, 65535);
843 attr->start_index = start_index;
844 attr->end_index = end_index;
845 pango_attr_list_insert(attr_list, attr);
846 } else {
847 attr_list = pango_attr_list_ref(entry->preedit.attr_list);
848 }
849
850 if (entry->preedit.text && !entry->preedit.attr_list) {
851 PangoAttribute *attr;
852
853 if (!attr_list)
854 attr_list = pango_attr_list_new();
855
856 attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
857 attr->start_index = entry->cursor;
858 attr->end_index = entry->cursor + strlen(entry->preedit.text);
859 pango_attr_list_insert(attr_list, attr);
860 }
861
862 if (entry->layout) {
863 pango_layout_set_text(entry->layout, text, -1);
864 pango_layout_set_attributes(entry->layout, attr_list);
865 }
866
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200867 free(text);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100868 pango_attr_list_unref(attr_list);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200869}
870
871static void
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100872text_entry_update(struct text_entry *entry)
873{
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200874 struct rectangle cursor_rectangle;
875
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800876 zwp_text_input_v1_set_content_type(entry->text_input,
877 ZWP_TEXT_INPUT_V1_CONTENT_HINT_NONE,
878 entry->content_purpose);
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100879
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800880 zwp_text_input_v1_set_surrounding_text(entry->text_input,
881 entry->text,
882 entry->cursor,
883 entry->anchor);
Jan Arne Petersen0eabcaa2013-01-31 15:52:20 +0100884
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200885 if (entry->preferred_language)
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800886 zwp_text_input_v1_set_preferred_language(entry->text_input,
887 entry->preferred_language);
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200888
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200889 text_entry_get_cursor_rectangle(entry, &cursor_rectangle);
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800890 zwp_text_input_v1_set_cursor_rectangle(entry->text_input,
891 cursor_rectangle.x,
892 cursor_rectangle.y,
893 cursor_rectangle.width,
894 cursor_rectangle.height);
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200895
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800896 zwp_text_input_v1_commit_state(entry->text_input, ++entry->serial);
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100897}
898
899static void
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100900text_entry_insert_at_cursor(struct text_entry *entry, const char *text,
901 int32_t cursor, int32_t anchor)
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200902{
Derek Foreman22044922014-11-20 15:42:35 -0600903 char *new_text = xmalloc(strlen(entry->text) + strlen(text) + 1);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200904
905 strncpy(new_text, entry->text, entry->cursor);
906 strcpy(new_text + entry->cursor, text);
907 strcpy(new_text + entry->cursor + strlen(text),
908 entry->text + entry->cursor);
909
910 free(entry->text);
911 entry->text = new_text;
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100912 if (anchor >= 0)
913 entry->anchor = entry->cursor + strlen(text) + anchor;
914 else
915 entry->anchor = entry->cursor + 1 + anchor;
Jan Arne Petersen68516862013-04-18 16:47:42 +0200916
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100917 if (cursor >= 0)
918 entry->cursor += strlen(text) + cursor;
919 else
920 entry->cursor += 1 + cursor;
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200921
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200922 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100923
924 widget_schedule_redraw(entry->widget);
925
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100926 text_entry_update(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200927}
928
929static void
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100930text_entry_reset_preedit(struct text_entry *entry)
931{
932 entry->preedit.cursor = 0;
933
934 free(entry->preedit.text);
935 entry->preedit.text = NULL;
936
937 free(entry->preedit.commit);
938 entry->preedit.commit = NULL;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100939
940 pango_attr_list_unref(entry->preedit.attr_list);
941 entry->preedit.attr_list = NULL;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100942}
943
944static void
945text_entry_commit_and_reset(struct text_entry *entry)
946{
947 char *commit = NULL;
948
949 if (entry->preedit.commit)
950 commit = strdup(entry->preedit.commit);
951
952 text_entry_reset_preedit(entry);
953 if (commit) {
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100954 text_entry_insert_at_cursor(entry, commit, 0, 0);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100955 free(commit);
956 }
Jan Arne Petersen08015b62013-04-18 16:47:18 +0200957
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800958 zwp_text_input_v1_reset(entry->text_input);
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200959 text_entry_update(entry);
960 entry->reset_serial = entry->serial;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100961}
962
963static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200964text_entry_set_preedit(struct text_entry *entry,
965 const char *preedit_text,
966 int preedit_cursor)
967{
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100968 text_entry_reset_preedit(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200969
970 if (!preedit_text)
971 return;
972
Jan Arne Petersen46535312013-01-16 21:26:38 +0100973 entry->preedit.text = strdup(preedit_text);
974 entry->preedit.cursor = preedit_cursor;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200975
976 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100977
978 widget_schedule_redraw(entry->widget);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200979}
980
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100981static uint32_t
982text_entry_try_invoke_preedit_action(struct text_entry *entry,
983 int32_t x, int32_t y,
984 uint32_t button,
985 enum wl_pointer_button_state state)
986{
987 int index, trailing;
988 uint32_t cursor;
Jan Arne Petersen68516862013-04-18 16:47:42 +0200989 const char *text;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100990
991 if (!entry->preedit.text)
992 return 0;
993
994 pango_layout_xy_to_index(entry->layout,
995 x * PANGO_SCALE, y * PANGO_SCALE,
996 &index, &trailing);
Jan Arne Petersen68516862013-04-18 16:47:42 +0200997
998 text = pango_layout_get_text(entry->layout);
999 cursor = g_utf8_offset_to_pointer(text + index, trailing) - text;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001000
1001 if (cursor < entry->cursor ||
1002 cursor > entry->cursor + strlen(entry->preedit.text)) {
1003 return 0;
1004 }
1005
1006 if (state == WL_POINTER_BUTTON_STATE_RELEASED)
Jonas Ådahl3bcba342015-11-17 16:00:29 +08001007 zwp_text_input_v1_invoke_action(entry->text_input,
1008 button,
1009 cursor - entry->cursor);
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001010
1011 return 1;
1012}
1013
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001014static bool
1015text_entry_has_preedit(struct text_entry *entry)
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001016{
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001017 return entry->preedit.text && (strlen(entry->preedit.text) > 0);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001018}
1019
1020static void
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001021text_entry_set_cursor_position(struct text_entry *entry,
1022 int32_t x, int32_t y,
1023 bool move_anchor)
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001024{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001025 int index, trailing;
Jan Arne Petersen68516862013-04-18 16:47:42 +02001026 const char *text;
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001027 uint32_t cursor;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001028
1029 pango_layout_xy_to_index(entry->layout,
1030 x * PANGO_SCALE, y * PANGO_SCALE,
1031 &index, &trailing);
Jan Arne Petersen68516862013-04-18 16:47:42 +02001032
1033 text = pango_layout_get_text(entry->layout);
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001034
1035 cursor = g_utf8_offset_to_pointer(text + index, trailing) - text;
1036
1037 if (move_anchor)
1038 entry->anchor = cursor;
1039
1040 if (text_entry_has_preedit(entry)) {
1041 text_entry_commit_and_reset(entry);
1042
1043 assert(!text_entry_has_preedit(entry));
1044 }
1045
1046 if (entry->cursor == cursor)
1047 return;
1048
1049 entry->cursor = cursor;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001050
1051 text_entry_update_layout(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001052
1053 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001054
Jan Arne Petersen0558a932013-01-16 21:26:45 +01001055 text_entry_update(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001056}
1057
1058static void
Jan Arne Petersene202bae2012-09-09 23:08:44 +02001059text_entry_delete_text(struct text_entry *entry,
1060 uint32_t index, uint32_t length)
1061{
Jan Arne Petersen68516862013-04-18 16:47:42 +02001062 uint32_t l;
1063
Jan Arne Petersen895a1282013-05-30 13:57:04 +02001064 assert(index <= strlen(entry->text));
1065 assert(index + length <= strlen(entry->text));
1066 assert(index + length >= length);
Jan Arne Petersen80ad1a92012-09-17 15:28:10 +02001067
Jan Arne Petersen68516862013-04-18 16:47:42 +02001068 l = strlen(entry->text + index + length);
1069 memmove(entry->text + index,
1070 entry->text + index + length,
1071 l + 1);
Jan Arne Petersene202bae2012-09-09 23:08:44 +02001072
Jan Arne Petersen9eaa8e52013-05-30 13:57:03 +02001073 if (entry->cursor > (index + length))
1074 entry->cursor -= length;
1075 else if (entry->cursor > index)
1076 entry->cursor = index;
1077
1078 entry->anchor = entry->cursor;
1079
Jan Arne Petersene202bae2012-09-09 23:08:44 +02001080 text_entry_update_layout(entry);
1081
1082 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001083
Jan Arne Petersen0558a932013-01-16 21:26:45 +01001084 text_entry_update(entry);
Jan Arne Petersene202bae2012-09-09 23:08:44 +02001085}
1086
1087static void
Jan Arne Petersene386dd22012-09-17 15:28:09 +02001088text_entry_delete_selected_text(struct text_entry *entry)
1089{
1090 uint32_t start_index = entry->anchor < entry->cursor ? entry->anchor : entry->cursor;
1091 uint32_t end_index = entry->anchor < entry->cursor ? entry->cursor : entry->anchor;
1092
1093 if (entry->anchor == entry->cursor)
1094 return;
1095
1096 text_entry_delete_text(entry, start_index, end_index - start_index);
1097
1098 entry->anchor = entry->cursor;
1099}
1100
1101static void
Jan Arne Petersenfe89e712013-04-18 16:47:27 +02001102text_entry_get_cursor_rectangle(struct text_entry *entry, struct rectangle *rectangle)
1103{
1104 struct rectangle allocation;
1105 PangoRectangle extents;
1106 PangoRectangle cursor_pos;
1107
1108 widget_get_allocation(entry->widget, &allocation);
1109
1110 if (entry->preedit.text && entry->preedit.cursor < 0) {
1111 rectangle->x = 0;
1112 rectangle->y = 0;
1113 rectangle->width = 0;
1114 rectangle->height = 0;
1115 return;
1116 }
1117
Jan Arne Petersen68516862013-04-18 16:47:42 +02001118
Jan Arne Petersenfe89e712013-04-18 16:47:27 +02001119 pango_layout_get_extents(entry->layout, &extents, NULL);
1120 pango_layout_get_cursor_pos(entry->layout,
1121 entry->cursor + entry->preedit.cursor,
1122 &cursor_pos, NULL);
1123
1124 rectangle->x = allocation.x + (allocation.height / 2) + PANGO_PIXELS(cursor_pos.x);
1125 rectangle->y = allocation.y + 10 + PANGO_PIXELS(cursor_pos.y);
1126 rectangle->width = PANGO_PIXELS(cursor_pos.width);
1127 rectangle->height = PANGO_PIXELS(cursor_pos.height);
1128}
1129
1130static void
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001131text_entry_draw_cursor(struct text_entry *entry, cairo_t *cr)
1132{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001133 PangoRectangle extents;
1134 PangoRectangle cursor_pos;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001135
Jan Arne Petersen46535312013-01-16 21:26:38 +01001136 if (entry->preedit.text && entry->preedit.cursor < 0)
1137 return;
1138
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001139 pango_layout_get_extents(entry->layout, &extents, NULL);
1140 pango_layout_get_cursor_pos(entry->layout,
1141 entry->cursor + entry->preedit.cursor,
1142 &cursor_pos, NULL);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001143
1144 cairo_set_line_width(cr, 1.0);
Peter Maatmanb9a23f42013-07-06 20:55:54 +02001145 cairo_move_to(cr, PANGO_PIXELS(cursor_pos.x), PANGO_PIXELS(cursor_pos.y));
1146 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 +02001147 cairo_stroke(cr);
1148}
1149
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001150static int
1151text_offset_left(struct rectangle *allocation)
1152{
1153 return 10;
1154}
1155
1156static int
1157text_offset_top(struct rectangle *allocation)
1158{
1159 return allocation->height / 2;
1160}
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +02001161
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +02001162static void
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001163text_entry_redraw_handler(struct widget *widget, void *data)
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001164{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001165 struct text_entry *entry = data;
1166 cairo_surface_t *surface;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001167 struct rectangle allocation;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001168 cairo_t *cr;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001169
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001170 surface = window_get_surface(entry->window);
1171 widget_get_allocation(entry->widget, &allocation);
1172
1173 cr = cairo_create(surface);
1174 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
1175 cairo_clip(cr);
1176
1177 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
1178
1179 cairo_push_group(cr);
1180 cairo_translate(cr, allocation.x, allocation.y);
1181
1182 cairo_set_source_rgba(cr, 1, 1, 1, 1);
1183 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
1184 cairo_fill(cr);
1185
1186 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
1187
1188 if (entry->active) {
1189 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
1190 cairo_set_line_width (cr, 3);
1191 cairo_set_source_rgba(cr, 0, 0, 1, 1.0);
1192 cairo_stroke(cr);
1193 }
1194
1195 cairo_set_source_rgba(cr, 0, 0, 0, 1);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001196
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001197 cairo_translate(cr,
1198 text_offset_left(&allocation),
1199 text_offset_top(&allocation));
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001200
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001201 if (!entry->layout)
1202 entry->layout = pango_cairo_create_layout(cr);
1203 else
1204 pango_cairo_update_layout(cr, entry->layout);
1205
1206 text_entry_update_layout(entry);
1207
1208 pango_cairo_show_layout(cr, entry->layout);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001209
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001210 text_entry_draw_cursor(entry, cr);
1211
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001212 cairo_pop_group_to_source(cr);
1213 cairo_paint(cr);
1214
1215 cairo_destroy(cr);
1216 cairo_surface_destroy(surface);
1217}
1218
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001219static int
1220text_entry_motion_handler(struct widget *widget,
1221 struct input *input, uint32_t time,
1222 float x, float y, void *data)
1223{
1224 struct text_entry *entry = data;
1225 struct rectangle allocation;
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001226 int tx, ty;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001227
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001228 if (!entry->button_pressed) {
1229 return CURSOR_IBEAM;
1230 }
1231
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001232 widget_get_allocation(entry->widget, &allocation);
1233
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001234 tx = x - allocation.x - text_offset_left(&allocation);
1235 ty = y - allocation.y - text_offset_top(&allocation);
1236
1237 text_entry_set_cursor_position(entry, tx, ty, false);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001238
1239 return CURSOR_IBEAM;
1240}
1241
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001242static void
1243text_entry_button_handler(struct widget *widget,
1244 struct input *input, uint32_t time,
1245 uint32_t button,
1246 enum wl_pointer_button_state state, void *data)
1247{
1248 struct text_entry *entry = data;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001249 struct rectangle allocation;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001250 struct editor *editor;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001251 int32_t x, y;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001252 uint32_t result;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001253
1254 widget_get_allocation(entry->widget, &allocation);
1255 input_get_position(input, &x, &y);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001256
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001257 x -= allocation.x + text_offset_left(&allocation);
1258 y -= allocation.y + text_offset_top(&allocation);
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001259
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001260 editor = window_get_user_data(entry->window);
1261
Manuel Bachmann22f34302015-03-30 01:57:44 +02001262 switch (button) {
1263 case BTN_LEFT:
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001264 entry->button_pressed = (state == WL_POINTER_BUTTON_STATE_PRESSED);
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001265 if (state == WL_POINTER_BUTTON_STATE_PRESSED)
1266 input_grab(input, entry->widget, button);
1267 else
1268 input_ungrab(input);
Manuel Bachmann22f34302015-03-30 01:57:44 +02001269 break;
1270 case BTN_RIGHT:
1271 if (state == WL_POINTER_BUTTON_STATE_PRESSED)
1272 show_menu(editor, input, time);
1273 break;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001274 }
1275
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001276 if (text_entry_has_preedit(entry)) {
1277 result = text_entry_try_invoke_preedit_action(entry, x, y, button, state);
1278
1279 if (result)
1280 return;
1281 }
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001282
Manuel Bachmann22f34302015-03-30 01:57:44 +02001283 if (state == WL_POINTER_BUTTON_STATE_PRESSED &&
1284 button == BTN_LEFT) {
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001285 struct wl_seat *seat = input_get_seat(input);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001286
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001287 text_entry_activate(entry, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001288 editor->active_entry = entry;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001289
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001290 text_entry_set_cursor_position(entry, x, y, true);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001291 }
1292}
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001293
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001294static void
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -08001295text_entry_touch_handler(struct widget *widget, struct input *input,
1296 uint32_t serial, uint32_t time, int32_t id,
1297 float tx, float ty, void *data)
1298{
1299 struct text_entry *entry = data;
1300 struct wl_seat *seat = input_get_seat(input);
1301 struct rectangle allocation;
1302 struct editor *editor;
1303 int32_t x, y;
1304
1305 widget_get_allocation(entry->widget, &allocation);
1306
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001307 x = tx - (allocation.x + text_offset_left(&allocation));
1308 y = ty - (allocation.y + text_offset_top(&allocation));
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -08001309
1310 editor = window_get_user_data(entry->window);
1311 text_entry_activate(entry, seat);
1312 editor->active_entry = entry;
1313
1314 text_entry_set_cursor_position(entry, x, y, true);
1315}
1316
1317static void
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001318editor_button_handler(struct widget *widget,
1319 struct input *input, uint32_t time,
1320 uint32_t button,
1321 enum wl_pointer_button_state state, void *data)
1322{
1323 struct editor *editor = data;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001324
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001325 if (button != BTN_LEFT) {
1326 return;
1327 }
Jan Arne Petersene829adc2012-08-10 16:47:22 +02001328
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001329 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
1330 struct wl_seat *seat = input_get_seat(input);
1331
Jan Arne Petersene829adc2012-08-10 16:47:22 +02001332 text_entry_deactivate(editor->entry, seat);
1333 text_entry_deactivate(editor->editor, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001334 editor->active_entry = NULL;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001335 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001336}
1337
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -08001338static void
1339editor_touch_handler(struct widget *widget, struct input *input,
1340 uint32_t serial, uint32_t time, int32_t id,
1341 float tx, float ty, void *data)
1342{
1343 struct editor *editor = data;
1344
1345 struct wl_seat *seat = input_get_seat(input);
1346
1347 text_entry_deactivate(editor->entry, seat);
1348 text_entry_deactivate(editor->editor, seat);
1349 editor->active_entry = NULL;
1350}
Kristian Høgsberg78858902014-01-01 23:57:42 -08001351
1352static void
1353keyboard_focus_handler(struct window *window,
1354 struct input *device, void *data)
1355{
1356 struct editor *editor = data;
1357
1358 window_schedule_redraw(editor->window);
1359}
1360
Manuel Bachmann22f34302015-03-30 01:57:44 +02001361static int
1362handle_bound_key(struct editor *editor,
1363 struct input *input, uint32_t sym, uint32_t time)
1364{
1365 switch (sym) {
1366 case XKB_KEY_X:
1367 editor_copy_cut(editor, input, true);
1368 return 1;
1369 case XKB_KEY_C:
1370 editor_copy_cut(editor, input, false);
1371 return 1;
1372 case XKB_KEY_V:
1373 editor_paste(editor, input);
1374 return 1;
1375 default:
1376 return 0;
1377 }
1378}
1379
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001380static void
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001381key_handler(struct window *window,
1382 struct input *input, uint32_t time,
1383 uint32_t key, uint32_t sym, enum wl_keyboard_key_state state,
1384 void *data)
1385{
1386 struct editor *editor = data;
1387 struct text_entry *entry;
Jan Arne Petersen68516862013-04-18 16:47:42 +02001388 const char *new_char;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001389 char text[16];
Manuel Bachmann22f34302015-03-30 01:57:44 +02001390 uint32_t modifiers;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001391
1392 if (!editor->active_entry)
1393 return;
1394
1395 entry = editor->active_entry;
1396
1397 if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
1398 return;
1399
Manuel Bachmann22f34302015-03-30 01:57:44 +02001400 modifiers = input_get_modifiers(input);
1401 if ((modifiers & MOD_CONTROL_MASK) &&
1402 (modifiers & MOD_SHIFT_MASK) &&
1403 handle_bound_key(editor, input, sym, time))
1404 return;
1405
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001406 switch (sym) {
1407 case XKB_KEY_BackSpace:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001408 text_entry_commit_and_reset(entry);
1409
Jan Arne Petersen68516862013-04-18 16:47:42 +02001410 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
1411 if (new_char != NULL)
1412 text_entry_delete_text(entry,
1413 new_char - entry->text,
1414 (entry->text + entry->cursor) - new_char);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001415 break;
1416 case XKB_KEY_Delete:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001417 text_entry_commit_and_reset(entry);
1418
Jan Arne Petersen68516862013-04-18 16:47:42 +02001419 new_char = utf8_next_char(entry->text + entry->cursor);
1420 if (new_char != NULL)
1421 text_entry_delete_text(entry,
1422 entry->cursor,
1423 new_char - (entry->text + entry->cursor));
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001424 break;
1425 case XKB_KEY_Left:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001426 text_entry_commit_and_reset(entry);
1427
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001428 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
1429 if (new_char != NULL) {
1430 entry->cursor = new_char - entry->text;
Rob Bradford70002832013-07-11 16:00:00 +01001431 if (!(input_get_modifiers(input) & MOD_SHIFT_MASK))
1432 entry->anchor = entry->cursor;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001433 widget_schedule_redraw(entry->widget);
1434 }
1435 break;
1436 case XKB_KEY_Right:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001437 text_entry_commit_and_reset(entry);
1438
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001439 new_char = utf8_next_char(entry->text + entry->cursor);
1440 if (new_char != NULL) {
1441 entry->cursor = new_char - entry->text;
Rob Bradford70002832013-07-11 16:00:00 +01001442 if (!(input_get_modifiers(input) & MOD_SHIFT_MASK))
1443 entry->anchor = entry->cursor;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001444 widget_schedule_redraw(entry->widget);
1445 }
1446 break;
Manuel Bachmann8986c182014-04-18 12:50:14 +02001447 case XKB_KEY_Up:
1448 text_entry_commit_and_reset(entry);
1449
1450 move_up(entry->text, &entry->cursor);
1451 if (!(input_get_modifiers(input) & MOD_SHIFT_MASK))
1452 entry->anchor = entry->cursor;
1453 widget_schedule_redraw(entry->widget);
1454 break;
1455 case XKB_KEY_Down:
1456 text_entry_commit_and_reset(entry);
1457
1458 move_down(entry->text, &entry->cursor);
1459 if (!(input_get_modifiers(input) & MOD_SHIFT_MASK))
1460 entry->anchor = entry->cursor;
1461 widget_schedule_redraw(entry->widget);
1462 break;
Peter Maatman08c38d42013-07-06 20:42:59 +02001463 case XKB_KEY_Escape:
1464 break;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001465 default:
1466 if (xkb_keysym_to_utf8(sym, text, sizeof(text)) <= 0)
1467 break;
1468
Peter Maatman08c38d42013-07-06 20:42:59 +02001469 text_entry_commit_and_reset(entry);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001470
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +01001471 text_entry_insert_at_cursor(entry, text, 0, 0);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001472 break;
1473 }
1474
1475 widget_schedule_redraw(entry->widget);
1476}
1477
1478static void
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001479global_handler(struct display *display, uint32_t name,
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001480 const char *interface, uint32_t version, void *data)
1481{
1482 struct editor *editor = data;
1483
Jonas Ådahl3bcba342015-11-17 16:00:29 +08001484 if (!strcmp(interface, "zwp_text_input_manager_v1")) {
Jan Arne Petersen78d00e42013-04-18 16:47:24 +02001485 editor->text_input_manager =
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001486 display_bind(display, name,
Jonas Ådahl3bcba342015-11-17 16:00:29 +08001487 &zwp_text_input_manager_v1_interface, 1);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001488 }
1489}
1490
1491int
1492main(int argc, char *argv[])
1493{
1494 struct editor editor;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001495 int i;
1496 uint32_t click_to_show = 0;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001497 const char *preferred_language = NULL;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001498
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001499 for (i = 1; i < argc; i++) {
Jan Arne Petersen61381972013-01-31 15:52:21 +01001500 if (strcmp("--click-to-show", argv[i]) == 0)
1501 click_to_show = 1;
Bill Spitzakbb0bb9c2014-08-08 12:59:58 -07001502 else if (strcmp("--preferred-language", argv[i]) == 0 &&
1503 i + 1 < argc) {
1504 preferred_language = argv[i + 1];
1505 i++;
1506 } else {
1507 printf("Usage: %s [OPTIONS]\n"
1508 " --click-to-show\n"
1509 " --preferred-language LANGUAGE\n",
1510 argv[0]);
1511 return 1;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001512 }
1513 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001514
Jan Arne Petersen25f6db52012-11-05 03:26:40 +01001515 memset(&editor, 0, sizeof editor);
1516
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001517#ifdef HAVE_PANGO
1518 g_type_init();
1519#endif
1520
Kristian Høgsberg4172f662013-02-20 15:27:49 -05001521 editor.display = display_create(&argc, argv);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001522 if (editor.display == NULL) {
1523 fprintf(stderr, "failed to create display: %m\n");
1524 return -1;
1525 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001526
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001527 display_set_user_data(editor.display, &editor);
1528 display_set_global_handler(editor.display, global_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001529
Olivier Blin30e1f3c2014-09-16 19:13:17 +02001530 if (editor.text_input_manager == NULL) {
1531 fprintf(stderr, "No text input manager global\n");
1532 return -1;
1533 }
1534
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001535 editor.window = window_create(editor.display);
Jason Ekstrandee7fefc2013-10-13 19:08:38 -05001536 editor.widget = window_frame_create(editor.window, &editor);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001537
1538 editor.entry = text_entry_create(&editor, "Entry");
Jan Arne Petersen61381972013-01-31 15:52:21 +01001539 editor.entry->click_to_show = click_to_show;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001540 if (preferred_language)
1541 editor.entry->preferred_language = strdup(preferred_language);
Jan Arne Petersen0558a932013-01-16 21:26:45 +01001542 editor.editor = text_entry_create(&editor, "Numeric");
Jonas Ådahl3bcba342015-11-17 16:00:29 +08001543 editor.editor->content_purpose = ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_NUMBER;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001544 editor.editor->click_to_show = click_to_show;
Manuel Bachmann22f34302015-03-30 01:57:44 +02001545 editor.selection = NULL;
1546 editor.selected_text = NULL;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001547
1548 window_set_title(editor.window, "Text Editor");
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001549 window_set_key_handler(editor.window, key_handler);
Kristian Høgsberg78858902014-01-01 23:57:42 -08001550 window_set_keyboard_focus_handler(editor.window,
1551 keyboard_focus_handler);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001552 window_set_user_data(editor.window, &editor);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001553
1554 widget_set_redraw_handler(editor.widget, redraw_handler);
1555 widget_set_resize_handler(editor.widget, resize_handler);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001556 widget_set_button_handler(editor.widget, editor_button_handler);
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -08001557 widget_set_touch_down_handler(editor.widget, editor_touch_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001558
1559 window_schedule_resize(editor.window, 500, 400);
1560
1561 display_run(editor.display);
1562
Manuel Bachmann22f34302015-03-30 01:57:44 +02001563 if (editor.selected_text)
1564 free(editor.selected_text);
1565 if (editor.selection)
1566 wl_data_source_destroy(editor.selection);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001567 text_entry_destroy(editor.entry);
1568 text_entry_destroy(editor.editor);
vivek31732f72014-05-15 18:58:16 +05301569 widget_destroy(editor.widget);
1570 window_destroy(editor.window);
1571 display_destroy(editor.display);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001572
1573 return 0;
1574}