946 lines
29 KiB
C
946 lines
29 KiB
C
#define E_COMP_WL
|
|
#include "e.h"
|
|
#include "text-input-unstable-v1-server-protocol.h"
|
|
#include "input-method-unstable-v1-server-protocol.h"
|
|
|
|
typedef struct _E_Text_Input E_Text_Input;
|
|
typedef struct _E_Input_Method E_Input_Method;
|
|
typedef struct _E_Input_Method_Context E_Input_Method_Context;
|
|
|
|
struct _E_Text_Input
|
|
{
|
|
struct wl_resource *resource;
|
|
|
|
E_Client *ec;
|
|
Eina_List *input_methods;
|
|
Eina_Rectangle *cursor_rect;
|
|
Eina_Bool input_panel_visible;
|
|
};
|
|
|
|
struct _E_Input_Method
|
|
{
|
|
struct wl_resource *resource;
|
|
|
|
E_Text_Input *model;
|
|
E_Input_Method_Context *context;
|
|
Eina_List *handlers;
|
|
};
|
|
|
|
struct _E_Input_Method_Context
|
|
{
|
|
struct wl_resource *resource;
|
|
|
|
E_Text_Input *model;
|
|
E_Input_Method *input_method;
|
|
|
|
struct
|
|
{
|
|
struct wl_resource *resource;
|
|
Eina_List *handlers;
|
|
Eina_Bool grabbed;
|
|
} kbd;
|
|
};
|
|
|
|
static struct wl_global *text_input_manager_global;
|
|
|
|
static void
|
|
_e_text_input_event_visible_change_send(Eina_Bool visible)
|
|
{
|
|
E_Event_Text_Input_Panel_Visibility_Change *ev;
|
|
|
|
ev = E_NEW(E_Event_Text_Input_Panel_Visibility_Change, 1);
|
|
ev->visible = visible;
|
|
ecore_event_add(E_EVENT_TEXT_INPUT_PANEL_VISIBILITY_CHANGE, ev, NULL, NULL);
|
|
}
|
|
|
|
static void
|
|
_e_text_input_method_context_key_send(E_Input_Method_Context *context, unsigned int keycode, unsigned int timestamp, enum wl_keyboard_key_state state)
|
|
{
|
|
uint32_t serial, nk;
|
|
|
|
nk = keycode - 8;
|
|
|
|
serial = wl_display_next_serial(e_comp->wl_comp_data->wl.disp);
|
|
wl_keyboard_send_key(context->kbd.resource, serial, timestamp, nk, state);
|
|
}
|
|
|
|
static Eina_Bool
|
|
_e_text_input_method_context_ecore_cb_key_down(void *data, int ev_type EINA_UNUSED, Ecore_Event_Key *ev)
|
|
{
|
|
E_Input_Method_Context *context = data;
|
|
|
|
_e_text_input_method_context_key_send(context, ev->keycode, ev->timestamp,
|
|
WL_KEYBOARD_KEY_STATE_PRESSED);
|
|
|
|
return ECORE_CALLBACK_RENEW;
|
|
}
|
|
|
|
static Eina_Bool
|
|
_e_text_input_method_context_ecore_cb_key_up(void *data, int ev_type EINA_UNUSED, Ecore_Event_Key *ev)
|
|
{
|
|
E_Input_Method_Context *context = data;
|
|
|
|
_e_text_input_method_context_key_send(context, ev->keycode, ev->timestamp,
|
|
WL_KEYBOARD_KEY_STATE_RELEASED);
|
|
|
|
return ECORE_CALLBACK_RENEW;
|
|
}
|
|
|
|
static void
|
|
_e_text_input_method_context_grab_set(E_Input_Method_Context *context, Eina_Bool set)
|
|
{
|
|
if (set == context->kbd.grabbed)
|
|
return;
|
|
|
|
context->kbd.grabbed = set;
|
|
|
|
if (set)
|
|
{
|
|
E_LIST_HANDLER_APPEND(context->kbd.handlers, ECORE_EVENT_KEY_DOWN,
|
|
_e_text_input_method_context_ecore_cb_key_down,
|
|
context);
|
|
E_LIST_HANDLER_APPEND(context->kbd.handlers, ECORE_EVENT_KEY_UP,
|
|
_e_text_input_method_context_ecore_cb_key_up,
|
|
context);
|
|
|
|
e_comp_grab_input(0, 1);
|
|
}
|
|
else
|
|
{
|
|
E_FREE_LIST(context->kbd.handlers, ecore_event_handler_del);
|
|
e_comp_ungrab_input(0, 1);
|
|
}
|
|
}
|
|
|
|
static void
|
|
_e_text_input_deactivate(E_Text_Input *text_input, E_Input_Method *input_method)
|
|
{
|
|
if (input_method->model == text_input)
|
|
{
|
|
if ((input_method->context) && (input_method->resource))
|
|
{
|
|
if (input_method->context)
|
|
_e_text_input_method_context_grab_set(input_method->context,
|
|
EINA_FALSE);
|
|
|
|
zwp_input_method_v1_send_deactivate(input_method->resource,
|
|
input_method->context->resource);
|
|
}
|
|
|
|
input_method->model = NULL;
|
|
input_method->context = NULL;
|
|
|
|
text_input->input_methods = eina_list_remove(text_input->input_methods, input_method);
|
|
|
|
zwp_text_input_v1_send_leave(text_input->resource);
|
|
}
|
|
}
|
|
|
|
static void
|
|
_e_text_input_method_context_cb_destroy(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
|
|
{
|
|
wl_resource_destroy(resource);
|
|
}
|
|
|
|
static void
|
|
_e_text_input_method_context_cb_string_commit(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t serial, const char *text)
|
|
{
|
|
E_Input_Method_Context *context = wl_resource_get_user_data(resource);
|
|
|
|
if (!context)
|
|
{
|
|
wl_resource_post_error(resource,
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
"No Input Method Context For Resource");
|
|
return;
|
|
}
|
|
|
|
if (context->model)
|
|
zwp_text_input_v1_send_commit_string(context->model->resource,
|
|
serial, text);
|
|
}
|
|
|
|
static void
|
|
_e_text_input_method_context_cb_preedit_string(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t serial, const char *text, const char *commit)
|
|
{
|
|
E_Input_Method_Context *context = wl_resource_get_user_data(resource);
|
|
|
|
if (!context)
|
|
{
|
|
wl_resource_post_error(resource,
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
"No Input Method Context For Resource");
|
|
return;
|
|
}
|
|
|
|
if (context->model)
|
|
zwp_text_input_v1_send_preedit_string(context->model->resource,
|
|
serial, text, commit);
|
|
}
|
|
|
|
static void
|
|
_e_text_input_method_context_cb_preedit_styling(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t index, uint32_t length, uint32_t style)
|
|
{
|
|
E_Input_Method_Context *context = wl_resource_get_user_data(resource);
|
|
|
|
if (!context)
|
|
{
|
|
wl_resource_post_error(resource,
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
"No Input Method Context For Resource");
|
|
return;
|
|
}
|
|
|
|
if (context->model)
|
|
zwp_text_input_v1_send_preedit_styling(context->model->resource,
|
|
index, length, style);
|
|
}
|
|
|
|
static void
|
|
_e_text_input_method_context_cb_preedit_cursor(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, int32_t cursor)
|
|
{
|
|
E_Input_Method_Context *context = wl_resource_get_user_data(resource);
|
|
|
|
if (!context)
|
|
{
|
|
wl_resource_post_error(resource,
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
"No Input Method Context For Resource");
|
|
return;
|
|
}
|
|
|
|
if (context->model)
|
|
zwp_text_input_v1_send_preedit_cursor(context->model->resource,
|
|
cursor);
|
|
}
|
|
|
|
static void
|
|
_e_text_input_method_context_cb_surrounding_text_delete(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, int32_t index, uint32_t length)
|
|
{
|
|
E_Input_Method_Context *context = wl_resource_get_user_data(resource);
|
|
|
|
if (!context)
|
|
{
|
|
wl_resource_post_error(resource,
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
"No Input Method Context For Resource");
|
|
return;
|
|
}
|
|
|
|
if (context->model)
|
|
zwp_text_input_v1_send_delete_surrounding_text(context->model->resource,
|
|
index, length);
|
|
}
|
|
|
|
static void
|
|
_e_text_input_method_context_cb_cursor_position(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, int32_t index, int32_t anchor)
|
|
{
|
|
E_Input_Method_Context *context = wl_resource_get_user_data(resource);
|
|
|
|
if (!context)
|
|
{
|
|
wl_resource_post_error(resource,
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
"No Input Method Context For Resource");
|
|
return;
|
|
}
|
|
|
|
if (context->model)
|
|
zwp_text_input_v1_send_cursor_position(context->model->resource,
|
|
index, anchor);
|
|
}
|
|
|
|
static void
|
|
_e_text_input_method_context_cb_modifiers_map(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_array *map)
|
|
{
|
|
E_Input_Method_Context *context = wl_resource_get_user_data(resource);
|
|
|
|
if (!context)
|
|
{
|
|
wl_resource_post_error(resource,
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
"No Input Method Context For Resource");
|
|
return;
|
|
}
|
|
|
|
if (context->model)
|
|
zwp_text_input_v1_send_modifiers_map(context->model->resource, map);
|
|
}
|
|
|
|
static void
|
|
_e_text_input_method_context_cb_keysym(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t serial, uint32_t time, uint32_t sym, uint32_t state, uint32_t modifiers)
|
|
{
|
|
E_Input_Method_Context *context = wl_resource_get_user_data(resource);
|
|
|
|
if (!context)
|
|
{
|
|
wl_resource_post_error(resource,
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
"No Input Method Context For Resource");
|
|
return;
|
|
}
|
|
|
|
if (context->model)
|
|
zwp_text_input_v1_send_keysym(context->model->resource,
|
|
serial, time, sym, state, modifiers);
|
|
}
|
|
|
|
static void
|
|
_e_text_input_method_context_keyboard_unbind(struct wl_resource *resource)
|
|
{
|
|
E_Input_Method_Context *context;
|
|
|
|
context = wl_resource_get_user_data(resource);
|
|
|
|
_e_text_input_method_context_grab_set(context, EINA_FALSE);
|
|
|
|
context->kbd.resource = NULL;
|
|
}
|
|
|
|
static void
|
|
_e_text_input_method_context_cb_keyboard_grab(struct wl_client *client, struct wl_resource *resource, uint32_t id)
|
|
{
|
|
E_Input_Method_Context *context;
|
|
struct wl_resource *new_resource;
|
|
|
|
DBG("Input Method Context - grab keyboard %d", wl_resource_get_id(resource));
|
|
|
|
context = wl_resource_get_user_data(resource);
|
|
if (!context)
|
|
{
|
|
wl_resource_post_error(resource,
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
"No Input Method Context For Resource");
|
|
return;
|
|
}
|
|
|
|
new_resource = wl_resource_create(client, &wl_keyboard_interface, 1, id);
|
|
if (!new_resource)
|
|
{
|
|
wl_resource_post_no_memory(resource);
|
|
return;
|
|
}
|
|
|
|
wl_resource_set_implementation(new_resource, NULL, context,
|
|
_e_text_input_method_context_keyboard_unbind);
|
|
|
|
e_comp_wl_input_keymap_send(new_resource);
|
|
|
|
context->kbd.resource = new_resource;
|
|
|
|
_e_text_input_method_context_grab_set(context, EINA_TRUE);
|
|
}
|
|
|
|
static void
|
|
_e_text_input_method_context_cb_key(struct wl_client *client EINA_UNUSED, struct wl_resource *resource EINA_UNUSED, uint32_t serial EINA_UNUSED, uint32_t time EINA_UNUSED, uint32_t key EINA_UNUSED, uint32_t state_w EINA_UNUSED)
|
|
{
|
|
DBG("Input Method Context - key %d", wl_resource_get_id(resource));
|
|
}
|
|
|
|
static void
|
|
_e_text_input_method_context_cb_modifiers(struct wl_client *client EINA_UNUSED, struct wl_resource *resource EINA_UNUSED, uint32_t serial EINA_UNUSED, uint32_t mods_depressed EINA_UNUSED, uint32_t mods_latched EINA_UNUSED, uint32_t mods_locked EINA_UNUSED, uint32_t group EINA_UNUSED)
|
|
{
|
|
DBG("Input Method Context - modifiers %d", wl_resource_get_id(resource));
|
|
}
|
|
|
|
static void
|
|
_e_text_input_method_context_cb_language(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t serial, const char *language)
|
|
{
|
|
E_Input_Method_Context *context = wl_resource_get_user_data(resource);
|
|
|
|
if (!context)
|
|
{
|
|
wl_resource_post_error(resource,
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
"No Input Method Context For Resource");
|
|
return;
|
|
}
|
|
|
|
if (context->model)
|
|
zwp_text_input_v1_send_language(context->model->resource,
|
|
serial, language);
|
|
}
|
|
|
|
static void
|
|
_e_text_input_method_context_cb_text_direction(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t serial, uint32_t direction)
|
|
{
|
|
E_Input_Method_Context *context = wl_resource_get_user_data(resource);
|
|
|
|
if (!context)
|
|
{
|
|
wl_resource_post_error(resource,
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
"No Input Method Context For Resource");
|
|
return;
|
|
}
|
|
|
|
if (context->model)
|
|
zwp_text_input_v1_send_text_direction(context->model->resource,
|
|
serial, direction);
|
|
}
|
|
|
|
static const struct zwp_input_method_context_v1_interface _e_text_input_method_context_implementation = {
|
|
_e_text_input_method_context_cb_destroy,
|
|
_e_text_input_method_context_cb_string_commit,
|
|
_e_text_input_method_context_cb_preedit_string,
|
|
_e_text_input_method_context_cb_preedit_styling,
|
|
_e_text_input_method_context_cb_preedit_cursor,
|
|
_e_text_input_method_context_cb_surrounding_text_delete,
|
|
_e_text_input_method_context_cb_cursor_position,
|
|
_e_text_input_method_context_cb_modifiers_map,
|
|
_e_text_input_method_context_cb_keysym,
|
|
_e_text_input_method_context_cb_keyboard_grab,
|
|
_e_text_input_method_context_cb_key,
|
|
_e_text_input_method_context_cb_modifiers,
|
|
_e_text_input_method_context_cb_language,
|
|
_e_text_input_method_context_cb_text_direction
|
|
};
|
|
|
|
static void
|
|
_e_text_input_method_context_cb_resource_destroy(struct wl_resource *resource)
|
|
{
|
|
E_Input_Method_Context *context = wl_resource_get_user_data(resource);
|
|
|
|
if (!context)
|
|
{
|
|
wl_resource_post_error(resource,
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
"No Input Method Context For Resource");
|
|
return;
|
|
}
|
|
|
|
if (context->kbd.resource)
|
|
wl_resource_destroy(context->kbd.resource);
|
|
|
|
if ((context->input_method) &&
|
|
(context->input_method->context == context))
|
|
context->input_method->context = NULL;
|
|
|
|
free(context);
|
|
}
|
|
|
|
static Eina_Bool
|
|
_e_text_input_cb_event_client_focus_in(void *data, int type EINA_UNUSED, void *event)
|
|
{
|
|
E_Input_Method *input_method = data;
|
|
E_Event_Client *ev = event;
|
|
|
|
if (!input_method->model)
|
|
return ECORE_CALLBACK_RENEW;
|
|
|
|
if ((!ev->ec) ||
|
|
(input_method->model->ec != ev->ec))
|
|
{
|
|
_e_text_input_deactivate(input_method->model, input_method);
|
|
_e_text_input_event_visible_change_send(EINA_FALSE);
|
|
}
|
|
|
|
return ECORE_CALLBACK_RENEW;
|
|
}
|
|
|
|
static void
|
|
_e_text_input_cb_activate(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat, struct wl_resource *surface)
|
|
{
|
|
E_Text_Input *text_input;
|
|
E_Input_Method *input_method;
|
|
E_Text_Input *old;
|
|
E_Input_Method_Context *context;
|
|
|
|
text_input = wl_resource_get_user_data(resource);
|
|
if (!text_input)
|
|
{
|
|
wl_resource_post_error(resource,
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
"No Text Input For Resource");
|
|
return;
|
|
}
|
|
|
|
input_method =
|
|
wl_resource_get_user_data(e_comp->wl_comp_data->seat.im.resource);
|
|
if (!input_method)
|
|
{
|
|
wl_resource_post_error(seat,
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
"No Input Method For Seat");
|
|
return;
|
|
}
|
|
|
|
old = input_method->model;
|
|
if (old == text_input)
|
|
return;
|
|
|
|
if (old)
|
|
_e_text_input_deactivate(old, input_method);
|
|
|
|
input_method->model = text_input;
|
|
text_input->input_methods =
|
|
eina_list_append(text_input->input_methods, input_method);
|
|
|
|
text_input->ec = wl_resource_get_user_data(surface);
|
|
|
|
if (input_method->resource)
|
|
{
|
|
context = E_NEW(E_Input_Method_Context, 1);
|
|
if (!context)
|
|
{
|
|
wl_client_post_no_memory(client);
|
|
ERR("Could not allocate space for Input_Method_Context");
|
|
return;
|
|
}
|
|
|
|
context->resource =
|
|
wl_resource_create(wl_resource_get_client(input_method->resource),
|
|
&zwp_input_method_context_v1_interface, 1, 0);
|
|
wl_resource_set_implementation(context->resource,
|
|
&_e_text_input_method_context_implementation,
|
|
context, _e_text_input_method_context_cb_resource_destroy);
|
|
|
|
context->model = text_input;
|
|
context->input_method = input_method;
|
|
input_method->context = context;
|
|
|
|
zwp_input_method_v1_send_activate(input_method->resource, context->resource);
|
|
}
|
|
|
|
if (text_input->input_panel_visible)
|
|
_e_text_input_event_visible_change_send(EINA_TRUE);
|
|
|
|
zwp_text_input_v1_send_enter(text_input->resource, surface);
|
|
}
|
|
|
|
static void
|
|
_e_text_input_cb_deactivate(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, struct wl_resource *seat)
|
|
{
|
|
E_Text_Input *text_input;
|
|
E_Input_Method *input_method;
|
|
|
|
text_input = wl_resource_get_user_data(resource);
|
|
if (!text_input)
|
|
{
|
|
wl_resource_post_error(resource,
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
"No Text Input For Resource");
|
|
return;
|
|
}
|
|
|
|
input_method =
|
|
wl_resource_get_user_data(e_comp->wl_comp_data->seat.im.resource);
|
|
if (!input_method)
|
|
{
|
|
wl_resource_post_error(seat,
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
"No Input Method For Seat");
|
|
return;
|
|
}
|
|
|
|
_e_text_input_deactivate(text_input, input_method);
|
|
_e_text_input_event_visible_change_send(EINA_FALSE);
|
|
|
|
}
|
|
|
|
static void
|
|
_e_text_input_cb_input_panel_show(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
|
|
{
|
|
E_Text_Input *text_input = wl_resource_get_user_data(resource);
|
|
E_Input_Method *input_method;
|
|
Eina_List *l;
|
|
|
|
if (!text_input)
|
|
{
|
|
wl_resource_post_error(resource,
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
"No Text Input For Resource");
|
|
return;
|
|
}
|
|
|
|
text_input->input_panel_visible = 1;
|
|
|
|
EINA_LIST_FOREACH(text_input->input_methods, l, input_method)
|
|
{
|
|
if (input_method->model == text_input)
|
|
_e_text_input_event_visible_change_send(EINA_TRUE);
|
|
}
|
|
}
|
|
|
|
static void
|
|
_e_text_input_cb_input_panel_hide(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
|
|
{
|
|
E_Text_Input *text_input = wl_resource_get_user_data(resource);
|
|
E_Input_Method *input_method;
|
|
Eina_List *l;
|
|
|
|
if (!text_input)
|
|
{
|
|
wl_resource_post_error(resource,
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
"No Text Input For Resource");
|
|
return;
|
|
}
|
|
|
|
text_input->input_panel_visible = 0;
|
|
|
|
EINA_LIST_FOREACH(text_input->input_methods, l, input_method)
|
|
{
|
|
if (input_method->model == text_input)
|
|
_e_text_input_event_visible_change_send(EINA_FALSE);
|
|
}
|
|
}
|
|
|
|
static void
|
|
_e_text_input_cb_reset(struct wl_client *client EINA_UNUSED, struct wl_resource *resource)
|
|
{
|
|
E_Text_Input *text_input = wl_resource_get_user_data(resource);
|
|
E_Input_Method *input_method;
|
|
Eina_List *l;
|
|
|
|
if (!text_input)
|
|
{
|
|
wl_resource_post_error(resource,
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
"No Text Input For Resource");
|
|
return;
|
|
}
|
|
|
|
EINA_LIST_FOREACH(text_input->input_methods, l, input_method)
|
|
{
|
|
if (!input_method->context) continue;
|
|
zwp_input_method_context_v1_send_reset(input_method->context->resource);
|
|
}
|
|
}
|
|
|
|
static void
|
|
_e_text_input_cb_surrounding_text_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, const char *text, uint32_t cursor, uint32_t anchor)
|
|
{
|
|
E_Text_Input *text_input = wl_resource_get_user_data(resource);
|
|
E_Input_Method *input_method;
|
|
Eina_List *l;
|
|
|
|
if (!text_input)
|
|
{
|
|
wl_resource_post_error(resource,
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
"No Text Input For Resource");
|
|
return;
|
|
}
|
|
|
|
EINA_LIST_FOREACH(text_input->input_methods, l, input_method)
|
|
{
|
|
if (!input_method->context) continue;
|
|
zwp_input_method_context_v1_send_surrounding_text(input_method->context->resource,
|
|
text, cursor, anchor);
|
|
}
|
|
}
|
|
|
|
static void
|
|
_e_text_input_cb_content_type_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t hint, uint32_t purpose)
|
|
{
|
|
E_Text_Input *text_input = wl_resource_get_user_data(resource);
|
|
E_Input_Method *input_method;
|
|
Eina_List *l;
|
|
|
|
if (!text_input)
|
|
{
|
|
wl_resource_post_error(resource,
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
"No Text Input For Resource");
|
|
return;
|
|
}
|
|
|
|
EINA_LIST_FOREACH(text_input->input_methods, l, input_method)
|
|
{
|
|
if (!input_method->context) continue;
|
|
zwp_input_method_context_v1_send_content_type(input_method->context->resource,
|
|
hint, purpose);
|
|
}
|
|
}
|
|
|
|
static void
|
|
_e_text_input_cb_cursor_rectangle_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height)
|
|
{
|
|
E_Text_Input *text_input = wl_resource_get_user_data(resource);
|
|
|
|
if (!text_input)
|
|
{
|
|
wl_resource_post_error(resource,
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
"No Text Input For Resource");
|
|
return;
|
|
}
|
|
|
|
text_input->cursor_rect = eina_rectangle_new(x, y, width, height);
|
|
|
|
// TODO: issue event update input_panel
|
|
}
|
|
|
|
static void
|
|
_e_text_input_cb_preferred_language_set(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, const char *language)
|
|
{
|
|
E_Text_Input *text_input = wl_resource_get_user_data(resource);
|
|
E_Input_Method *input_method;
|
|
Eina_List *l;
|
|
|
|
if (!text_input)
|
|
{
|
|
wl_resource_post_error(resource,
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
"No Text Input For Resource");
|
|
return;
|
|
}
|
|
|
|
EINA_LIST_FOREACH(text_input->input_methods, l, input_method)
|
|
{
|
|
if (!input_method->context) continue;
|
|
zwp_input_method_context_v1_send_preferred_language(input_method->context->resource,
|
|
language);
|
|
}
|
|
}
|
|
|
|
static void
|
|
_e_text_input_cb_state_commit(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t serial)
|
|
{
|
|
E_Text_Input *text_input = wl_resource_get_user_data(resource);
|
|
E_Input_Method *input_method;
|
|
Eina_List *l;
|
|
|
|
if (!text_input)
|
|
{
|
|
wl_resource_post_error(resource,
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
"No Text Input For Resource");
|
|
return;
|
|
}
|
|
|
|
EINA_LIST_FOREACH(text_input->input_methods, l, input_method)
|
|
{
|
|
if (!input_method->context) continue;
|
|
zwp_input_method_context_v1_send_commit_state(input_method->context->resource, serial);
|
|
}
|
|
}
|
|
|
|
static void
|
|
_e_text_input_cb_action_invoke(struct wl_client *client EINA_UNUSED, struct wl_resource *resource, uint32_t button, uint32_t index)
|
|
{
|
|
E_Text_Input *text_input = wl_resource_get_user_data(resource);
|
|
E_Input_Method *input_method;
|
|
Eina_List *l;
|
|
|
|
if (!text_input)
|
|
{
|
|
wl_resource_post_error(resource,
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
"No Text Input For Resource");
|
|
return;
|
|
}
|
|
|
|
EINA_LIST_FOREACH(text_input->input_methods, l, input_method)
|
|
{
|
|
if (!input_method->context) continue;
|
|
zwp_input_method_context_v1_send_invoke_action(input_method->context->resource,
|
|
button, index);
|
|
}
|
|
}
|
|
|
|
static const struct zwp_text_input_v1_interface _e_text_input_implementation = {
|
|
_e_text_input_cb_activate,
|
|
_e_text_input_cb_deactivate,
|
|
_e_text_input_cb_input_panel_show,
|
|
_e_text_input_cb_input_panel_hide,
|
|
_e_text_input_cb_reset,
|
|
_e_text_input_cb_surrounding_text_set,
|
|
_e_text_input_cb_content_type_set,
|
|
_e_text_input_cb_cursor_rectangle_set,
|
|
_e_text_input_cb_preferred_language_set,
|
|
_e_text_input_cb_state_commit,
|
|
_e_text_input_cb_action_invoke
|
|
};
|
|
|
|
static void
|
|
_e_text_input_cb_destroy(struct wl_resource *resource)
|
|
{
|
|
E_Text_Input *text_input = wl_resource_get_user_data(resource);
|
|
E_Input_Method *input_method;
|
|
|
|
if (!text_input)
|
|
{
|
|
wl_resource_post_error(resource,
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
"No Text Input For Resource");
|
|
return;
|
|
}
|
|
|
|
EINA_LIST_FREE(text_input->input_methods, input_method)
|
|
_e_text_input_deactivate(text_input, input_method);
|
|
|
|
eina_rectangle_free(text_input->cursor_rect);
|
|
free(text_input);
|
|
}
|
|
|
|
static void
|
|
_e_text_input_manager_cb_text_input_create(struct wl_client *client, struct wl_resource *resource EINA_UNUSED, uint32_t id)
|
|
{
|
|
E_Text_Input *text_input;
|
|
|
|
text_input = E_NEW(E_Text_Input, 1);
|
|
if (!text_input)
|
|
{
|
|
wl_client_post_no_memory(client);
|
|
ERR("Could not allocate space for Text_Input");
|
|
return;
|
|
}
|
|
|
|
text_input->resource = wl_resource_create(client,
|
|
&zwp_text_input_v1_interface,
|
|
1, id);
|
|
if (!text_input->resource)
|
|
{
|
|
free(text_input);
|
|
wl_client_post_no_memory(client);
|
|
ERR("could not create wl_resource for text input");
|
|
return;
|
|
}
|
|
|
|
wl_resource_set_implementation(text_input->resource,
|
|
&_e_text_input_implementation,
|
|
text_input, _e_text_input_cb_destroy);
|
|
}
|
|
|
|
static const struct zwp_text_input_manager_v1_interface _e_text_input_manager_implementation = {
|
|
_e_text_input_manager_cb_text_input_create
|
|
};
|
|
|
|
static void
|
|
_e_text_cb_bind_text_input_manager(struct wl_client *client, void *data EINA_UNUSED, uint32_t version EINA_UNUSED, uint32_t id)
|
|
{
|
|
struct wl_resource *resource;
|
|
|
|
resource = wl_resource_create(client, &zwp_text_input_manager_v1_interface, 1, id);
|
|
if (!resource)
|
|
{
|
|
wl_client_post_no_memory(client);
|
|
ERR("could not create resource for text input manager");
|
|
return;
|
|
}
|
|
|
|
wl_resource_set_implementation(resource, &_e_text_input_manager_implementation, NULL, NULL);
|
|
}
|
|
|
|
static void
|
|
_e_text_input_method_cb_unbind(struct wl_resource *resource)
|
|
{
|
|
E_Input_Method *input_method;
|
|
|
|
e_comp->wl_comp_data->seat.im.resource = NULL;
|
|
|
|
input_method = wl_resource_get_user_data(resource);
|
|
if (!input_method)
|
|
{
|
|
wl_resource_post_error(resource,
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
"No Input Method For Resource");
|
|
return;
|
|
}
|
|
|
|
if (input_method->model)
|
|
_e_text_input_deactivate(input_method->model, input_method);
|
|
|
|
E_FREE_FUNC(input_method->handlers, ecore_event_handler_del);
|
|
|
|
input_method->resource = NULL;
|
|
input_method->context = NULL;
|
|
|
|
free(input_method);
|
|
}
|
|
|
|
static void
|
|
_e_text_cb_bind_input_method(struct wl_client *client, void *data EINA_UNUSED, uint32_t version EINA_UNUSED, uint32_t id)
|
|
{
|
|
E_Input_Method *input_method;
|
|
struct wl_resource *resource;
|
|
pid_t pid;
|
|
|
|
resource = wl_resource_create(client, &zwp_input_method_v1_interface, 1, id);
|
|
if (!resource)
|
|
{
|
|
wl_client_post_no_memory(client);
|
|
ERR("could not create wl_resource for input method");
|
|
return;
|
|
}
|
|
|
|
if (e_comp->wl_comp_data->seat.im.resource)
|
|
{
|
|
wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
"interface object already bound");
|
|
wl_resource_destroy(resource);
|
|
return;
|
|
}
|
|
|
|
wl_client_get_credentials(client, &pid, NULL, NULL);
|
|
if (pid != getpid())
|
|
{
|
|
ERR("Permission to bind input method denied");
|
|
wl_resource_post_error(resource,
|
|
WL_DISPLAY_ERROR_INVALID_OBJECT,
|
|
"permission to bind input_method denied");
|
|
wl_resource_destroy(resource);
|
|
return;
|
|
}
|
|
|
|
input_method = E_NEW(E_Input_Method, 1);
|
|
if (!input_method)
|
|
{
|
|
wl_client_post_no_memory(client);
|
|
wl_resource_destroy(resource);
|
|
ERR("Could not allocate space for Input_Method");
|
|
return;
|
|
}
|
|
|
|
wl_resource_set_implementation(resource, NULL, input_method,
|
|
_e_text_input_method_cb_unbind);
|
|
|
|
input_method->model = NULL;
|
|
input_method->context = NULL;
|
|
input_method->resource = resource;
|
|
|
|
e_comp->wl_comp_data->seat.im.resource = resource;
|
|
|
|
E_LIST_HANDLER_APPEND(input_method->handlers, E_EVENT_CLIENT_FOCUS_IN,
|
|
_e_text_input_cb_event_client_focus_in, input_method);
|
|
}
|
|
|
|
E_API E_Module_Api e_modapi = { E_MODULE_API_VERSION, "Wl_Text_Input" };
|
|
|
|
E_API void *
|
|
e_modapi_init(E_Module *m)
|
|
{
|
|
// FIXME: create only one input method object per seat.
|
|
e_comp->wl_comp_data->seat.im.global =
|
|
wl_global_create(e_comp->wl_comp_data->wl.disp, &zwp_input_method_v1_interface, 1,
|
|
NULL, _e_text_cb_bind_input_method);
|
|
if (!e_comp->wl_comp_data->seat.im.global)
|
|
{
|
|
ERR("failed to create wl_global for input method");
|
|
return NULL;
|
|
}
|
|
|
|
text_input_manager_global =
|
|
wl_global_create(e_comp->wl_comp_data->wl.disp, &zwp_text_input_manager_v1_interface, 1,
|
|
NULL, _e_text_cb_bind_text_input_manager);
|
|
if (!text_input_manager_global)
|
|
{
|
|
ERR("failed to create wl_global for text input manager");
|
|
E_FREE_FUNC(e_comp->wl_comp_data->seat.im.global, wl_global_destroy);
|
|
return NULL;
|
|
}
|
|
|
|
return m;
|
|
}
|
|
|
|
E_API int
|
|
e_modapi_shutdown(E_Module *m EINA_UNUSED)
|
|
{
|
|
E_FREE_FUNC(e_comp->wl_comp_data->seat.im.global, wl_global_destroy);
|
|
E_FREE_FUNC(text_input_manager_global, wl_global_destroy);
|
|
|
|
return 1;
|
|
}
|