e_comp_wl & e_comp_wl_input: added pointer constraints feature
authorSungjin Park <sj76.park@samsung.com>
Sat, 22 Apr 2023 07:06:04 +0000 (16:06 +0900)
committerSungjin Park <sj76.park@samsung.com>
Mon, 24 Apr 2023 09:08:26 +0000 (18:08 +0900)
Signed-off-by: Sungjin Park <sj76.park@samsung.com>
src/bin/e_comp_wl.c
src/bin/e_comp_wl.h
src/bin/e_comp_wl_input.c

index d05095307837f2808be32845035188ec1c05a6ff..8ffd4d613f947a6c24e6626ed12101788975dbf6 100644 (file)
@@ -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 */
index a12d36604dc3e0dd0053ce125a090dabc9905440..6caac0cc782c19777335c988ca3c42f4bd54d3a0 100644 (file)
@@ -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);
 
index 64b619e1e8f267241378fd07d199f1c041fd1062..9f4223963144dcfa086727ce1e92687868c179de 100644 (file)
@@ -1,12 +1,55 @@
 #define EXECUTIVE_MODE_ENABLED
 #include "e.h"
 #include <sys/mman.h>
+#include <pixman.h>
+
+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);