e_input/e_devicemgr: handle relative_motion_grab/ungrab requests 51/315651/1
authorduna.oh <duna.oh@samsung.com>
Thu, 18 Jul 2024 11:15:24 +0000 (20:15 +0900)
committerTizen Window System <tizen.windowsystem@gmail.com>
Tue, 6 Aug 2024 02:00:21 +0000 (11:00 +0900)
E20 clamps the pointer position inside the boundary of a screen.
If there is a client requesting to grab relative motion, E20 sends
relative motion events when pointer is restricted at the edges
of the output.

Change-Id: Ic8a613681c81927c194ad88d34a2ed7971757f05

src/bin/Makefile.mk
src/bin/inputmgr/e_devicemgr_intern.h
src/bin/inputmgr/e_devicemgr_relative_motion_grab.c [new file with mode: 0644]
src/bin/inputmgr/e_input_evdev.c
src/bin/server/e_comp_wl.c
src/bin/server/e_devicemgr_wl.c
src/bin/server/e_devicemgr_wl_intern.h
src/include/e_devicemgr.h

index 8b142d6..8121fd8 100644 (file)
@@ -237,6 +237,7 @@ src/bin/inputmgr/e_input_evdev.c \
 src/bin/inputmgr/e_input_thread_client.c \
 src/bin/inputmgr/e_device.c \
 src/bin/inputmgr/e_devicemgr_keyboard_grab.c \
+src/bin/inputmgr/e_devicemgr_relative_motion_grab.c \
 src/bin/inputmgr/e_devicemgr.c \
 src/bin/inputmgr/e_devicemgr_conf.c \
 src/bin/inputmgr/e_devicemgr_block.c \
