e_pointer: make an internal header
[platform/upstream/enlightenment.git] / src / bin / e_pointer.c
index 513b480..b97100b 100644 (file)
 #include "e.h"
-
-typedef struct _E_Pointer_Stack E_Pointer_Stack;
-struct _E_Pointer_Stack
-{
-   void *obj;
-   const char *type;
-};
+#include "e_pointer_intern.h"
+#include "e_input_intern.h"
 
 /* local variables */
-static Eina_List *_hdlrs = NULL;
 static Eina_List *_ptrs = NULL;
+static Eina_Bool _initted = EINA_FALSE;
 
-static inline void
-_e_pointer_theme_buf(E_Pointer *ptr, char cursor[1024])
-{
-   if (ptr->color)
-     snprintf(cursor, 1024, "e/pointer/enlightenment/%s/color", ptr->type);
-   else
-     snprintf(cursor, 1024, "e/pointer/enlightenment/%s/mono", ptr->type);
-}
-
-static inline void 
-_e_pointer_hot_update(E_Pointer *ptr, int x, int y)
-{
-   if ((ptr->hot.x != x) || (ptr->hot.y != y))
-     {
-        ptr->hot.x = x;
-        ptr->hot.y = y;
-        ptr->hot.update = EINA_TRUE;
-     }
-}
-
-static void 
-_e_pointer_active(E_Pointer *ptr)
-{
-   if (!ptr->idle) return;
-   if (ptr->o_ptr)
-     edje_object_signal_emit(ptr->o_ptr, "e,state,mouse,active", "e");
-   ptr->idle = EINA_FALSE;
-}
-
-static void 
-_e_pointer_idle(E_Pointer *ptr)
+static int _e_pointer_hooks_delete = 0;
+static int _e_pointer_hooks_walking = 0;
+static Eina_Inlist *_e_pointer_hooks[] =
 {
-   if (ptr->idle) return;
-   if (ptr->o_ptr)
-     edje_object_signal_emit(ptr->o_ptr, "e,state,mouse,idle", "e");
-   ptr->idle = EINA_TRUE;
-}
+   [E_POINTER_HOOK_TOUCH_MOVE] = NULL,
+   [E_POINTER_HOOK_MOUSE_MOVE] = NULL,
+   [E_POINTER_HOOK_SHOW] = NULL,
+   [E_POINTER_HOOK_HIDE] = NULL,
+};
 
-static Eina_Bool 
-_e_pointer_cb_idle_poller(void *data)
+static void
+_e_pointer_configured_output_resolution_ratio_get(E_Client *ec, double *ratio)
 {
-   E_Pointer *ptr;
-   int x = 0, y = 0;
+   E_Output *output;
+   E_Zone *zone;
+   double cal_ratio_w, cal_ratio_h, cal_ratio;
 
-   if (!(ptr = data)) return ECORE_CALLBACK_RENEW;
+   if (!ratio) return;
 
-   if ((e_powersave_mode_get() >= E_POWERSAVE_MODE_MEDIUM) || 
-       (!e_config->idle_cursor))
-     {
-        ptr->idle_poll = NULL;
-        return ECORE_CALLBACK_CANCEL;
-     }
+   *ratio = 1.0;
 
-   if (ptr->canvas)
-     ecore_evas_pointer_xy_get(ptr->ee, &x, &y);
-#ifndef HAVE_WAYLAND_ONLY
-   else
-     ecore_x_pointer_xy_get(ptr->win, &x, &y);
-#endif
+   if (!e_config->cursor_configured_output_resolution.use) return;
+   if (e_config->cursor_configured_output_resolution.w == 0) return;
+   if (e_config->cursor_configured_output_resolution.h == 0) return;
 
-   if ((ptr->x != x) || (ptr->y != y))
-     {
-        ptr->x = x;
-        ptr->y = y;
-        if (ptr->idle) _e_pointer_active(ptr);
-        return ECORE_CALLBACK_RENEW;
-     }
+   if (!ec) return;
 
-   if (!ptr->idle) _e_pointer_idle(ptr);
+   zone = e_comp_zone_find_by_ec(ec);
+   if (!zone) return;
 
-   return ECORE_CALLBACK_RENEW;
-}
+   output = e_output_find(zone->output_id);
+   if (!output) return;
+   if (output->config.geom.w == 0) return;
+   if (output->config.geom.h == 0) return;
 
-static Eina_Bool 
-_e_pointer_cb_idle_wait(void *data)
-{
-   E_Pointer *ptr;
+   cal_ratio_w = (double)output->config.geom.w /
+                 (double)e_config->cursor_configured_output_resolution.w;
 
-   if (!(ptr = data)) return ECORE_CALLBACK_RENEW;
-   ptr->idle_tmr = NULL;
-   if ((e_powersave_mode_get() >= E_POWERSAVE_MODE_MEDIUM) || 
-       (!e_config->idle_cursor))
-     {
-        E_FREE_FUNC(ptr->idle_poll, ecore_poller_del);
-        return ECORE_CALLBACK_CANCEL;
-     }
+   cal_ratio_h = (double)output->config.geom.h /
+                 (double)e_config->cursor_configured_output_resolution.h;
 
-   if (!ptr->idle_poll)
-     ptr->idle_poll = ecore_poller_add(ECORE_POLLER_CORE, 64, 
-                                       _e_pointer_cb_idle_poller, ptr);
+   cal_ratio = MIN(cal_ratio_w, cal_ratio_h);
 
-   return ECORE_CALLBACK_CANCEL;
+   *ratio = cal_ratio;
 }
 
