Commit: 7bed048243fef51e92b86e4383fa48d1d18d12ac
Author: Brecht Van Lommel
Date:   Thu Dec 27 15:22:20 2018 +0100
Branches: blender2.7
https://developer.blender.org/rB7bed048243fef51e92b86e4383fa48d1d18d12ac

X11: support multiple tablet devices.

Previously we would try to guess what the main tablet device is, but this is
error prone. Now we keep a list of X11 devices and try to match events to
them. On the Blender side there are still some limitations in regards to using
multiple devices at the same time, but this should improve things already.

Fixes T59645.

===================================================================

M       intern/ghost/intern/GHOST_SystemX11.cpp
M       intern/ghost/intern/GHOST_SystemX11.h
M       intern/ghost/intern/GHOST_WindowX11.cpp

===================================================================

diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp 
b/intern/ghost/intern/GHOST_SystemX11.cpp
index 3befb700c55..1791908f670 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -228,9 +228,6 @@ GHOST_SystemX11(
        }
 #endif  /* USE_XINPUT_HOTPLUG */
 
-       /* initialize incase X11 fails to load */
-       memset(&m_xtablet, 0, sizeof(m_xtablet));
-
        refreshXInputDevices();
 #endif  /* WITH_X11_XINPUT */
 }
@@ -245,12 +242,8 @@ GHOST_SystemX11::
 #endif
 
 #ifdef WITH_X11_XINPUT
