Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.cpp248
-rw-r--r--intern/ghost/intern/GHOST_SystemX11.h19
-rw-r--r--intern/ghost/intern/GHOST_WindowX11.cpp47
3 files changed, 143 insertions, 171 deletions
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp
index e53379a4f22..1afffb85037 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -235,9 +235,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 */
}
@@ -252,12 +249,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) {
@@ -769,17 +762,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 */
@@ -876,9 +858,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;
}
@@ -1472,59 +1460,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;
@@ -2304,6 +2297,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])) {
@@ -2330,16 +2337,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);
@@ -2351,72 +2350,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)) {
-// 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 = (m_xtablet.PressureLevels > 0);
+ 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);
@@ -2426,4 +2404,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 aaed0c3d837..a4c997c7bf9 100644
--- a/intern/ghost/intern/GHOST_SystemX11.h
+++ b/intern/ghost/intern/GHOST_SystemX11.h
@@ -309,28 +309,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
@@ -384,7 +378,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.
@@ -414,6 +408,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 01b4991ec72..3751f7f78ea 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());
}
}