-static Eina_Bool 
-_e_pointer_cb_idle_pre(void *data)
+/* move the cursor image with the calcaultion of the hot spot */
+static void
+_e_pointer_position_update(E_Pointer *ptr)
 {
-   E_Pointer *ptr;
+   int nx, ny;
+   int rotation;
+   int cursor_w, cursor_h;
+   E_Client *ec;
+   double ratio = 1.0;
+   int hot_x = 0, hot_y = 0;
 
-   if (!(ptr = data)) return ECORE_CALLBACK_RENEW;
+   if (!ptr->o_ptr) return;
 
-   if (ptr->canvas)
-     ecore_evas_pointer_xy_get(ptr->ee, &ptr->x, &ptr->y);
-#ifndef HAVE_WAYLAND_ONLY
-   else
-     ecore_x_pointer_xy_get(ptr->win, &ptr->x, &ptr->y);
-#endif
+   ec = e_comp_object_client_get(ptr->o_ptr);
+   EINA_SAFETY_ON_NULL_RETURN(ec);
 
-   ptr->idle_tmr = ecore_timer_loop_add(4.0, _e_pointer_cb_idle_wait, ptr);
+   rotation = ptr->rotation;
 
-   return ECORE_CALLBACK_CANCEL;
-}
+   evas_object_geometry_get(ec->frame, NULL, NULL, &cursor_w, &cursor_h);
+   _e_pointer_configured_output_resolution_ratio_get(ec, &ratio);
 
-static void 
-_e_pointer_active_handle(E_Pointer *ptr)
-{
-   _e_pointer_active(ptr);
-   if (ptr->idle_tmr)
-     ecore_timer_reset(ptr->idle_tmr);
+   if (ratio != 1.0)
+     {
+        hot_x = (int)((double)ptr->hot.x * ratio);
+        hot_y = (int)((double)ptr->hot.y * ratio);
+     }
    else
      {
-        E_FREE_FUNC(ptr->idle_poll, ecore_poller_del);
-        if (e_powersave_mode_get() >= E_POWERSAVE_MODE_MEDIUM) return;
-        if (!e_config->idle_cursor) return;
-        ptr->idle_tmr = ecore_timer_loop_add(1.0, _e_pointer_cb_idle_pre, ptr);
+        hot_x = ptr->hot.x;
+        hot_y = ptr->hot.y;
      }
-}
-
-static Eina_Bool 
-_e_pointer_cb_mouse_down(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED)
-{
-   Eina_List *l;
-   E_Pointer *ptr;
 
-   EINA_LIST_FOREACH(_ptrs, l, ptr)
+   switch (rotation)
      {
-        _e_pointer_active_handle(ptr);
-        if (e_powersave_mode_get() < E_POWERSAVE_MODE_EXTREME)
-          {
-             if (ptr->o_ptr)
-               edje_object_signal_emit(ptr->o_ptr, "e,action,mouse,down", "e");
-          }
+      case 0:
+        nx = ptr->x - hot_x;
+        ny = ptr->y - hot_y;
+        break;
+      case 90:
+        nx = ptr->x - hot_y;
+        ny = ptr->y + hot_x;
+        break;
+      case 180:
+        nx = ptr->x + hot_x;
+        ny = ptr->y + hot_y;
+        break;
+      case 270:
+        nx = ptr->x + hot_y;
+        ny = ptr->y - hot_x;
+        break;
+      default:
+        nx = ptr->x - hot_x;
+        ny = ptr->y - hot_y;
+        break;
      }
 
-   return ECORE_CALLBACK_PASS_ON;
+   evas_object_move(ptr->o_ptr, nx, ny);
 }
 
-static Eina_Bool 
-_e_pointer_cb_mouse_up(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED)
+static void
+_e_pointer_map_apply(E_Pointer *ptr)
 {
-   Eina_List *l;
-   E_Pointer *ptr;
+   E_Map *map;
+   int x, y, w, h;
+   E_Client *ec;
+   int rotation = 0;
+   double ratio = 1.0;
 
-   EINA_LIST_FOREACH(_ptrs, l, ptr)
-     {
-        _e_pointer_active_handle(ptr);
-        if (e_powersave_mode_get() < E_POWERSAVE_MODE_EXTREME)
-          {
-             if (ptr->o_ptr)
-               edje_object_signal_emit(ptr->o_ptr, "e,action,mouse,up", "e");
-          }
-     }
+   EINA_SAFETY_ON_NULL_RETURN(ptr);
+   if (!ptr->o_ptr) return;
 
-   return ECORE_CALLBACK_PASS_ON;
-}
+   ec = e_comp_object_client_get(ptr->o_ptr);
+   EINA_SAFETY_ON_NULL_RETURN(ec);
 
-static Eina_Bool 
-_e_pointer_cb_mouse_move(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED)
-{
-   Eina_List *l;
-   E_Pointer *ptr;
+   _e_pointer_configured_output_resolution_ratio_get(ec, &ratio);
+   rotation = ptr->rotation;
 
-   EINA_LIST_FOREACH(_ptrs, l, ptr)
+   if ((ratio == 1.0) &&
+       ((rotation == 0) || (rotation % 90 != 0) || (rotation / 90 > 3)))
      {
-        _e_pointer_active_handle(ptr);
-        if (e_powersave_mode_get() < E_POWERSAVE_MODE_HIGH)
-          {
-             if (ptr->o_ptr)
-               edje_object_signal_emit(ptr->o_ptr, "e,action,mouse,move", "e");
-          }
+        e_client_map_enable_set(ec, EINA_FALSE);
+        e_client_map_set(ec, NULL);
+        return;
      }
 
-   return ECORE_CALLBACK_PASS_ON;
-}
+   evas_object_geometry_get(ec->frame, &x, &y, &w, &h);
 
