diff options
Diffstat (limited to 'intern')
-rw-r--r-- | intern/ghost/intern/GHOST_SystemX11.cpp | 251 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_SystemX11.h | 19 | ||||
-rw-r--r-- | intern/ghost/intern/GHOST_WindowX11.cpp | 47 |
3 files changed, 143 insertions, 174 deletions
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) { @@ -671,17 +664,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) { /* we could have true/false/not-found return value, but for now false is OK */ @@ -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_valuator_class = true; + GHOST_TabletX11 xtablet = {tablet_mode}; + xtablet.ID = device_info[i].id; + xtablet.Device = XOpenDevice(m_display, xtablet.ID); - break; + if (xtablet.Device != NULL) { + /* Find how many pressure levels tablet has */ + XAnyClassPtr ici = device_info[i].inputclassinfo; + + for (int j = 0; j < xtablet.Device->num_classes; ++j) { + if (ici->c_class == ValuatorClass) { + XValuatorInfo *xvi = (XValuatorInfo *)ici; + 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.. */ + xtablet.XtiltLevels = xvi->axes[3].max_value; + xtablet.YtiltLevels = xvi->axes[4].max_value; + } + else { + xtablet.XtiltLevels = 0; + xtablet.YtiltLevels = 0; } - ici = (XAnyClassPtr)(((char *)ici) + ici->length); + break; } - if (!found_valuator_class) { - /* In case our name matching detects a device that - * isn't actually a stylus. For example there can - * be "XPPEN Tablet" and "XPPEN Tablet Pen", but - * only the latter is a stylus. */ - XCloseDevice(m_display, m_xtablet.StylusDevice); - m_xtablet.StylusDevice = NULL; - m_xtablet.StylusID = 0; - } + ici = (XAnyClassPtr)(((char *)ici) + ici->length); } - else { - m_xtablet.StylusID = 0; - } - } - else if ((m_xtablet.EraserDevice == NULL) && - (tablet_mode == GHOST_kTabletModeEraser)) - { -// printf("\tfound eraser\n"); - m_xtablet.EraserID = device_info[i].id; - m_xtablet.EraserDevice = XOpenDevice(m_display, m_xtablet.EraserID); - if (m_xtablet.EraserDevice == NULL) m_xtablet.EraserID = 0; - } - if (device_type) { - XFree((void *)device_type); + m_xtablets.push_back(xtablet); } + } XFreeDeviceList(device_info); @@ -2331,4 +2306,14 @@ void GHOST_SystemX11::refreshXInputDevices() } } +void GHOST_SystemX11::clearXInputDevices() +{ + for (GHOST_TabletX11& xtablet: m_xtablets) { + if (xtablet.Device) + XCloseDevice(m_display, xtablet.Device); + } + + m_xtablets.clear(); +} + #endif /* WITH_X11_XINPUT */ diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h index e9312ceb683..b5d06eed412 100644 --- a/intern/ghost/intern/GHOST_SystemX11.h +++ b/intern/ghost/intern/GHOST_SystemX11.h @@ -289,28 +289,22 @@ public: #ifdef WITH_X11_XINPUT typedef struct GHOST_TabletX11 { - XDevice *StylusDevice; - XDevice *EraserDevice; - - XID StylusID, EraserID; + GHOST_TTabletMode mode; + XDevice *Device; + XID ID; int MotionEvent; int ProxInEvent; int ProxOutEvent; int PressEvent; - int MotionEventEraser; - int ProxInEventEraser; - int ProxOutEventEraser; - int PressEventEraser; - int PressureLevels; int XtiltLevels, YtiltLevels; } GHOST_TabletX11; - GHOST_TabletX11 &GetXTablet() + std::vector<GHOST_TabletX11> &GetXTablets() { - return m_xtablet; + return m_xtablets; } #endif // WITH_X11_XINPUT @@ -364,7 +358,7 @@ private: #ifdef WITH_X11_XINPUT /* Tablet devices */ - GHOST_TabletX11 m_xtablet; + std::vector<GHOST_TabletX11> m_xtablets; #endif /// The vector of windows that need to be updated. @@ -394,6 +388,7 @@ private: #endif #ifdef WITH_X11_XINPUT + void clearXInputDevices(); void refreshXInputDevices(); #endif diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index a4ccdef3788..ee8218b4827 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -648,37 +648,26 @@ bool GHOST_WindowX11::createX11_XIC() void GHOST_WindowX11::refreshXInputDevices() { if (m_system->m_xinput_version.present) { - GHOST_SystemX11::GHOST_TabletX11 &xtablet = m_system->GetXTablet(); - XEventClass xevents[8], ev; - int dcount = 0; - - /* With modern XInput (xlib 1.6.2 at least and/or evdev 2.9.0) and some 'no-name' tablets - * like 'UC-LOGIC Tablet WP5540U', we also need to 'select' ButtonPress for motion event, - * otherwise we do not get any tablet motion event once pen is pressed... See T43367. - */ - - if (xtablet.StylusDevice) { - DeviceMotionNotify(xtablet.StylusDevice, xtablet.MotionEvent, ev); - if (ev) xevents[dcount++] = ev; - DeviceButtonPress(xtablet.StylusDevice, xtablet.PressEvent, ev); - if (ev) xevents[dcount++] = ev; - ProximityIn(xtablet.StylusDevice, xtablet.ProxInEvent, ev); - if (ev) xevents[dcount++] = ev; - ProximityOut(xtablet.StylusDevice, xtablet.ProxOutEvent, ev); - if (ev) xevents[dcount++] = ev; - } - if (xtablet.EraserDevice) { - DeviceMotionNotify(xtablet.EraserDevice, xtablet.MotionEventEraser, ev); - if (ev) xevents[dcount++] = ev; - DeviceButtonPress(xtablet.EraserDevice, xtablet.PressEventEraser, ev); - if (ev) xevents[dcount++] = ev; - ProximityIn(xtablet.EraserDevice, xtablet.ProxInEventEraser, ev); - if (ev) xevents[dcount++] = ev; - ProximityOut(xtablet.EraserDevice, xtablet.ProxOutEventEraser, ev); - if (ev) xevents[dcount++] = ev; + std::vector<XEventClass> xevents; + + for (GHOST_SystemX11::GHOST_TabletX11& xtablet: m_system->GetXTablets()) { + /* With modern XInput (xlib 1.6.2 at least and/or evdev 2.9.0) and some 'no-name' tablets + * like 'UC-LOGIC Tablet WP5540U', we also need to 'select' ButtonPress for motion event, + * otherwise we do not get any tablet motion event once pen is pressed... See T43367. + */ + XEventClass ev; + + DeviceMotionNotify(xtablet.Device, xtablet.MotionEvent, ev); + if (ev) xevents.push_back(ev); + DeviceButtonPress(xtablet.Device, xtablet.PressEvent, ev); + if (ev) xevents.push_back(ev); + ProximityIn(xtablet.Device, xtablet.ProxInEvent, ev); + if (ev) xevents.push_back(ev); + ProximityOut(xtablet.Device, xtablet.ProxOutEvent, ev); + if (ev) xevents.push_back(ev); } - XSelectExtensionEvent(m_display, m_window, xevents, dcount); + XSelectExtensionEvent(m_display, m_window, xevents.data(), (int)xevents.size()); } } |