2 * Copyright © 2012 Openismus GmbH
3 * Copyright © 2012 Intel Corporation
5 * Permission to use, copy, modify, distribute, and sell this software and
6 * its documentation for any purpose is hereby granted without fee, provided
7 * that the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation, and that the name of the copyright holders not be used in
10 * advertising or publicity pertaining to distribution of the software
11 * without specific, written prior permission. The copyright holders make
12 * no representations about the suitability of this software for any
13 * purpose. It is provided "as is" without express or implied warranty.
15 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
16 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
19 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
20 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
31 #include <linux/input.h>
34 #include <pango/pangocairo.h>
37 #include "text-client-protocol.h"
40 struct widget *widget;
41 struct window *window;
50 PangoAttrList *attr_list;
53 PangoAttrList *attr_list;
60 struct text_input *text_input;
63 xkb_mod_mask_t shift_mask;
66 uint32_t content_purpose;
67 uint32_t click_to_show;
68 char *preferred_language;
72 struct text_input_manager *text_input_manager;
73 struct display *display;
74 struct window *window;
75 struct widget *widget;
76 struct text_entry *entry;
77 struct text_entry *editor;
78 struct text_entry *active_entry;
82 utf8_start_char(const char *text, const char *p)
84 for (; p >= text; --p) {
85 if ((*p & 0xc0) != 0x80)
92 utf8_prev_char(const char *text, const char *p)
95 return utf8_start_char(text, --p);
100 utf8_end_char(const char *p)
102 while ((*p & 0xc0) == 0x80)
108 utf8_next_char(const char *p)
111 return utf8_end_char(++p);
115 static void text_entry_redraw_handler(struct widget *widget, void *data);
116 static void text_entry_button_handler(struct widget *widget,
117 struct input *input, uint32_t time,
119 enum wl_pointer_button_state state, void *data);
120 static void text_entry_insert_at_cursor(struct text_entry *entry, const char *text,
121 int32_t cursor, int32_t anchor);
122 static void text_entry_set_preedit(struct text_entry *entry,
123 const char *preedit_text,
125 static void text_entry_delete_text(struct text_entry *entry,
126 uint32_t index, uint32_t length);
127 static void text_entry_delete_selected_text(struct text_entry *entry);
128 static void text_entry_reset_preedit(struct text_entry *entry);
129 static void text_entry_commit_and_reset(struct text_entry *entry);
132 text_input_commit_string(void *data,
133 struct text_input *text_input,
137 struct text_entry *entry = data;
139 text_entry_reset_preedit(entry);
141 text_entry_delete_selected_text(entry);
142 text_entry_insert_at_cursor(entry, text,
143 entry->pending_commit.cursor,
144 entry->pending_commit.anchor);
146 memset(&entry->pending_commit, 0, sizeof entry->pending_commit);
148 widget_schedule_redraw(entry->widget);
152 text_input_preedit_string(void *data,
153 struct text_input *text_input,
158 struct text_entry *entry = data;
160 text_entry_delete_selected_text(entry);
161 text_entry_set_preedit(entry, text, entry->preedit_info.cursor);
162 entry->preedit.commit = strdup(commit);
163 entry->preedit.attr_list = entry->preedit_info.attr_list;
165 entry->preedit_info.cursor = 0;
166 entry->preedit_info.attr_list = NULL;
168 widget_schedule_redraw(entry->widget);
172 text_input_delete_surrounding_text(void *data,
173 struct text_input *text_input,
178 struct text_entry *entry = data;
179 uint32_t cursor_index = index + entry->cursor;
180 const char *start, *end;
182 if (cursor_index > strlen(entry->text)) {
183 fprintf(stderr, "Invalid cursor index %d\n", index);
187 if (cursor_index + length > strlen(entry->text)) {
188 fprintf(stderr, "Invalid length %d\n", length);
195 start = utf8_start_char(entry->text, entry->text + cursor_index);
196 end = utf8_end_char(entry->text + cursor_index + length);
198 text_entry_delete_text(entry,
204 text_input_cursor_position(void *data,
205 struct text_input *text_input,
210 struct text_entry *entry = data;
212 entry->pending_commit.cursor = index;
213 entry->pending_commit.anchor = anchor;
217 text_input_preedit_styling(void *data,
218 struct text_input *text_input,
224 struct text_entry *entry = data;
225 PangoAttribute *attr1 = NULL;
226 PangoAttribute *attr2 = NULL;
228 if (!entry->preedit_info.attr_list)
229 entry->preedit_info.attr_list = pango_attr_list_new();
232 case TEXT_INPUT_PREEDIT_STYLE_DEFAULT:
233 case TEXT_INPUT_PREEDIT_STYLE_UNDERLINE:
234 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
236 case TEXT_INPUT_PREEDIT_STYLE_INCORRECT:
237 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_ERROR);
238 attr2 = pango_attr_underline_color_new(65535, 0, 0);
240 case TEXT_INPUT_PREEDIT_STYLE_SELECTION:
241 attr1 = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
242 attr2 = pango_attr_foreground_new(65535, 65535, 65535);
244 case TEXT_INPUT_PREEDIT_STYLE_HIGHLIGHT:
245 case TEXT_INPUT_PREEDIT_STYLE_ACTIVE:
246 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
247 attr2 = pango_attr_weight_new(PANGO_WEIGHT_BOLD);
249 case TEXT_INPUT_PREEDIT_STYLE_INACTIVE:
250 attr1 = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
251 attr2 = pango_attr_foreground_new(0.3 * 65535, 0.3 * 65535, 0.3 * 65535);
256 attr1->start_index = entry->cursor + index;
257 attr1->end_index = entry->cursor + index + length;
258 pango_attr_list_insert(entry->preedit_info.attr_list, attr1);
262 attr2->start_index = entry->cursor + index;
263 attr2->end_index = entry->cursor + index + length;
264 pango_attr_list_insert(entry->preedit_info.attr_list, attr2);
269 text_input_preedit_cursor(void *data,
270 struct text_input *text_input,
274 struct text_entry *entry = data;
276 entry->preedit_info.cursor = index;
280 text_input_modifiers_map(void *data,
281 struct text_input *text_input,
282 struct wl_array *map)
284 struct text_entry *entry = data;
286 entry->keysym.shift_mask = keysym_modifiers_get_mask(map, "Shift");
290 text_input_keysym(void *data,
291 struct text_input *text_input,
298 struct text_entry *entry = data;
299 const char *state_label = "release";
300 const char *key_label = "Unknown";
301 const char *new_char;
303 if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
304 state_label = "pressed";
307 if (key == XKB_KEY_Left ||
308 key == XKB_KEY_Right) {
309 if (state != WL_KEYBOARD_KEY_STATE_RELEASED)
312 if (key == XKB_KEY_Left)
313 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
315 new_char = utf8_next_char(entry->text + entry->cursor);
317 if (new_char != NULL) {
318 entry->cursor = new_char - entry->text;
319 if (!(modifiers & entry->keysym.shift_mask))
320 entry->anchor = entry->cursor;
321 widget_schedule_redraw(entry->widget);
327 if (key == XKB_KEY_BackSpace) {
328 const char *start, *end;
330 text_entry_commit_and_reset(entry);
332 start = utf8_prev_char(entry->text, entry->text + entry->cursor);
337 end = utf8_end_char(entry->text + entry->cursor);
338 text_entry_delete_text(entry,
349 case XKB_KEY_KP_Enter:
355 fprintf(stderr, "%s key was %s.\n", key_label, state_label);
359 text_input_enter(void *data,
360 struct text_input *text_input,
361 struct wl_surface *surface)
363 struct text_entry *entry = data;
365 if (surface != window_get_wl_surface(entry->window))
370 widget_schedule_redraw(entry->widget);
374 text_input_leave(void *data,
375 struct text_input *text_input)
377 struct text_entry *entry = data;
379 text_entry_commit_and_reset(entry);
383 text_input_hide_input_panel(text_input);
385 widget_schedule_redraw(entry->widget);
389 text_input_input_panel_state(void *data,
390 struct text_input *text_input,
396 text_input_language(void *data,
397 struct text_input *text_input,
399 const char *language)
401 fprintf(stderr, "input language is %s \n", language);
405 text_input_text_direction(void *data,
406 struct text_input *text_input,
410 struct text_entry *entry = data;
411 PangoContext *context = pango_layout_get_context(entry->layout);
412 PangoDirection pango_direction;
416 case TEXT_INPUT_TEXT_DIRECTION_LTR:
417 pango_direction = PANGO_DIRECTION_LTR;
419 case TEXT_INPUT_TEXT_DIRECTION_RTL:
420 pango_direction = PANGO_DIRECTION_RTL;
422 case TEXT_INPUT_TEXT_DIRECTION_AUTO:
424 pango_direction = PANGO_DIRECTION_NEUTRAL;
427 pango_context_set_base_dir(context, pango_direction);
430 static const struct text_input_listener text_input_listener = {
433 text_input_modifiers_map,
434 text_input_input_panel_state,
435 text_input_preedit_string,
436 text_input_preedit_styling,
437 text_input_preedit_cursor,
438 text_input_commit_string,
439 text_input_cursor_position,
440 text_input_delete_surrounding_text,
443 text_input_text_direction
446 static struct text_entry*
447 text_entry_create(struct editor *editor, const char *text)
449 struct text_entry *entry;
451 entry = calloc(1, sizeof *entry);
453 entry->widget = widget_add_widget(editor->widget, entry);
454 entry->window = editor->window;
455 entry->text = strdup(text);
457 entry->cursor = strlen(text);
458 entry->anchor = entry->cursor;
459 entry->text_input = text_input_manager_create_text_input(editor->text_input_manager);
460 text_input_add_listener(entry->text_input, &text_input_listener, entry);
462 widget_set_redraw_handler(entry->widget, text_entry_redraw_handler);
463 widget_set_button_handler(entry->widget, text_entry_button_handler);
469 text_entry_destroy(struct text_entry *entry)
471 widget_destroy(entry->widget);
472 text_input_destroy(entry->text_input);
473 g_clear_object(&entry->layout);
479 redraw_handler(struct widget *widget, void *data)
481 struct editor *editor = data;
482 cairo_surface_t *surface;
483 struct rectangle allocation;
486 surface = window_get_surface(editor->window);
487 widget_get_allocation(editor->widget, &allocation);
489 cr = cairo_create(surface);
490 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
493 cairo_translate(cr, allocation.x, allocation.y);
495 /* Draw background */
496 cairo_push_group(cr);
497 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
498 cairo_set_source_rgba(cr, 1, 1, 1, 1);
499 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
502 cairo_pop_group_to_source(cr);
506 cairo_surface_destroy(surface);
510 text_entry_allocate(struct text_entry *entry, int32_t x, int32_t y,
511 int32_t width, int32_t height)
513 widget_set_allocation(entry->widget, x, y, width, height);
517 resize_handler(struct widget *widget,
518 int32_t width, int32_t height, void *data)
520 struct editor *editor = data;
521 struct rectangle allocation;
523 widget_get_allocation(editor->widget, &allocation);
525 text_entry_allocate(editor->entry,
526 allocation.x + 20, allocation.y + 20,
527 width - 40, height / 2 - 40);
528 text_entry_allocate(editor->editor,
529 allocation.x + 20, allocation.y + height / 2 + 20,
530 width - 40, height / 2 - 40);
534 text_entry_activate(struct text_entry *entry,
535 struct wl_seat *seat)
537 struct wl_surface *surface = window_get_wl_surface(entry->window);
539 if (entry->click_to_show && entry->active) {
540 text_input_show_input_panel(entry->text_input);
545 if (!entry->click_to_show)
546 text_input_show_input_panel(entry->text_input);
550 text_input_activate(entry->text_input,
557 text_entry_deactivate(struct text_entry *entry,
558 struct wl_seat *seat)
560 text_input_deactivate(entry->text_input,
565 text_entry_update_layout(struct text_entry *entry)
568 PangoAttrList *attr_list;
570 assert(((unsigned int)entry->cursor) <= strlen(entry->text) +
571 (entry->preedit.text ? strlen(entry->preedit.text) : 0));
573 if (entry->preedit.text) {
574 text = malloc(strlen(entry->text) + strlen(entry->preedit.text) + 1);
575 strncpy(text, entry->text, entry->cursor);
576 strcpy(text + entry->cursor, entry->preedit.text);
577 strcpy(text + entry->cursor + strlen(entry->preedit.text),
578 entry->text + entry->cursor);
580 text = strdup(entry->text);
583 if (entry->cursor != entry->anchor) {
584 int start_index = MIN(entry->cursor, entry->anchor);
585 int end_index = MAX(entry->cursor, entry->anchor);
586 PangoAttribute *attr;
588 attr_list = pango_attr_list_copy(entry->preedit.attr_list);
591 attr_list = pango_attr_list_new();
593 attr = pango_attr_background_new(0.3 * 65535, 0.3 * 65535, 65535);
594 attr->start_index = start_index;
595 attr->end_index = end_index;
596 pango_attr_list_insert(attr_list, attr);
598 attr = pango_attr_foreground_new(65535, 65535, 65535);
599 attr->start_index = start_index;
600 attr->end_index = end_index;
601 pango_attr_list_insert(attr_list, attr);
603 attr_list = pango_attr_list_ref(entry->preedit.attr_list);
606 if (entry->preedit.text && !entry->preedit.attr_list) {
607 PangoAttribute *attr;
610 attr_list = pango_attr_list_new();
612 attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE);
613 attr->start_index = entry->cursor;
614 attr->end_index = entry->cursor + strlen(entry->preedit.text);
615 pango_attr_list_insert(attr_list, attr);
619 pango_layout_set_text(entry->layout, text, -1);
620 pango_layout_set_attributes(entry->layout, attr_list);
624 pango_attr_list_unref(attr_list);
628 text_entry_update(struct text_entry *entry)
630 text_input_set_content_type(entry->text_input,
631 TEXT_INPUT_CONTENT_HINT_NONE,
632 entry->content_purpose);
634 text_input_set_surrounding_text(entry->text_input,
639 if (entry->preferred_language)
640 text_input_set_preferred_language(entry->text_input,
641 entry->preferred_language);
643 text_input_commit_state(entry->text_input);
647 text_entry_insert_at_cursor(struct text_entry *entry, const char *text,
648 int32_t cursor, int32_t anchor)
650 char *new_text = malloc(strlen(entry->text) + strlen(text) + 1);
652 strncpy(new_text, entry->text, entry->cursor);
653 strcpy(new_text + entry->cursor, text);
654 strcpy(new_text + entry->cursor + strlen(text),
655 entry->text + entry->cursor);
658 entry->text = new_text;
660 entry->anchor = entry->cursor + strlen(text) + anchor;
662 entry->anchor = entry->cursor + 1 + anchor;
664 entry->cursor += strlen(text) + cursor;
666 entry->cursor += 1 + cursor;
668 text_entry_update_layout(entry);
670 widget_schedule_redraw(entry->widget);
672 text_entry_update(entry);
676 text_entry_reset_preedit(struct text_entry *entry)
678 entry->preedit.cursor = 0;
680 free(entry->preedit.text);
681 entry->preedit.text = NULL;
683 free(entry->preedit.commit);
684 entry->preedit.commit = NULL;
686 pango_attr_list_unref(entry->preedit.attr_list);
687 entry->preedit.attr_list = NULL;
691 text_entry_commit_and_reset(struct text_entry *entry)
695 if (entry->preedit.commit)
696 commit = strdup(entry->preedit.commit);
698 text_entry_reset_preedit(entry);
700 text_entry_insert_at_cursor(entry, commit, 0, 0);
705 text_input_reset(entry->text_input, entry->serial);
709 text_entry_set_preedit(struct text_entry *entry,
710 const char *preedit_text,
713 text_entry_reset_preedit(entry);
718 entry->preedit.text = strdup(preedit_text);
719 entry->preedit.cursor = preedit_cursor;
721 text_entry_update_layout(entry);
723 widget_schedule_redraw(entry->widget);
727 text_entry_try_invoke_preedit_action(struct text_entry *entry,
728 int32_t x, int32_t y,
730 enum wl_pointer_button_state state)
735 if (!entry->preedit.text)
738 pango_layout_xy_to_index(entry->layout,
739 x * PANGO_SCALE, y * PANGO_SCALE,
741 cursor = index + trailing;
743 if (cursor < entry->cursor ||
744 cursor > entry->cursor + strlen(entry->preedit.text)) {
748 if (state == WL_POINTER_BUTTON_STATE_RELEASED)
749 text_input_invoke_action(entry->text_input,
751 cursor - entry->cursor);
757 text_entry_set_cursor_position(struct text_entry *entry,
758 int32_t x, int32_t y)
762 text_entry_commit_and_reset(entry);
764 pango_layout_xy_to_index(entry->layout,
765 x * PANGO_SCALE, y * PANGO_SCALE,
767 entry->cursor = index + trailing;
769 text_entry_update_layout(entry);
771 widget_schedule_redraw(entry->widget);
773 text_entry_update(entry);
777 text_entry_set_anchor_position(struct text_entry *entry,
778 int32_t x, int32_t y)
782 pango_layout_xy_to_index(entry->layout,
783 x * PANGO_SCALE, y * PANGO_SCALE,
785 entry->anchor = index + trailing;
787 text_entry_update_layout(entry);
789 widget_schedule_redraw(entry->widget);
791 text_entry_update(entry);
795 text_entry_delete_text(struct text_entry *entry,
796 uint32_t index, uint32_t length)
798 if (entry->cursor > index)
799 entry->cursor -= length;
801 entry->anchor = entry->cursor;
803 entry->text[index] = '\0';
804 strcat(entry->text, entry->text + index + length);
806 text_entry_update_layout(entry);
808 widget_schedule_redraw(entry->widget);
810 text_entry_update(entry);
814 text_entry_delete_selected_text(struct text_entry *entry)
816 uint32_t start_index = entry->anchor < entry->cursor ? entry->anchor : entry->cursor;
817 uint32_t end_index = entry->anchor < entry->cursor ? entry->cursor : entry->anchor;
819 if (entry->anchor == entry->cursor)
822 text_entry_delete_text(entry, start_index, end_index - start_index);
824 entry->anchor = entry->cursor;
828 text_entry_draw_cursor(struct text_entry *entry, cairo_t *cr)
830 PangoRectangle extents;
831 PangoRectangle cursor_pos;
833 if (entry->preedit.text && entry->preedit.cursor < 0)
836 pango_layout_get_extents(entry->layout, &extents, NULL);
837 pango_layout_get_cursor_pos(entry->layout,
838 entry->cursor + entry->preedit.cursor,
841 cairo_set_line_width(cr, 1.0);
842 cairo_move_to(cr, PANGO_PIXELS(cursor_pos.x), PANGO_PIXELS(extents.height) + 2);
843 cairo_line_to(cr, PANGO_PIXELS(cursor_pos.x), - 2);
847 static const int text_offset_left = 10;
850 text_entry_redraw_handler(struct widget *widget, void *data)
852 struct text_entry *entry = data;
853 cairo_surface_t *surface;
854 struct rectangle allocation;
857 surface = window_get_surface(entry->window);
858 widget_get_allocation(entry->widget, &allocation);
860 cr = cairo_create(surface);
861 cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
864 cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
866 cairo_push_group(cr);
867 cairo_translate(cr, allocation.x, allocation.y);
869 cairo_set_source_rgba(cr, 1, 1, 1, 1);
870 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
873 cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
876 cairo_rectangle(cr, 0, 0, allocation.width, allocation.height);
877 cairo_set_line_width (cr, 3);
878 cairo_set_source_rgba(cr, 0, 0, 1, 1.0);
882 cairo_set_source_rgba(cr, 0, 0, 0, 1);
884 cairo_translate(cr, text_offset_left, allocation.height / 2);
887 entry->layout = pango_cairo_create_layout(cr);
889 pango_cairo_update_layout(cr, entry->layout);
891 text_entry_update_layout(entry);
893 pango_cairo_show_layout(cr, entry->layout);
895 text_entry_draw_cursor(entry, cr);
897 cairo_pop_group_to_source(cr);
901 cairo_surface_destroy(surface);
905 text_entry_motion_handler(struct widget *widget,
906 struct input *input, uint32_t time,
907 float x, float y, void *data)
909 struct text_entry *entry = data;
910 struct rectangle allocation;
912 widget_get_allocation(entry->widget, &allocation);
914 text_entry_set_cursor_position(entry,
915 x - allocation.x - text_offset_left,
916 y - allocation.y - text_offset_left);
922 text_entry_button_handler(struct widget *widget,
923 struct input *input, uint32_t time,
925 enum wl_pointer_button_state state, void *data)
927 struct text_entry *entry = data;
928 struct rectangle allocation;
929 struct editor *editor;
933 widget_get_allocation(entry->widget, &allocation);
934 input_get_position(input, &x, &y);
936 x -= allocation.x + text_offset_left;
937 y -= allocation.y + text_offset_left;
939 editor = window_get_user_data(entry->window);
941 result = text_entry_try_invoke_preedit_action(entry, x, y, button, state);
946 if (button != BTN_LEFT) {
950 text_entry_set_cursor_position(entry, x, y);
952 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
953 struct wl_seat *seat = input_get_seat(input);
955 text_entry_activate(entry, seat);
956 editor->active_entry = entry;
958 text_entry_set_anchor_position(entry, x, y);
960 widget_set_motion_handler(entry->widget, text_entry_motion_handler);
962 widget_set_motion_handler(entry->widget, NULL);
967 editor_button_handler(struct widget *widget,
968 struct input *input, uint32_t time,
970 enum wl_pointer_button_state state, void *data)
972 struct editor *editor = data;
974 if (button != BTN_LEFT) {
978 if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
979 struct wl_seat *seat = input_get_seat(input);
981 text_entry_deactivate(editor->entry, seat);
982 text_entry_deactivate(editor->editor, seat);
983 editor->active_entry = NULL;
988 key_handler(struct window *window,
989 struct input *input, uint32_t time,
990 uint32_t key, uint32_t sym, enum wl_keyboard_key_state state,
993 struct editor *editor = data;
994 struct text_entry *entry;
995 const char *start, *end, *new_char;
998 if (!editor->active_entry)
1001 entry = editor->active_entry;
1003 if (state != WL_KEYBOARD_KEY_STATE_PRESSED)
1007 case XKB_KEY_BackSpace:
1008 text_entry_commit_and_reset(entry);
1010 start = utf8_prev_char(entry->text, entry->text + entry->cursor);
1015 end = utf8_end_char(entry->text + entry->cursor);
1016 text_entry_delete_text(entry,
1017 start - entry->text,
1020 case XKB_KEY_Delete:
1021 text_entry_commit_and_reset(entry);
1023 start = utf8_start_char(entry->text, entry->text + entry->cursor);
1028 end = utf8_next_char(start);
1033 text_entry_delete_text(entry,
1034 start - entry->text,
1038 text_entry_commit_and_reset(entry);
1040 new_char = utf8_prev_char(entry->text, entry->text + entry->cursor);
1041 if (new_char != NULL) {
1042 entry->cursor = new_char - entry->text;
1043 entry->anchor = entry->cursor;
1044 widget_schedule_redraw(entry->widget);
1048 text_entry_commit_and_reset(entry);
1050 new_char = utf8_next_char(entry->text + entry->cursor);
1051 if (new_char != NULL) {
1052 entry->cursor = new_char - entry->text;
1053 entry->anchor = entry->cursor;
1054 widget_schedule_redraw(entry->widget);
1058 if (xkb_keysym_to_utf8(sym, text, sizeof(text)) <= 0)
1061 text_entry_commit_and_reset(entry);
1063 text_entry_insert_at_cursor(entry, text, 0, 0);
1067 widget_schedule_redraw(entry->widget);
1071 global_handler(struct display *display, uint32_t name,
1072 const char *interface, uint32_t version, void *data)
1074 struct editor *editor = data;
1076 if (!strcmp(interface, "text_input_manager")) {
1077 editor->text_input_manager =
1078 display_bind(display, name,
1079 &text_input_manager_interface, 1);
1084 main(int argc, char *argv[])
1086 struct editor editor;
1088 uint32_t click_to_show = 0;
1089 const char *preferred_language = NULL;
1091 for (i = 1; i < argc; i++) {
1092 if (strcmp("--click-to-show", argv[i]) == 0)
1094 else if (strcmp("--preferred-language", argv[i]) == 0) {
1096 preferred_language = argv[i + 1];
1102 memset(&editor, 0, sizeof editor);
1108 editor.display = display_create(&argc, argv);
1109 if (editor.display == NULL) {
1110 fprintf(stderr, "failed to create display: %m\n");
1114 display_set_user_data(editor.display, &editor);
1115 display_set_global_handler(editor.display, global_handler);
1117 editor.window = window_create(editor.display);
1118 editor.widget = frame_create(editor.window, &editor);
1120 editor.entry = text_entry_create(&editor, "Entry");
1121 editor.entry->click_to_show = click_to_show;
1122 if (preferred_language)
1123 editor.entry->preferred_language = strdup(preferred_language);
1124 editor.editor = text_entry_create(&editor, "Numeric");
1125 editor.editor->content_purpose = TEXT_INPUT_CONTENT_PURPOSE_NUMBER;
1126 editor.editor->click_to_show = click_to_show;
1128 window_set_title(editor.window, "Text Editor");
1129 window_set_key_handler(editor.window, key_handler);
1130 window_set_user_data(editor.window, &editor);
1132 widget_set_redraw_handler(editor.widget, redraw_handler);
1133 widget_set_resize_handler(editor.widget, resize_handler);
1134 widget_set_button_handler(editor.widget, editor_button_handler);
1136 window_schedule_resize(editor.window, 500, 400);
1138 display_run(editor.display);
1140 text_entry_destroy(editor.entry);
1141 text_entry_destroy(editor.editor);