From: Sungjin Park Date: Sat, 22 Apr 2023 07:06:04 +0000 (+0900) Subject: e_comp_wl & e_comp_wl_input: added pointer constraints feature X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=b79a00d55ba4e89d34c49eeba4194a2f476cd6b0;p=platform%2Fupstream%2Fenlightenment.git e_comp_wl & e_comp_wl_input: added pointer constraints feature Signed-off-by: Sungjin Park --- diff --git a/src/bin/e_comp_wl.c b/src/bin/e_comp_wl.c index d050953078..8ffd4d613f 100644 --- a/src/bin/e_comp_wl.c +++ b/src/bin/e_comp_wl.c @@ -656,6 +656,8 @@ _e_comp_wl_evas_cb_hide(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj EIN if (ec->comp_data->sub.below_obj) evas_object_hide(ec->comp_data->sub.below_obj); + + wl_signal_emit(&e_comp_wl->ptr_constraints.surface_unmap_signal, ec); } static void @@ -3428,6 +3430,7 @@ _e_comp_wl_compositor_cb_surface_create(struct wl_client *client, struct wl_reso ec->client.w = ec->client.h = 1; ec->comp_data->surface = res; ec->icccm.accepts_focus = 1; + wl_list_init(&ec->comp_data->pointer_constraints); } /* set reference to pixmap so we can fetch it later */ @@ -3921,6 +3924,7 @@ _e_comp_wl_client_cb_focus_set(void *data EINA_UNUSED, E_Client *ec) } e_comp_wl->kbd.focus = ec->comp_data->surface; + wl_signal_emit(&e_comp_wl->ptr_constraints.surface_focus_signal, ec); } static void @@ -4428,46 +4432,59 @@ _e_comp_wl_gl_shutdown(void) static Eina_Bool _e_comp_wl_cb_mouse_move_1st(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Event_Mouse_Move *ev) { - static int prev_x = 0; - static int prev_y = 0; + static int last_x = -1; + static int last_y = -1; static int saved_x = -1; static int saved_y = -1; - int dx; - int dy; + E_Client *focus = e_client_focused_get(); - dx = ev->x - prev_x; - dy = ev->y - prev_y; + if ((!e_comp_wl->ptr_constraints.activated) || + (!focus) || + (e_comp_wl->ptr_constraints.ec != focus)) + { + last_x = ev->x; + last_y = ev->y; - ERR("[_e_comp_wl_cb_mouse_move_1st] ev->x=%d, ev->y=%d, prev_x=%d, prev_y=%d, dx=%d, dy=%d", ev->x, ev->y, prev_x, prev_y, dx, dy); + if (saved_x != -1 || saved_y != -1) + { + e_input_device_pointer_warp(NULL, saved_x, saved_y); + last_x = saved_x; + last_y = saved_y; + saved_x = -1; + saved_y = -1; + } - prev_x = ev->x; - prev_y = ev->y; + return ECORE_CALLBACK_RENEW; + } - if (downKeycode) - { - E_Client *focus = e_client_focused_get(); - if (focus) - { - if (saved_x == -1 && saved_y == -1) - { - saved_x = ev->x; - saved_y = ev->y; - } + int dx; + int dy; - e_comp_wl_mouse_relative_motion_send(focus, dx, dy, dx, dy, NULL, 0); - return ECORE_CALLBACK_DONE; - } + if (saved_x == -1 || saved_y == -1) + { + saved_x = ev->x; + saved_y = ev->y; } - if (saved_x != -1 && saved_y != -1) + if (last_x < 0 || last_y < 0) { - e_input_device_pointer_warp(NULL, saved_x, saved_y); - saved_x = -1; - saved_y = -1; + last_x = ev->x; + last_y = ev->y; + return ECORE_CALLBACK_RENEW; } - return ECORE_CALLBACK_RENEW; + dx = ev->x - last_x; + dy = ev->y - last_y; + + ERR("[_e_comp_wl_cb_mouse_move_1st] ev->x=%d, ev->y=%d, last_x=%d, last_y=%d, dx=%d, dy=%d, saved_x=%d, saved_y=%d", + ev->x, ev->y, last_x, last_y, dx, dy, saved_x, saved_y); + e_comp_wl_mouse_relative_motion_send(focus, dx, dy, dx, dy, NULL, 0); + + last_x = ev->x; + last_y = ev->y; + + return ECORE_CALLBACK_DONE; } /* public functions */ diff --git a/src/bin/e_comp_wl.h b/src/bin/e_comp_wl.h index a12d36604d..6caac0cc78 100644 --- a/src/bin/e_comp_wl.h +++ b/src/bin/e_comp_wl.h @@ -48,6 +48,7 @@ typedef struct _E_Comp_Wl_Output E_Comp_Wl_Output; typedef struct _E_Comp_Wl_Intercept_Hook E_Comp_Wl_Intercept_Hook; typedef struct _E_Comp_Wl_Evas_Gl E_Comp_Wl_Evas_Gl; typedef struct _E_Comp_Wl_Seat E_Comp_Wl_Seat; +typedef struct _E_Comp_Wl_Pointer_Constraint E_Comp_Wl_Pointer_Constraint; typedef enum _E_Comp_Wl_Buffer_Type { @@ -242,19 +243,22 @@ struct _E_Comp_Wl_Data struct { Eina_List *resources; + Eina_List *manager_resources; E_Client *ec; - Eina_Bool enabled : 1; + Eina_Bool activated : 1; struct wl_global *global; - struct wl_resource *resource; } relative_ptr; struct { Eina_List *resources; E_Client *ec; - Eina_Bool enabled : 1; + Eina_Bool activated : 1; + struct wl_signal pointer_destroy_signal; + struct wl_signal surface_unmap_signal; + struct wl_signal surface_commit_signal; + struct wl_signal surface_focus_signal; struct wl_global *global; - struct wl_resource *resource; } ptr_constraints; struct @@ -514,6 +518,8 @@ struct _E_Comp_Wl_Client_Data } sh_v6; const char *role_name; + + struct wl_list pointer_constraints; }; struct _E_Comp_Wl_Output @@ -566,6 +572,46 @@ struct _E_Comp_Wl_Seat Eina_Bool is_first_resource : 1; }; +/* +typedef enum _E_Comp_Wl_Pointer_Constraint_Type +{ + E_COMP_WL_POINTER_CONSTRAINT_TYPE_NONE = 0, + E_COMP_WL_POINTER_CONSTRAINT_TYPE_LOCK = 1, + E_COMP_WL_POINTER_CONSTRAINT_TYPE_CONFINE = 2, +} E_Comp_Wl_Pointer_Constraint_Type; + +struct _E_Comp_Wl_Pointer_Constraint +{ + struct wl_list link; + + E_Client *ec; + struct wl_resource *surface; + struct wl_resource *resource; + struct wl_resource *pointer; + Eina_Bool active; + + E_Comp_Wl_Pointer_Constraint_Type type; + int lifetime; + + pixman_region32_t region; + pixman_region32_t region_pending; + Eina_Bool is_region_pending; + Eina_Bool has_region_set; + + wl_fixed_t hint_x; + wl_fixed_t hint_y; + wl_fixed_t hint_x_pending; + wl_fixed_t hint_y_pending; + Eina_Bool is_hint_pending; + Eina_Bool has_hint_set; + + struct wl_listener pointer_destroy_listener; + struct wl_listener surface_unmap_listener; + struct wl_listener surface_commit_listener; + struct wl_listener surface_activate_listener; +}; +*/ + EINTERN Eina_Bool e_comp_wl_init(void); EINTERN void e_comp_wl_shutdown(void); diff --git a/src/bin/e_comp_wl_input.c b/src/bin/e_comp_wl_input.c index 64b619e1e8..9f42239631 100644 --- a/src/bin/e_comp_wl_input.c +++ b/src/bin/e_comp_wl_input.c @@ -1,12 +1,55 @@ #define EXECUTIVE_MODE_ENABLED #include "e.h" #include +#include + +typedef struct _E_Comp_Wl_Pointer_Constraint E_Comp_Wl_Pointer_Constraint; + +typedef enum _E_Comp_Wl_Pointer_Constraint_Type +{ + E_COMP_WL_POINTER_CONSTRAINT_TYPE_NONE = 0, + E_COMP_WL_POINTER_CONSTRAINT_TYPE_LOCK = 1, + E_COMP_WL_POINTER_CONSTRAINT_TYPE_CONFINE = 2, +} E_Comp_Wl_Pointer_Constraint_Type; + +struct _E_Comp_Wl_Pointer_Constraint +{ + struct wl_list link; + + E_Client *ec; + struct wl_resource *surface; + struct wl_resource *resource; + struct wl_resource *pointer; + Eina_Bool active; + + E_Comp_Wl_Pointer_Constraint_Type type; + int lifetime; + + pixman_region32_t region; + pixman_region32_t region_pending; + Eina_Bool is_region_pending; + Eina_Bool has_region_set; + + wl_fixed_t hint_x; + wl_fixed_t hint_y; + wl_fixed_t hint_x_pending; + wl_fixed_t hint_y_pending; + Eina_Bool is_hint_pending; + Eina_Bool has_hint_set; + + struct wl_listener pointer_destroy_listener; + struct wl_listener surface_unmap_listener; + struct wl_listener surface_commit_listener; + struct wl_listener surface_focus_listener; +}; E_API int E_EVENT_TEXT_INPUT_PANEL_VISIBILITY_CHANGE = -1; static Eina_Bool dont_set_e_input_keymap = EINA_FALSE; static Eina_Bool dont_use_xkb_cache = EINA_FALSE; static Eina_Bool use_cache_keymap = EINA_FALSE; +static E_Comp_Wl_Hook *_surface_commit_hook = NULL; + /* default XKB values from enviroment variables */ static char *_env_e_default_xkb_rules = NULL; static char *_env_e_default_xkb_model = NULL; @@ -167,6 +210,8 @@ _e_comp_wl_input_cb_pointer_unbind(struct wl_resource *resource) { e_comp_wl->ptr.resources = eina_list_remove(e_comp_wl->ptr.resources, resource); + + wl_signal_emit(&e_comp_wl->ptr_constraints.pointer_destroy_signal, resource); } static void @@ -465,7 +510,8 @@ _e_comp_wl_cb_relative_pointer_manager_get_relative_pointer(struct wl_client *cl /* FIXME: must consider destroying relative pointer together when the wl_pointer is destroyed */ (void) pointer_resource; - wl_resource_set_implementation(res, &_e_relative_pointer_interface, NULL, _e_comp_wl_cb_unbind_relative_pointer); + wl_resource_set_implementation(res, &_e_relative_pointer_interface, + NULL, _e_comp_wl_cb_unbind_relative_pointer); } static const struct zwp_relative_pointer_manager_v1_interface _e_relative_pointer_manager_interface = { @@ -473,6 +519,15 @@ static const struct zwp_relative_pointer_manager_v1_interface _e_relative_pointe _e_comp_wl_cb_relative_pointer_manager_get_relative_pointer, }; +static void +_e_comp_wl_cb_unbind_relative_pointer_manager(struct wl_resource *resource) +{ + ERR("Unbind relative_pointer_manager: (resource: %u) (client: %p)", wl_resource_get_id(resource), wl_resource_get_client(resource)); + + e_comp_wl->relative_ptr.manager_resources = + eina_list_remove(e_comp_wl->relative_ptr.manager_resources, resource); +} + static void _e_comp_wl_input_cb_bind_relative_pointer_manager(struct wl_client *client, void *data EINA_UNUSED, uint32_t version, uint32_t id) { @@ -489,8 +544,588 @@ _e_comp_wl_input_cb_bind_relative_pointer_manager(struct wl_client *client, void DBG("Bind relative pointer: (resource:%u) (client: %p)", wl_resource_get_id(resource), client); - wl_resource_set_implementation(resource, &_e_relative_pointer_manager_interface, NULL, NULL); - //FIXME: consider to add unbind fucntion + e_comp_wl->relative_ptr.manager_resources = + eina_list_append(e_comp_wl->relative_ptr.manager_resources, resource); + wl_resource_set_implementation(resource, &_e_relative_pointer_manager_interface, + NULL, _e_comp_wl_cb_unbind_relative_pointer_manager); +} + +static void +_e_comp_wl_convert_eina_tiler_to_pixman_region32(const Eina_Tiler *tiler, + pixman_region32_t *region) +{ + Eina_Iterator *itr; + Eina_Rectangle *rect; + + itr = eina_tiler_iterator_new(tiler); + EINA_ITERATOR_FOREACH(itr, rect) + { + pixman_region32_union_rect(region, region, rect->x, rect->y, rect->w, rect->h); + } + eina_iterator_free(itr); +} + +static void +_e_comp_wl_pointer_constraint_notify_deactivated(E_Comp_Wl_Pointer_Constraint *constraint) +{ + struct wl_resource *resource = constraint->resource; + E_Comp_Wl_Pointer_Constraint_Type type = constraint->type; + + if (E_COMP_WL_POINTER_CONSTRAINT_TYPE_LOCK == type) + zwp_locked_pointer_v1_send_unlocked(resource); + else if (E_COMP_WL_POINTER_CONSTRAINT_TYPE_CONFINE == type) + zwp_confined_pointer_v1_send_unconfined(resource); + else + abort(); + + ERR("pointer constraint deactivated (type=%d, ec=%p)", constraint->type, constraint->ec); +} + +static void +_e_comp_wl_pointer_constraint_deactivate(E_Comp_Wl_Pointer_Constraint *constraint) +{ + constraint->active = EINA_FALSE; + e_comp_wl->ptr_constraints.activated = EINA_FALSE; + e_comp_wl->ptr_constraints.ec = NULL; + _e_comp_wl_pointer_constraint_notify_deactivated(constraint); + wl_list_remove(&constraint->surface_unmap_listener.link); + wl_list_init(&constraint->surface_unmap_listener.link); +} + +static void +_e_comp_wl_pointer_constraint_destroy(E_Comp_Wl_Pointer_Constraint *constraint) +{ + if (constraint->active) + _e_comp_wl_pointer_constraint_deactivate(constraint); + + wl_list_remove(&constraint->pointer_destroy_listener.link); + wl_list_remove(&constraint->surface_focus_listener.link); + wl_list_remove(&constraint->surface_unmap_listener.link); + wl_list_remove(&constraint->surface_commit_listener.link); + + wl_resource_set_user_data(constraint->resource, NULL); + pixman_region32_fini(&constraint->region); + wl_list_remove(&constraint->link); + + free(constraint); +} + +static Eina_Bool +_e_comp_wl_is_position_inside_constraint_region(E_Comp_Wl_Pointer_Constraint *constraint, + wl_fixed_t fx, + wl_fixed_t fy) +{ + //return EINA_TRUE here before using region provided from client + return EINA_TRUE; + + pixman_region32_t *region = &constraint->region; + pixman_region32_t cregion; + pixman_region32_t input_region; + + pixman_region32_init(&cregion); + pixman_region32_init(&input_region); + + //FIXME: get input_region from ec's input region (Eina_Tiler *tiler) + E_Client *ec = constraint->ec; + pixman_region32_init_rect(&input_region, 0, 0, ec->w, ec->h); + pixman_region32_intersect(&cregion, &input_region, region); + + Eina_Bool inside = pixman_region32_contains_point(&cregion, + wl_fixed_to_int(fx), + wl_fixed_to_int(fy), + NULL); + + pixman_region32_fini(&cregion); + pixman_region32_fini(&input_region); + return inside; +} + +static void +_e_comp_wl_pointer_constraint_notify_activated(E_Comp_Wl_Pointer_Constraint *constraint) +{ + struct wl_resource *resource = constraint->resource; + E_Comp_Wl_Pointer_Constraint_Type type = constraint->type; + + if (E_COMP_WL_POINTER_CONSTRAINT_TYPE_LOCK == type) + zwp_locked_pointer_v1_send_locked(resource); + else if (E_COMP_WL_POINTER_CONSTRAINT_TYPE_CONFINE == type) + zwp_confined_pointer_v1_send_confined(resource); + else + abort(); + + ERR("pointer constraint activated (type=%d, ec=%p)", constraint->type, constraint->ec); +} + +static void +_e_comp_wl_pointer_constraint_enable(E_Comp_Wl_Pointer_Constraint *constraint) +{ + if (constraint->active) + { + ERR("ERROR! Pointer constraint has been activated already !"); + return; + } + + constraint->active = EINA_TRUE; + E_Client *ec = constraint->ec; + e_comp_wl->ptr_constraints.activated = EINA_TRUE; + e_comp_wl->ptr_constraints.ec = ec; + _e_comp_wl_pointer_constraint_notify_activated(constraint); + wl_signal_add(&e_comp_wl->ptr_constraints.surface_unmap_signal, + &constraint->surface_unmap_listener); +} + +static void +_e_comp_wl_pointer_constraints_check_enable(E_Comp_Wl_Pointer_Constraint *constraint) +{ + if (!constraint || !constraint->ec) + { + ERR("Invalid constraint or ec of it."); + return; + } + + E_Client *ec = constraint->ec; + + if ((!e_comp_wl->ptr.ec) || (e_comp_wl->ptr.ec != ec) + || (!ec->pointer_enter_sent)) + return; + + if (!_e_comp_wl_is_position_inside_constraint_region(constraint, + e_comp_wl->ptr.x, + e_comp_wl->ptr.y)) + return; + + _e_comp_wl_pointer_constraint_enable(constraint); +} + +static void +_e_comp_wl_pointer_constraint_disable(E_Comp_Wl_Pointer_Constraint *constraint) +{ + int lifetime = constraint->lifetime; + + if (lifetime == ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT) + _e_comp_wl_pointer_constraint_destroy(constraint); + else if (lifetime == ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT) + _e_comp_wl_pointer_constraint_deactivate(constraint); + else + abort(); +} + +static void +_e_comp_wl_pointer_constraints_pointer_destroyed(struct wl_listener *listener, + void *data) +{ + struct wl_resource *pointer_resource = (struct wl_resource *)data; + E_Comp_Wl_Pointer_Constraint *constraint = container_of(listener, + E_Comp_Wl_Pointer_Constraint, + pointer_destroy_listener); + + ERR("[pointer destroyed -> pointer constraints will be destroyed]"); + + if (pointer_resource == constraint->pointer) + _e_comp_wl_pointer_constraint_destroy(constraint); +} + +static void +_e_comp_wl_pointer_constraints_surface_focused(struct wl_listener *listener, + void *data) +{ + E_Client *ec = (E_Client *)data; + E_Comp_Wl_Pointer_Constraint *constraint = container_of(listener, + E_Comp_Wl_Pointer_Constraint, + surface_focus_listener); + + Eina_Bool found = EINA_FALSE; + E_Comp_Wl_Pointer_Constraint *tmp_constraint; + wl_list_for_each(tmp_constraint, &ec->comp_data->pointer_constraints, link) + { + if (tmp_constraint == constraint) + { + found = EINA_TRUE; + break; + } + } + + ERR("[surface focused -> pointer constraints will be checked, enabled or disabled]"); + + if (found && !constraint->active) + _e_comp_wl_pointer_constraints_check_enable(constraint); + else if (!found && constraint->active) + _e_comp_wl_pointer_constraint_disable(constraint); +} + +static void +_e_comp_wl_pointer_constraints_surface_committed(struct wl_listener *listener, + void *data) +{ + E_Client *ec = (E_Client *)data; + E_Comp_Wl_Pointer_Constraint *constraint = container_of(listener, + E_Comp_Wl_Pointer_Constraint, + surface_commit_listener); + + if (ec != constraint->ec) + return; + + if (constraint->is_hint_pending) + { + constraint->is_hint_pending = EINA_FALSE; + constraint->hint_x = constraint->hint_x_pending; + constraint->hint_y = constraint->hint_y_pending; + } + + if (constraint->is_region_pending) + { + constraint->is_region_pending = EINA_FALSE; + pixman_region32_copy(&constraint->region, + &constraint->region_pending); + pixman_region32_fini(&constraint->region_pending); + pixman_region32_init(&constraint->region_pending); + } + + ERR("[surface committed -> pointer constraints' region/hint will be updated if required]"); + + //CHECKME: check if the updated region can take effect on the given constraint +} + +static void +_e_comp_wl_pointer_constraints_surface_unmapped(struct wl_listener *listener, + void *data) +{ + E_Client *ec = (E_Client *)data; + E_Comp_Wl_Pointer_Constraint *constraint = container_of(listener, + E_Comp_Wl_Pointer_Constraint, + surface_unmap_listener); + + ERR("[surface unmapped -> pointer constraints will be disabled if required]"); + + if (ec == constraint->ec) + _e_comp_wl_pointer_constraint_disable(constraint); +} + +static E_Comp_Wl_Pointer_Constraint * +_e_comp_wl_pointer_constraint_create(E_Client *ec, + struct wl_resource *resource, + struct wl_resource *pointer, + struct wl_resource *region, + enum zwp_pointer_constraints_v1_lifetime lifetime, + E_Comp_Wl_Pointer_Constraint_Type type) +{ + E_Comp_Wl_Pointer_Constraint *constraint; + + constraint = E_NEW(E_Comp_Wl_Pointer_Constraint, 1); + + if (!constraint) + { + ERR("Could not allocate memory for pointer constrant: %m"); + return NULL; + } + + constraint->active = EINA_FALSE; + constraint->ec = ec; + constraint->lifetime = lifetime; + constraint->type = type; + constraint->pointer = pointer; + constraint->resource = resource; + constraint->surface = ec->comp_data->surface; + wl_list_init(&constraint->link); + wl_list_insert(&ec->comp_data->pointer_constraints, &constraint->link); + pixman_region32_init(&constraint->region); + pixman_region32_init(&constraint->region_pending); + + if (region) + { + Eina_Tiler *tiler = wl_resource_get_user_data(region); + pixman_region32_t given_region; + + if (tiler) + { + pixman_region32_init(&given_region); + _e_comp_wl_convert_eina_tiler_to_pixman_region32(tiler, &given_region); + pixman_region32_copy(&constraint->region, &given_region); + pixman_region32_fini(&given_region); + } + else + { + //CHECKME: check whether this situation is a kind of bug + ERR("Invalid tiler from region (pointer constraint region!"); + pixman_region32_fini(&constraint->region); + pixman_region32_init_rect(&constraint->region, + INT32_MIN, INT32_MIN, + UINT32_MAX, UINT32_MAX); + } + } + else + { + pixman_region32_fini(&constraint->region); + pixman_region32_init_rect(&constraint->region, + INT32_MIN, INT32_MIN, + UINT32_MAX, UINT32_MAX); + constraint->has_region_set = EINA_TRUE; + } + + constraint->pointer_destroy_listener.notify = + _e_comp_wl_pointer_constraints_pointer_destroyed; + constraint->surface_commit_listener.notify = + _e_comp_wl_pointer_constraints_surface_committed; + constraint->surface_focus_listener.notify = + _e_comp_wl_pointer_constraints_surface_focused; + constraint->surface_unmap_listener.notify = + _e_comp_wl_pointer_constraints_surface_unmapped; + + wl_signal_add(&e_comp_wl->ptr_constraints.pointer_destroy_signal, + &constraint->pointer_destroy_listener); + wl_signal_add(&e_comp_wl->ptr_constraints.surface_commit_signal, + &constraint->surface_commit_listener); + wl_signal_add(&e_comp_wl->ptr_constraints.surface_focus_signal, + &constraint->surface_focus_listener); + + return constraint; +} + +static Eina_Bool +_e_comp_wl_has_pointer_constraints_for_pointer(E_Client *ec, struct wl_resource *pointer) +{ + E_Comp_Wl_Pointer_Constraint *constraint; + + wl_list_for_each(constraint, &ec->comp_data->pointer_constraints, link) + { + if (constraint->pointer == pointer) + return EINA_TRUE; + } + + return EINA_FALSE; +} + +static void +_e_comp_wl_cb_unbind_locked_pointer(struct wl_resource *resource) +{ + E_Comp_Wl_Pointer_Constraint *constraint; + constraint = wl_resource_get_user_data(resource); + + if (!constraint) + return; + + _e_comp_wl_pointer_constraint_destroy(constraint); +} + +static void +_e_comp_wl_cb_locked_pointer_destroy(struct wl_client *client, + struct wl_resource *resource) +{ + E_Comp_Wl_Pointer_Constraint *constraint; + constraint = wl_resource_get_user_data(resource); + + if (constraint && + constraint->ec && + constraint->has_hint_set && + _e_comp_wl_is_position_inside_constraint_region(constraint, + constraint->hint_x, + constraint->hint_y)) + { + E_Client *ec = constraint->ec; + int cx = ec->client.x + wl_fixed_to_int(constraint->hint_x); + int cy = ec->client.x + wl_fixed_to_int(constraint->hint_y); + e_input_device_pointer_warp(NULL, cx, cy); + } + + wl_resource_destroy(resource); +} + +static void +_e_comp_wl_cb_locked_pointer_set_cursor_position_hint(struct wl_client *client, + struct wl_resource *resource, + wl_fixed_t surface_x, + wl_fixed_t surface_y) +{ + E_Comp_Wl_Pointer_Constraint *constraint = + (E_Comp_Wl_Pointer_Constraint *)wl_resource_get_user_data(resource); + + constraint->hint_x_pending = surface_x; + constraint->hint_y_pending = surface_y; + constraint->is_hint_pending = EINA_TRUE; + constraint->has_hint_set = EINA_TRUE; +} + +static void +_e_comp_wl_cb_locked_pointer_set_region(struct wl_client *client, + struct wl_resource *resource, + struct wl_resource *region) +{ + E_Comp_Wl_Pointer_Constraint *constraint = + (E_Comp_Wl_Pointer_Constraint *)wl_resource_get_user_data(resource); + + if (region) + { + Eina_Tiler *tiler = wl_resource_get_user_data(region); + + pixman_region32_t t_region; + + if (tiler) + { + pixman_region32_init(&t_region); + _e_comp_wl_convert_eina_tiler_to_pixman_region32(tiler, &t_region); + pixman_region32_copy(&constraint->region, &t_region); + pixman_region32_fini(&t_region); + } + else + { + //CHECKME: check whether this situation is a kind of bug + ERR("Invalid tiler from region (pointer constraint region!"); + pixman_region32_fini(&constraint->region); + pixman_region32_init_rect(&constraint->region, + INT32_MIN, INT32_MIN, + UINT32_MAX, UINT32_MAX); + } + + constraint->has_region_set = EINA_TRUE; + } + else + { + pixman_region32_fini(&constraint->region); + pixman_region32_init_rect(&constraint->region, + INT32_MIN, INT32_MIN, + UINT32_MAX, UINT32_MAX); + } + + constraint->is_region_pending = EINA_TRUE; +} + +static const struct zwp_locked_pointer_v1_interface _e_comp_wl_locked_pointer_interface = +{ + _e_comp_wl_cb_locked_pointer_destroy, + _e_comp_wl_cb_locked_pointer_set_cursor_position_hint, + _e_comp_wl_cb_locked_pointer_set_region, +}; + +static void +_e_comp_wl_cb_pointer_constraints_lock_pointer(struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *surface, + struct wl_resource *pointer, + struct wl_resource *region, + uint32_t lifetime) +{ + if (!pointer || !surface) + { + ERR("Pointer resource or surface resource is invalid !"); + return; + } + + E_Client *ec = wl_resource_get_user_data(surface); + + if (!ec) + { + ERR("Could not get ec from surface resource !"); + return; + } + + if (_e_comp_wl_has_pointer_constraints_for_pointer(ec, pointer)) + { + ERR("Pointer constraints has been created already (ec: %p, pointer_resource: %u)", + ec, wl_resource_get_id(resource)); + wl_resource_post_error(resource, + ZWP_POINTER_CONSTRAINTS_V1_ERROR_ALREADY_CONSTRAINED, + "the pointer has a lock set already on this surface"); + return; + } + + struct wl_resource *res; + res = wl_resource_create(client, &zwp_locked_pointer_v1_interface, 1, id); + + if (!res) + { + ERR("Could not create a resource for pointer constraints lock: %m"); + wl_client_post_no_memory(client); + return; + } + + E_Comp_Wl_Pointer_Constraint *constraint; + constraint = _e_comp_wl_pointer_constraint_create(ec, res, pointer, region, lifetime, + E_COMP_WL_POINTER_CONSTRAINT_TYPE_LOCK); + + if (!constraint) + { + ERR("Could not create a pointer constraint."); + wl_client_post_no_memory(client); + return; + } + + wl_resource_set_implementation(res, &_e_comp_wl_locked_pointer_interface, + constraint, _e_comp_wl_cb_unbind_locked_pointer); + + _e_comp_wl_pointer_constraints_check_enable(constraint); +} + +static void +_e_comp_wl_cb_pointer_constraints_confine_pointer(struct wl_client *client, + struct wl_resource *resource, + uint32_t id, + struct wl_resource *surface_resource, + struct wl_resource *pointer_resource, + struct wl_resource *region_resource, + uint32_t lifetime) +{ + (void) client; + (void) resource; + (void) id; + (void) surface_resource; + (void) pointer_resource; + (void) region_resource; + (void) lifetime; + + /* + todo: pointer constraints confine + */ +} + +static void +_e_comp_wl_cb_pointer_constraints_destroy(struct wl_client *client, + struct wl_resource *resource) +{ + ERR("Destroy pointer constraints: (resource:%u) (client: %p)", wl_resource_get_id(resource), client); + wl_resource_destroy(resource); +} + +static const struct zwp_pointer_constraints_v1_interface _e_pointer_constraints_interface = { + _e_comp_wl_cb_pointer_constraints_destroy, + _e_comp_wl_cb_pointer_constraints_lock_pointer, + _e_comp_wl_cb_pointer_constraints_confine_pointer, +}; + +static void +_e_comp_wl_cb_unbind_pointer_constraints(struct wl_resource *resource) +{ + ERR("Unbind pointer constraints : (resource: %u) (client: %p)", wl_resource_get_id(resource), wl_resource_get_client(resource)); + + e_comp_wl->ptr_constraints.resources = + eina_list_remove(e_comp_wl->ptr_constraints.resources, resource); +} + +static void +_e_comp_wl_input_cb_bind_pointer_constraints(struct wl_client *client, void *data EINA_UNUSED, uint32_t version, uint32_t id) +{ + struct wl_resource *resource; + + resource = wl_resource_create(client, &zwp_pointer_constraints_v1_interface, version, id); + + if (!resource) + { + ERR("Could not create pointer constraints resource: %m"); + return; + } + + ERR("Bind pointer constraints: (resource: %u) (client: %p)", wl_resource_get_id(resource), client); + + e_comp_wl->ptr_constraints.resources = + eina_list_append(e_comp_wl->ptr_constraints.resources, resource); + wl_resource_set_implementation(resource, &_e_pointer_constraints_interface, + NULL, _e_comp_wl_cb_unbind_pointer_constraints); +} + +static void +_e_comp_wl_surface_cb_commit(void *data EINA_UNUSED, E_Client *ec) +{ + wl_signal_emit(&e_comp_wl->ptr_constraints.surface_commit_signal, ec); } static void @@ -727,6 +1362,30 @@ e_comp_wl_input_init(void) return EINA_FALSE; } + /* create the global resource for pointer-constraints */ + e_comp_wl->ptr_constraints.global = + wl_global_create(e_comp_wl->wl.disp, + &zwp_pointer_constraints_v1_interface, 1, + e_comp->wl_comp_data, + _e_comp_wl_input_cb_bind_pointer_constraints); + if (!e_comp_wl->ptr_constraints.global) + { + ERR("Could not create global for pointer constraints: %m"); + return EINA_FALSE; + } + + e_comp_wl->ptr_constraints.ec = NULL; + e_comp_wl->ptr_constraints.activated = EINA_FALSE; + wl_signal_init(&e_comp_wl->ptr_constraints.pointer_destroy_signal); + wl_signal_init(&e_comp_wl->ptr_constraints.surface_unmap_signal); + wl_signal_init(&e_comp_wl->ptr_constraints.surface_commit_signal); + wl_signal_init(&e_comp_wl->ptr_constraints.surface_focus_signal); + + _surface_commit_hook = e_comp_wl_hook_add(E_COMP_WL_HOOK_CLIENT_SURFACE_COMMIT, + _e_comp_wl_surface_cb_commit, + NULL); + + wl_array_init(&e_comp_wl->kbd.keys); wl_array_init(&e_comp_wl->kbd.routed_keys); @@ -754,6 +1413,13 @@ e_comp_wl_input_shutdown(void) E_FREE(_env_e_default_xkb_variant); E_FREE(_env_e_default_xkb_opts ); + /* delete surface commit hook */ + if (_surface_commit_hook) + { + e_comp_wl_hook_del(_surface_commit_hook); + _surface_commit_hook = NULL; + } + /* destroy pointer resources */ EINA_LIST_FREE(e_comp_wl->ptr.resources, res) wl_resource_destroy(res); @@ -761,7 +1427,14 @@ e_comp_wl_input_shutdown(void) /* destroy relative pointer resources */ EINA_LIST_FREE(e_comp_wl->relative_ptr.resources, res) wl_resource_destroy(res); - //FIXME: destroy relative_pointer_manager + + /* destroy relative pointer manager resources */ + EINA_LIST_FREE(e_comp_wl->relative_ptr.manager_resources, res) + wl_resource_destroy(res); + + /* destroy pointer constraints resources */ + EINA_LIST_FREE(e_comp_wl->ptr_constraints.resources, res) + wl_resource_destroy(res); /* destroy keyboard resources */ EINA_LIST_FREE(e_comp_wl->kbd.resources, res) @@ -798,6 +1471,11 @@ e_comp_wl_input_shutdown(void) wl_global_destroy(e_comp_wl->relative_ptr.global); e_comp_wl->relative_ptr.global = NULL; + /* destroy the global pointer constraints resource */ + if (e_comp_wl->ptr_constraints.global) + wl_global_destroy(e_comp_wl->ptr_constraints.global); + e_comp_wl->ptr_constraints.global = NULL; + /* destroy the global seat resource */ if (e_comp_wl->seat.global) wl_global_destroy(e_comp_wl->seat.global);