e_comp_wl & e_comp_wl_input: added implementation for zwp_pointer_constraints_v1_inte... 08/292008/1
authorSungjin Park <sj76.park@samsung.com>
Tue, 25 Apr 2023 11:18:24 +0000 (20:18 +0900)
committerSungjin Park <sj76.park@samsung.com>
Wed, 26 Apr 2023 06:55:20 +0000 (15:55 +0900)
Change-Id: Ib8393b03d78761e97cd92cd2b179d0d877ff1c25
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 cf51e1d0112fd6608ac575e2be2e1840c2b70d47..72a342e95049dc55c578c716208025b070d83aaa 100644 (file)
@@ -3429,6 +3429,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 */
@@ -5617,11 +5618,7 @@ e_comp_wl_mouse_relative_motion_send(E_Client *ec,
    E_Client *focused = e_client_focused_get();
    if ((focused) && (ec != focused)) return EINA_FALSE;
 
-   e_comp_wl->relative_ptr.ec = ec;
-   e_comp_wl->relative_ptr.activated = EINA_TRUE;
-
    wc = wl_resource_get_client(ec->comp_data->surface);
-
    EINA_LIST_FOREACH(e_comp_wl->relative_ptr.resources, l, res)
      {
         if (!e_comp_wl_input_relative_pointer_check(res)) continue;
index e16ff040e605aac4f73260eeb550390b4329636c..c002261c30ad055887d32494c6964688384cd3a3 100644 (file)
@@ -15,6 +15,7 @@ typedef struct _E_Comp_Wl_Pid_Hook E_Comp_Wl_Pid_Hook;
 #  include <xkbcommon/xkbcommon.h>
 
 #  include <relative-pointer-unstable-v1-server-protocol.h>
+#  include <pointer-constraints-unstable-v1-server-protocol.h>
 
 #  ifdef __linux__
 #   include <linux/input.h>
@@ -47,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
 {
@@ -247,6 +249,18 @@ struct _E_Comp_Wl_Data
         struct wl_global *global;
      } relative_ptr;
 
+   struct
+     {
+        Eina_List *resources;
+        E_Client *ec;
+        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;
+     } ptr_constraints;
+
    struct
      {
         Eina_List *resources;
@@ -504,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
index fdfff741110849292570b56de66ae97b2cf2cb70..8c2f9bf119abf1690a4343d6a67840aa6754d2fe 100644 (file)
@@ -1,6 +1,47 @@
 #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;
@@ -497,6 +538,564 @@ _e_comp_wl_input_cb_bind_relative_pointer_manager(struct wl_client *client,
                                   NULL, _e_comp_wl_input_cb_unbind_relative_pointer_manager);
 }
 
+static void
+_e_comp_wl_input_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_input_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
+     ERR("unknown pointer constraint type (%d) !", type);
+}
+
+static void
+_e_comp_wl_input_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->relative_ptr.activated = EINA_FALSE;
+   e_comp_wl->relative_ptr.ec = NULL;
+   _e_comp_wl_input_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_input_pointer_constraint_destroy(E_Comp_Wl_Pointer_Constraint *constraint)
+{
+   if (constraint->active)
+     _e_comp_wl_input_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_input_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_input_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
+     ERR("unknown pointer constraint type (%d) !", type);
+}
+
+static void
+_e_comp_wl_input_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->relative_ptr.activated = EINA_TRUE;
+   e_comp_wl->relative_ptr.ec = ec;
+   _e_comp_wl_input_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_input_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_input_is_position_inside_constraint_region(constraint,
+                                                              e_comp_wl->ptr.x,
+                                                              e_comp_wl->ptr.y))
+     return;
+
+   _e_comp_wl_input_pointer_constraint_enable(constraint);
+}
+
+static void
+_e_comp_wl_input_pointer_constraint_disable(E_Comp_Wl_Pointer_Constraint *constraint)
+{
+   int lifetime = constraint->lifetime;
+
+   if (lifetime == ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT)
+     _e_comp_wl_input_pointer_constraint_destroy(constraint);
+   else if (lifetime == ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT)
+     _e_comp_wl_input_pointer_constraint_deactivate(constraint);
+   else
+     ERR("unknown pointer constraint lifetime (%d) !", lifetime);
+}
+
+static void
+_e_comp_wl_input_cb_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);
+
+   if (pointer_resource == constraint->pointer)
+     _e_comp_wl_input_pointer_constraint_destroy(constraint);
+}
+
+static void
+_e_comp_wl_input_cb_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;
+          }
+     }
+
+   if (found && !constraint->active)
+     _e_comp_wl_input_pointer_constraints_check_enable(constraint);
+   else if (!found && constraint->active)
+     _e_comp_wl_input_pointer_constraint_disable(constraint);
+}
+
+static void
+_e_comp_wl_input_cb_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);
+     }
+
+   //CHECKME: check if the updated region can take effect on the given constraint
+}
+
+static void
+_e_comp_wl_input_cb_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);
+
+   if (ec == constraint->ec)
+     _e_comp_wl_input_pointer_constraint_disable(constraint);
+}
+
+static E_Comp_Wl_Pointer_Constraint *
+_e_comp_wl_input_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_input_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_input_cb_pointer_constraints_pointer_destroyed;
+   constraint->surface_commit_listener.notify =
+     _e_comp_wl_input_cb_pointer_constraints_surface_committed;
+   constraint->surface_focus_listener.notify =
+     _e_comp_wl_input_cb_pointer_constraints_surface_focused;
+   constraint->surface_unmap_listener.notify =
+     _e_comp_wl_input_cb_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_input_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_input_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_input_pointer_constraint_destroy(constraint);
+}
+
+static void
+_e_comp_wl_input_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_input_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_input_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_input_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_input_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_input_cb_locked_pointer_destroy,
+   _e_comp_wl_input_cb_locked_pointer_set_cursor_position_hint,
+   _e_comp_wl_input_cb_locked_pointer_set_region,
+};
+
+static void
+_e_comp_wl_input_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_input_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_input_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_input_cb_unbind_locked_pointer);
+
+   _e_comp_wl_input_pointer_constraints_check_enable(constraint);
+}
+
+static void
+_e_comp_wl_input_cb_pointer_constraints_confine_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)
+{
+   (void) client;
+   (void) resource;
+   (void) id;
+   (void) surface;
+   (void) pointer;
+   (void) region;
+   (void) lifetime;
+
+   /* TODO: pointer constraints confine */
+}
+
+static void
+_e_comp_wl_input_cb_pointer_constraints_destroy(struct wl_client *client,
+                                          struct wl_resource *resource)
+{
+   wl_resource_destroy(resource);
+}
+
+static const struct zwp_pointer_constraints_v1_interface _e_pointer_constraints_interface = {
+       _e_comp_wl_input_cb_pointer_constraints_destroy,
+       _e_comp_wl_input_cb_pointer_constraints_lock_pointer,
+       _e_comp_wl_input_cb_pointer_constraints_confine_pointer,
+};
+
+static void
+_e_comp_wl_input_cb_unbind_pointer_constraints(struct wl_resource *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;
+     }
+
+   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_input_cb_unbind_pointer_constraints);
+}
+
 static void
 _e_comp_wl_input_keymap_cache_create(const char *keymap_path, char *keymap_data)
 {
@@ -731,6 +1330,25 @@ 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);
+
    wl_array_init(&e_comp_wl->kbd.keys);
    wl_array_init(&e_comp_wl->kbd.routed_keys);
 
@@ -770,6 +1388,10 @@ e_comp_wl_input_shutdown(void)
    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)
      wl_resource_destroy(res);
@@ -805,6 +1427,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);