|
|
@ -27,6 +27,7 @@ |
|
|
|
#include <stdio.h> |
|
|
|
#include <stdio.h> |
|
|
|
#include <stdlib.h> |
|
|
|
#include <stdlib.h> |
|
|
|
#include <string.h> |
|
|
|
#include <string.h> |
|
|
|
|
|
|
|
#include <stdbool.h> |
|
|
|
|
|
|
|
|
|
|
|
#include <linux/input.h> |
|
|
|
#include <linux/input.h> |
|
|
|
#include <cairo.h> |
|
|
|
#include <cairo.h> |
|
|
@ -69,6 +70,7 @@ struct text_entry { |
|
|
|
uint32_t content_purpose; |
|
|
|
uint32_t content_purpose; |
|
|
|
uint32_t click_to_show; |
|
|
|
uint32_t click_to_show; |
|
|
|
char *preferred_language; |
|
|
|
char *preferred_language; |
|
|
|
|
|
|
|
bool button_pressed; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
struct editor { |
|
|
|
struct editor { |
|
|
@ -112,6 +114,9 @@ static void text_entry_button_handler(struct widget *widget, |
|
|
|
struct input *input, uint32_t time, |
|
|
|
struct input *input, uint32_t time, |
|
|
|
uint32_t button, |
|
|
|
uint32_t button, |
|
|
|
enum wl_pointer_button_state state, void *data); |
|
|
|
enum wl_pointer_button_state state, void *data); |
|
|
|
|
|
|
|
static int text_entry_motion_handler(struct widget *widget, |
|
|
|
|
|
|
|
struct input *input, uint32_t time, |
|
|
|
|
|
|
|
float x, float y, void *data); |
|
|
|
static void text_entry_insert_at_cursor(struct text_entry *entry, const char *text, |
|
|
|
static void text_entry_insert_at_cursor(struct text_entry *entry, const char *text, |
|
|
|
int32_t cursor, int32_t anchor); |
|
|
|
int32_t cursor, int32_t anchor); |
|
|
|
static void text_entry_set_preedit(struct text_entry *entry, |
|
|
|
static void text_entry_set_preedit(struct text_entry *entry, |
|
|
@ -472,6 +477,7 @@ text_entry_create(struct editor *editor, const char *text) |
|
|
|
|
|
|
|
|
|
|
|
widget_set_redraw_handler(entry->widget, text_entry_redraw_handler); |
|
|
|
widget_set_redraw_handler(entry->widget, text_entry_redraw_handler); |
|
|
|
widget_set_button_handler(entry->widget, text_entry_button_handler); |
|
|
|
widget_set_button_handler(entry->widget, text_entry_button_handler); |
|
|
|
|
|
|
|
widget_set_motion_handler(entry->widget, text_entry_motion_handler); |
|
|
|
|
|
|
|
|
|
|
|
return entry; |
|
|
|
return entry; |
|
|
|
} |
|
|
|
} |
|
|
@ -772,42 +778,42 @@ text_entry_try_invoke_preedit_action(struct text_entry *entry, |
|
|
|
return 1; |
|
|
|
return 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static bool |
|
|
|
|
|
|
|
text_entry_has_preedit(struct text_entry *entry) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
return entry->preedit.text && (strlen(entry->preedit.text) > 0); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void |
|
|
|
static void |
|
|
|
text_entry_set_cursor_position(struct text_entry *entry, |
|
|
|
text_entry_set_cursor_position(struct text_entry *entry, |
|
|
|
int32_t x, int32_t y) |
|
|
|
int32_t x, int32_t y, |
|
|
|
|
|
|
|
bool move_anchor) |
|
|
|
{ |
|
|
|
{ |
|
|
|
int index, trailing; |
|
|
|
int index, trailing; |
|
|
|
const char *text; |
|
|
|
const char *text; |
|
|
|
|
|
|
|
uint32_t cursor; |
|
|
|
text_entry_commit_and_reset(entry); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pango_layout_xy_to_index(entry->layout, |
|
|
|
pango_layout_xy_to_index(entry->layout, |
|
|
|
x * PANGO_SCALE, y * PANGO_SCALE, |
|
|
|
x * PANGO_SCALE, y * PANGO_SCALE, |
|
|
|
&index, &trailing); |
|
|
|
&index, &trailing); |
|
|
|
|
|
|
|
|
|
|
|
text = pango_layout_get_text(entry->layout); |
|
|
|
text = pango_layout_get_text(entry->layout); |
|
|
|
entry->cursor = g_utf8_offset_to_pointer(text + index, trailing) - text; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
text_entry_update_layout(entry); |
|
|
|
cursor = g_utf8_offset_to_pointer(text + index, trailing) - text; |
|
|
|
|
|
|
|
|
|
|
|
widget_schedule_redraw(entry->widget); |
|
|
|
if (move_anchor) |
|
|
|
|
|
|
|
entry->anchor = cursor; |
|
|
|
|
|
|
|
|
|
|
|
text_entry_update(entry); |
|
|
|
if (text_entry_has_preedit(entry)) { |
|
|
|
} |
|
|
|
text_entry_commit_and_reset(entry); |
|
|
|
|
|
|
|
|
|
|
|
static void |
|
|
|
assert(!text_entry_has_preedit(entry)); |
|
|
|
text_entry_set_anchor_position(struct text_entry *entry, |
|
|
|
} |
|
|
|
int32_t x, int32_t y) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
int index, trailing; |
|
|
|
|
|
|
|
const char *text; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pango_layout_xy_to_index(entry->layout, |
|
|
|
if (entry->cursor == cursor) |
|
|
|
x * PANGO_SCALE, y * PANGO_SCALE, |
|
|
|
return; |
|
|
|
&index, &trailing); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
text = pango_layout_get_text(entry->layout); |
|
|
|
entry->cursor = cursor; |
|
|
|
entry->anchor = g_utf8_offset_to_pointer(text + index, trailing) - text; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
text_entry_update_layout(entry); |
|
|
|
text_entry_update_layout(entry); |
|
|
|
|
|
|
|
|
|
|
@ -967,11 +973,16 @@ text_entry_motion_handler(struct widget *widget, |
|
|
|
struct text_entry *entry = data; |
|
|
|
struct text_entry *entry = data; |
|
|
|
struct rectangle allocation; |
|
|
|
struct rectangle allocation; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!entry->button_pressed) { |
|
|
|
|
|
|
|
return CURSOR_IBEAM; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
widget_get_allocation(entry->widget, &allocation); |
|
|
|
widget_get_allocation(entry->widget, &allocation); |
|
|
|
|
|
|
|
|
|
|
|
text_entry_set_cursor_position(entry, |
|
|
|
text_entry_set_cursor_position(entry, |
|
|
|
x - allocation.x - text_offset_left, |
|
|
|
x - allocation.x - text_offset_left, |
|
|
|
y - allocation.y - text_offset_left); |
|
|
|
y - allocation.y - text_offset_left, |
|
|
|
|
|
|
|
false); |
|
|
|
|
|
|
|
|
|
|
|
return CURSOR_IBEAM; |
|
|
|
return CURSOR_IBEAM; |
|
|
|
} |
|
|
|
} |
|
|
@ -996,28 +1007,29 @@ text_entry_button_handler(struct widget *widget, |
|
|
|
|
|
|
|
|
|
|
|
editor = window_get_user_data(entry->window); |
|
|
|
editor = window_get_user_data(entry->window); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (button == BTN_LEFT) { |
|
|
|
|
|
|
|
entry->button_pressed = (state == WL_POINTER_BUTTON_STATE_PRESSED); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (state == WL_POINTER_BUTTON_STATE_PRESSED) |
|
|
|
|
|
|
|
input_grab(input, entry->widget, button); |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
input_ungrab(input); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (text_entry_has_preedit(entry)) { |
|
|
|
result = text_entry_try_invoke_preedit_action(entry, x, y, button, state); |
|
|
|
result = text_entry_try_invoke_preedit_action(entry, x, y, button, state); |
|
|
|
|
|
|
|
|
|
|
|
if (result) |
|
|
|
if (result) |
|
|
|
return; |
|
|
|
return; |
|
|
|
|
|
|
|
|
|
|
|
if (button != BTN_LEFT) { |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
text_entry_set_cursor_position(entry, x, y); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (state == WL_POINTER_BUTTON_STATE_PRESSED) { |
|
|
|
if (state == WL_POINTER_BUTTON_STATE_PRESSED) { |
|
|
|
struct wl_seat *seat = input_get_seat(input); |
|
|
|
struct wl_seat *seat = input_get_seat(input); |
|
|
|
|
|
|
|
|
|
|
|
text_entry_activate(entry, seat); |
|
|
|
text_entry_activate(entry, seat); |
|
|
|
editor->active_entry = entry; |
|
|
|
editor->active_entry = entry; |
|
|
|
|
|
|
|
|
|
|
|
text_entry_set_anchor_position(entry, x, y); |
|
|
|
text_entry_set_cursor_position(entry, x, y, true); |
|
|
|
|
|
|
|
|
|
|
|
widget_set_motion_handler(entry->widget, text_entry_motion_handler); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
widget_set_motion_handler(entry->widget, NULL); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|