-static Eina_Bool 
-_e_pointer_cb_mouse_wheel(void *data EINA_UNUSED, int type EINA_UNUSED, void *event EINA_UNUSED)
-{
-   Eina_List *l;
-   E_Pointer *ptr;
+   map = e_map_new();
+   EINA_SAFETY_ON_NULL_RETURN(map);
 
-   EINA_LIST_FOREACH(_ptrs, l, ptr)
+   e_map_util_points_populate_from_object_full(map, ec->frame, 0);
+
+   if (ratio != 1.0)
      {
-        _e_pointer_active_handle(ptr);
-        if (e_powersave_mode_get() < E_POWERSAVE_MODE_EXTREME)
-          {
-             if (ptr->o_ptr)
-               edje_object_signal_emit(ptr->o_ptr, "e,action,mouse,wheel", "e");
-          }
+        e_map_point_coord_set(map, 1, x + (int)((double)w * ratio), y, 0);
+        e_map_point_coord_set(map, 2, x + (int)((double)w * ratio),
+                             y + (int)((double)h * ratio), 0);
+        e_map_point_coord_set(map, 3, x, y + (int)((double)h * ratio), 0);
      }
 
-   return ECORE_CALLBACK_PASS_ON;
-}
+   if (rotation)
+     {
+        if (rotation == 90)
+          rotation = 270;
+        else if (rotation == 270)
+          rotation = 90;
 
-static void 
-_e_pointer_cb_hot_move(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
-{
-   E_Pointer *ptr = data;
-   int x = 0, y = 0;
+        e_map_util_rotate(map, rotation, x, y);
+     }
 
-   if (!ptr->e_cursor) return;
-   if (!evas_object_visible_get(ptr->o_ptr)) return;
-   edje_object_part_geometry_get(ptr->o_ptr, "e.swallow.hotspot", 
-                                 &x, &y, NULL, NULL);
-   _e_pointer_hot_update(ptr, x, y);
-}
+   e_map_util_points_color_set(map, 255, 255, 255, 255);
+   e_map_util_object_move_sync_set(map, EINA_TRUE);
 
-static void 
-_e_pointer_cb_hot_show(void *data, Evas *evas EINA_UNUSED, Evas_Object *obj EINA_UNUSED, void *event EINA_UNUSED)
-{
-   E_Pointer *ptr = data;
-   int x = 0, y = 0;
+   e_client_map_set(ec, map);
+   e_client_map_enable_set(ec, EINA_TRUE);
 
-   if (!ptr->e_cursor) return;
-   edje_object_part_geometry_get(ptr->o_ptr, "e.swallow.hotspot", 
-                                 &x, &y, NULL, NULL);
-   _e_pointer_hot_update(ptr, x, y);
+   e_map_free(map);
 }
 
 static void
-_e_pointer_pointer_canvas_init(E_Pointer *ptr, Evas *e, Evas_Object **o_ptr, Evas_Object **o_hot)
+_e_pointer_cb_object_del(void *data, Evas *e EINA_UNUSED, Evas_Object *obj, void *event_info EINA_UNUSED)
 {
-   /* create pointer object */
-   *o_ptr = edje_object_add(e);
-
-   /* create hotspot object */
-   *o_hot = evas_object_rectangle_add(e);
-   evas_object_color_set(*o_hot, 0, 0, 0, 0);
+   E_Pointer *ptr = (E_Pointer *)data;
 
-   evas_object_event_callback_add(*o_hot, EVAS_CALLBACK_MOVE,
-                                  _e_pointer_cb_hot_move, ptr);
-   evas_object_event_callback_add(*o_hot, EVAS_CALLBACK_SHOW,
-                                  _e_pointer_cb_hot_show, ptr);
-
-   evas_object_move(*o_ptr, 0, 0);
-   evas_object_resize(*o_ptr, ptr->w, ptr->h);
+   ptr->o_ptr = NULL;
+   ptr->device = E_POINTER_NONE;
+   ptr->hot.x = 0;
+   ptr->hot.y = 0;
 }
 
-static void 
-_e_pointer_canvas_del(E_Pointer *ptr)
+static void
+_e_pointer_object_set(E_Pointer *ptr, Evas_Object *obj)
 {
-   E_FREE_FUNC(ptr->buffer_o_hot, evas_object_del);
-   E_FREE_FUNC(ptr->buffer_o_ptr, evas_object_del);
-   E_FREE_FUNC(ptr->buffer_evas, evas_free);
-   E_FREE(ptr->pixels);
-}
+   if (ptr->o_ptr == obj) return;
 
-static void 
-_e_pointer_canvas_add(E_Pointer *ptr)
-{
-   Evas_Engine_Info_Buffer *einfo;
-   int method = 0;
-
-   /* try to create new canvas */
-   if (!(ptr->buffer_evas = evas_new())) goto err;
-
-   method = evas_render_method_lookup("buffer");
-   evas_output_method_set(ptr->buffer_evas, method);
-   evas_output_size_set(ptr->buffer_evas, ptr->w, ptr->h);
-   evas_output_viewport_set(ptr->buffer_evas, 0, 0, ptr->w, ptr->h);
-
-   /* try to allocate space for pixels */
-   if (!(ptr->pixels = malloc(ptr->w * ptr->h * sizeof(int))))
-     goto err;
-
-   /* try to get the buffer engine info */
-   einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(ptr->buffer_evas);
-   if (!einfo) goto err;
-
-   /* fill in buffer engine info */
-   einfo->info.depth_type = EVAS_ENGINE_BUFFER_DEPTH_ARGB32;
-   einfo->info.dest_buffer = ptr->pixels;
-   einfo->info.dest_buffer_row_bytes = (ptr->w * sizeof(int));
-   einfo->info.use_color_key = 0;
-   einfo->info.alpha_threshold = 0;
-   einfo->info.func.new_update_region = NULL;
-   einfo->info.func.free_update_region = NULL;
-
-   /* set buffer engine info */
-   evas_engine_info_set(ptr->buffer_evas, (Evas_Engine_Info *)einfo);
-
-   _e_pointer_pointer_canvas_init(ptr, ptr->buffer_evas, &ptr->buffer_o_ptr, &ptr->buffer_o_hot);
-   if (!ptr->evas)
+   if (ptr->o_ptr)
      {
-        ptr->evas = ptr->buffer_evas;
-        ptr->o_ptr = ptr->buffer_o_ptr;
-        ptr->o_hot = ptr->buffer_o_hot;
+         evas_object_event_callback_del_full(ptr->o_ptr, EVAS_CALLBACK_DEL, _e_pointer_cb_object_del, ptr);
+         ptr->o_ptr = NULL;
      }
-   return;
-
-err:
-   _e_pointer_canvas_del(ptr);
-}
-
-static void 
-_e_pointer_canvas_resize(E_Pointer *ptr, int w, int h)
-{
-   Evas_Engine_Info_Buffer *einfo;
-
-   if ((ptr->w == w) && (ptr->h == h)) return;
-   ptr->w = w;
-   ptr->h = h;
-   evas_output_size_set(ptr->buffer_evas, w, h);
-   evas_output_viewport_set(ptr->buffer_evas, 0, 0, w, h);
-
-   ptr->pixels = realloc(ptr->pixels, (ptr->w * ptr->h * sizeof(int)));
 
-   einfo = (Evas_Engine_Info_Buffer *)evas_engine_info_get(ptr->buffer_evas);
-   EINA_SAFETY_ON_NULL_RETURN(einfo);
-
-   einfo->info.dest_buffer = ptr->pixels;
-   einfo->info.dest_buffer_row_bytes = (ptr->w * sizeof(int));
-   evas_engine_info_set(ptr->buffer_evas, (Evas_Engine_Info *)einfo);
-
-   evas_object_move(ptr->buffer_o_ptr, 0, 0);
-   evas_object_resize(ptr->buffer_o_ptr, ptr->w, ptr->h);
-}
-
-static void 
-_e_pointer_stack_free(E_Pointer_Stack *stack)
-{
-   if (stack->type) eina_stringshare_del(stack->type);
-   free(stack);
+   if (obj)
+     {
+        evas_object_event_callback_add(obj, EVAS_CALLBACK_DEL, _e_pointer_cb_object_del, ptr);
+        ptr->o_ptr = obj;
+     }
 }
 
-static void 
+static void
 _e_pointer_cb_free(E_Pointer *ptr)
 {
-   _ptrs = eina_list_remove(_ptrs, ptr);
-
-   E_FREE_LIST(ptr->stack, _e_pointer_stack_free);
-
-   eina_stringshare_del(ptr->type);
+   _e_pointer_object_set(ptr, NULL);
 
-   E_FREE_FUNC(ptr->idle_tmr, ecore_timer_del);
-   E_FREE_FUNC(ptr->idle_poll, ecore_poller_del);
-
-   if (ptr->buffer_evas) _e_pointer_canvas_del(ptr);
+   _ptrs = eina_list_remove(_ptrs, ptr);
 
    free(ptr);
 }
 
 static void
-_e_pointer_x11_setup(E_Pointer *ptr, const char *cursor)
+_e_pointer_hooks_clean(void)
 {
-   if (ptr->e_cursor)
-     {
-        /* create a pointer canvas if we need to */
-        if ((!ptr->buffer_evas) && ptr->win) _e_pointer_canvas_add(ptr);
-        if (ptr->buffer_o_ptr && (ptr->buffer_o_ptr != ptr->o_ptr))
-          {
-             e_theme_edje_object_set(ptr->buffer_o_ptr, "base/theme/pointer", cursor);
-             edje_object_part_swallow(ptr->buffer_o_ptr, "e.swallow.hotspot", ptr->buffer_o_hot);
-          }
-        return;
-     }
-   if (ptr->buffer_evas) _e_pointer_canvas_del(ptr);
-#ifndef HAVE_WAYLAND_ONLY
-   if (!e_comp_util_has_x()) return;
-   Ecore_X_Cursor curs = 0;
-
-   if (!strcmp(ptr->type, "move"))
-     curs = ecore_x_cursor_shape_get(ECORE_X_CURSOR_FLEUR);
-# if 0
-   else if (!strcmp(ptr->type, "resize"))
-     curs = ecore_x_cursor_shape_get(ECORE_X_CURSOR_SIZING);
-# endif
-   else if (!strcmp(ptr->type, "resize_tl"))
-     curs = ecore_x_cursor_shape_get(ECORE_X_CURSOR_TOP_LEFT_CORNER);
-   else if (!strcmp(ptr->type, "resize_t"))
-     curs = ecore_x_cursor_shape_get(ECORE_X_CURSOR_TOP_SIDE);
-   else if (!strcmp(ptr->type, "resize_tr"))
-     curs = ecore_x_cursor_shape_get(ECORE_X_CURSOR_TOP_RIGHT_CORNER);
-   else if (!strcmp(ptr->type, "resize_r"))
-     curs = ecore_x_cursor_shape_get(ECORE_X_CURSOR_RIGHT_SIDE);
-   else if (!strcmp(ptr->type, "resize_br"))
-     curs = ecore_x_cursor_shape_get(ECORE_X_CURSOR_BOTTOM_RIGHT_CORNER);
-   else if (!strcmp(ptr->type, "resize_b"))
-     curs = ecore_x_cursor_shape_get(ECORE_X_CURSOR_BOTTOM_SIDE);
-   else if (!strcmp(ptr->type, "resize_bl"))
-     curs = ecore_x_cursor_shape_get(ECORE_X_CURSOR_BOTTOM_LEFT_CORNER);
-   else if (!strcmp(ptr->type, "resize_l"))
-     curs = ecore_x_cursor_shape_get(ECORE_X_CURSOR_LEFT_SIDE);
-   else if (!strcmp(ptr->type, "entry"))
-     curs = ecore_x_cursor_shape_get(ECORE_X_CURSOR_XTERM);
-   else if (!strcmp(ptr->type, "default"))
-     curs = ecore_x_cursor_shape_get(ECORE_X_CURSOR_LEFT_PTR);
-   else if (!strcmp(ptr->type, "plus"))
-     curs = ecore_x_cursor_shape_get(ECORE_X_CURSOR_PLUS);
-   else if (!strcmp(ptr->type, "hand"))
-     curs = ecore_x_cursor_shape_get(ECORE_X_CURSOR_HAND1);
-   else if (!strcmp(ptr->type, "rotate"))
-     curs = ecore_x_cursor_shape_get(ECORE_X_CURSOR_EXCHANGE);
-   else
-     {
-        WRN("Unknown pointer ptr->type: %s\n", ptr->type);
-        curs = ecore_x_cursor_shape_get(ECORE_X_CURSOR_ARROW);
-     }
-   if (!curs) WRN("X Cursor for %s is missing\n", ptr->type);
-   ecore_x_window_cursor_set(ptr->win, curs);
-   if (curs) ecore_x_cursor_free(curs);
-#endif
-}
+   Eina_Inlist *l;
+   E_Pointer_Hook *ph;
+   unsigned int x;
 
-static void 
-_e_pointer_type_set(E_Pointer *ptr, const char *type)
-{
-   /* check if pointer type is already set */
-   if (!e_util_strcmp(ptr->type, type)) return;
+   for (x = 0; x < E_POINTER_HOOK_LAST; x++)
+     EINA_INLIST_FOREACH_SAFE(_e_pointer_hooks[x], l, ph)
+       {
+          if (!ph->delete_me) continue;
+          _e_pointer_hooks[x] = eina_inlist_remove(_e_pointer_hooks[x], EINA_INLIST_GET(ph));
+          free(ph);
+       }
 
-   eina_stringshare_replace(&ptr->type, type);
+   _e_pointer_hooks_delete = 0;
+}
 
-   /* don't show cursor if in hidden mode */
-   if (!e_config->show_cursor)
-     {
-        e_pointer_hide(ptr);
-        return;
-     }
+static Eina_Bool
+_e_pointer_hook_call(E_Pointer_Hook_Point hookpoint, E_Pointer *ptr)
+{
+   E_Pointer_Hook *ph;
 
-   if (ptr->e_cursor)
+   e_object_ref(E_OBJECT(ptr));
+   _e_pointer_hooks_walking++;
+   EINA_INLIST_FOREACH(_e_pointer_hooks[hookpoint], ph)
      {
-        char cursor[1024];
-        int x = 0, y = 0;
-
-        if ((!ptr->buffer_evas) && ptr->win) _e_pointer_canvas_add(ptr);
-        _e_pointer_theme_buf(ptr, cursor);
-
-        /* try to set the edje object theme */
-        if (!e_theme_edje_object_set(ptr->o_ptr, "base/theme/pointer", cursor))
-          cursor[0] = 0;
-        _e_pointer_x11_setup(ptr, cursor);
-        if (!cursor[0]) return;
-
-        edje_object_part_geometry_get(ptr->o_ptr, "e.swallow.hotspot", 
-                                      &x, &y, NULL, NULL);
-        _e_pointer_hot_update(ptr, x, y);
-
-        if (ptr->canvas)
-          e_pointer_object_set(ptr, NULL, 0, 0);
-        else
-          evas_object_show(ptr->o_ptr);
-
+        if (ph->delete_me) continue;
+        ph->func(ph->data, ptr);
+        if (e_object_is_del(E_OBJECT(ptr)))
+          break;
      }
-   else
-     _e_pointer_x11_setup(ptr, NULL);
+   _e_pointer_hooks_walking--;
+   if ((_e_pointer_hooks_walking == 0) && (_e_pointer_hooks_delete > 0))
+     _e_pointer_hooks_clean();
+   return !!e_object_unref(E_OBJECT(ptr));
 }
 
-EINTERN int 
+EINTERN int
 e_pointer_init(void)
 {
-   E_LIST_HANDLER_APPEND(_hdlrs, ECORE_EVENT_MOUSE_BUTTON_DOWN, 
-                         _e_pointer_cb_mouse_down, NULL);
-   E_LIST_HANDLER_APPEND(_hdlrs, ECORE_EVENT_MOUSE_BUTTON_UP, 
-                         _e_pointer_cb_mouse_up, NULL);
-   E_LIST_HANDLER_APPEND(_hdlrs, ECORE_EVENT_MOUSE_MOVE, 
-                         _e_pointer_cb_mouse_move, NULL);
-   E_LIST_HANDLER_APPEND(_hdlrs, ECORE_EVENT_MOUSE_WHEEL, 
-                         _e_pointer_cb_mouse_wheel, NULL);
+   _initted = EINA_TRUE;
    return 1;
 }
 
-EINTERN int 
+EINTERN int
 e_pointer_shutdown(void)
 {
-   E_FREE_LIST(_hdlrs, ecore_event_handler_del);
+   _initted = EINA_FALSE;
    return 1;
 }
 
-E_API E_Pointer *
-e_pointer_window_new(Ecore_Window win, Eina_Bool filled)
-{
-   E_Pointer *ptr = NULL;
-
-   EINA_SAFETY_ON_FALSE_RETURN_VAL(win, NULL);
-
-   /* allocate space for new pointer */
-   if (!(ptr = E_OBJECT_ALLOC(E_Pointer, E_POINTER_TYPE, _e_pointer_cb_free)))
-     return NULL;
-
-   /* set default pointer properties */
-   ptr->w = ptr->h = e_config->cursor_size;
-   ptr->e_cursor = e_config->use_e_cursor;
-   ptr->win = win;
-   ptr->color = EINA_FALSE;
-   if (e_comp->pointer)
-     ptr->color = e_comp->pointer->color;
-
-   /* set pointer default type */
-   if (filled) e_pointer_type_push(ptr, ptr, "default");
-
-   /* append this pointer to the list */
-   _ptrs = eina_list_append(_ptrs, ptr);
-
-   return ptr;
-}
-
-E_API E_Pointer *
+EINTERN E_Pointer *
 e_pointer_canvas_new(Ecore_Evas *ee, Eina_Bool filled)
 {
    E_Pointer *ptr = NULL;
+   E_Output *output = NULL;
 
    EINA_SAFETY_ON_FALSE_RETURN_VAL(ee, NULL);
+   if (!_initted) return NULL;
 
    /* allocate space for new pointer */
    if (!(ptr = E_OBJECT_ALLOC(E_Pointer, E_POINTER_TYPE, _e_pointer_cb_free)))
      return NULL;
 
    /* set default pointer properties */
-   ptr->color = EINA_TRUE;
    ptr->canvas = EINA_TRUE;
    ptr->w = ptr->h = e_config->cursor_size;
    ptr->e_cursor = e_config->use_e_cursor;
+   output = e_output_find_by_index(0);
+   if (output)
+     {
+        ptr->x = output->config.mode.w / 2;
+        ptr->y = output->config.mode.h / 2;
+     }
 
    ptr->ee = ee;
    ptr->evas = ecore_evas_get(ee);
-   _e_pointer_pointer_canvas_init(ptr, ptr->evas, &ptr->o_ptr, &ptr->o_hot);
 
-   /* set pointer default type */
-   if (filled) e_pointer_type_push(ptr, ptr, "default");
-
-     /* append this pointer to the list */
+   /* append this pointer to the list */
    _ptrs = eina_list_append(_ptrs, ptr);
 
-   _e_pointer_active_handle(ptr);
-
    return ptr;
 }
 
-E_API void 
-e_pointers_size_set(int size)
+static Eina_Bool
+_e_pointer_object_hide(E_Pointer *ptr, Evas_Object *obj)
 {
-   Eina_List *l;
-   E_Pointer *ptr;
+   E_Client *ec;
+   Eina_Bool res = EINA_FALSE;
 
-   if (!e_config->show_cursor) return;
+   ec = e_comp_object_client_get(obj);
+   if ((ec) && (!e_object_is_del(E_OBJECT(ec))))
+     {
+        ec->hidden = 1;
+        ec->visible = EINA_FALSE;
+        ec->visibility.obscured = E_VISIBILITY_FULLY_OBSCURED;
+        ec->comp_data->mapped = EINA_FALSE;
+        ec->override = 1; /* ignore the previous cursor_ec */
+     }
 
-   EINA_LIST_FOREACH(_ptrs, l, ptr)
+   /* hide cursor object */
+   if (evas_object_visible_get(obj))
      {
-        if ((ptr->w == size) && (ptr->h == size)) continue;
-        if (ptr->buffer_evas)
-          _e_pointer_canvas_resize(ptr, size, size);
-        if (ptr->canvas)
-          {
-             ptr->w = size;
-             ptr->h = size;
-             evas_object_resize(ptr->o_ptr, size, size);
-          }
+        res = EINA_TRUE;
+        evas_object_hide(obj);
      }
-#ifndef HAVE_WAYLAND_ONLY
-   if (e_comp_util_has_x())
-     ecore_x_cursor_size_set(e_config->cursor_size * 3 / 4);
-#endif
-}
 
-E_API void 
-e_pointer_hide(E_Pointer *ptr)
-{
-   if (ptr->buffer_evas)
-     _e_pointer_canvas_del(ptr);
-   if (ptr->canvas)
-     evas_object_hide(ptr->o_ptr);
-#ifndef HAVE_WAYLAND_ONLY
-   if (ptr->win)
-     ecore_x_window_cursor_set(ptr->win, 0);
-#endif
+   _e_pointer_object_set(ptr, NULL);
+   ptr->device = E_POINTER_NONE;
+
+   return res;
 }
 
-E_API void 
-e_pointer_type_push(E_Pointer *ptr, void *obj, const char *type)
+static Eina_Bool
+_e_pointer_object_show(E_Pointer *ptr, Evas_Object *obj)
 {
-   E_Pointer_Stack *stack;
+   E_Client *ec;
+   Eina_Bool res = EINA_FALSE;
 
-   EINA_SAFETY_ON_NULL_RETURN(ptr);
+   ec = e_comp_object_client_get(obj);
+   if (ec && e_pixmap_usable_get(ec->pixmap))
+     {
+        ec->hidden = 0;
+        ec->visible = EINA_TRUE;
+        ec->visibility.obscured = E_VISIBILITY_UNOBSCURED;
+        evas_object_geometry_set(ec->frame, ec->x, ec->y, ec->w, ec->h);
+        ec->comp_data->mapped = EINA_TRUE;
+        ec->override = 0; /* do not ignore the cursor_ec to set the image object */
+     }
 
-   _e_pointer_type_set(ptr, type);
+   /* show cursor object */
+   if (!evas_object_visible_get(obj))
+     {
+        res = EINA_TRUE;
+        evas_object_show(obj);
+     }
 
-   if (!(stack = E_NEW(E_Pointer_Stack, 1))) return;
-   stack->type = eina_stringshare_ref(ptr->type);
-   stack->obj = obj;
-   ptr->stack = eina_list_prepend(ptr->stack, stack);
+   _e_pointer_object_set(ptr, obj);
+
+   return res;
 }
 
-E_API void 
-e_pointer_type_pop(E_Pointer *ptr, void *obj, const char *type)
+EINTERN void
+e_pointer_object_set(E_Pointer *ptr, Evas_Object *obj, int x, int y)
 {
-   Eina_List *l, *ll;
-   E_Pointer_Stack *stack;
+   Eina_Bool need_call_hide = EINA_FALSE;
 
    EINA_SAFETY_ON_NULL_RETURN(ptr);
 
-   EINA_LIST_FOREACH_SAFE(ptr->stack, l, ll, stack)
+   /* don't show cursor if in hidden mode */
+   if ((!e_config->show_cursor) || (!e_comp_wl->ptr.enabled))
      {
-        if ((stack->obj == obj) && 
-            ((!type) || (!e_util_strcmp(stack->type, type))))
-          {
-             _e_pointer_stack_free(stack);
-             ptr->stack = eina_list_remove_list(ptr->stack, l);
-             if (type) break;
-          }
+        if (ptr->o_ptr && _e_pointer_object_hide(ptr, ptr->o_ptr))
+          _e_pointer_hook_call(E_POINTER_HOOK_HIDE, ptr);
+
+        return;
      }
 
-   if (!ptr->stack)
+   /* hide and unset the existed ptr->o_ptr */
+   if (ptr->o_ptr && (ptr->o_ptr != obj))
      {
-        e_pointer_hide(ptr);
-        eina_stringshare_replace(&ptr->type, NULL);
-        return;
+        if (_e_pointer_object_hide(ptr, ptr->o_ptr))
+          need_call_hide = EINA_TRUE;
      }
 
-   if (!(stack = eina_list_data_get(ptr->stack))) return;
+   /* update the hot spot of the cursor */
+   ptr->hot.x = x;
+   ptr->hot.y = y;
 
-   _e_pointer_type_set(ptr, stack->type);
+   /* if obj is not null, set the obj to ptr->o_ptr */
+   if (obj && (ptr->o_ptr != obj))
+     {
+        if (_e_pointer_object_show(ptr, obj))
+          {
+             need_call_hide = EINA_FALSE;
+             _e_pointer_hook_call(E_POINTER_HOOK_SHOW, ptr);
+          }
+
+        /* apply the cursor obj map */
+        _e_pointer_map_apply(ptr);
 
-   eina_stringshare_refplace(&ptr->type, stack->type);
+        /* move the pointer to the current position */
+        _e_pointer_position_update(ptr);
+     }
+
+   if (need_call_hide)
+     _e_pointer_hook_call(E_POINTER_HOOK_HIDE, ptr);
 }
 
-E_API void 
-e_pointer_mode_push(void *obj, E_Pointer_Mode mode)
+EINTERN void
+e_pointer_touch_move(E_Pointer *ptr, int x, int y)
 {
-   switch (mode)
-     {
-      case E_POINTER_RESIZE_TL:
-        e_pointer_type_push(e_comp->pointer, obj, "resize_tl");
-        break;
+   EINA_SAFETY_ON_NULL_RETURN(ptr);
 
-      case E_POINTER_RESIZE_T:
-        e_pointer_type_push(e_comp->pointer, obj, "resize_t");
-        break;
+   if (!e_config->show_cursor) return;
 
-      case E_POINTER_RESIZE_TR:
-        e_pointer_type_push(e_comp->pointer, obj, "resize_tr");
-        break;
+   /* save the current position */
+   ptr->x = x;
+   ptr->y = y;
 
-      case E_POINTER_RESIZE_R:
-        e_pointer_type_push(e_comp->pointer, obj, "resize_r");
-        break;
+   if (ptr->device != E_POINTER_TOUCH) ptr->device = E_POINTER_TOUCH;
 
-      case E_POINTER_RESIZE_BR:
-        e_pointer_type_push(e_comp->pointer, obj, "resize_br");
-        break;
+   _e_pointer_position_update(ptr);
 
-      case E_POINTER_RESIZE_B:
-        e_pointer_type_push(e_comp->pointer, obj, "resize_b");
-        break;
+   _e_pointer_hook_call(E_POINTER_HOOK_TOUCH_MOVE, ptr);
+}
 
-      case E_POINTER_RESIZE_BL:
-        e_pointer_type_push(e_comp->pointer, obj, "resize_bl");
-        break;
+E_API void
+e_pointer_mouse_move(E_Pointer *ptr, int x, int y)
+{
+   EINA_SAFETY_ON_NULL_RETURN(ptr);
 
-      case E_POINTER_RESIZE_L:
-        e_pointer_type_push(e_comp->pointer, obj, "resize_l");
-        break;
+   if (!e_config->show_cursor) return;
 
-      case E_POINTER_MOVE:
-        e_pointer_type_push(e_comp->pointer, obj, "move");
-        break;
+   /* save the current position */
+   ptr->x = x;
+   ptr->y = y;
 
-      default: break;
-     }
+   if (ptr->device != E_POINTER_MOUSE) ptr->device = E_POINTER_MOUSE;
+
+   _e_pointer_position_update(ptr);
+
+   _e_pointer_hook_call(E_POINTER_HOOK_MOUSE_MOVE, ptr);
 }
 
-E_API void 
-e_pointer_mode_pop(void *obj, E_Pointer_Mode mode)
+EINTERN void
+e_pointer_hide(E_Pointer *ptr)
 {
-   switch (mode)
-     {
-      case E_POINTER_RESIZE_TL:
-        e_pointer_type_pop(e_comp->pointer, obj, "resize_tl");
-        break;
+   EINA_SAFETY_ON_NULL_RETURN(ptr);
+   if (!ptr->o_ptr) return;
+   if (!evas_object_visible_get(ptr->o_ptr)) return;
 
-      case E_POINTER_RESIZE_T:
-        e_pointer_type_pop(e_comp->pointer, obj, "resize_t");
-        break;
+   evas_object_hide(ptr->o_ptr);
+}
 
-      case E_POINTER_RESIZE_TR:
-        e_pointer_type_pop(e_comp->pointer, obj, "resize_tr");
-        break;
+E_API Eina_Bool
+e_pointer_is_hidden(E_Pointer *ptr)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(ptr, EINA_TRUE);
 
-      case E_POINTER_RESIZE_R:
-        e_pointer_type_pop(e_comp->pointer, obj, "resize_r");
-        break;
+   if (!e_config->show_cursor) return EINA_TRUE;
+   if (ptr->o_ptr && evas_object_visible_get(ptr->o_ptr)) return EINA_FALSE;
 
-      case E_POINTER_RESIZE_BR:
-        e_pointer_type_pop(e_comp->pointer, obj, "resize_br");
-        break;
+   return EINA_TRUE;
+}
 
-      case E_POINTER_RESIZE_B:
-        e_pointer_type_pop(e_comp->pointer, obj, "resize_b");
-        break;
+E_API void
+e_pointer_rotation_set(E_Pointer *ptr, int rotation)
+{
+   const Eina_List *l;
+   E_Input_Device *dev;
 
-      case E_POINTER_RESIZE_BL:
-        e_pointer_type_pop(e_comp->pointer, obj, "resize_bl");
-        break;
+   EINA_SAFETY_ON_NULL_RETURN(ptr);
+   if (ptr->rotation == rotation) return;
 
-      case E_POINTER_RESIZE_L:
-        e_pointer_type_pop(e_comp->pointer, obj, "resize_l");
-        break;
+   ptr->rotation = rotation;
 
-      case E_POINTER_MOVE:
-        e_pointer_type_pop(e_comp->pointer, obj, "move");
-        break;
+   _e_pointer_map_apply(ptr);
+   _e_pointer_position_update(ptr);
 
-      default: break;
-     }
+   EINA_LIST_FOREACH(e_input_devices_get(), l, dev)
+     e_input_device_pointer_rotation_set(dev, rotation);
 }
 
