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

Reply via email to