efl/src/modules/ecore_imf/wayland/wayland_imcontext.c

1109 lines
33 KiB
C

/*
* Copyright © 2012, 2013 Intel Corporation
*
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee, provided
* that the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of the copyright holders not be used in
* advertising or publicity pertaining to distribution of the software
* without specific, written prior permission. The copyright holders make
* no representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied warranty.
*
* THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
* CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <Ecore.h>
#include <Ecore_Evas.h>
#include <Ecore_Input.h>
#include "wayland_imcontext.h"
#define HIDE_TIMER_INTERVAL 0.05
static Eina_Bool _clear_hide_timer(void);
static Ecore_Timer *_hide_timer = NULL;
struct _WaylandIMContext
{
Ecore_IMF_Context *ctx;
struct zwp_text_input_manager_v1 *text_input_manager;
struct zwp_text_input_v1 *text_input;
Ecore_Wl2_Window *window;
Ecore_Wl2_Input *input;
Evas *canvas;
char *preedit_text;
char *preedit_commit;
char *language;
Eina_List *preedit_attrs;
int32_t preedit_cursor;
struct
{
Eina_List *attrs;
int32_t cursor;
} pending_preedit;
struct
{
int32_t cursor;
int32_t anchor;
uint32_t delete_index;
uint32_t delete_length;
} pending_commit;
struct
{
int x;
int y;
int width;
int height;
Eina_Bool do_set : 1;
} cursor_location;
xkb_mod_mask_t control_mask;
xkb_mod_mask_t alt_mask;
xkb_mod_mask_t shift_mask;
uint32_t serial;
uint32_t reset_serial;
uint32_t content_purpose;
uint32_t content_hint;
};
static unsigned int
utf8_offset_to_characters(const char *str, int offset)
{
int index = 0;
unsigned int i = 0;
for (; index < offset; i++)
{
if (eina_unicode_utf8_next_get(str, &index) == 0)
break;
}
return i;
}
static void
update_state(WaylandIMContext *imcontext)
{
char *surrounding = NULL;
int cursor_pos;
Ecore_Evas *ee;
int canvas_x = 0, canvas_y = 0;
Eina_Bool changed = EINA_FALSE;
if (!imcontext->ctx)
return;
/* cursor_pos is a byte index */
if (ecore_imf_context_surrounding_get(imcontext->ctx, &surrounding, &cursor_pos))
{
if (imcontext->text_input)
{
zwp_text_input_v1_set_surrounding_text(imcontext->text_input,
surrounding,
cursor_pos, cursor_pos);
changed = EINA_TRUE;
}
if (surrounding)
free(surrounding);
}
if (imcontext->canvas)
{
ee = ecore_evas_ecore_evas_get(imcontext->canvas);
if (ee)
ecore_evas_geometry_get(ee, &canvas_x, &canvas_y, NULL, NULL);
}
EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, "canvas (x: %d, y: %d)",
canvas_x, canvas_y);
if (imcontext->text_input)
{
if (imcontext->cursor_location.do_set)
{
zwp_text_input_v1_set_cursor_rectangle(imcontext->text_input,
imcontext->cursor_location.x + canvas_x,
imcontext->cursor_location.y + canvas_y,
imcontext->cursor_location.width,
imcontext->cursor_location.height);
imcontext->cursor_location.do_set = EINA_FALSE;
changed = EINA_TRUE;
}
}
if (changed)
zwp_text_input_v1_commit_state(imcontext->text_input, ++imcontext->serial);
_clear_hide_timer();
}
static Eina_Bool
_clear_hide_timer(void)
{
if (_hide_timer)
{
ecore_timer_del(_hide_timer);
_hide_timer = NULL;
return EINA_TRUE;
}
return EINA_FALSE;
}
static void
_send_input_panel_hide_request(Ecore_IMF_Context *ctx)
{
WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
if (imcontext && imcontext->text_input)
zwp_text_input_v1_hide_input_panel(imcontext->text_input);
}
static Eina_Bool
_hide_timer_handler(void *data)
{
Ecore_IMF_Context *ctx = (Ecore_IMF_Context *)data;
_send_input_panel_hide_request(ctx);
_hide_timer = NULL;
return ECORE_CALLBACK_CANCEL;
}
static void
_input_panel_hide_timer_start(void *data)
{
if (!_hide_timer)
{
_hide_timer =
ecore_timer_add(HIDE_TIMER_INTERVAL, _hide_timer_handler, data);
}
}
static void
_input_panel_hide(Ecore_IMF_Context *ctx, Eina_Bool instant)
{
if (instant || (_hide_timer && ecore_timer_pending_get(_hide_timer) <= 0.0))
{
_clear_hide_timer();
_send_input_panel_hide_request(ctx);
}
else
{
_input_panel_hide_timer_start(ctx);
}
}
static Eina_Bool
check_serial(WaylandIMContext *imcontext, uint32_t serial)
{
Ecore_IMF_Preedit_Attr *attr;
if ((imcontext->serial - serial) >
(imcontext->serial - imcontext->reset_serial))
{
EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom,
"outdated serial: %u, current: %u, reset: %u",
serial, imcontext->serial, imcontext->reset_serial);
/* Clear pending data */
imcontext->pending_commit.delete_index = 0;
imcontext->pending_commit.delete_length = 0;
imcontext->pending_commit.cursor = 0;
imcontext->pending_commit.anchor = 0;
imcontext->pending_preedit.cursor = 0;
if (imcontext->pending_preedit.attrs)
{
EINA_LIST_FREE(imcontext->pending_preedit.attrs, attr) free(attr);
imcontext->pending_preedit.attrs = NULL;
}
return EINA_FALSE;
}
return EINA_TRUE;
}
static void
clear_preedit(WaylandIMContext *imcontext)
{
Ecore_IMF_Preedit_Attr *attr = NULL;
imcontext->preedit_cursor = 0;
if (imcontext->preedit_text)
{
free(imcontext->preedit_text);
imcontext->preedit_text = NULL;
}
if (imcontext->preedit_commit)
{
free(imcontext->preedit_commit);
imcontext->preedit_commit = NULL;
}
if (imcontext->preedit_attrs)
{
EINA_LIST_FREE(imcontext->preedit_attrs, attr)
free(attr);
}
imcontext->preedit_attrs = NULL;
}
static void
text_input_commit_string(void *data,
struct zwp_text_input_v1 *text_input EINA_UNUSED,
uint32_t serial, const char *text)
{
WaylandIMContext *imcontext = (WaylandIMContext *)data;
Eina_Bool old_preedit = EINA_FALSE;
char *surrounding = NULL;
int cursor_pos, cursor;
Ecore_IMF_Event_Delete_Surrounding ev;
EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom,
"commit event (text: `%s', current pre-edit: `%s')",
text,
imcontext->preedit_text ? imcontext->preedit_text : "");
old_preedit =
imcontext->preedit_text && strlen(imcontext->preedit_text) > 0;
if (!imcontext->ctx)
return;
if (!check_serial(imcontext, serial))
return;
if (old_preedit)
{
ecore_imf_context_event_callback_call(imcontext->ctx,
ECORE_IMF_CALLBACK_PREEDIT_END,
NULL);
}
clear_preedit(imcontext);
if (imcontext->pending_commit.delete_length > 0)
{
/* cursor_pos is a byte index */
if (ecore_imf_context_surrounding_get(imcontext->ctx, &surrounding,
&cursor_pos))
{
ev.ctx = imcontext->ctx;
/* offset and n_chars are in characters */
ev.offset = utf8_offset_to_characters(surrounding, cursor_pos + imcontext->pending_commit.delete_index);
ev.n_chars = utf8_offset_to_characters(surrounding,
cursor_pos + imcontext->pending_commit.delete_index + imcontext->pending_commit.delete_length) - ev.offset;
/* cursor in characters */
cursor = utf8_offset_to_characters(surrounding, cursor_pos);
ev.offset -= cursor;
EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom,
"delete on commit (text: `%s', offset `%d', length: `%d')",
surrounding, ev.offset, ev.n_chars);
if (surrounding)
free(surrounding);
ecore_imf_context_event_callback_call(imcontext->ctx, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, &ev);
}
}
imcontext->pending_commit.delete_index = 0;
imcontext->pending_commit.delete_length = 0;
imcontext->pending_commit.cursor = 0;
imcontext->pending_commit.anchor = 0;
ecore_imf_context_event_callback_call(imcontext->ctx, ECORE_IMF_CALLBACK_COMMIT, (void *)text);
}
static void
commit_preedit(WaylandIMContext *imcontext)
{
if (!imcontext->preedit_commit)
return;
if (!imcontext->ctx)
return;
ecore_imf_context_event_callback_call(imcontext->ctx,
ECORE_IMF_CALLBACK_PREEDIT_CHANGED,
NULL);
ecore_imf_context_event_callback_call(imcontext->ctx,
ECORE_IMF_CALLBACK_PREEDIT_END, NULL);
ecore_imf_context_event_callback_call(imcontext->ctx,
ECORE_IMF_CALLBACK_COMMIT,
(void *)imcontext->preedit_commit);
}
static void
set_focus(Ecore_IMF_Context *ctx)
{
WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
Ecore_Wl2_Input *input;
input = ecore_wl2_display_input_find_by_name(ecore_wl2_window_display_get(imcontext->window), "default");
if (!input)
return;
struct wl_seat *seat = ecore_wl2_input_seat_get(input);
if (!seat)
return;
imcontext->input = input;
zwp_text_input_v1_activate(imcontext->text_input, seat,
ecore_wl2_window_surface_get(imcontext->window));
}
static Eina_Bool
show_input_panel(Ecore_IMF_Context *ctx)
{
WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
char *surrounding = NULL;
int cursor_pos;
if ((!imcontext) || (!imcontext->window) || (!imcontext->text_input))
return EINA_FALSE;
if (!imcontext->input)
set_focus(ctx);
_clear_hide_timer();
zwp_text_input_v1_set_content_type(imcontext->text_input,
imcontext->content_hint,
imcontext->content_purpose);
if (ecore_imf_context_surrounding_get(imcontext->ctx, &surrounding, &cursor_pos))
{
if (imcontext->text_input)
zwp_text_input_v1_set_surrounding_text(imcontext->text_input, surrounding,
cursor_pos, cursor_pos);
if (surrounding)
{
free(surrounding);
surrounding = NULL;
}
}
zwp_text_input_v1_show_input_panel(imcontext->text_input);
return EINA_TRUE;
}
static void
text_input_preedit_string(void *data,
struct zwp_text_input_v1 *text_input EINA_UNUSED,
uint32_t serial, const char *text, const char *commit)
{
WaylandIMContext *imcontext = (WaylandIMContext *)data;
Eina_Bool old_preedit = EINA_FALSE;
EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom,
"preedit event (text: `%s', current pre-edit: `%s')",
text,
imcontext->preedit_text ? imcontext->preedit_text : "");
if (!check_serial(imcontext, serial))
return;
old_preedit =
imcontext->preedit_text && strlen(imcontext->preedit_text) > 0;
clear_preedit(imcontext);
imcontext->preedit_text = strdup(text);
imcontext->preedit_commit = strdup(commit);
imcontext->preedit_cursor =
utf8_offset_to_characters(text, imcontext->pending_preedit.cursor);
imcontext->preedit_attrs = imcontext->pending_preedit.attrs;
imcontext->pending_preedit.attrs = NULL;
if (!old_preedit)
{
ecore_imf_context_event_callback_call(imcontext->ctx,
ECORE_IMF_CALLBACK_PREEDIT_START,
NULL);
}
ecore_imf_context_event_callback_call(imcontext->ctx,
ECORE_IMF_CALLBACK_PREEDIT_CHANGED,
NULL);
if (imcontext->preedit_text && strlen(imcontext->preedit_text) == 0)
{
ecore_imf_context_event_callback_call(imcontext->ctx,
ECORE_IMF_CALLBACK_PREEDIT_END,
NULL);
}
}
static void
text_input_delete_surrounding_text(void *data,
struct zwp_text_input_v1 *text_input EINA_UNUSED,
int32_t index, uint32_t length)
{
WaylandIMContext *imcontext = (WaylandIMContext *)data;
Ecore_IMF_Event_Delete_Surrounding ev;
EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom,
"delete surrounding text (index: %d, length: %u)",
index, length);
imcontext->pending_commit.delete_index = ev.offset = index;
imcontext->pending_commit.delete_length = ev.n_chars = length;
ecore_imf_context_event_callback_call(imcontext->ctx, ECORE_IMF_CALLBACK_DELETE_SURROUNDING, &ev);
}
static void
text_input_cursor_position(void *data,
struct zwp_text_input_v1 *text_input EINA_UNUSED,
int32_t index, int32_t anchor)
{
WaylandIMContext *imcontext = (WaylandIMContext *)data;
EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom,
"cursor_position for next commit (index: %d, anchor: %d)",
index, anchor);
imcontext->pending_commit.cursor = index;
imcontext->pending_commit.anchor = anchor;
}
static void
text_input_preedit_styling(void *data,
struct zwp_text_input_v1 *text_input EINA_UNUSED,
uint32_t index, uint32_t length, uint32_t style)
{
WaylandIMContext *imcontext = (WaylandIMContext *)data;
Ecore_IMF_Preedit_Attr *attr = calloc(1, sizeof(*attr));
if (!attr) return;
switch (style)
{
case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_DEFAULT:
case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_UNDERLINE:
case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_INCORRECT:
case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_HIGHLIGHT:
case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_ACTIVE:
case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_INACTIVE:
attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB1;
break;
case ZWP_TEXT_INPUT_V1_PREEDIT_STYLE_SELECTION:
attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB2;
break;
default:
attr->preedit_type = ECORE_IMF_PREEDIT_TYPE_SUB1;
break;
}
attr->start_index = index;
attr->end_index = index + length;
imcontext->pending_preedit.attrs =
eina_list_append(imcontext->pending_preedit.attrs, attr);
}
static void
text_input_preedit_cursor(void *data,
struct zwp_text_input_v1 *text_input EINA_UNUSED,
int32_t index)
{
WaylandIMContext *imcontext = (WaylandIMContext *)data;
imcontext->pending_preedit.cursor = index;
}
static xkb_mod_index_t
modifiers_get_index(struct wl_array *modifiers_map, const char *name)
{
xkb_mod_index_t index = 0;
char *p = modifiers_map->data;
while ((const char *)p < ((const char *)modifiers_map->data + modifiers_map->size))
{
if (strcmp(p, name) == 0)
return index;
index++;
p += strlen(p) + 1;
}
return XKB_MOD_INVALID;
}
static xkb_mod_mask_t
modifiers_get_mask(struct wl_array *modifiers_map, const char *name)
{
xkb_mod_index_t index = modifiers_get_index(modifiers_map, name);
if (index == XKB_MOD_INVALID)
return XKB_MOD_INVALID;
return 1 << index;
}
static void
text_input_modifiers_map(void *data,
struct zwp_text_input_v1 *text_input EINA_UNUSED,
struct wl_array *map)
{
WaylandIMContext *imcontext = (WaylandIMContext *)data;
imcontext->shift_mask = modifiers_get_mask(map, "Shift");
imcontext->control_mask = modifiers_get_mask(map, "Control");
imcontext->alt_mask = modifiers_get_mask(map, "Mod1");
}
static void
text_input_keysym(void *data,
struct zwp_text_input_v1 *text_input EINA_UNUSED,
uint32_t serial EINA_UNUSED, uint32_t time, uint32_t sym,
uint32_t state, uint32_t modifiers)
{
WaylandIMContext *imcontext = (WaylandIMContext *)data;
char string[32], key[32], keyname[32];
Ecore_Event_Key *e;
memset(key, 0, sizeof(key));
xkb_keysym_get_name(sym, key, sizeof(key));
memset(keyname, 0, sizeof(keyname));
xkb_keysym_get_name(sym, keyname, sizeof(keyname));
if (keyname[0] == '\0')
snprintf(keyname, sizeof(keyname), "Keysym-%u", sym);
memset(string, 0, sizeof(string));
if (!xkb_keysym_to_utf8(sym, string, 32)) return;
EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom,
"key event (key: %s)",
keyname);
e = calloc(1, sizeof(Ecore_Event_Key) + strlen(key) + strlen(keyname) +
strlen(string) + 3);
if (!e) return;
e->keyname = (char *)(e + 1);
e->key = e->keyname + strlen(keyname) + 1;
e->string = e->key + strlen(key) + 1;
e->compose = e->string;
strcpy((char *)e->keyname, keyname);
strcpy((char *)e->key, key);
strcpy((char *)e->string, string);
e->window = (Ecore_Window)imcontext->window;
e->event_window = (Ecore_Window)imcontext->window;
e->timestamp = time;
e->modifiers = 0;
if (modifiers & imcontext->shift_mask)
e->modifiers |= ECORE_EVENT_MODIFIER_SHIFT;
if (modifiers & imcontext->control_mask)
e->modifiers |= ECORE_EVENT_MODIFIER_CTRL;
if (modifiers & imcontext->alt_mask)
e->modifiers |= ECORE_EVENT_MODIFIER_ALT;
if (state)
ecore_event_add(ECORE_EVENT_KEY_DOWN, e, NULL, NULL);
else
ecore_event_add(ECORE_EVENT_KEY_UP, e, NULL, NULL);
}
static void
text_input_enter(void *data,
struct zwp_text_input_v1 *text_input EINA_UNUSED,
struct wl_surface *surface EINA_UNUSED)
{
WaylandIMContext *imcontext = (WaylandIMContext *)data;
update_state(imcontext);
imcontext->reset_serial = imcontext->serial;
}
static void
text_input_leave(void *data,
struct zwp_text_input_v1 *text_input EINA_UNUSED)
{
WaylandIMContext *imcontext = (WaylandIMContext *)data;
/* clear preedit */
commit_preedit(imcontext);
clear_preedit(imcontext);
}
static void
text_input_input_panel_state(void *data EINA_UNUSED,
struct zwp_text_input_v1 *text_input EINA_UNUSED,
uint32_t state EINA_UNUSED)
{
}
static void
text_input_language(void *data,
struct zwp_text_input_v1 *text_input EINA_UNUSED,
uint32_t serial EINA_UNUSED, const char *language)
{
WaylandIMContext *imcontext = (WaylandIMContext *)data;
Eina_Bool changed = EINA_FALSE;
if (!imcontext || !language) return;
if (imcontext->language)
{
if (strcmp(imcontext->language, language) != 0)
{
changed = EINA_TRUE;
free(imcontext->language);
}
}
else
changed = EINA_TRUE;
if (changed)
{
imcontext->language = strdup(language);
if (imcontext->ctx)
ecore_imf_context_input_panel_event_callback_call(imcontext->ctx, ECORE_IMF_INPUT_PANEL_LANGUAGE_EVENT, 0);
}
}
static void
text_input_text_direction(void *data EINA_UNUSED,
struct zwp_text_input_v1 *text_input EINA_UNUSED,
uint32_t serial EINA_UNUSED,
uint32_t direction EINA_UNUSED)
{
}
static const struct zwp_text_input_v1_listener text_input_listener =
{
text_input_enter,
text_input_leave,
text_input_modifiers_map,
text_input_input_panel_state,
text_input_preedit_string,
text_input_preedit_styling,
text_input_preedit_cursor,
text_input_commit_string,
text_input_cursor_position,
text_input_delete_surrounding_text,
text_input_keysym,
text_input_language,
text_input_text_direction
};
void
wayland_im_context_add(Ecore_IMF_Context *ctx)
{
WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, "context_add");
imcontext->ctx = ctx;
imcontext->text_input =
zwp_text_input_manager_v1_create_text_input(imcontext->text_input_manager);
if (imcontext->text_input)
zwp_text_input_v1_add_listener(imcontext->text_input,
&text_input_listener, imcontext);
}
void
wayland_im_context_del(Ecore_IMF_Context *ctx)
{
WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, "context_del");
_clear_hide_timer();
if (imcontext->language)
{
free(imcontext->language);
imcontext->language = NULL;
}
if (imcontext->text_input)
zwp_text_input_v1_destroy(imcontext->text_input);
clear_preedit(imcontext);
free(imcontext);
}
void
wayland_im_context_reset(Ecore_IMF_Context *ctx)
{
WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
commit_preedit(imcontext);
clear_preedit(imcontext);
if (imcontext->text_input)
zwp_text_input_v1_reset(imcontext->text_input);
update_state(imcontext);
imcontext->reset_serial = imcontext->serial;
}
void
wayland_im_context_focus_in(Ecore_IMF_Context *ctx)
{
EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, "focus-in");
set_focus(ctx);
if (ecore_imf_context_input_panel_enabled_get(ctx))
if (!ecore_imf_context_input_panel_show_on_demand_get (ctx))
show_input_panel(ctx);
}
void
wayland_im_context_focus_out(Ecore_IMF_Context *ctx)
{
WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, "focus-out");
if (!imcontext->input) return;
if (imcontext->text_input)
{
if (ecore_imf_context_input_panel_enabled_get(ctx))
_input_panel_hide(ctx, EINA_FALSE);
zwp_text_input_v1_deactivate(imcontext->text_input,
ecore_wl2_input_seat_get(imcontext->input));
}
imcontext->input = NULL;
}
void
wayland_im_context_preedit_string_get(Ecore_IMF_Context *ctx,
char **str, int *cursor_pos)
{
WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom,
"pre-edit string requested (preedit: `%s')",
imcontext->preedit_text ? imcontext->preedit_text : "");
if (str)
*str = strdup(imcontext->preedit_text ? imcontext->preedit_text : "");
if (cursor_pos)
*cursor_pos = imcontext->preedit_cursor;
}
void
wayland_im_context_preedit_string_with_attributes_get(Ecore_IMF_Context *ctx,
char **str,
Eina_List **attrs,
int *cursor_pos)
{
WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom,
"pre-edit string with attributes requested (preedit: `%s')",
imcontext->preedit_text ? imcontext->preedit_text : "");
if (str)
*str = strdup(imcontext->preedit_text ? imcontext->preedit_text : "");
if (attrs)
{
Eina_List *l;
Ecore_IMF_Preedit_Attr *a, *attr;
EINA_LIST_FOREACH(imcontext->preedit_attrs, l, a)
{
attr = malloc(sizeof(*attr));
if (attr)
{
attr = memcpy(attr, a, sizeof(*attr));
*attrs = eina_list_append(*attrs, attr);
}
}
}
if (cursor_pos)
*cursor_pos = imcontext->preedit_cursor;
}
void
wayland_im_context_cursor_position_set(Ecore_IMF_Context *ctx, int cursor_pos)
{
WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom,
"set cursor position (cursor: %d)",
cursor_pos);
update_state(imcontext);
}
void
wayland_im_context_use_preedit_set(Ecore_IMF_Context *ctx EINA_UNUSED,
Eina_Bool use_preedit EINA_UNUSED)
{
}
void
wayland_im_context_client_window_set(Ecore_IMF_Context *ctx, void *window)
{
WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, "client window set (window: %p)", window);
if (window != NULL)
{
imcontext->window = window;
}
}
void
wayland_im_context_client_canvas_set(Ecore_IMF_Context *ctx, void *canvas)
{
WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, "client canvas set (canvas: %p)", canvas);
if (canvas != NULL)
imcontext->canvas = canvas;
}
void
wayland_im_context_show(Ecore_IMF_Context *ctx)
{
EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, "context_show");
show_input_panel(ctx);
}
void
wayland_im_context_hide(Ecore_IMF_Context *ctx)
{
EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, "context_hide");
_input_panel_hide(ctx, EINA_FALSE);
}
Eina_Bool
wayland_im_context_filter_event(Ecore_IMF_Context *ctx,
Ecore_IMF_Event_Type type,
Ecore_IMF_Event *event EINA_UNUSED)
{
if (type == ECORE_IMF_EVENT_MOUSE_UP)
{
if (ecore_imf_context_input_panel_enabled_get(ctx))
show_input_panel(ctx);
}
return EINA_FALSE;
}
void
wayland_im_context_cursor_location_set(Ecore_IMF_Context *ctx, int x, int y, int width, int height)
{
WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, "cursor_location_set (x: %d, y: %d, w: %d, h: %d)", x, y, width, height);
if ((imcontext->cursor_location.x != x) ||
(imcontext->cursor_location.y != y) ||
(imcontext->cursor_location.width != width) ||
(imcontext->cursor_location.height != height))
{
imcontext->cursor_location.x = x;
imcontext->cursor_location.y = y;
imcontext->cursor_location.width = width;
imcontext->cursor_location.height = height;
imcontext->cursor_location.do_set = EINA_TRUE;
update_state(imcontext);
}
}
void
wayland_im_context_autocapital_type_set(Ecore_IMF_Context *ctx,
Ecore_IMF_Autocapital_Type autocapital_type)
{
WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
imcontext->content_hint &= ~(ZWP_TEXT_INPUT_V1_CONTENT_HINT_AUTO_CAPITALIZATION |
ZWP_TEXT_INPUT_V1_CONTENT_HINT_UPPERCASE |
ZWP_TEXT_INPUT_V1_CONTENT_HINT_LOWERCASE);
if (autocapital_type == ECORE_IMF_AUTOCAPITAL_TYPE_SENTENCE)
imcontext->content_hint |= ZWP_TEXT_INPUT_V1_CONTENT_HINT_AUTO_CAPITALIZATION;
else if (autocapital_type == ECORE_IMF_AUTOCAPITAL_TYPE_ALLCHARACTER)
imcontext->content_hint |= ZWP_TEXT_INPUT_V1_CONTENT_HINT_UPPERCASE;
else
imcontext->content_hint |= ZWP_TEXT_INPUT_V1_CONTENT_HINT_LOWERCASE;
}
void
wayland_im_context_input_panel_layout_set(Ecore_IMF_Context *ctx, Ecore_IMF_Input_Panel_Layout layout)
{
WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
switch (layout) {
case ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBER:
imcontext->content_purpose = ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_NUMBER;
break;
case ECORE_IMF_INPUT_PANEL_LAYOUT_EMAIL:
imcontext->content_purpose = ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_EMAIL;
break;
case ECORE_IMF_INPUT_PANEL_LAYOUT_URL:
imcontext->content_purpose = ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_URL;
break;
case ECORE_IMF_INPUT_PANEL_LAYOUT_PHONENUMBER:
imcontext->content_purpose = ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_PHONE;
break;
case ECORE_IMF_INPUT_PANEL_LAYOUT_IP:
imcontext->content_purpose = ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_NUMBER;
break;
case ECORE_IMF_INPUT_PANEL_LAYOUT_MONTH:
imcontext->content_purpose = ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_DATE;
break;
case ECORE_IMF_INPUT_PANEL_LAYOUT_NUMBERONLY:
imcontext->content_purpose = ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_DIGITS;
break;
case ECORE_IMF_INPUT_PANEL_LAYOUT_TERMINAL:
imcontext->content_purpose = ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_TERMINAL;
break;
case ECORE_IMF_INPUT_PANEL_LAYOUT_PASSWORD:
imcontext->content_purpose = ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_PASSWORD;
break;
case ECORE_IMF_INPUT_PANEL_LAYOUT_DATETIME:
imcontext->content_purpose = ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_DATETIME;
break;
default:
imcontext->content_purpose = ZWP_TEXT_INPUT_V1_CONTENT_PURPOSE_NORMAL;
break;
}
}
void
wayland_im_context_input_mode_set(Ecore_IMF_Context *ctx,
Ecore_IMF_Input_Mode input_mode)
{
WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
if (input_mode & ECORE_IMF_INPUT_MODE_INVISIBLE)
imcontext->content_hint |= ZWP_TEXT_INPUT_V1_CONTENT_HINT_PASSWORD;
else
imcontext->content_hint &= ~ZWP_TEXT_INPUT_V1_CONTENT_HINT_PASSWORD;
}
void
wayland_im_context_input_hint_set(Ecore_IMF_Context *ctx,
Ecore_IMF_Input_Hints input_hints)
{
WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
if (input_hints & ECORE_IMF_INPUT_HINT_AUTO_COMPLETE)
imcontext->content_hint |= ZWP_TEXT_INPUT_V1_CONTENT_HINT_AUTO_COMPLETION;
else
imcontext->content_hint &= ~ZWP_TEXT_INPUT_V1_CONTENT_HINT_AUTO_COMPLETION;
if (input_hints & ECORE_IMF_INPUT_HINT_SENSITIVE_DATA)
imcontext->content_hint |= ZWP_TEXT_INPUT_V1_CONTENT_HINT_SENSITIVE_DATA;
else
imcontext->content_hint &= ~ZWP_TEXT_INPUT_V1_CONTENT_HINT_SENSITIVE_DATA;
if (input_hints & ECORE_IMF_INPUT_HINT_MULTILINE)
imcontext->content_hint |= ZWP_TEXT_INPUT_V1_CONTENT_HINT_MULTILINE;
else
imcontext->content_hint &= ~ZWP_TEXT_INPUT_V1_CONTENT_HINT_MULTILINE;
}
void
wayland_im_context_input_panel_language_set(Ecore_IMF_Context *ctx,
Ecore_IMF_Input_Panel_Lang lang)
{
WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
if (lang == ECORE_IMF_INPUT_PANEL_LANG_ALPHABET)
imcontext->content_hint |= ZWP_TEXT_INPUT_V1_CONTENT_HINT_LATIN;
else
imcontext->content_hint &= ~ZWP_TEXT_INPUT_V1_CONTENT_HINT_LATIN;
}
void
wayland_im_context_input_panel_language_locale_get(Ecore_IMF_Context *ctx,
char **locale)
{
WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
if (locale)
*locale = strdup(imcontext->language ? imcontext->language : "");
}
void
wayland_im_context_prediction_allow_set(Ecore_IMF_Context *ctx,
Eina_Bool prediction)
{
WaylandIMContext *imcontext = (WaylandIMContext *)ecore_imf_context_data_get(ctx);
if (prediction)
imcontext->content_hint |= ZWP_TEXT_INPUT_V1_CONTENT_HINT_AUTO_COMPLETION;
else
imcontext->content_hint &= ~ZWP_TEXT_INPUT_V1_CONTENT_HINT_AUTO_COMPLETION;
}
WaylandIMContext *
wayland_im_context_new(struct zwp_text_input_manager_v1 *text_input_manager)
{
WaylandIMContext *context = calloc(1, sizeof(WaylandIMContext));
if (context)
{
EINA_LOG_DOM_INFO(_ecore_imf_wayland_log_dom, "new context created");
context->text_input_manager = text_input_manager;
}
return context;
}
/* vim:ts=8 sw=3 sts=3 expandtab cino=>5n-3f0^-2{2(0W1st0
*/