-E_API void 
-e_pointer_idler_before(void)
+EINTERN void
+e_pointer_position_get(E_Pointer *ptr, int *x, int *y)
 {
-   Eina_List *l;
-   E_Pointer *ptr;
+   EINA_SAFETY_ON_NULL_RETURN(ptr);
 
    if (!e_config->show_cursor) return;
+   if (!ptr->o_ptr) return;
+   if (!evas_object_visible_get(ptr->o_ptr)) return;
+
+   *x = ptr->x;
+   *y = ptr->y;
+}
+
+EINTERN E_Pointer *
+e_pointer_get(E_Client *ec)
+{
+   const Eina_List *l;
+   E_Pointer *ptr;
+   E_Client *ptr_ec = NULL;
+
+   if ((!ec) || (e_object_is_del(E_OBJECT(ec)))) return NULL;
 
    EINA_LIST_FOREACH(_ptrs, l, ptr)
      {
-        if ((!ptr->e_cursor) || (!ptr->buffer_evas)) continue;
-
-        if (ptr->hot.update)
-          _e_pointer_type_set(ptr, ptr->type);
-        if (ptr->buffer_evas)
+        if (ptr->o_ptr)
           {
-             Eina_List *updates;
-
-             if ((updates = evas_render_updates(ptr->buffer_evas)))
-               {
-#ifndef HAVE_WAYLAND_ONLY
-                  Ecore_X_Cursor cur;
-
-                  cur = ecore_x_cursor_new(ptr->win, ptr->pixels, ptr->w, 
-                                           ptr->h, ptr->hot.x, ptr->hot.y);
-                  ecore_x_window_cursor_set(ptr->win, cur);
-                  ecore_x_cursor_free(cur);
-#endif
-                  evas_render_updates_free(updates);
-               }
+             ptr_ec = e_comp_object_client_get(ptr->o_ptr);
+             if (ptr_ec == ec)
+                return ptr;
           }
-
-        ptr->hot.update = EINA_FALSE;
      }
+
+  return NULL;
 }
 