-       /* close tablet devices */
-       if (m_xtablet.StylusDevice)
-               XCloseDevice(m_display, m_xtablet.StylusDevice);
-
-       if (m_xtablet.EraserDevice)
-               XCloseDevice(m_display, m_xtablet.EraserDevice);
+       /* Close tablet devices. */
+       clearXInputDevices();
 #endif /* WITH_X11_XINPUT */
 
        if (m_xkb_descr) {
@@ -670,17 +663,6 @@ processEvents(
 }
 
 
-#ifdef WITH_X11_XINPUT
-/* set currently using tablet mode (stylus or eraser) depending on device ID */
-static void setTabletMode(GHOST_SystemX11 *system, GHOST_WindowX11 *window, 
XID deviceid)
-{
-       if (deviceid == system->GetXTablet().StylusID)
-               window->GetTabletData()->Active = GHOST_kTabletModeStylus;
-       else if (deviceid == system->GetXTablet().EraserID)
-               window->GetTabletData()->Active = GHOST_kTabletModeEraser;
-}
-#endif /* WITH_X11_XINPUT */
-
 #ifdef WITH_X11_XINPUT
 static bool checkTabletProximity(Display *display, XDevice *device)
 {
@@ -778,9 +760,15 @@ GHOST_SystemX11::processEvent(XEvent *xe)
         * 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)
-               {
+               bool any_proximity = false;
+
+               for (GHOST_TabletX11& xtablet: m_xtablets) {
+                       if (checkTabletProximity(xe->xany.display, 
xtablet.Device)) {
+                               any_proximity = true;
+                       }
+               }
+
+               if (!any_proximity) {
                        // printf("proximity disable\n");
                        window->GetTabletData()->Active = GHOST_kTabletModeNone;
                }
@@ -1374,59 +1362,64 @@ GHOST_SystemX11::processEvent(XEvent *xe)
                default:
                {
 #ifdef WITH_X11_XINPUT
-                       if (xe->type == m_xtablet.MotionEvent ||
-                           xe->type == m_xtablet.MotionEventEraser ||
-                           xe->type == m_xtablet.PressEvent ||
-                           xe->type == m_xtablet.PressEventEraser)
-                       {
-                               XDeviceMotionEvent *data = (XDeviceMotionEvent 
*)xe;
-                               const unsigned char axis_first = 
data->first_axis;
-                               const unsigned char axes_end = axis_first + 
data->axes_count;  /* after the last */
-                               int axis_value;
-
-                               /* stroke might begin without leading ProxyIn 
event,
-                                * this happens when window is opened when 
stylus is already hovering
-                                * around tablet surface */
-                               setTabletMode(this, window, data->deviceid);
-
-                               /* Note: This event might be generated with 
incomplete dataset (don't exactly know why, looks like in
-                                *       some cases, if the value does not 
change, it is not included in subsequent XDeviceMotionEvent
-                                *       events). So we have to check which 
values this event actually contains!
-                                */
+                       for (GHOST_TabletX11& xtablet: m_xtablets) {
+                               if (xe->type == xtablet.MotionEvent || xe->type 
== xtablet.PressEvent) {
+                                       XDeviceMotionEvent *data = 
(XDeviceMotionEvent *)xe;
+                                       if (data->deviceid != xtablet.ID) {
+                                               continue;
+                                       }
+
+                                       const unsigned char axis_first = 
data->first_axis;
+                                       const unsigned char axes_end = 
axis_first + data->axes_count;  /* after the last */
+                                       int axis_value;
+
+                                       /* stroke might begin without leading 
ProxyIn event,
+                                        * this happens when window is opened 
when stylus is already hovering
+                                        * around tablet surface */
+                                       window->GetTabletData()->Active = 
xtablet.mode;
+
+                                       /* Note: This event might be generated 
with incomplete dataset (don't exactly know why, looks like in
+                                        *       some cases, if the value does 
not change, it is not included in subsequent XDeviceMotionEvent
+                                        *       events). So we have to check 
which values this event actually contains!
+                                        */
 
 #define AXIS_VALUE_GET(axis, val) \
        ((axis_first <= axis && axes_end > axis) && ((void)(val = 
data->axis_data[axis - axis_first]), true))
 
-                               if (AXIS_VALUE_GET(2, axis_value)) {
-                                       window->GetTabletData()->Pressure = 
axis_value / ((float)m_xtablet.PressureLevels);
-                               }
+                                       if (AXIS_VALUE_GET(2, axis_value)) {
+                                               
window->GetTabletData()->Pressure = axis_value / 
((float)xtablet.PressureLevels);
+                                       }
 
-                               /* the (short) cast and the & 0xffff is bizarre 
and unexplained anywhere,
-                                * but I got garbage data without it. Found it 
in the xidump.c source --matt
-                                *
-                                * The '& 0xffff' just truncates the value to 
its two lowest bytes, this probably means
-                                * some drivers do not properly set the whole 
int value? Since we convert to float afterward,
-                                * I don't think we need to cast to short here, 
but do not have a device to check this. --mont29
-                                */
-                               if (AXIS_VALUE_GET(3, axis_value)) {
-                                       window->GetTabletData()->Xtilt = 
(short)(axis_value & 0xffff) /
-                                                                        
((float)m_xtablet.XtiltLevels);
-                               }
-                               if (AXIS_VALUE_GET(4, axis_value)) {
-                                       window->GetTabletData()->Ytilt = 
(short)(axis_value & 0xffff) /
-                                                                        
((float)m_xtablet.YtiltLevels);
-                               }
+                                       /* the (short) cast and the & 0xffff is 
bizarre and unexplained anywhere,
+                                        * but I got garbage data without it. 
Found it in the xidump.c source --matt
+                                        *
+                                        * The '& 0xffff' just truncates the 
value to its two lowest bytes, this probably means
+                                        * some drivers do not properly set the 
whole int value? Since we convert to float afterward,
+                                        * I don't think we need to cast to 
short here, but do not have a device to check this. --mont29
+                                        */
+                                       if (AXIS_VALUE_GET(3, axis_value)) {
+                                               window->GetTabletData()->Xtilt 
= (short)(axis_value & 0xffff) /
+                                                                               
                                 ((float)xtablet.XtiltLevels);
+                                       }
+                                       if (AXIS_VALUE_GET(4, axis_value)) {
+                                               window->GetTabletData()->Ytilt 
= (short)(axis_value & 0xffff) /
+                                                                               
                                 ((float)xtablet.YtiltLevels);
+                                       }
 
 #undef AXIS_VALUE_GET
 
-                       }
-                       else if (xe->type == m_xtablet.ProxInEvent) {
-                               XProximityNotifyEvent *data = 
(XProximityNotifyEvent *)xe;
+                               }
+                               else if (xe->type == xtablet.ProxInEvent) {
+                                       XProximityNotifyEvent *data = 
(XProximityNotifyEvent *)xe;
+                                       if (data->deviceid != xtablet.ID) {
+                                               continue;
+                                       }
 
-                               setTabletMode(this, window, data->deviceid);
-                       }
-                       else if (xe->type == m_xtablet.ProxOutEvent) {
-                               window->GetTabletData()->Active = 
GHOST_kTabletModeNone;
+                                       window->GetTabletData()->Active = 
xtablet.mode;
+                               }
+                               else if (xe->type == xtablet.ProxOutEvent) {
+                                       window->GetTabletData()->Active = 
GHOST_kTabletModeNone;
+                               }
                        }
 #endif // WITH_X11_XINPUT
                        break;
@@ -2206,6 +2199,20 @@ static GHOST_TTabletMode tablet_mode_from_name(const 
char *name, const char *typ
                NULL
        };
 
+       static const char* type_blacklist[] = {
+               "pad",
+               "cursor",
+               "touch",
+               NULL
+       };
+
+       /* Skip some known unsupported types. */
+       for (i=0; type_blacklist[i] != NULL; i++) {
+               if (type && (strcasecmp(type, type_blacklist[i]) == 0)) {
+                       return GHOST_kTabletModeNone;
+               }
+       }
+
        /* First check device type to avoid cases where name is "Pen and 
Eraser" and type is "ERASER" */
        for (i=0; tablet_stylus_whitelist[i] != NULL; i++) {
                if (type && match_token(type, tablet_stylus_whitelist[i])) {
@@ -2232,16 +2239,8 @@ static GHOST_TTabletMode tablet_mode_from_name(const 
char *name, const char *typ
 void GHOST_SystemX11::refreshXInputDevices()
 {
        if (m_xinput_version.present) {
-
-               if (m_xtablet.StylusDevice) {
-                       XCloseDevice(m_display, m_xtablet.StylusDevice);
-                       m_xtablet.StylusDevice = NULL;
-               }
-
-               if (m_xtablet.EraserDevice) {
-                       XCloseDevice(m_display, m_xtablet.EraserDevice);
-                       m_xtablet.EraserDevice = NULL;
-               }
+               /* Close tablet devices. */
+               clearXInputDevices();
 
                /* Install our error handler to override Xlib's termination 
behavior */
                GHOST_X11_ERROR_HANDLERS_OVERRIDE(handler_store);
@@ -2253,75 +2252,51 @@ void GHOST_SystemX11::refreshXInputDevices()
 
                        for (int i = 0; i < device_count; ++i) {
                                char *device_type = device_info[i].type ? 
XGetAtomName(m_display, device_info[i].type) : NULL;
+                               GHOST_TTabletMode tablet_mode = 
tablet_mode_from_name(device_info[i].name, device_type);
 
 //                             printf("Tablet type:'%s', name:'%s', 
index:%d\n", device_type, device_info[i].name, i);
 
-                               GHOST_TTabletMode tablet_mode = 
tablet_mode_from_name(device_info[i].name, device_type);
+                               if (device_type) {
+                                       XFree((void *)device_type);
+                               }
 
-                               if ((m_xtablet.StylusDevice == NULL) &&
-                                   ((tablet_mode == GHOST_kTabletModeStylus) 
&& (device_info[i].type != m_atom.TABLET)))
-                                   /* for libinput to work reliable, only 
lookup ValuatorClass in Tablet type:'STYLUS' */
-                               {
-//                                     printf("\tfound stylus\n");
-                                       m_xtablet.StylusID = device_info[i].id;
-                                       m_xtablet.StylusDevice = 
XOpenDevice(m_display, m_xtablet.StylusID);
-
-                                       if (m_xtablet.StylusDevice != NULL) {
-                                               /* Find how many pressure 
levels tablet has */
-                                               XAnyClassPtr ici = 
device_info[i].inputclassinfo;
-                                               bool found_valuator_class = 
false;
-
-                                               for (int j = 0; j < 
m_xtablet.StylusDevice->num_classes; ++j) {
-                                                       if (ici->c_class == 
ValuatorClass) {
-//                                                             
printf("\t\tfound ValuatorClass\n");
-                                                               XValuatorInfo 
*xvi = (XValuatorInfo *)ici;
-                                                               
m_xtablet.PressureLevels = xvi->axes[2].max_value;
-
-                                                               if 
(xvi->num_axes > 3) {
-                                                                       /* this 
is assuming that the tablet has the same tilt resolution in both
-                                                                        * 
positive and negative directions. It would be rather weird if it didn't.. */
-                                                                       
m_xtablet.XtiltLevels = xvi->axes[3].max_value;
-                                                                       
m_xtablet.YtiltLevels = xvi->axes[4].max_value;
-                                                               }
-                                                               else {
-                                                                       
m_xtablet.XtiltLevels = 0;
-                                                                       
m_xtablet.YtiltLevels = 0;
-                                                               }
+                               if (!(tablet_mode == GHOST_kTabletModeStylus || 
tablet_mode == GHOST_kTabletModeEraser)) {
+                                       continue;
+                               }
 
-                                                               found_v

@@ Diff output truncated at 10240 characters. @@

_______________________________________________
Bf-blender-cvs mailing list
[email protected]
https://lists.blender.org/mailman/listinfo/bf-blender-cvs

Reply via email to