evas: handle existing pointer grabs when changing object pointer mode
authorMike Blumenkrantz <zmike@osg.samsung.com>
Tue, 22 Dec 2015 21:10:36 +0000 (16:10 -0500)
committerMike Blumenkrantz <zmike@osg.samsung.com>
Tue, 22 Dec 2015 21:21:11 +0000 (16:21 -0500)
in the case that pointer mode is changed on an object at any time after
a grab has been acquired by the object, grabs/flags must be adjusted for
this and other "pointer-in" objects in order to avoid permanently
breaking canvas events

@fix

src/lib/evas/canvas/evas_events.c

index 3089cf0..0ef5e91 100644 (file)
@@ -2863,8 +2863,71 @@ _evas_object_propagate_events_get(Eo *eo_obj EINA_UNUSED, Evas_Object_Protected_
 }
 
 EOLIAN void
-_evas_object_pointer_mode_set(Eo *eo_obj EINA_UNUSED, Evas_Object_Protected_Data *obj, Evas_Object_Pointer_Mode setting)
+_evas_object_pointer_mode_set(Eo *eo_obj, Evas_Object_Protected_Data *obj, Evas_Object_Pointer_Mode setting)
 {
+   int addgrab;
+   Evas_Object *cobj;
+   const Eina_List *l;
+
+   /* ignore no-ops */
+   if (obj->pointer_mode == setting) return;
+
+   /* adjust by number of pointer down events */
+   addgrab = obj->layer->evas->pointer.downs;
+   switch (obj->pointer_mode)
+     {
+      /* nothing needed */
+      case EVAS_OBJECT_POINTER_MODE_NOGRAB: break;
+      /* decrement canvas nogrep (NO Grab/REPeat) counter */
+      case EVAS_OBJECT_POINTER_MODE_NOGRAB_NO_REPEAT_UPDOWN:
+        if (obj->mouse_grabbed)
+          obj->layer->evas->pointer.nogrep--;
+        /* fall through */
+      /* remove related grabs from canvas and object */
+      case EVAS_OBJECT_POINTER_MODE_AUTOGRAB:
+        if (obj->mouse_grabbed)
+          {
+             obj->layer->evas->pointer.mouse_grabbed -= obj->mouse_grabbed;
+             obj->mouse_grabbed = 0;
+          }
+     }
+   /* adjustments for new mode */
+   switch (setting)
+     {
+      /* nothing needed */
+      case EVAS_OBJECT_POINTER_MODE_NOGRAB: break;
+      /* increment canvas nogrep (NO Grab/REPeat) counter */
+      case EVAS_OBJECT_POINTER_MODE_NOGRAB_NO_REPEAT_UPDOWN:
+        obj->layer->evas->pointer.nogrep++;
+        /* having nogrep set indicates that any object following it in
+         * the pointer.object.in list will not be receiving events, meaning
+         * that they will fail to unset any existing grabs/flags. unset them
+         * now to avoid breaking the canvas
+         */
+        EINA_LIST_FOREACH(obj->layer->evas->pointer.object.in, l, cobj)
+          {
+             Evas_Object_Protected_Data *cobj_data;
+
+             /* skip to the current object */
+             if (cobj != eo_obj) continue;
+             /* only change objects past it */
+             EINA_LIST_FOREACH(l->next, l, cobj)
+               {
+                  cobj_data = eo_data_scope_get(cobj, EVAS_OBJECT_CLASS);
+                  if (!cobj_data->mouse_grabbed) continue;
+                  cobj_data->mouse_grabbed -= addgrab;
+                  cobj_data->layer->evas->pointer.mouse_grabbed -= addgrab;
+                  if (cobj_data->pointer_mode == EVAS_OBJECT_POINTER_MODE_NOGRAB_NO_REPEAT_UPDOWN)
+                    cobj_data->layer->evas->pointer.nogrep--;
+               }
+             break;
+          }
+        /* fall through */
+      /* add all button grabs to this object */
+      case EVAS_OBJECT_POINTER_MODE_AUTOGRAB:
+        obj->mouse_grabbed += addgrab;
+        obj->layer->evas->pointer.mouse_grabbed += addgrab;
+     }
    obj->pointer_mode = setting;
 }