blob: 150ceb606e7016e8faed790ea264bc8027bb5e2d [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
Bryce Harrington3d90da22016-11-21 13:26:22 -080040#include "shared/config-parser.h"
Jon Cruz35b2eaa2015-06-15 15:37:08 -070041#include "shared/helpers.h"
Bryce Harringtone99e4bf2016-03-16 14:15:18 -070042#include "shared/xalloc.h"
Jan Arne Petersencba9e472012-06-21 21:52:19 +020043#include "window.h"
Jonas Ådahl3bcba342015-11-17 16:00:29 +080044#include "text-input-unstable-v1-client-protocol.h"
Jan Arne Petersencba9e472012-06-21 21:52:19 +020045
46struct text_entry {
47 struct widget *widget;
Jan Arne Petersene829adc2012-08-10 16:47:22 +020048 struct window *window;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020049 char *text;
50 int active;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +020051 uint32_t cursor;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +020052 uint32_t anchor;
Jan Arne Petersen46535312013-01-16 21:26:38 +010053 struct {
54 char *text;
55 int32_t cursor;
56 char *commit;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010057 PangoAttrList *attr_list;
Jan Arne Petersen46535312013-01-16 21:26:38 +010058 } preedit;
59 struct {
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010060 PangoAttrList *attr_list;
Jan Arne Petersen46535312013-01-16 21:26:38 +010061 int32_t cursor;
62 } preedit_info;
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +010063 struct {
64 int32_t cursor;
65 int32_t anchor;
Jan Arne Petersen919bc142013-04-18 16:47:34 +020066 uint32_t delete_index;
67 uint32_t delete_length;
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +020068 bool invalid_delete;
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +010069 } pending_commit;
Jonas Ådahl3bcba342015-11-17 16:00:29 +080070 struct zwp_text_input_v1 *text_input;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +010071 PangoLayout *layout;
Jan Arne Petersencd997062012-11-18 19:06:44 +010072 struct {
73 xkb_mod_mask_t shift_mask;
74 } keysym;
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +010075 uint32_t serial;
Jan Arne Petersen00191c72013-04-18 16:47:33 +020076 uint32_t reset_serial;
Jan Arne Petersen0558a932013-01-16 21:26:45 +010077 uint32_t content_purpose;
Jan Arne Petersen61381972013-01-31 15:52:21 +010078 uint32_t click_to_show;
Jan Arne Petersen9d419132013-04-18 16:47:16 +020079 char *preferred_language;
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +020080 bool button_pressed;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020081};
82
83struct editor {
Jonas Ådahl3bcba342015-11-17 16:00:29 +080084 struct zwp_text_input_manager_v1 *text_input_manager;
Manuel Bachmann22f34302015-03-30 01:57:44 +020085 struct wl_data_source *selection;
86 char *selected_text;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020087 struct display *display;
88 struct window *window;
89 struct widget *widget;
90 struct text_entry *entry;
91 struct text_entry *editor;
Rob Bradford9d1d32b2012-11-18 19:06:49 +010092 struct text_entry *active_entry;
Jan Arne Petersencba9e472012-06-21 21:52:19 +020093};
94
Jan Arne Petersen6345faa2012-11-05 03:26:39 +010095static const char *
Jan Arne Petersen6345faa2012-11-05 03:26:39 +010096utf8_end_char(const char *p)
97{
98 while ((*p & 0xc0) == 0x80)
99 p++;
100 return p;
101}
102
103static const char *
Jan Arne Petersen68516862013-04-18 16:47:42 +0200104utf8_prev_char(const char *s, const char *p)
105{
106 for (--p; p >= s; --p) {
107 if ((*p & 0xc0) != 0x80)
108 return p;
109 }
110 return NULL;
111}
112
113static const char *
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100114utf8_next_char(const char *p)
115{
116 if (*p != 0)
117 return utf8_end_char(++p);
118 return NULL;
119}
120
Manuel Bachmann8986c182014-04-18 12:50:14 +0200121static void
122move_up(const char *p, uint32_t *cursor)
123{
124 const char *posr, *posr_i;
125 char text[16];
126
127 xkb_keysym_to_utf8(XKB_KEY_Return, text, sizeof(text));
128
129 posr = strstr(p, text);
130 while (posr) {
131 if (*cursor > (unsigned)(posr-p)) {
132 posr_i = strstr(posr+1, text);
133 if (!posr_i || !(*cursor > (unsigned)(posr_i-p))) {
134 *cursor = posr-p;
135 break;
136 }
137 posr = posr_i;
138 } else {
139 break;
140 }
141 }
142}
143
144static void
145move_down(const char *p, uint32_t *cursor)
146{
147 const char *posr;
148 char text[16];
149
150 xkb_keysym_to_utf8(XKB_KEY_Return, text, sizeof(text));
151
152 posr = strstr(p, text);
153 while (posr) {
154 if (*cursor <= (unsigned)(posr-p)) {
155 *cursor = posr-p + 1;
156 break;
157 }
158 posr = strstr(posr+1, text);
159 }
160}
161
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200162static void text_entry_redraw_handler(struct widget *widget, void *data);
163static void text_entry_button_handler(struct widget *widget,
164 struct input *input, uint32_t time,
165 uint32_t button,
166 enum wl_pointer_button_state state, void *data);
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -0800167static void text_entry_touch_handler(struct widget *widget, struct input *input,
168 uint32_t serial, uint32_t time, int32_t id,
169 float tx, float ty, void *data);
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +0200170static int text_entry_motion_handler(struct widget *widget,
171 struct input *input, uint32_t time,
172 float x, float y, void *data);
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100173static void text_entry_insert_at_cursor(struct text_entry *entry, const char *text,
174 int32_t cursor, int32_t anchor);
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200175static void text_entry_set_preedit(struct text_entry *entry,
176 const char *preedit_text,
177 int preedit_cursor);
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200178static void text_entry_delete_text(struct text_entry *entry,
179 uint32_t index, uint32_t length);
Jan Arne Petersene386dd22012-09-17 15:28:09 +0200180static void text_entry_delete_selected_text(struct text_entry *entry);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100181static void text_entry_reset_preedit(struct text_entry *entry);
182static void text_entry_commit_and_reset(struct text_entry *entry);
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200183static void text_entry_get_cursor_rectangle(struct text_entry *entry, struct rectangle *rectangle);
184static void text_entry_update(struct text_entry *entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200185
186static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200187text_input_commit_string(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800188 struct zwp_text_input_v1 *text_input,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100189 uint32_t serial,
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100190 const char *text)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200191{
192 struct text_entry *entry = data;
193
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200194 if ((entry->serial - serial) > (entry->serial - entry->reset_serial)) {
195 fprintf(stderr, "Ignore commit. Serial: %u, Current: %u, Reset: %u\n",
196 serial, entry->serial, entry->reset_serial);
197 return;
198 }
199
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200200 if (entry->pending_commit.invalid_delete) {
201 fprintf(stderr, "Ignore commit. Invalid previous delete_surrounding event.\n");
202 memset(&entry->pending_commit, 0, sizeof entry->pending_commit);
203 return;
204 }
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100205
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200206 text_entry_reset_preedit(entry);
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200207
208 if (entry->pending_commit.delete_length) {
209 text_entry_delete_text(entry,
210 entry->pending_commit.delete_index,
211 entry->pending_commit.delete_length);
Jan Arne Petersena96953d2013-05-30 13:57:02 +0200212 } else {
213 text_entry_delete_selected_text(entry);
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200214 }
215
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100216 text_entry_insert_at_cursor(entry, text,
217 entry->pending_commit.cursor,
218 entry->pending_commit.anchor);
219
220 memset(&entry->pending_commit, 0, sizeof entry->pending_commit);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200221
222 widget_schedule_redraw(entry->widget);
223}
224
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200225static void
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200226clear_pending_preedit(struct text_entry *entry)
227{
228 memset(&entry->pending_commit, 0, sizeof entry->pending_commit);
229
230 pango_attr_list_unref(entry->preedit_info.attr_list);
231
232 entry->preedit_info.cursor = 0;
233 entry->preedit_info.attr_list = NULL;
234
235 memset(&entry->preedit_info, 0, sizeof entry->preedit_info);
236}
237
238static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200239text_input_preedit_string(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800240 struct zwp_text_input_v1 *text_input,
Jan Arne Petersenc7d2a982013-01-16 21:26:39 +0100241 uint32_t serial,
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200242 const char *text,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100243 const char *commit)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200244{
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200245 struct text_entry *entry = data;
246
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200247 if ((entry->serial - serial) > (entry->serial - entry->reset_serial)) {
248 fprintf(stderr, "Ignore preedit_string. Serial: %u, Current: %u, Reset: %u\n",
249 serial, entry->serial, entry->reset_serial);
250 clear_pending_preedit(entry);
251 return;
252 }
253
254 if (entry->pending_commit.invalid_delete) {
255 fprintf(stderr, "Ignore preedit_string. Invalid previous delete_surrounding event.\n");
256 clear_pending_preedit(entry);
257 return;
258 }
259
Jan Arne Petersena96953d2013-05-30 13:57:02 +0200260 if (entry->pending_commit.delete_length) {
261 text_entry_delete_text(entry,
262 entry->pending_commit.delete_index,
263 entry->pending_commit.delete_length);
264 } else {
265 text_entry_delete_selected_text(entry);
266 }
Jan Arne Petersena96953d2013-05-30 13:57:02 +0200267
Jan Arne Petersen46535312013-01-16 21:26:38 +0100268 text_entry_set_preedit(entry, text, entry->preedit_info.cursor);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100269 entry->preedit.commit = strdup(commit);
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200270 entry->preedit.attr_list = pango_attr_list_ref(entry->preedit_info.attr_list);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100271
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200272 clear_pending_preedit(entry);
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200273
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200274 text_entry_update(entry);
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200275
Jan Arne Petersen43f4aa82012-09-09 23:08:43 +0200276 widget_schedule_redraw(entry->widget);
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200277}
278
279static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200280text_input_delete_surrounding_text(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800281 struct zwp_text_input_v1 *text_input,
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200282 int32_t index,
283 uint32_t length)
284{
285 struct text_entry *entry = data;
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200286 uint32_t text_length;
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200287
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200288 entry->pending_commit.delete_index = entry->cursor + index;
289 entry->pending_commit.delete_length = length;
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200290 entry->pending_commit.invalid_delete = false;
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200291
Jan Arne Petersen68516862013-04-18 16:47:42 +0200292 text_length = strlen(entry->text);
Jan Arne Petersen919bc142013-04-18 16:47:34 +0200293
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200294 if (entry->pending_commit.delete_index > text_length ||
295 length > text_length ||
Jan Arne Petersen895a1282013-05-30 13:57:04 +0200296 entry->pending_commit.delete_index + length > text_length) {
Jan Arne Petersen8ccb7cc2013-05-30 13:57:05 +0200297 fprintf(stderr, "delete_surrounding_text: Invalid index: %d," \
298 "length %u'; cursor: %u text length: %u\n", index, length, entry->cursor, text_length);
299 entry->pending_commit.invalid_delete = true;
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200300 return;
301 }
Jan Arne Petersene202bae2012-09-09 23:08:44 +0200302}
303
304static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200305text_input_cursor_position(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800306 struct zwp_text_input_v1 *text_input,
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100307 int32_t index,
308 int32_t anchor)
309{
310 struct text_entry *entry = data;
311
312 entry->pending_commit.cursor = index;
313 entry->pending_commit.anchor = anchor;
314}
315
316static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200317text_input_preedit_styling(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800318 struct zwp_text_input_v1 *text_input,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100319 uint32_t index,
320 uint32_t length,
321 uint32_t style)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200322{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100323 struct text_entry *entry = data;
324 PangoAttribute *attr1 = NULL;
325 PangoAttribute *attr2 = NULL;
326
327 if (!entry->preedit_info.attr_list)
328 entry->preedit_info.attr_list = pango_attr_list_new();
329
330 switch (style) {
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800331 case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_DEFAULT:
332 case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_UNDERLINE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100333 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
334 break;
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800335 case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_INCORRECT:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100336 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_ERROR);
337 attr2 = pango_attr_underline_color_new(65535, 0, 0);
338 break;
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800339 case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_SELECTION:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100340 attr1 = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
341 attr2 = pango_attr_foreground_new(65535, 65535, 65535);
342 break;
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800343 case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_HIGHLIGHT:
344 case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_ACTIVE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100345 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
346 attr2 = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
347 break;
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800348 case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_INACTIVE:
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100349 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
350 attr2 = pango_attr_foreground_new(0.3 * 65535, 0.3 * 65535, 0.3 * 65535);
351 break;
352 }
353
354 if (attr1) {
355 attr1->start_index = entry->cursor + index;
356 attr1->end_index = entry->cursor + index + length;
357 pango_attr_list_insert(entry->preedit_info.attr_list, attr1);
358 }
359
360 if (attr2) {
361 attr2->start_index = entry->cursor + index;
362 attr2->end_index = entry->cursor + index + length;
363 pango_attr_list_insert(entry->preedit_info.attr_list, attr2);
364 }
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200365}
366
367static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200368text_input_preedit_cursor(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800369 struct zwp_text_input_v1 *text_input,
Jan Arne Petersen46535312013-01-16 21:26:38 +0100370 int32_t index)
371{
372 struct text_entry *entry = data;
373
374 entry->preedit_info.cursor = index;
375}
376
377static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200378text_input_modifiers_map(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800379 struct zwp_text_input_v1 *text_input,
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100380 struct wl_array *map)
381{
Jan Arne Petersencd997062012-11-18 19:06:44 +0100382 struct text_entry *entry = data;
383
384 entry->keysym.shift_mask = keysym_modifiers_get_mask(map, "Shift");
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100385}
386
387static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200388text_input_keysym(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800389 struct zwp_text_input_v1 *text_input,
Jan Arne Petersend9be93b2012-11-18 19:06:43 +0100390 uint32_t serial,
391 uint32_t time,
392 uint32_t key,
393 uint32_t state,
394 uint32_t modifiers)
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200395{
Jan Arne Petersen8aba11d2012-09-17 15:28:07 +0200396 struct text_entry *entry = data;
Jan Arne Petersen6345faa2012-11-05 03:26:39 +0100397 const char *new_char;
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200398
Jan Arne Petersencd997062012-11-18 19:06:44 +0100399 if (key == XKB_KEY_Left ||
400 key == XKB_KEY_Right) {
401 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
402 return;
403
404 if (key == XKB_KEY_Left)
405 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
406 else
407 new_char = utf8_next_char(entry->text + entry->cursor);
408
409 if (new_char != NULL) {
410 entry->cursor = new_char - entry->text;
Jan Arne Petersencd997062012-11-18 19:06:44 +0100411 }
412
Jan Arne Petersen68516862013-04-18 16:47:42 +0200413 if (!(modifiers & entry->keysym.shift_mask))
414 entry->anchor = entry->cursor;
415 widget_schedule_redraw(entry->widget);
416
Jan Arne Petersencd997062012-11-18 19:06:44 +0100417 return;
418 }
419
Manuel Bachmann8986c182014-04-18 12:50:14 +0200420 if (key == XKB_KEY_Up ||
421 key == XKB_KEY_Down) {
422 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
423 return;
424
425 if (key == XKB_KEY_Up)
426 move_up(entry->text, &entry->cursor);
427 else
428 move_down(entry->text, &entry->cursor);
429
430 if (!(modifiers & entry->keysym.shift_mask))
431 entry->anchor = entry->cursor;
432 widget_schedule_redraw(entry->widget);
433
434 return;
435 }
436
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100437 if (key == XKB_KEY_BackSpace) {
438 const char *start, *end;
439
Jan Arne Petersendfd34462013-04-18 16:47:26 +0200440 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
441 return;
442
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100443 text_entry_commit_and_reset(entry);
444
445 start = utf8_prev_char(entry->text, entry->text + entry->cursor);
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100446 if (start == NULL)
447 return;
448
Daiki Uenob08b3292013-06-28 18:59:44 +0900449 end = utf8_next_char(start);
450
Jan Arne Petersen3fb6e712013-01-16 21:26:52 +0100451 text_entry_delete_text(entry,
452 start - entry->text,
453 end - start);
454
455 return;
456 }
457
Manuel Bachmann8986c182014-04-18 12:50:14 +0200458 if (key == XKB_KEY_Tab ||
459 key == XKB_KEY_KP_Enter ||
460 key == XKB_KEY_Return) {
461 char text[16];
Jan Arne Petersence8a4432012-09-09 23:08:45 +0200462
Manuel Bachmann8986c182014-04-18 12:50:14 +0200463 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
464 return;
465
466 xkb_keysym_to_utf8(key, text, sizeof(text));
467
468 text_entry_insert_at_cursor(entry, text, 0, 0);
469
470 return;
471 }
Jan Arne Petersen72f60822012-08-10 16:47:19 +0200472}
473
474static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200475text_input_enter(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800476 struct zwp_text_input_v1 *text_input,
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200477 struct wl_surface *surface)
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200478{
479 struct text_entry *entry = data;
480
Jan Arne Petersen680275f2012-09-24 14:51:14 +0200481 if (surface != window_get_wl_surface(entry->window))
482 return;
483
Derek Foreman237a6842014-12-17 09:43:58 -0600484 entry->active++;
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200485
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200486 text_entry_update(entry);
487 entry->reset_serial = entry->serial;
488
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200489 widget_schedule_redraw(entry->widget);
490}
491
492static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200493text_input_leave(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800494 struct zwp_text_input_v1 *text_input)
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200495{
496 struct text_entry *entry = data;
497
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100498 text_entry_commit_and_reset(entry);
Derek Foreman237a6842014-12-17 09:43:58 -0600499 entry->active--;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100500
Derek Foreman237a6842014-12-17 09:43:58 -0600501 if (!entry->active)
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800502 zwp_text_input_v1_hide_input_panel(text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100503
Jan Arne Petersende3b6a12012-08-10 16:47:21 +0200504 widget_schedule_redraw(entry->widget);
505}
506
Jan Arne Petersen61381972013-01-31 15:52:21 +0100507static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200508text_input_input_panel_state(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800509 struct zwp_text_input_v1 *text_input,
Jan Arne Petersen61381972013-01-31 15:52:21 +0100510 uint32_t state)
511{
512}
513
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200514static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200515text_input_language(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800516 struct zwp_text_input_v1 *text_input,
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200517 uint32_t serial,
518 const char *language)
519{
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200520 fprintf(stderr, "input language is %s \n", language);
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200521}
522
523static void
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200524text_input_text_direction(void *data,
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800525 struct zwp_text_input_v1 *text_input,
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200526 uint32_t serial,
527 uint32_t direction)
528{
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200529 struct text_entry *entry = data;
530 PangoContext *context = pango_layout_get_context(entry->layout);
531 PangoDirection pango_direction;
532
533
534 switch (direction) {
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800535 case ZWP_TEXT_INPUT_V1_TEXT_DIRECTION_LTR:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200536 pango_direction = PANGO_DIRECTION_LTR;
537 break;
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800538 case ZWP_TEXT_INPUT_V1_TEXT_DIRECTION_RTL:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200539 pango_direction = PANGO_DIRECTION_RTL;
540 break;
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800541 case ZWP_TEXT_INPUT_V1_TEXT_DIRECTION_AUTO:
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200542 default:
543 pango_direction = PANGO_DIRECTION_NEUTRAL;
544 }
Jan Arne Petersen62ece762013-04-18 16:47:36 +0200545
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200546 pango_context_set_base_dir(context, pango_direction);
Jan Arne Petersenece6b5a2013-04-18 16:47:15 +0200547}
548
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800549static const struct zwp_text_input_v1_listener text_input_listener = {
Jan Arne Petersen78d00e42013-04-18 16:47:24 +0200550 text_input_enter,
551 text_input_leave,
552 text_input_modifiers_map,
553 text_input_input_panel_state,
554 text_input_preedit_string,
555 text_input_preedit_styling,
556 text_input_preedit_cursor,
557 text_input_commit_string,
558 text_input_cursor_position,
559 text_input_delete_surrounding_text,
560 text_input_keysym,
561 text_input_language,
562 text_input_text_direction
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200563};
564
Manuel Bachmann22f34302015-03-30 01:57:44 +0200565static void
566data_source_target(void *data,
567 struct wl_data_source *source, const char *mime_type)
568{
569}
570
571static void
572data_source_send(void *data,
573 struct wl_data_source *source,
574 const char *mime_type, int32_t fd)
575{
576 struct editor *editor = data;
577
Bryce Harrington7dd12ec2015-05-19 15:32:09 -0700578 if (write(fd, editor->selected_text, strlen(editor->selected_text) + 1) < 0)
579 fprintf(stderr, "write failed: %m\n");
Derek Foreman2af7e202016-07-07 10:52:17 -0500580
581 close(fd);
Manuel Bachmann22f34302015-03-30 01:57:44 +0200582}
583
584static void
585data_source_cancelled(void *data, struct wl_data_source *source)
586{
587 wl_data_source_destroy(source);
588}
589
590static const struct wl_data_source_listener data_source_listener = {
591 data_source_target,
592 data_source_send,
593 data_source_cancelled
594};
595
596static void
597paste_func(void *buffer, size_t len,
598 int32_t x, int32_t y, void *data)
599{
600 struct editor *editor = data;
601 struct text_entry *entry = editor->active_entry;
602 char *pasted_text;
603
604 if (!entry)
605 return;
606
607 pasted_text = malloc(len + 1);
608 strncpy(pasted_text, buffer, len);
609 pasted_text[len] = '\0';
610
611 text_entry_insert_at_cursor(entry, pasted_text, 0, 0);
612
613 free(pasted_text);
614}
615
616static void
617editor_copy_cut(struct editor *editor, struct input *input, bool cut)
618{
619 struct text_entry *entry = editor->active_entry;
620
621 if (!entry)
622 return;
Michael Vetter2a18a522015-05-15 17:17:47 +0200623
Manuel Bachmann22f34302015-03-30 01:57:44 +0200624 if (entry->cursor != entry->anchor) {
625 int start_index = MIN(entry->cursor, entry->anchor);
626 int end_index = MAX(entry->cursor, entry->anchor);
627 int len = end_index - start_index;
628
629 editor->selected_text = realloc(editor->selected_text, len + 1);
630 strncpy(editor->selected_text, &entry->text[start_index], len);
631 editor->selected_text[len] = '\0';
632
633 if (cut)
634 text_entry_delete_text(entry, start_index, len);
635
636 editor->selection =
637 display_create_data_source(editor->display);
638 wl_data_source_offer(editor->selection,
639 "text/plain;charset=utf-8");
640 wl_data_source_add_listener(editor->selection,
641 &data_source_listener, editor);
642 input_set_selection(input, editor->selection,
643 display_get_serial(editor->display));
644 }
645}
646
647static void
648editor_paste(struct editor *editor, struct input *input)
649{
650 input_receive_selection_data(input,
651 "text/plain;charset=utf-8",
652 paste_func, editor);
653}
654
655static void
656menu_func(void *data, struct input *input, int index)
657{
658 struct window *window = data;
659 struct editor *editor = window_get_user_data(window);
660
661 fprintf(stderr, "picked entry %d\n", index);
662
663 switch (index) {
664 case 0:
665 editor_copy_cut(editor, input, true);
666 break;
667 case 1:
668 editor_copy_cut(editor, input, false);
669 break;
670 case 2:
671 editor_paste(editor, input);
672 break;
673 }
674}
675
676static void
677show_menu(struct editor *editor, struct input *input, uint32_t time)
678{
679 int32_t x, y;
680 static const char *entries[] = {
681 "Cut", "Copy", "Paste"
682 };
683
684 input_get_position(input, &x, &y);
685 window_show_menu(editor->display, input, time, editor->window,
686 x + 10, y + 20, menu_func,
687 entries, ARRAY_LENGTH(entries));
688}
689
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200690static struct text_entry*
691text_entry_create(struct editor *editor, const char *text)
692{
693 struct text_entry *entry;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200694
Ryo Munakata5e653ca2015-08-07 20:20:46 +0900695 entry = xzalloc(sizeof *entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200696
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200697 entry->widget = widget_add_widget(editor->widget, entry);
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200698 entry->window = editor->window;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200699 entry->text = strdup(text);
700 entry->active = 0;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +0200701 entry->cursor = strlen(text);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +0200702 entry->anchor = entry->cursor;
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800703 entry->text_input =
704 zwp_text_input_manager_v1_create_text_input(editor->text_input_manager);
705 zwp_text_input_v1_add_listener(entry->text_input,
706 &text_input_listener, entry);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200707
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200708 widget_set_redraw_handler(entry->widget, text_entry_redraw_handler);
709 widget_set_button_handler(entry->widget, text_entry_button_handler);
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +0200710 widget_set_motion_handler(entry->widget, text_entry_motion_handler);
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -0800711 widget_set_touch_down_handler(entry->widget, text_entry_touch_handler);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200712
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200713 return entry;
714}
715
716static void
717text_entry_destroy(struct text_entry *entry)
718{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200719 widget_destroy(entry->widget);
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800720 zwp_text_input_v1_destroy(entry->text_input);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100721 g_clear_object(&entry->layout);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200722 free(entry->text);
Silvan Jegene31d95f2016-11-17 21:43:06 +0100723 free(entry->preferred_language);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200724 free(entry);
725}
726
727static void
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200728redraw_handler(struct widget *widget, void *data)
729{
730 struct editor *editor = data;
731 cairo_surface_t *surface;
732 struct rectangle allocation;
733 cairo_t *cr;
734
735 surface = window_get_surface(editor->window);
736 widget_get_allocation(editor->widget, &allocation);
737
738 cr = cairo_create(surface);
739 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
740 cairo_clip(cr);
741
742 cairo_translate(cr, allocation.x, allocation.y);
743
744 /* Draw background */
745 cairo_push_group(cr);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200746 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200747 cairo_set_source_rgba(cr, 1, 1, 1, 1);
748 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
749 cairo_fill(cr);
750
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200751 cairo_pop_group_to_source(cr);
752 cairo_paint(cr);
753
754 cairo_destroy(cr);
755 cairo_surface_destroy(surface);
756}
757
758static void
759text_entry_allocate(struct text_entry *entry, int32_t x, int32_t y,
760 int32_t width, int32_t height)
761{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200762 widget_set_allocation(entry->widget, x, y, width, height);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200763}
764
765static void
766resize_handler(struct widget *widget,
767 int32_t width, int32_t height, void *data)
768{
769 struct editor *editor = data;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200770 struct rectangle allocation;
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200771
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200772 widget_get_allocation(editor->widget, &allocation);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200773
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200774 text_entry_allocate(editor->entry,
775 allocation.x + 20, allocation.y + 20,
776 width - 40, height / 2 - 40);
777 text_entry_allocate(editor->editor,
778 allocation.x + 20, allocation.y + height / 2 + 20,
779 width - 40, height / 2 - 40);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200780}
781
782static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200783text_entry_activate(struct text_entry *entry,
Jan Arne Petersenf80bc062012-09-09 23:08:34 +0200784 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200785{
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200786 struct wl_surface *surface = window_get_wl_surface(entry->window);
787
Jan Arne Petersen61381972013-01-31 15:52:21 +0100788 if (entry->click_to_show && entry->active) {
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800789 zwp_text_input_v1_show_input_panel(entry->text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100790
791 return;
792 }
793
794 if (!entry->click_to_show)
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800795 zwp_text_input_v1_show_input_panel(entry->text_input);
Jan Arne Petersen61381972013-01-31 15:52:21 +0100796
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800797 zwp_text_input_v1_activate(entry->text_input,
798 seat,
799 surface);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200800}
801
802static void
Jan Arne Petersene829adc2012-08-10 16:47:22 +0200803text_entry_deactivate(struct text_entry *entry,
804 struct wl_seat *seat)
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200805{
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800806 zwp_text_input_v1_deactivate(entry->text_input,
807 seat);
Jan Arne Petersencba9e472012-06-21 21:52:19 +0200808}
809
810static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200811text_entry_update_layout(struct text_entry *entry)
812{
813 char *text;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100814 PangoAttrList *attr_list;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200815
Jan Arne Petersen68516862013-04-18 16:47:42 +0200816 assert(entry->cursor <= (strlen(entry->text) +
817 (entry->preedit.text ? strlen(entry->preedit.text) : 0)));
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200818
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100819 if (entry->preedit.text) {
Derek Foreman22044922014-11-20 15:42:35 -0600820 text = xmalloc(strlen(entry->text) + strlen(entry->preedit.text) + 1);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100821 strncpy(text, entry->text, entry->cursor);
822 strcpy(text + entry->cursor, entry->preedit.text);
823 strcpy(text + entry->cursor + strlen(entry->preedit.text),
824 entry->text + entry->cursor);
825 } else {
826 text = strdup(entry->text);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200827 }
828
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100829 if (entry->cursor != entry->anchor) {
830 int start_index = MIN(entry->cursor, entry->anchor);
831 int end_index = MAX(entry->cursor, entry->anchor);
832 PangoAttribute *attr;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200833
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100834 attr_list = pango_attr_list_copy(entry->preedit.attr_list);
835
836 if (!attr_list)
837 attr_list = pango_attr_list_new();
838
839 attr = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
840 attr->start_index = start_index;
841 attr->end_index = end_index;
842 pango_attr_list_insert(attr_list, attr);
843
844 attr = pango_attr_foreground_new(65535, 65535, 65535);
845 attr->start_index = start_index;
846 attr->end_index = end_index;
847 pango_attr_list_insert(attr_list, attr);
848 } else {
849 attr_list = pango_attr_list_ref(entry->preedit.attr_list);
850 }
851
852 if (entry->preedit.text && !entry->preedit.attr_list) {
853 PangoAttribute *attr;
854
855 if (!attr_list)
856 attr_list = pango_attr_list_new();
857
858 attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
859 attr->start_index = entry->cursor;
860 attr->end_index = entry->cursor + strlen(entry->preedit.text);
861 pango_attr_list_insert(attr_list, attr);
862 }
863
864 if (entry->layout) {
865 pango_layout_set_text(entry->layout, text, -1);
866 pango_layout_set_attributes(entry->layout, attr_list);
867 }
868
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200869 free(text);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100870 pango_attr_list_unref(attr_list);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200871}
872
873static void
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100874text_entry_update(struct text_entry *entry)
875{
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200876 struct rectangle cursor_rectangle;
877
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800878 zwp_text_input_v1_set_content_type(entry->text_input,
879 ZWP_TEXT_INPUT_V1_CONTENT_HINT_NONE,
880 entry->content_purpose);
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100881
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800882 zwp_text_input_v1_set_surrounding_text(entry->text_input,
883 entry->text,
884 entry->cursor,
885 entry->anchor);
Jan Arne Petersen0eabcaa2013-01-31 15:52:20 +0100886
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200887 if (entry->preferred_language)
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800888 zwp_text_input_v1_set_preferred_language(entry->text_input,
889 entry->preferred_language);
Jan Arne Petersen9d419132013-04-18 16:47:16 +0200890
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200891 text_entry_get_cursor_rectangle(entry, &cursor_rectangle);
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800892 zwp_text_input_v1_set_cursor_rectangle(entry->text_input,
893 cursor_rectangle.x,
894 cursor_rectangle.y,
895 cursor_rectangle.width,
896 cursor_rectangle.height);
Jan Arne Petersenfe89e712013-04-18 16:47:27 +0200897
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800898 zwp_text_input_v1_commit_state(entry->text_input, ++entry->serial);
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100899}
900
901static void
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100902text_entry_insert_at_cursor(struct text_entry *entry, const char *text,
903 int32_t cursor, int32_t anchor)
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200904{
Derek Foreman22044922014-11-20 15:42:35 -0600905 char *new_text = xmalloc(strlen(entry->text) + strlen(text) + 1);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200906
907 strncpy(new_text, entry->text, entry->cursor);
908 strcpy(new_text + entry->cursor, text);
909 strcpy(new_text + entry->cursor + strlen(text),
910 entry->text + entry->cursor);
911
912 free(entry->text);
913 entry->text = new_text;
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100914 if (anchor >= 0)
915 entry->anchor = entry->cursor + strlen(text) + anchor;
916 else
917 entry->anchor = entry->cursor + 1 + anchor;
Jan Arne Petersen68516862013-04-18 16:47:42 +0200918
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100919 if (cursor >= 0)
920 entry->cursor += strlen(text) + cursor;
921 else
922 entry->cursor += 1 + cursor;
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200923
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200924 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100925
926 widget_schedule_redraw(entry->widget);
927
Jan Arne Petersen0558a932013-01-16 21:26:45 +0100928 text_entry_update(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200929}
930
931static void
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100932text_entry_reset_preedit(struct text_entry *entry)
933{
934 entry->preedit.cursor = 0;
935
936 free(entry->preedit.text);
937 entry->preedit.text = NULL;
938
939 free(entry->preedit.commit);
940 entry->preedit.commit = NULL;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100941
942 pango_attr_list_unref(entry->preedit.attr_list);
943 entry->preedit.attr_list = NULL;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100944}
945
946static void
947text_entry_commit_and_reset(struct text_entry *entry)
948{
949 char *commit = NULL;
950
951 if (entry->preedit.commit)
952 commit = strdup(entry->preedit.commit);
953
954 text_entry_reset_preedit(entry);
955 if (commit) {
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +0100956 text_entry_insert_at_cursor(entry, commit, 0, 0);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100957 free(commit);
958 }
Jan Arne Petersen08015b62013-04-18 16:47:18 +0200959
Jonas Ådahl3bcba342015-11-17 16:00:29 +0800960 zwp_text_input_v1_reset(entry->text_input);
Jan Arne Petersen00191c72013-04-18 16:47:33 +0200961 text_entry_update(entry);
962 entry->reset_serial = entry->serial;
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100963}
964
965static void
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200966text_entry_set_preedit(struct text_entry *entry,
967 const char *preedit_text,
968 int preedit_cursor)
969{
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +0100970 text_entry_reset_preedit(entry);
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200971
972 if (!preedit_text)
973 return;
974
Jan Arne Petersen46535312013-01-16 21:26:38 +0100975 entry->preedit.text = strdup(preedit_text);
976 entry->preedit.cursor = preedit_cursor;
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +0200977
978 text_entry_update_layout(entry);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +0100979
980 widget_schedule_redraw(entry->widget);
Jan Arne Petersen09e7c962012-09-09 23:08:37 +0200981}
982
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100983static uint32_t
984text_entry_try_invoke_preedit_action(struct text_entry *entry,
985 int32_t x, int32_t y,
986 uint32_t button,
987 enum wl_pointer_button_state state)
988{
989 int index, trailing;
990 uint32_t cursor;
Jan Arne Petersen68516862013-04-18 16:47:42 +0200991 const char *text;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +0100992
993 if (!entry->preedit.text)
994 return 0;
995
996 pango_layout_xy_to_index(entry->layout,
997 x * PANGO_SCALE, y * PANGO_SCALE,
998 &index, &trailing);
Jan Arne Petersen68516862013-04-18 16:47:42 +0200999
1000 text = pango_layout_get_text(entry->layout);
1001 cursor = g_utf8_offset_to_pointer(text + index, trailing) - text;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001002
1003 if (cursor < entry->cursor ||
1004 cursor > entry->cursor + strlen(entry->preedit.text)) {
1005 return 0;
1006 }
1007
1008 if (state == WL_POINTER_BUTTON_STATE_RELEASED)
Jonas Ådahl3bcba342015-11-17 16:00:29 +08001009 zwp_text_input_v1_invoke_action(entry->text_input,
1010 button,
1011 cursor - entry->cursor);
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001012
1013 return 1;
1014}
1015
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001016static bool
1017text_entry_has_preedit(struct text_entry *entry)
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001018{
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001019 return entry->preedit.text && (strlen(entry->preedit.text) > 0);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001020}
1021
1022static void
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001023text_entry_set_cursor_position(struct text_entry *entry,
1024 int32_t x, int32_t y,
1025 bool move_anchor)
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001026{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001027 int index, trailing;
Jan Arne Petersen68516862013-04-18 16:47:42 +02001028 const char *text;
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001029 uint32_t cursor;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001030
1031 pango_layout_xy_to_index(entry->layout,
1032 x * PANGO_SCALE, y * PANGO_SCALE,
1033 &index, &trailing);
Jan Arne Petersen68516862013-04-18 16:47:42 +02001034
1035 text = pango_layout_get_text(entry->layout);
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001036
1037 cursor = g_utf8_offset_to_pointer(text + index, trailing) - text;
1038
1039 if (move_anchor)
1040 entry->anchor = cursor;
1041
1042 if (text_entry_has_preedit(entry)) {
1043 text_entry_commit_and_reset(entry);
1044
1045 assert(!text_entry_has_preedit(entry));
1046 }
1047
1048 if (entry->cursor == cursor)
1049 return;
1050
1051 entry->cursor = cursor;
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001052
1053 text_entry_update_layout(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001054
1055 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001056
Jan Arne Petersen0558a932013-01-16 21:26:45 +01001057 text_entry_update(entry);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001058}
1059
1060static void
Jan Arne Petersene202bae2012-09-09 23:08:44 +02001061text_entry_delete_text(struct text_entry *entry,
1062 uint32_t index, uint32_t length)
1063{
Jan Arne Petersen68516862013-04-18 16:47:42 +02001064 uint32_t l;
1065
Jan Arne Petersen895a1282013-05-30 13:57:04 +02001066 assert(index <= strlen(entry->text));
1067 assert(index + length <= strlen(entry->text));
1068 assert(index + length >= length);
Jan Arne Petersen80ad1a92012-09-17 15:28:10 +02001069
Jan Arne Petersen68516862013-04-18 16:47:42 +02001070 l = strlen(entry->text + index + length);
1071 memmove(entry->text + index,
1072 entry->text + index + length,
1073 l + 1);
Jan Arne Petersene202bae2012-09-09 23:08:44 +02001074
Jan Arne Petersen9eaa8e52013-05-30 13:57:03 +02001075 if (entry->cursor > (index + length))
1076 entry->cursor -= length;
1077 else if (entry->cursor > index)
1078 entry->cursor = index;
1079
1080 entry->anchor = entry->cursor;
1081
Jan Arne Petersene202bae2012-09-09 23:08:44 +02001082 text_entry_update_layout(entry);
1083
1084 widget_schedule_redraw(entry->widget);
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001085
Jan Arne Petersen0558a932013-01-16 21:26:45 +01001086 text_entry_update(entry);
Jan Arne Petersene202bae2012-09-09 23:08:44 +02001087}
1088
1089static void
Jan Arne Petersene386dd22012-09-17 15:28:09 +02001090text_entry_delete_selected_text(struct text_entry *entry)
1091{
1092 uint32_t start_index = entry->anchor < entry->cursor ? entry->anchor : entry->cursor;
1093 uint32_t end_index = entry->anchor < entry->cursor ? entry->cursor : entry->anchor;
1094
1095 if (entry->anchor == entry->cursor)
1096 return;
1097
1098 text_entry_delete_text(entry, start_index, end_index - start_index);
1099
1100 entry->anchor = entry->cursor;
1101}
1102
1103static void
Jan Arne Petersenfe89e712013-04-18 16:47:27 +02001104text_entry_get_cursor_rectangle(struct text_entry *entry, struct rectangle *rectangle)
1105{
1106 struct rectangle allocation;
1107 PangoRectangle extents;
1108 PangoRectangle cursor_pos;
1109
1110 widget_get_allocation(entry->widget, &allocation);
1111
1112 if (entry->preedit.text && entry->preedit.cursor < 0) {
1113 rectangle->x = 0;
1114 rectangle->y = 0;
1115 rectangle->width = 0;
1116 rectangle->height = 0;
1117 return;
1118 }
1119
Jan Arne Petersen68516862013-04-18 16:47:42 +02001120
Jan Arne Petersenfe89e712013-04-18 16:47:27 +02001121 pango_layout_get_extents(entry->layout, &extents, NULL);
1122 pango_layout_get_cursor_pos(entry->layout,
1123 entry->cursor + entry->preedit.cursor,
1124 &cursor_pos, NULL);
1125
1126 rectangle->x = allocation.x + (allocation.height / 2) + PANGO_PIXELS(cursor_pos.x);
1127 rectangle->y = allocation.y + 10 + PANGO_PIXELS(cursor_pos.y);
1128 rectangle->width = PANGO_PIXELS(cursor_pos.width);
1129 rectangle->height = PANGO_PIXELS(cursor_pos.height);
1130}
1131
1132static void
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001133text_entry_draw_cursor(struct text_entry *entry, cairo_t *cr)
1134{
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001135 PangoRectangle extents;
1136 PangoRectangle cursor_pos;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001137
Jan Arne Petersen46535312013-01-16 21:26:38 +01001138 if (entry->preedit.text && entry->preedit.cursor < 0)
1139 return;
1140
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001141 pango_layout_get_extents(entry->layout, &extents, NULL);
1142 pango_layout_get_cursor_pos(entry->layout,
1143 entry->cursor + entry->preedit.cursor,
1144 &cursor_pos, NULL);
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001145
1146 cairo_set_line_width(cr, 1.0);
Peter Maatmanb9a23f42013-07-06 20:55:54 +02001147 cairo_move_to(cr, PANGO_PIXELS(cursor_pos.x), PANGO_PIXELS(cursor_pos.y));
1148 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 +02001149 cairo_stroke(cr);
1150}
1151
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001152static int
1153text_offset_left(struct rectangle *allocation)
1154{
1155 return 10;
1156}
1157
1158static int
1159text_offset_top(struct rectangle *allocation)
1160{
1161 return allocation->height / 2;
1162}
Philipp Brüschweiler9f897c72012-10-02 11:06:53 +02001163
Jan Arne Petersenc1fbcb72012-09-09 23:08:39 +02001164static void
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001165text_entry_redraw_handler(struct widget *widget, void *data)
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001166{
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001167 struct text_entry *entry = data;
1168 cairo_surface_t *surface;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001169 struct rectangle allocation;
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001170 cairo_t *cr;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001171
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001172 surface = window_get_surface(entry->window);
1173 widget_get_allocation(entry->widget, &allocation);
1174
1175 cr = cairo_create(surface);
1176 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
1177 cairo_clip(cr);
1178
1179 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
1180
1181 cairo_push_group(cr);
1182 cairo_translate(cr, allocation.x, allocation.y);
1183
1184 cairo_set_source_rgba(cr, 1, 1, 1, 1);
1185 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
1186 cairo_fill(cr);
1187
1188 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
1189
1190 if (entry->active) {
1191 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
1192 cairo_set_line_width (cr, 3);
1193 cairo_set_source_rgba(cr, 0, 0, 1, 1.0);
1194 cairo_stroke(cr);
1195 }
1196
1197 cairo_set_source_rgba(cr, 0, 0, 0, 1);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001198
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001199 cairo_translate(cr,
1200 text_offset_left(&allocation),
1201 text_offset_top(&allocation));
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001202
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001203 if (!entry->layout)
1204 entry->layout = pango_cairo_create_layout(cr);
1205 else
1206 pango_cairo_update_layout(cr, entry->layout);
1207
1208 text_entry_update_layout(entry);
1209
1210 pango_cairo_show_layout(cr, entry->layout);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001211
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001212 text_entry_draw_cursor(entry, cr);
1213
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001214 cairo_pop_group_to_source(cr);
1215 cairo_paint(cr);
1216
1217 cairo_destroy(cr);
1218 cairo_surface_destroy(surface);
1219}
1220
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001221static int
1222text_entry_motion_handler(struct widget *widget,
1223 struct input *input, uint32_t time,
1224 float x, float y, void *data)
1225{
1226 struct text_entry *entry = data;
1227 struct rectangle allocation;
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001228 int tx, ty;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001229
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001230 if (!entry->button_pressed) {
1231 return CURSOR_IBEAM;
1232 }
1233
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001234 widget_get_allocation(entry->widget, &allocation);
1235
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001236 tx = x - allocation.x - text_offset_left(&allocation);
1237 ty = y - allocation.y - text_offset_top(&allocation);
1238
1239 text_entry_set_cursor_position(entry, tx, ty, false);
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001240
1241 return CURSOR_IBEAM;
1242}
1243
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001244static void
1245text_entry_button_handler(struct widget *widget,
1246 struct input *input, uint32_t time,
1247 uint32_t button,
1248 enum wl_pointer_button_state state, void *data)
1249{
1250 struct text_entry *entry = data;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001251 struct rectangle allocation;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001252 struct editor *editor;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001253 int32_t x, y;
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001254 uint32_t result;
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001255
1256 widget_get_allocation(entry->widget, &allocation);
1257 input_get_position(input, &x, &y);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001258
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001259 x -= allocation.x + text_offset_left(&allocation);
1260 y -= allocation.y + text_offset_top(&allocation);
Jan Arne Petersen3489ba92013-01-16 21:26:47 +01001261
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001262 editor = window_get_user_data(entry->window);
1263
Manuel Bachmann22f34302015-03-30 01:57:44 +02001264 switch (button) {
1265 case BTN_LEFT:
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001266 entry->button_pressed = (state == WL_POINTER_BUTTON_STATE_PRESSED);
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001267 if (state == WL_POINTER_BUTTON_STATE_PRESSED)
1268 input_grab(input, entry->widget, button);
1269 else
1270 input_ungrab(input);
Manuel Bachmann22f34302015-03-30 01:57:44 +02001271 break;
1272 case BTN_RIGHT:
1273 if (state == WL_POINTER_BUTTON_STATE_PRESSED)
1274 show_menu(editor, input, time);
1275 break;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001276 }
1277
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001278 if (text_entry_has_preedit(entry)) {
1279 result = text_entry_try_invoke_preedit_action(entry, x, y, button, state);
1280
1281 if (result)
1282 return;
1283 }
Jan Arne Petersen7e634a02012-09-09 23:08:36 +02001284
Manuel Bachmann22f34302015-03-30 01:57:44 +02001285 if (state == WL_POINTER_BUTTON_STATE_PRESSED &&
1286 button == BTN_LEFT) {
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001287 struct wl_seat *seat = input_get_seat(input);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001288
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001289 text_entry_activate(entry, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001290 editor->active_entry = entry;
Jan Arne Petersen0e5bd452012-09-09 23:08:38 +02001291
Jan Arne Petersen1c45b4a2013-05-30 13:57:01 +02001292 text_entry_set_cursor_position(entry, x, y, true);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001293 }
1294}
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001295
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001296static void
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -08001297text_entry_touch_handler(struct widget *widget, struct input *input,
1298 uint32_t serial, uint32_t time, int32_t id,
1299 float tx, float ty, void *data)
1300{
1301 struct text_entry *entry = data;
1302 struct wl_seat *seat = input_get_seat(input);
1303 struct rectangle allocation;
1304 struct editor *editor;
1305 int32_t x, y;
1306
1307 widget_get_allocation(entry->widget, &allocation);
1308
Ander Conselvan de Oliveira8e37d962014-05-08 14:55:50 +03001309 x = tx - (allocation.x + text_offset_left(&allocation));
1310 y = ty - (allocation.y + text_offset_top(&allocation));
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -08001311
1312 editor = window_get_user_data(entry->window);
1313 text_entry_activate(entry, seat);
1314 editor->active_entry = entry;
1315
1316 text_entry_set_cursor_position(entry, x, y, true);
1317}
1318
1319static void
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001320editor_button_handler(struct widget *widget,
1321 struct input *input, uint32_t time,
1322 uint32_t button,
1323 enum wl_pointer_button_state state, void *data)
1324{
1325 struct editor *editor = data;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001326
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001327 if (button != BTN_LEFT) {
1328 return;
1329 }
Jan Arne Petersene829adc2012-08-10 16:47:22 +02001330
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001331 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
1332 struct wl_seat *seat = input_get_seat(input);
1333
Jan Arne Petersene829adc2012-08-10 16:47:22 +02001334 text_entry_deactivate(editor->entry, seat);
1335 text_entry_deactivate(editor->editor, seat);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001336 editor->active_entry = NULL;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001337 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001338}
1339
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -08001340static void
1341editor_touch_handler(struct widget *widget, struct input *input,
1342 uint32_t serial, uint32_t time, int32_t id,
1343 float tx, float ty, void *data)
1344{
1345 struct editor *editor = data;
1346
1347 struct wl_seat *seat = input_get_seat(input);
1348
1349 text_entry_deactivate(editor->entry, seat);
1350 text_entry_deactivate(editor->editor, seat);
1351 editor->active_entry = NULL;
1352}
Kristian Høgsberg78858902014-01-01 23:57:42 -08001353
1354static void
1355keyboard_focus_handler(struct window *window,
1356 struct input *device, void *data)
1357{
1358 struct editor *editor = data;
1359
1360 window_schedule_redraw(editor->window);
1361}
1362
Manuel Bachmann22f34302015-03-30 01:57:44 +02001363static int
1364handle_bound_key(struct editor *editor,
1365 struct input *input, uint32_t sym, uint32_t time)
1366{
1367 switch (sym) {
1368 case XKB_KEY_X:
1369 editor_copy_cut(editor, input, true);
1370 return 1;
1371 case XKB_KEY_C:
1372 editor_copy_cut(editor, input, false);
1373 return 1;
1374 case XKB_KEY_V:
1375 editor_paste(editor, input);
1376 return 1;
1377 default:
1378 return 0;
1379 }
1380}
1381
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001382static void
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001383key_handler(struct window *window,
1384 struct input *input, uint32_t time,
1385 uint32_t key, uint32_t sym, enum wl_keyboard_key_state state,
1386 void *data)
1387{
1388 struct editor *editor = data;
1389 struct text_entry *entry;
Jan Arne Petersen68516862013-04-18 16:47:42 +02001390 const char *new_char;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001391 char text[16];
Manuel Bachmann22f34302015-03-30 01:57:44 +02001392 uint32_t modifiers;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001393
1394 if (!editor->active_entry)
1395 return;
1396
1397 entry = editor->active_entry;
1398
1399 if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
1400 return;
1401
Manuel Bachmann22f34302015-03-30 01:57:44 +02001402 modifiers = input_get_modifiers(input);
1403 if ((modifiers & MOD_CONTROL_MASK) &&
1404 (modifiers & MOD_SHIFT_MASK) &&
1405 handle_bound_key(editor, input, sym, time))
1406 return;
1407
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001408 switch (sym) {
1409 case XKB_KEY_BackSpace:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001410 text_entry_commit_and_reset(entry);
1411
Jan Arne Petersen68516862013-04-18 16:47:42 +02001412 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
1413 if (new_char != NULL)
1414 text_entry_delete_text(entry,
1415 new_char - entry->text,
1416 (entry->text + entry->cursor) - new_char);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001417 break;
1418 case XKB_KEY_Delete:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001419 text_entry_commit_and_reset(entry);
1420
Jan Arne Petersen68516862013-04-18 16:47:42 +02001421 new_char = utf8_next_char(entry->text + entry->cursor);
1422 if (new_char != NULL)
1423 text_entry_delete_text(entry,
1424 entry->cursor,
1425 new_char - (entry->text + entry->cursor));
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001426 break;
1427 case XKB_KEY_Left:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001428 text_entry_commit_and_reset(entry);
1429
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001430 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
1431 if (new_char != NULL) {
1432 entry->cursor = new_char - entry->text;
Rob Bradford70002832013-07-11 16:00:00 +01001433 if (!(input_get_modifiers(input) & MOD_SHIFT_MASK))
1434 entry->anchor = entry->cursor;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001435 widget_schedule_redraw(entry->widget);
1436 }
1437 break;
1438 case XKB_KEY_Right:
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001439 text_entry_commit_and_reset(entry);
1440
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001441 new_char = utf8_next_char(entry->text + entry->cursor);
1442 if (new_char != NULL) {
1443 entry->cursor = new_char - entry->text;
Rob Bradford70002832013-07-11 16:00:00 +01001444 if (!(input_get_modifiers(input) & MOD_SHIFT_MASK))
1445 entry->anchor = entry->cursor;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001446 widget_schedule_redraw(entry->widget);
1447 }
1448 break;
Manuel Bachmann8986c182014-04-18 12:50:14 +02001449 case XKB_KEY_Up:
1450 text_entry_commit_and_reset(entry);
1451
1452 move_up(entry->text, &entry->cursor);
1453 if (!(input_get_modifiers(input) & MOD_SHIFT_MASK))
1454 entry->anchor = entry->cursor;
1455 widget_schedule_redraw(entry->widget);
1456 break;
1457 case XKB_KEY_Down:
1458 text_entry_commit_and_reset(entry);
1459
1460 move_down(entry->text, &entry->cursor);
1461 if (!(input_get_modifiers(input) & MOD_SHIFT_MASK))
1462 entry->anchor = entry->cursor;
1463 widget_schedule_redraw(entry->widget);
1464 break;
Peter Maatman08c38d42013-07-06 20:42:59 +02001465 case XKB_KEY_Escape:
1466 break;
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001467 default:
1468 if (xkb_keysym_to_utf8(sym, text, sizeof(text)) <= 0)
1469 break;
1470
Peter Maatman08c38d42013-07-06 20:42:59 +02001471 text_entry_commit_and_reset(entry);
Jan Arne Petersen4a17fae2013-01-16 21:26:40 +01001472
Jan Arne Petersen1cc9e082013-01-31 15:52:23 +01001473 text_entry_insert_at_cursor(entry, text, 0, 0);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001474 break;
1475 }
1476
1477 widget_schedule_redraw(entry->widget);
1478}
1479
1480static void
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001481global_handler(struct display *display, uint32_t name,
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001482 const char *interface, uint32_t version, void *data)
1483{
1484 struct editor *editor = data;
1485
Jonas Ådahl3bcba342015-11-17 16:00:29 +08001486 if (!strcmp(interface, "zwp_text_input_manager_v1")) {
Jan Arne Petersen78d00e42013-04-18 16:47:24 +02001487 editor->text_input_manager =
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001488 display_bind(display, name,
Jonas Ådahl3bcba342015-11-17 16:00:29 +08001489 &zwp_text_input_manager_v1_interface, 1);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001490 }
1491}
1492
Bryce Harrington3d90da22016-11-21 13:26:22 -08001493/** Display help for command line options, and exit */
1494static uint32_t opt_help = 0;
1495
1496/** Require a distinct click to show the input panel (virtual keyboard) */
1497static uint32_t opt_click_to_show = 0;
1498
1499/** Set a specific (RFC-3066) language. Used for the virtual keyboard, etc. */
1500static const char *opt_preferred_language = NULL;
1501
1502/**
1503 * \brief command line options for editor
1504 */
1505static const struct weston_option editor_options[] = {
1506 { WESTON_OPTION_BOOLEAN, "help", 'h', &opt_help },
1507 { WESTON_OPTION_BOOLEAN, "click-to-show", 'C', &opt_click_to_show },
1508 { WESTON_OPTION_STRING, "preferred-language", 'L', &opt_preferred_language },
1509};
1510
1511static void
1512usage(const char *program_name, int exit_code)
1513{
1514 unsigned k;
1515
1516 fprintf(stderr, "Usage: %s [OPTIONS]\n\n", program_name);
1517 for (k = 0; k < ARRAY_LENGTH(editor_options); k++) {
1518 const struct weston_option *p = &editor_options[k];
1519 if (p->name) {
1520 fprintf(stderr, " --%s", p->name);
1521 if (p->type != WESTON_OPTION_BOOLEAN)
1522 fprintf(stderr, "=VALUE");
1523 fprintf(stderr, "\n");
1524 }
1525 if (p->short_name) {
1526 fprintf(stderr, " -%c", p->short_name);
1527 if (p->type != WESTON_OPTION_BOOLEAN)
1528 fprintf(stderr, "VALUE");
1529 fprintf(stderr, "\n");
1530 }
1531 }
1532 exit(exit_code);
1533}
1534
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001535int
1536main(int argc, char *argv[])
1537{
1538 struct editor editor;
Jan Arne Petersen61381972013-01-31 15:52:21 +01001539
Bryce Harrington3d90da22016-11-21 13:26:22 -08001540 parse_options(editor_options, ARRAY_LENGTH(editor_options),
1541 &argc, argv);
1542 if (opt_help)
1543 usage(argv[0], EXIT_SUCCESS);
1544
1545 if (argc > 1) {
1546 usage(argv[0], EXIT_FAILURE);
1547 /* FIXME: Use remaining arguments as a path/filename to load */
1548 return 0;
Jan Arne Petersen9d419132013-04-18 16:47:16 +02001549 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001550
Jan Arne Petersen25f6db52012-11-05 03:26:40 +01001551 memset(&editor, 0, sizeof editor);
1552
Jan Arne Petersen0a1cf392013-01-16 21:26:42 +01001553#ifdef HAVE_PANGO
1554 g_type_init();
1555#endif
1556
Kristian Høgsberg4172f662013-02-20 15:27:49 -05001557 editor.display = display_create(&argc, argv);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001558 if (editor.display == NULL) {
1559 fprintf(stderr, "failed to create display: %m\n");
1560 return -1;
1561 }
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001562
Kristian Høgsbergfa80e112012-10-10 21:34:26 -04001563 display_set_user_data(editor.display, &editor);
1564 display_set_global_handler(editor.display, global_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001565
Olivier Blin30e1f3c2014-09-16 19:13:17 +02001566 if (editor.text_input_manager == NULL) {
1567 fprintf(stderr, "No text input manager global\n");
1568 return -1;
1569 }
1570
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001571 editor.window = window_create(editor.display);
Jason Ekstrandee7fefc2013-10-13 19:08:38 -05001572 editor.widget = window_frame_create(editor.window, &editor);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001573
1574 editor.entry = text_entry_create(&editor, "Entry");
Bryce Harrington3d90da22016-11-21 13:26:22 -08001575 editor.entry->click_to_show = opt_click_to_show;
1576 if (opt_preferred_language)
1577 editor.entry->preferred_language = strdup(opt_preferred_language);
Jan Arne Petersen0558a932013-01-16 21:26:45 +01001578 editor.editor = text_entry_create(&editor, "Numeric");
Jonas Ådahl3bcba342015-11-17 16:00:29 +08001579 editor.editor->content_purpose = ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_NUMBER;
Bryce Harrington3d90da22016-11-21 13:26:22 -08001580 editor.editor->click_to_show = opt_click_to_show;
Manuel Bachmann22f34302015-03-30 01:57:44 +02001581 editor.selection = NULL;
1582 editor.selected_text = NULL;
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001583
1584 window_set_title(editor.window, "Text Editor");
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001585 window_set_key_handler(editor.window, key_handler);
Kristian Høgsberg78858902014-01-01 23:57:42 -08001586 window_set_keyboard_focus_handler(editor.window,
1587 keyboard_focus_handler);
Rob Bradford9d1d32b2012-11-18 19:06:49 +01001588 window_set_user_data(editor.window, &editor);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001589
1590 widget_set_redraw_handler(editor.widget, redraw_handler);
1591 widget_set_resize_handler(editor.widget, resize_handler);
Jan Arne Petersenf80bc062012-09-09 23:08:34 +02001592 widget_set_button_handler(editor.widget, editor_button_handler);
Kristian Høgsberg966e3ed2014-01-07 10:41:50 -08001593 widget_set_touch_down_handler(editor.widget, editor_touch_handler);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001594
1595 window_schedule_resize(editor.window, 500, 400);
1596
1597 display_run(editor.display);
1598
Manuel Bachmann22f34302015-03-30 01:57:44 +02001599 if (editor.selected_text)
1600 free(editor.selected_text);
1601 if (editor.selection)
1602 wl_data_source_destroy(editor.selection);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001603 text_entry_destroy(editor.entry);
1604 text_entry_destroy(editor.editor);
vivek31732f72014-05-15 18:58:16 +05301605 widget_destroy(editor.widget);
1606 window_destroy(editor.window);
1607 display_destroy(editor.display);
Jan Arne Petersencba9e472012-06-21 21:52:19 +02001608
1609 return 0;
1610}