fix for glitch in X11 with tablets.
authorCampbell Barton <ideasman42@gmail.com>
Wed, 16 Jan 2013 18:05:17 +0000 (18:05 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Wed, 16 Jan 2013 18:05:17 +0000 (18:05 +0000)
Notices this while using continuous-grab, since this is disabled when the tablet is being used.
Quite often I would use the tablet then drag a button with the mouse but blender would still have the tablet enabled.
This error would cause other parts of blender to behave incorrectly too since wmEvents would have wmTabletData set, operators check for this in some cases.

The problem was blender didn't reliably get ProximityOut events, eg:
  moving the cursor outside the window with the tablet, then back over the window with the mouse -
  meant blender didn't get a 'ProximityOut' event and would keep the active stylus value set.

For now, when the processing events and the active stylus is set, run a check that the tablet is still in proximity.

intern/ghost/intern/GHOST_SystemX11.cpp

index b7715de..f5c31c9 100644 (file)
@@ -518,6 +518,40 @@ static void setTabletMode(GHOST_SystemX11 *system, GHOST_WindowX11 *window, XID
 }
 #endif /* WITH_X11_XINPUT */
 
+#ifdef WITH_X11_XINPUT
+static bool checkTabletProximity(Display *display, XDevice *device)
+{
+       /* see: state.c from xinput, to get more data out of the device */
+       XDeviceState *state;
+
+       state = XQueryDeviceState(display, device);
+
+       if (state) {
+               XInputClass *cls = state->data;
+               // printf("%d class%s :\n", state->num_classes,
+               //       (state->num_classes > 1) ? "es" : "");
+               for(int loop=0; loop < state->num_classes; loop++) {
+                       switch(cls->c_class) {
+                               case ValuatorClass:
+                                       XValuatorState *val_state = (XValuatorState *) cls;
+                                       // printf("ValuatorClass Mode=%s Proximity=%s\n",
+                                       //        val_state->mode & 1 ? "Absolute" : "Relative",
+                                       //        val_state->mode & 2 ? "Out" : "In");
+
+                                       if ((val_state->mode & 2) == 0) {
+                                               XFreeDeviceState(state);
+                                               return true;
+                                       }
+                                       break;
+                       }
+                       cls = (XInputClass *) ((char *) cls + cls->length);
+               }
+               XFreeDeviceState(state);
+       }
+       return false;
+}
+#endif /* WITH_X11_XINPUT */
+
 void
 GHOST_SystemX11::processEvent(XEvent *xe)
 {
@@ -527,7 +561,23 @@ GHOST_SystemX11::processEvent(XEvent *xe)
        if (!window) {
                return;
        }
-       
+
+#ifdef WITH_X11_XINPUT
+       /* Proximity-Out Events are not reliable, if the tablet is active - check on each event
+        * this adds a little overhead but only while the tablet is in use.
+        * in the futire we could have a ghost call window->CheckTabletProximity()
+        * but for now enough parts of the code are checking 'Active'
+        * - campbell */
+       if (window->GetTabletData()->Active != GHOST_kTabletModeNone) {
+               if (checkTabletProximity(xe->xany.display, m_xtablet.StylusDevice) == false &&
+                   checkTabletProximity(xe->xany.display, m_xtablet.EraserDevice) == false)
+               {
+                       // printf("proximity disable\n");
+                       window->GetTabletData()->Active = GHOST_kTabletModeNone;
+               }
+       }
+#endif /* WITH_X11_XINPUT */
+
        switch (xe->type) {
                case Expose:
                {