index be32fad..34a849b 100644 (file)
@@ -142,6 +142,9 @@ EINTERN Eina_Bool e_devicemgr_keyboard_grab_subtype_is_grabbed(Ecore_Device_Subc
 EINTERN int       e_devicemgr_keyboard_ungrab(struct wl_client *client, struct wl_resource *surface);
 EINTERN int       e_devicemgr_keyboard_grab(struct wl_client *client, struct wl_resource *surface, uint32_t subclas);
 
+EINTERN int       e_devicemgr_relative_motion_grab(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface, uint32_t boundary);
+EINTERN int       e_devicemgr_relative_motion_ungrab(struct wl_client *client, struct wl_resource *resource, struct wl_resource *surface);
+EINTERN Eina_Bool e_devicemgr_relative_motion_is_grabbed(unsigned int boundaries);
 
 EINTERN void e_devicemgr_conf_init(E_Devicemgr_Config_Data *dconfig);
 EINTERN void e_devicemgr_conf_fini(E_Devicemgr_Config_Data *dconfig);
diff --git a/src/bin/inputmgr/e_devicemgr_relative_motion_grab.c b/src/bin/inputmgr/e_devicemgr_relative_motion_grab.c
new file mode 100644 (file)
index 0000000..1a63195
--- /dev/null
@@ -0,0 +1,147 @@
+#include "e_devicemgr_intern.h"
+#include "e_input_log.h"
+
+#include <tizen-extension-server-protocol.h>
+
+EINTERN Eina_Bool
+e_devicemgr_relative_motion_is_grabbed(unsigned int boundaries)
+{
+   if (e_devicemgr->relative_motion_grab.grabbed_boundaries & boundaries)
+     {
+        DMINF("e_devicemgr_relative_motion_is_grabbed() grabbed:%d, boundaries:%d",
+              e_devicemgr->relative_motion_grab.grabbed_boundaries, boundaries);
+        return EINA_TRUE;
+     }
+
+   return EINA_FALSE;
+}
+
+static unsigned int
+_e_devicemgr_relative_motion_grabbed_boundary_get(struct wl_client *client, E_Client *ec)
+{
+   unsigned int boundary = 0;
+
+   for (int i = 1; i < E_DEVICEMGR_BOUNDARY_MAX + 1; i++)
+     {
+        if (e_devicemgr->relative_motion_grab.boundaries[i].client == client &&
+            e_devicemgr->relative_motion_grab.boundaries[i].ec == ec)
+          {
+             boundary = i;
+             break;
+          }
+     }
+
+   return boundary;
+}
+
+static Eina_Bool
+_e_devicemgr_relative_motion_grab_surface_remove(E_Client *ec,
+                                                unsigned int boundary)
+{
+   if (ec != e_devicemgr->relative_motion_grab.boundaries[boundary].ec)
+     return EINA_FALSE;
+
+   e_devicemgr->relative_motion_grab.boundaries[boundary].client = NULL;
+   e_devicemgr->relative_motion_grab.boundaries[boundary].ec = NULL;
+   e_devicemgr->relative_motion_grab.boundaries[boundary].resource = NULL;
+   e_devicemgr->relative_motion_grab.grabbed_boundaries &= ~(1 << boundary);
+   e_devicemgr->relative_motion_grab.last_event_boundary = 0;
+
+   return EINA_TRUE;
+}
+
+static void
+_e_devicemgr_relative_motion_grab_surface_cb_destroy(struct wl_listener *l, void *data)
+{
+   struct wl_resource *surface = (struct wl_resource *)data;
+   E_Client *ec;
+
+   DMINF("Listener(%p) called: surface: %p is died", l, surface);
+
+   wl_list_remove(&l->link);
+   E_FREE(l);
+
+   ec = e_client_from_surface_resource(surface);
+
+   for (int i = 1; i < E_DEVICEMGR_BOUNDARY_MAX + 1; i++)
+     {
+        if (e_devicemgr->relative_motion_grab.boundaries[i].ec == ec)
+          {
+             _e_devicemgr_relative_motion_grab_surface_remove(ec, i);
+          }
+     }
+}
+
+static Eina_Bool
+_e_devicemgr_relative_motion_grab_surface_add(E_Client *ec, uint32_t boundary,
+                                              struct wl_client *client,
+                                              struct wl_resource *resource)
+{
+   if (ec == e_devicemgr->relative_motion_grab.boundaries[boundary].ec)
+     return EINA_TRUE;
+
+   e_devicemgr->relative_motion_grab.boundaries[boundary].client = client;
+   e_devicemgr->relative_motion_grab.boundaries[boundary].ec = ec;
+   e_devicemgr->relative_motion_grab.boundaries[boundary].resource = resource;
+   e_devicemgr->relative_motion_grab.grabbed_boundaries |= (1 << boundary);
+
+   return EINA_TRUE;
+}
+
+int
+e_devicemgr_relative_motion_grab(struct wl_client *client, struct wl_resource *resource,
+                                 struct wl_resource *surface, uint32_t boundary)
+{
+   int ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE;
+   E_Client *ec;
+   struct wl_listener *destroy_listener = NULL;
+
+   if (boundary <= 0 || boundary > E_DEVICEMGR_BOUNDARY_MAX)
+     return TIZEN_INPUT_DEVICE_MANAGER_ERROR_INVALID_PARAMETER;
+
+   if (e_devicemgr->relative_motion_grab.boundaries[boundary].client &&
+       e_devicemgr->relative_motion_grab.boundaries[boundary].client != client)
+     {
+        return TIZEN_INPUT_DEVICE_MANAGER_ERROR_NOT_ALLOWED;
+     }
+
+   ec = e_client_from_surface_resource(surface);
+   if (!ec)
+     return TIZEN_INPUT_DEVICE_MANAGER_ERROR_INVALID_SURFACE;
+
+   destroy_listener = E_NEW(struct wl_listener, 1);
+   if (!destroy_listener)
+     {
+        DMERR("Failed to allocate memory for wl_client destroy listener !");
+        return TIZEN_KEYROUTER_ERROR_NO_SYSTEM_RESOURCES;
+     }
+   destroy_listener->notify = _e_devicemgr_relative_motion_grab_surface_cb_destroy;
+   wl_resource_add_destroy_listener(surface, destroy_listener);
+
+   if (!_e_devicemgr_relative_motion_grab_surface_add(ec, boundary, client, resource))
+     ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NOT_ALLOWED;
+
+   return ret;
+}
+
+int
+e_devicemgr_relative_motion_ungrab(struct wl_client *client, struct wl_resource *resource,
+                                   struct wl_resource *surface)
+{
+   int ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE;
+   E_Client *ec;
+   unsigned int boundary;
+
+   ec = e_client_from_surface_resource(surface);
+   if (!ec)
+     return TIZEN_INPUT_DEVICE_MANAGER_ERROR_INVALID_SURFACE;
+
+   boundary = _e_devicemgr_relative_motion_grabbed_boundary_get(client, ec);
+   if (boundary == 0)
+       return TIZEN_INPUT_DEVICE_MANAGER_ERROR_NOT_ALLOWED;
+
+   if (!_e_devicemgr_relative_motion_grab_surface_remove(ec, boundary))
+     ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NOT_ALLOWED;
+
+   return ret;
+}
index 87a30cc..9702db5 100644 (file)
@@ -814,7 +814,6 @@ _device_pointer_motion(E_Input_Evdev *evdev, struct libinput_event_pointer *even
    Ecore_Event_Mouse_Move *ev;
    Ecore_Device *ecore_dev = NULL, *data, *detent_data = NULL;
    Eina_List *l;
-   int x = 0, y = 0, w = 0, h = 0;
    const char *device_name = NULL;
    uint32_t timestamp = 0;
 
@@ -865,18 +864,6 @@ _device_pointer_motion(E_Input_Evdev *evdev, struct libinput_event_pointer *even
 
    if (!(ev = calloc(1, sizeof(Ecore_Event_Mouse_Move)))) return;
 
-   _device_configured_size_get(evdev, &x, &y, &w, &h);
-
-   if (evdev->seat->ptr.ix < x)
-     evdev->seat->ptr.dx = evdev->seat->ptr.ix = x;
-   else if (evdev->seat->ptr.ix >= (x + w))
-     evdev->seat->ptr.dx = evdev->seat->ptr.ix = (x + w - 1);
-
-   if (evdev->seat->ptr.iy < y)
-     evdev->seat->ptr.dy = evdev->seat->ptr.iy = y;
-   else if (evdev->seat->ptr.iy >= (y + h))
-     evdev->seat->ptr.dy = evdev->seat->ptr.iy = (y + h - 1);
-
    evdev->mouse.dx = evdev->seat->ptr.dx;
    evdev->mouse.dy = evdev->seat->ptr.dy;
 
@@ -1002,7 +989,7 @@ _device_pointer_relative_motion(E_Input_Evdev *evdev, struct libinput_event_poin
 
    comp_conf = e_comp_config_get();
    if (comp_conf && comp_conf->input_log_enable)
-     ELOGF("Mouse", "Relative Move (time: %d, dx: %d, dy: %d, unaccel(%d, %d) device: %s)", NULL, ev->timestamp, ev->dx, ev->dy, ev->dx_unaccel, ev->dy_unaccel, ecore_device_name_get(ev->dev));
+     ELOGF("Mouse", "Relative Move (time: %d, dx: %.2f, dy: %.2f, unaccel(%.2f, %.2f) device: %s)", NULL, ev->timestamp, dx[0], dy[0], dx[1], dy[1], ecore_device_name_get(ev->dev));
 
    ecore_event_add(ECORE_EVENT_MOUSE_RELATIVE_MOVE, ev, _e_input_event_mouse_relative_move_cb_free, NULL);
 
@@ -1010,10 +997,47 @@ end:
    ecore_thread_main_loop_end();
 }
 
+static unsigned int
+_device_pointer_motion_clamp_for_output(E_Input_Evdev *evdev)
+{
+   int x = 0, y = 0, w = 0, h = 0;
+   unsigned int ret = 0;
+
+   _device_configured_size_get(evdev, &x, &y, &w, &h);
+
+   if (evdev->seat->ptr.dx < x)
+     {
+        evdev->seat->ptr.dx = x;
+        ret |= (1 << (unsigned int)E_DEVICEMGR_BOUNDARY_LEFT);
+     }
+   else if (evdev->seat->ptr.dx >= (x + w))
+     {
+        evdev->seat->ptr.dx = (x + w - 1);
+        ret |= (1 << (unsigned int)E_DEVICEMGR_BOUNDARY_RIGHT);
+     }
+
+   if (evdev->seat->ptr.dy < y)
+     {
+        evdev->seat->ptr.dy = y;
+        ret |= (1 << (unsigned int)E_DEVICEMGR_BOUNDARY_TOP);
+     }
+   else if (evdev->seat->ptr.dy >= (y + h))
+     {
+        evdev->seat->ptr.dy = (y + h - 1);
+        ret |= (1 << (unsigned int)E_DEVICEMGR_BOUNDARY_BOTTOM);
+     }
+
+   return ret;
+}
+
 static void
 _device_pointer_motion_send(E_Input_Evdev *evdev, struct libinput_event_pointer *event, double dx[2], double dy[2])
 {
+   static unsigned int clamped_boundaries = 0;
+   unsigned int boundaries;
+
    e_input_relative_motion_cb func = e_input_relative_motion_handler_get();
+
    if (func)
      {
         //func(dx, dy, time_us);
@@ -1056,6 +1080,27 @@ _device_pointer_motion_send(E_Input_Evdev *evdev, struct libinput_event_pointer
               return;
           }
 
+        boundaries = _device_pointer_motion_clamp_for_output(evdev);
+        if (boundaries != 0)
+          {
+             clamped_boundaries = boundaries;
+             if (e_devicemgr_relative_motion_is_grabbed(boundaries))
+               {
+                  e_devicemgr->relative_motion_grab.prev_boundaries = e_devicemgr->relative_motion_grab.curr_boundaries;
+                  e_devicemgr->relative_motion_grab.curr_boundaries = boundaries;
+                  _device_pointer_relative_motion(evdev, event, dx, dy);
+               }
+          }
+        else if (clamped_boundaries != 0)
+          {
+             if (e_devicemgr_relative_motion_is_grabbed(clamped_boundaries))
+               _device_pointer_relative_motion(evdev, event, dx, dy);
+
+             e_devicemgr->relative_motion_grab.prev_boundaries = e_devicemgr->relative_motion_grab.curr_boundaries;
+             e_devicemgr->relative_motion_grab.curr_boundaries = (unsigned int)E_DEVICEMGR_BOUNDARY_NONE;
+             clamped_boundaries = 0;
+          }
+
         evdev->seat->ptr.ix = evdev->seat->ptr.dx;
         evdev->seat->ptr.iy = evdev->seat->ptr.dy;
 
index d90c2ba..f66f057 100644 (file)
@@ -42,6 +42,7 @@
 #include "e_input_thread_client_intern.h"
 #include "e_display_intern.h"
 #include "e_view_client_intern.h"
+#include "e_devicemgr_wl_intern.h"
 
 #include <tizen-extension-server-protocol.h>
 #include <relative-pointer-unstable-v1-server-protocol.h>
@@ -2385,24 +2386,23 @@ _e_comp_wl_cb_mouse_move(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Event_Mou
    return ECORE_CALLBACK_RENEW;
 }
 
-static Eina_Bool
-_e_comp_wl_cb_mouse_relative_move(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Event_Mouse_Relative_Move *ev)
+static void
+_e_comp_wl_send_mouse_relative_move(E_Client *ec, int dx, int dy,
+                                    int dx_unaccel, int dy_unaccel,
+                                    unsigned int timestamp)
 {
-   E_Client *ec;
    struct wl_resource *surface;
    struct wl_resource *res;
    struct wl_client *wc;
    Eina_List *l;
    E_Comp_Config *comp_conf;
 
-   ec = e_comp_wl->ptr_constraints.ec;
-   EINA_SAFETY_ON_NULL_RETURN_VAL(ec, ECORE_CALLBACK_RENEW);
-
+   if (!ec) return;
+   if (e_object_is_del(E_OBJECT(ec))) return;
    surface = e_comp_wl_client_surface_get(ec);
-   EINA_SAFETY_ON_NULL_RETURN_VAL(surface, ECORE_CALLBACK_RENEW);
+   if (!surface) return;
 
    wc = wl_resource_get_client(surface);
-
    comp_conf = e_comp_config_get();
 
    EINA_LIST_FOREACH(e_comp_wl->relative_ptr.resources, l, res)
@@ -2412,16 +2412,64 @@ _e_comp_wl_cb_mouse_relative_move(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_
 
         if (comp_conf && comp_conf->input_log_enable)
           ELOGF("Mouse", "Relative Move (time: %d, dx:%d dy:%d, unaccel(%d, %d) name:%20s)",
-                ec, ev->timestamp, ev->dx, ev->dy, ev->dx_unaccel, ev->dy_unaccel,
+                ec, timestamp, dx, dy, dx_unaccel, dy_unaccel,
                 e_client_util_name_get(ec));
 
         zwp_relative_pointer_v1_send_relative_motion(res,
                                                      0,
-                                                     (uint32_t)(ev->timestamp),
-                                                     wl_fixed_from_int(ev->dx),
-                                                     wl_fixed_from_int(ev->dy),
-                                                     wl_fixed_from_int(ev->dx_unaccel),
-                                                     wl_fixed_from_int(ev->dy_unaccel));
+                                                     (uint32_t)(timestamp),
+                                                     wl_fixed_from_int(dx),
+                                                     wl_fixed_from_int(dy),
+                                                     wl_fixed_from_int(dx_unaccel),
+                                                     wl_fixed_from_int(dy_unaccel));
+     }
+}
+
+static Eina_Bool
+_e_comp_wl_cb_mouse_relative_move(void *d EINA_UNUSED, int t EINA_UNUSED, Ecore_Event_Mouse_Relative_Move *ev)
+{
+   E_Client *ec;
+
+   ec = e_comp_wl->ptr_constraints.ec;
+   if (!ec)
+     {
+        for (int i = 1; i < E_DEVICEMGR_BOUNDARY_MAX + 1; i++)
+          {
+             if ((e_devicemgr->relative_motion_grab.curr_boundaries & (1 << i)))
+               {
+                  if (e_devicemgr->relative_motion_grab.last_event_boundary != i)
+                    {
+                       e_devicemgr->relative_motion_grab.last_event_boundary = i;
+                       e_devicemgr_wl_event_boundary_send(e_devicemgr->relative_motion_grab.boundaries[i].resource, i);
+                    }
+                  ec = e_devicemgr->relative_motion_grab.boundaries[i].ec;
+                  if (ec)
+                    {
+                       ELOGF("Mouse", "Relative Move. Clamped boundary:%d", ec, i);
+                       _e_comp_wl_send_mouse_relative_move(ec, ev->dx, ev->dy, ev->dx_unaccel, ev->dy_unaccel, ev->timestamp);
+                    }
+               }
+             else if ((e_devicemgr->relative_motion_grab.prev_boundaries & (1 << i)))
+               {
+                  if (e_devicemgr->relative_motion_grab.last_event_boundary != i)
+                    {
+                       e_devicemgr->relative_motion_grab.last_event_boundary = i;
+                       e_devicemgr_wl_event_boundary_send(e_devicemgr->relative_motion_grab.boundaries[i].resource, i);
+                    }
+                  ec = e_devicemgr->relative_motion_grab.boundaries[i].ec;
+                  if (ec)
+                    {
+                       ELOGF("Mouse", "Relative Move. Prev Clamped boundary:%d", ec, i);
+                       _e_comp_wl_send_mouse_relative_move(ec, ev->dx, ev->dy, ev->dx_unaccel, ev->dy_unaccel, ev->timestamp);
+
+                       e_devicemgr->relative_motion_grab.prev_boundaries &= ~(1 << i);
+                    }
+               }
+          }
+     }
+   else
+     {
+        _e_comp_wl_send_mouse_relative_move(ec, ev->dx, ev->dy, ev->dx_unaccel, ev->dy_unaccel, ev->timestamp);
      }
 
    return ECORE_CALLBACK_DONE;
index ce49165..d555fd3 100644 (file)
@@ -303,6 +303,19 @@ e_devicemgr_wl_generator_with_sync_send_event(struct wl_resource *resource, int
    tizen_input_device_manager_send_error(resource, result);
 }
 
+void
+e_devicemgr_wl_event_boundary_send(struct wl_resource *resource, unsigned int boundary)
+{
+   uint32_t serial;
+
+   if(!resource) return;
+
+   DMINF("Relative Move. Event Boundary: %d", boundary);
+
+   serial = wl_display_next_serial(e_comp_wl->wl.disp);
+   tizen_input_device_manager_send_event_boundary(resource, serial, boundary);
+}
+
 static void
 _e_devicemgr_wl_cb_block_events(struct wl_client *client, struct wl_resource *resource, uint32_t serial, uint32_t clas, uint32_t duration)
 {
@@ -579,6 +592,45 @@ _e_devicemgr_wl_cb_keyboard_ungrab(struct wl_client *client, struct wl_resource
    tizen_input_device_manager_send_error(resource, ret);
 }
 
+static void
+_e_devicemgr_wl_cb_grab_relative_motion(struct wl_client *client, struct wl_resource *resource,
+                                   struct wl_resource *surface, uint32_t boundary)
+{
+   int ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE;
+
+#ifdef HAVE_CYNARA
+   if (EINA_FALSE == _e_devicemgr_util_do_privilege_check(client,
+                                                          E_PRIVILEGE_INTERNAL_DEFAULT_PLATFORM))
+     {
+        DMERR("grab relative motion request:priv check failed");
+        tizen_input_device_manager_send_error(resource, TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_PERMISSION);
+        return;
+     }
+#endif
+
+   ret = e_devicemgr_relative_motion_grab(client, resource, surface, boundary);
+   tizen_input_device_manager_send_error(resource, ret);
+}
+
+static void
+_e_devicemgr_wl_cb_ungrab_relative_motion(struct wl_client *client, struct wl_resource *resource,
+                                   struct wl_resource *surface)
+{
+   int ret = TIZEN_INPUT_DEVICE_MANAGER_ERROR_NONE;
+
+#ifdef HAVE_CYNARA
+   if (EINA_FALSE == _e_devicemgr_util_do_privilege_check(client,
+                                                          E_PRIVILEGE_INTERNAL_DEFAULT_PLATFORM))
+     {
+        DMERR("ungrab relative motion request:priv check failed");
+        tizen_input_device_manager_send_error(resource, TIZEN_INPUT_DEVICE_MANAGER_ERROR_NO_PERMISSION);
+        return;
+     }
+#endif
+
+   ret = e_devicemgr_relative_motion_ungrab(client, resource, surface);
+   tizen_input_device_manager_send_error(resource, ret);
+}
 
 static const struct tizen_input_device_manager_interface _e_devicemgr_wl_implementation = {
    _e_devicemgr_wl_cb_block_events,
@@ -595,7 +647,9 @@ static const struct tizen_input_device_manager_interface _e_devicemgr_wl_impleme
    _e_devicemgr_wl_cb_set_touch_count,
    _e_devicemgr_wl_cb_init_generator_with_sync,
    _e_devicemgr_wl_cb_keyboard_grab,
-   _e_devicemgr_wl_cb_keyboard_ungrab
+   _e_devicemgr_wl_cb_keyboard_ungrab,
+   _e_devicemgr_wl_cb_grab_relative_motion,
+   _e_devicemgr_wl_cb_ungrab_relative_motion
 };
 
 static void
@@ -737,7 +791,7 @@ e_devicemgr_wl_init(struct wl_display *display)
 
    /* try to add tizen_input_device_manager to wayland globals */
    g_tizen_devicemgr->global = wl_global_create(display,
-                                           &tizen_input_device_manager_interface, 6,
+                                           &tizen_input_device_manager_interface, 7,
                                            NULL, _e_devicemgr_wl_cb_bind);
    if (!g_tizen_devicemgr->global)
      {
index aefc628..3bbdeba 100644 (file)
@@ -18,5 +18,6 @@ EINTERN void e_devicemgr_wl_block_send_expired(struct wl_resource *resource);
 EINTERN void e_devicemgr_wl_detent_send_event(int detent);
 EINTERN void e_devicemgr_wl_touch_max_count_send(int slot, struct wl_resource *res, struct wl_resource *seat_res);
 EINTERN void e_devicemgr_wl_generator_with_sync_send_event(struct wl_resource *resource, int error);
+EINTERN void e_devicemgr_wl_event_boundary_send(struct wl_resource *resource, unsigned int boundary);
 
 #endif
index dc96064..0a739e4 100644 (file)
@@ -5,6 +5,8 @@
 
 #include <glib.h>
 
+#define E_DEVICEMGR_BOUNDARY_MAX 4
+
 typedef struct _E_Devicemgr             E_Devicemgr;
 typedef struct _E_Devicemgr_Conf_Edd    E_Devicemgr_Conf_Edd;
 typedef struct _E_Devicemgr_Config_Data E_Devicemgr_Config_Data;
@@ -30,6 +32,22 @@ typedef struct _E_Devicemgr_Input_Device_Multi
 
 typedef void (*E_Devicemgr_Block_Expire_Cb) (void *data);
 
+typedef struct _E_Devicemgr_Pointer_Boundary
+{
+   struct wl_client *client;
+   E_Client *ec;
+   struct wl_resource *resource;
+} E_Devicemgr_Pointer_Boundary;
+
+typedef enum _E_Devicemgr_Boundary
+{
+   E_DEVICEMGR_BOUNDARY_NONE = 0,
+   E_DEVICEMGR_BOUNDARY_TOP,
+   E_DEVICEMGR_BOUNDARY_RIGHT,
+   E_DEVICEMGR_BOUNDARY_BOTTOM,
+   E_DEVICEMGR_BOUNDARY_LEFT
+} E_Devicemgr_Boundary_Type;
+
 struct _E_Devicemgr
 {
    E_Devicemgr_Config_Data *dconfig;
@@ -82,6 +100,15 @@ struct _E_Devicemgr
       E_Client *ec;
       unsigned int subtype;
    } keyboard_grab;
+
+   struct
+   {
+      E_Devicemgr_Pointer_Boundary boundaries[E_DEVICEMGR_BOUNDARY_MAX + 1];
+      unsigned int grabbed_boundaries;
+      unsigned int curr_boundaries;
+      unsigned int prev_boundaries;
+      unsigned int last_event_boundary;
+   } relative_motion_grab;
 };
 
 extern E_API E_Devicemgr *e_devicemgr;