Commit: 6ce0ddae9612dc093331630a9eb55e1020d845fd
Author: Campbell Barton
Date: Tue Jun 28 13:34:53 2016 +1000
Branches: master
https://developer.blender.org/rB6ce0ddae9612dc093331630a9eb55e1020d845fd
GHOST/X11: Hotplug support for xinput
Allows to plug/unplug different tablets while Blender is running.
Also fixes crash unplugging tablet while Blender runs (T48750).
===================================================================
M intern/ghost/intern/GHOST_ContextGLX.cpp
M intern/ghost/intern/GHOST_SystemX11.cpp
M intern/ghost/intern/GHOST_SystemX11.h
M intern/ghost/intern/GHOST_WindowX11.cpp
M intern/ghost/intern/GHOST_WindowX11.h
===================================================================
diff --git a/intern/ghost/intern/GHOST_ContextGLX.cpp
b/intern/ghost/intern/GHOST_ContextGLX.cpp
index d4f67da..9ac61db 100644
--- a/intern/ghost/intern/GHOST_ContextGLX.cpp
+++ b/intern/ghost/intern/GHOST_ContextGLX.cpp
@@ -155,15 +155,7 @@ void GHOST_ContextGLX::initContextGLXEW()
GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext()
{
-#ifdef WITH_X11_XINPUT
- /* use our own event handlers to avoid exiting blender,
- * this would happen for eg:
- * if you open blender, unplug a tablet, then open a new window. */
- XErrorHandler old_handler = XSetErrorHandler
(GHOST_X11_ApplicationErrorHandler );
- XIOErrorHandler old_handler_io =
XSetIOErrorHandler(GHOST_X11_ApplicationIOErrorHandler);
-#endif
-
-
+ GHOST_X11_ERROR_HANDLERS_OVERRIDE(handler_store);
/* --------------------------------------------------------------------
*/
/* Begin Inline Glew */
@@ -350,11 +342,8 @@ const bool GLXEW_ARB_create_context_robustness =
success = GHOST_kFailure;
}
-#ifdef WITH_X11_XINPUT
- /* Restore handler */
- XSetErrorHandler (old_handler);
- XSetIOErrorHandler(old_handler_io);
-#endif
+
+ GHOST_X11_ERROR_HANDLERS_RESTORE(handler_store);
return success;
}
diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp
b/intern/ghost/intern/GHOST_SystemX11.cpp
index aeda95d..55d013f 100644
--- a/intern/ghost/intern/GHOST_SystemX11.cpp
+++ b/intern/ghost/intern/GHOST_SystemX11.cpp
@@ -73,6 +73,10 @@
/* for debugging - so we can breakpoint X11 errors */
// #define USE_X11_ERROR_HANDLERS
+#ifdef WITH_X11_XINPUT
+# define USE_XINPUT_HOTPLUG
+#endif
+
/* see [#34039] Fix Alt key glitch on Unity desktop */
#define USE_UNITY_WORKAROUND
@@ -169,11 +173,36 @@ GHOST_SystemX11(
}
#ifdef WITH_X11_XINPUT
+ /* detect if we have xinput (for reuse) */
+ {
+ memset(&m_xinput_version, 0, sizeof(m_xinput_version));
+ XExtensionVersion *version = XGetExtensionVersion(m_display,
INAME);
+ if (version && (version != (XExtensionVersion
*)NoSuchExtension)) {
+ if (version->present) {
+ m_xinput_version = *version;
+ }
+ XFree(version);
+ }
+ }
+
+#ifdef USE_XINPUT_HOTPLUG
+ if (m_xinput_version.present) {
+ XEventClass class_presence;
+ int xi_presence;
+ DevicePresence(m_display, xi_presence, class_presence);
+ XSelectExtensionEvent(
+ m_display,
+ RootWindow(m_display, DefaultScreen(m_display)),
+ &class_presence, 1);
+ (void)xi_presence;
+ }
+#endif /* USE_XINPUT_HOTPLUG */
+
/* initialize incase X11 fails to load */
memset(&m_xtablet, 0, sizeof(m_xtablet));
- initXInputDevices();
-#endif
+ refreshXInputDevices();
+#endif /* WITH_X11_XINPUT */
}
GHOST_SystemX11::
@@ -627,8 +656,13 @@ static bool checkTabletProximity(Display *display, XDevice
*device)
return false;
}
+ /* needed since unplugging will abort() without this */
+ GHOST_X11_ERROR_HANDLERS_OVERRIDE(handler_store);
+
state = XQueryDeviceState(display, device);
+ GHOST_X11_ERROR_HANDLERS_RESTORE(handler_store);
+
if (state) {
XInputClass *cls = state->data;
// printf("%d class%s :\n", state->num_classes,
@@ -661,6 +695,41 @@ GHOST_SystemX11::processEvent(XEvent *xe)
GHOST_WindowX11 *window = findGhostWindow(xe->xany.window);
GHOST_Event *g_event = NULL;
+#ifdef USE_XINPUT_HOTPLUG
+ /* Hot-Plug support */
+ if (m_xinput_version.present) {
+ XEventClass class_presence;
+ int xi_presence;
+
+ DevicePresence(m_display, xi_presence, class_presence);
+ (void)class_presence;
+
+ if (xe->type == xi_presence) {
+ XDevicePresenceNotifyEvent *notify_event =
(XDevicePresenceNotifyEvent *)xe;
+ if ((notify_event->devchange == DeviceEnabled) ||
+ (notify_event->devchange == DeviceDisabled) ||
+ (notify_event->devchange == DeviceAdded) ||
+ (notify_event->devchange == DeviceRemoved))
+ {
+ refreshXInputDevices();
+
+ /* update all window events */
+ {
+ vector<GHOST_IWindow *> & win_vec =
m_windowManager->getWindows();
+ vector<GHOST_IWindow *>::iterator
win_it = win_vec.begin();
+ vector<GHOST_IWindow *>::const_iterator
win_end = win_vec.end();
+
+ for (; win_it != win_end; ++win_it) {
+ GHOST_WindowX11 *window =
static_cast<GHOST_WindowX11 *>(*win_it);
+ window->refreshXInputDevices();
+ }
+ }
+ }
+ }
+ }
+#endif /* USE_XINPUT_HOTPLUG */
+
+
if (!window) {
return;
}
@@ -680,7 +749,6 @@ GHOST_SystemX11::processEvent(XEvent *xe)
}
}
#endif /* WITH_X11_XINPUT */
-
switch (xe->type) {
case Expose:
{
@@ -1917,8 +1985,6 @@ GHOST_TSuccess
GHOST_SystemX11::pushDragDropEvent(GHOST_TEventType eventType,
);
}
#endif
-
-#if defined(USE_X11_ERROR_HANDLERS) || defined(WITH_X11_XINPUT)
/*
* These callbacks can be used for debugging, so we can breakpoint on an X11
error.
@@ -1952,7 +2018,6 @@ int GHOST_X11_ApplicationIOErrorHandler(Display *
/*display*/)
/* No exit! - but keep lint happy */
return 0;
}
-#endif
#ifdef WITH_X11_XINPUT
/* These C functions are copied from Wine 1.1.13's wintab.c */
@@ -2049,23 +2114,27 @@ static BOOL is_eraser(const char *name, const char
*type)
#undef FALSE
/* end code copied from wine */
-void GHOST_SystemX11::initXInputDevices()
+void GHOST_SystemX11::refreshXInputDevices()
{
- static XErrorHandler old_handler = (XErrorHandler) 0;
- static XIOErrorHandler old_handler_io = (XIOErrorHandler) 0;
+ if (m_xinput_version.present) {
- XExtensionVersion *version = XGetExtensionVersion(m_display, INAME);
+ if (m_xtablet.StylusDevice) {
+ XCloseDevice(m_display, m_xtablet.StylusDevice);
+ m_xtablet.StylusDevice = NULL;
+ }
- if (version && (version != (XExtensionVersion *)NoSuchExtension)) {
- if (version->present) {
+ if (m_xtablet.EraserDevice) {
+ XCloseDevice(m_display, m_xtablet.EraserDevice);
+ m_xtablet.EraserDevice = NULL;
+ }
+
+ /* Install our error handler to override Xlib's termination
behavior */
+ GHOST_X11_ERROR_HANDLERS_OVERRIDE(handler_store);
+
+ {
int device_count;
XDeviceInfo *device_info = XListInputDevices(m_display,
&device_count);
- m_xtablet.StylusDevice = NULL;
- m_xtablet.EraserDevice = NULL;
- /* Install our error handler to override Xlib's
termination behavior */
- old_handler =
XSetErrorHandler(GHOST_X11_ApplicationErrorHandler);
- old_handler_io =
XSetIOErrorHandler(GHOST_X11_ApplicationIOErrorHandler);
for (int i = 0; i < device_count; ++i) {
char *device_type = device_info[i].type ?
XGetAtomName(m_display, device_info[i].type) : NULL;
@@ -2124,13 +2193,10 @@ void GHOST_SystemX11::initXInputDevices()
}
}
- /* Restore handler */
- (void) XSetErrorHandler(old_handler);
- (void) XSetIOErrorHandler(old_handler_io);
-
XFreeDeviceList(device_info);
}
- XFree(version);
+
+ GHOST_X11_ERROR_HANDLERS_RESTORE(handler_store);
}
}
diff --git a/intern/ghost/intern/GHOST_SystemX11.h
b/intern/ghost/intern/GHOST_SystemX11.h
index a0088db..e60cab6 100644
--- a/intern/ghost/intern/GHOST_SystemX11.h
+++ b/intern/ghost/intern/GHOST_SystemX11.h
@@ -52,6 +52,20 @@
int GHOST_X11_ApplicationErrorHandler(Display *display, XErrorEvent *theEvent);
int GHOST_X11_ApplicationIOErrorHandler(Display *display);
+#define GHOST_X11_ERROR_HANDLERS_OVERRIDE(var) \
+ struct { \
+ XErrorHandler handler; \
+ XIOErrorHandler handler_io; \
+ } var = { \
+ XSetErrorHandler(GHOST_X11_ApplicationErrorHandler), \
+ XSetIOErrorHandler(GHOST_X11_ApplicationIOErrorHandler), \
+ }
+
+#define GHOST_X11_ERROR_HANDLERS_RESTORE(var) \
+ { \
+ (void)XSetErrorHandler(var.handler); \
+ (void)XSetIOErrorHandler(var.handler_io); \
+ } ((void)0)
class GHOST_WindowX11;
@@ -328,6 +342,10 @@ public:
#endif
} m_atom;
+#ifdef WITH_X11_XINPUT
+ XExtensionVersion m_xinput_version;
+#endif
+
private:
Display *m_display;
@@ -367,7 +385,7 @@ private:
#endif
#ifdef WITH_X11_XINPUT
- void initXInputDevices();
+ void refreshXInputDevices();
#endif
GHOST_WindowX11 *
diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp
b/intern/ghost/intern/GHOST_WindowX11.cpp
index a12ecec..fd002ce 100644
--- a/intern/ghost/intern/GHOST_WindowX11.cpp
+++ b/intern/ghost/intern/GHOST_WindowX11.cpp
@@ -566,7 +566,7 @@ GHOST_WindowX11(GHOST_SystemX11 *system,
}
#ifdef WITH_X11_XINPUT
- initXInputDevices();
+ refreshXInputDevices();
m_tabletData.Active = GHOST_kTabletModeNone;
#endif
@@ -633,45 +633,40 @@ bool GHOST_WindowX11::createX11_XIC()
#endif
#ifdef WITH_X11_XINPUT
-void GHOST_WindowX11::initXInputDevices()
+void GHOST_WindowX11::refreshXInputDevices()
{
- XExtensionVersion *version = XGetExtensionVersion(m_display, INAME);
-
- if (version && (version != (XExtensionVersion *)NoSuchExtension)) {
- if (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;
- }
+ if (m_system->m_xinput_version.present) {
+ GHOST_SystemX11::GHOST_TabletX11 &xtablet =
m_system->GetXTablet();
+ XEventClass xevents[8],
@@ Diff output truncated at 10240 characters. @@
_______________________________________________
Bf-blender-cvs mailing list
[email protected]
https://lists.blender.org/mailman/listinfo/bf-blender-cvs