-E_API void
-e_pointer_object_set(E_Pointer *ptr, Evas_Object *obj, int x, int y)
+E_API E_Pointer_Hook *
+e_pointer_hook_add(E_Pointer_Hook_Point hookpoint, E_Pointer_Hook_Cb func, const void *data)
 {
-   Evas_Object *o;
-   E_Client *ec;
+   E_Pointer_Hook *ph;
 
-   ecore_evas_cursor_get(ptr->ee, &o, NULL, NULL, NULL);
-   if (o)
-     {
-        if (o == obj)
-          {
-             ecore_evas_object_cursor_set(ptr->ee, obj, EVAS_LAYER_MAX, x, y);
-             return;
-          }
-        ec = e_comp_object_client_get(o);
-        if (ec)
-          ec->hidden = 1;
-     }
-   ecore_evas_cursor_unset(ptr->ee);
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(hookpoint >= E_POINTER_HOOK_LAST, NULL);
+   ph = E_NEW(E_Pointer_Hook, 1);
+   if (!ph) return NULL;
+   ph->hookpoint = hookpoint;
+   ph->func = func;
+   ph->data = (void*)data;
+   _e_pointer_hooks[hookpoint] = eina_inlist_append(_e_pointer_hooks[hookpoint], EINA_INLIST_GET(ph));
+   return ph;
+}
 
-   if (obj)
+E_API void
+e_pointer_hook_del(E_Pointer_Hook *ph)
+{
+   ph->delete_me = 1;
+   if (_e_pointer_hooks_walking == 0)
      {
-        ec = e_comp_object_client_get(obj);
-        if (ec)
-          ec->hidden = 1;
-        ecore_evas_object_cursor_set(ptr->ee, obj, EVAS_LAYER_MAX, x, y);
+        _e_pointer_hooks[ph->hookpoint] = eina_inlist_remove(_e_pointer_hooks[ph->hookpoint], EINA_INLIST_GET(ph));
+        free(ph);
      }
    else
-     ecore_evas_object_cursor_set(ptr->ee, ptr->o_ptr, EVAS_LAYER_MAX, ptr->hot.x, ptr->hot.y);
+     _e_pointer_hooks_delete++;
 }