diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index 3c4b3f913a..706aba5e99 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -106,6 +106,12 @@ else() endif() IF(SPNAV_FOUND) + if (BUILD_QT5 AND UNIX AND NOT APPLE) + find_package(Qt5X11Extras REQUIRED) + include_directories(${Qt5X11Extras_INCLUDE_DIRS}) + list(APPEND FreeCADGui_LIBS ${Qt5X11Extras_LIBRARIES}) + endif() + add_definitions(-DSPNAV_FOUND) include_directories( ${SPNAV_INCLUDE_DIR} diff --git a/src/Gui/GuiApplicationNativeEventAware.cpp b/src/Gui/GuiApplicationNativeEventAware.cpp index 93749821b0..449092ecd1 100644 --- a/src/Gui/GuiApplicationNativeEventAware.cpp +++ b/src/Gui/GuiApplicationNativeEventAware.cpp @@ -23,9 +23,11 @@ #include "PreCompiled.h" #include -#ifdef Q_WS_X11 -#include -#endif +#if defined(Q_OS_UNIX) && defined(SPNAV_FOUND) + #include + #include + #include +#endif // if defined(Q_OS_UNIX) && defined(SPNAV_FOUND) #include #include #include @@ -34,12 +36,9 @@ #include "SpaceballEvent.h" #include "Application.h" -//linux dependency libspnav-dev -#ifdef Q_WS_X11 -#ifdef SPNAV_FOUND -#include -#endif -#endif +#if defined(Q_OS_UNIX) && defined(SPNAV_FOUND) + #include +#endif // if defined(Q_OS_UNIX) && defined(SPNAV_FOUND) #ifdef _USE_3DCONNEXION_SDK //windows @@ -56,24 +55,19 @@ Gui::GUIApplicationNativeEventAware::GUIApplicationNativeEventAware(int &argc, c Gui::GUIApplicationNativeEventAware::~GUIApplicationNativeEventAware() { -#ifdef Q_WS_X11 -#ifdef SPNAV_FOUND +#if defined(Q_OS_UNIX) && defined(SPNAV_FOUND) if (spnav_close()) Base::Console().Log("Couldn't disconnect from spacenav daemon\n"); else Base::Console().Log("Disconnected from spacenav daemon\n"); -#endif -#endif -#ifdef _USE_3DCONNEXION_SDK -#ifdef Q_OS_WIN +#elif defined(Q_OS_WIN) && defined(_USE_3DCONNEXION_SDK) if (gMouseInput == this) { gMouseInput = 0; Base::Console().Log("3Dconnexion device detached.\n"); } -#endif -//mac -#ifdef Q_OS_MACX + +#elif defined(Q_OS_MACX) && defined(_USE_3DCONNEXION_SDK) // if 3Dconnexion library was loaded at runtime if (InstallConnexionHandlers) { // Close our connection with the 3dx driver @@ -82,28 +76,34 @@ Gui::GUIApplicationNativeEventAware::~GUIApplicationNativeEventAware() CleanupConnexionHandlers(); Base::Console().Log("Disconnected from 3Dconnexion driver\n"); } -#endif -#endif +#endif // Platform switch } void Gui::GUIApplicationNativeEventAware::initSpaceball(QMainWindow *window) { mainWindow = window; -#ifdef Q_WS_X11 -#ifdef SPNAV_FOUND - if (spnav_x11_open(QX11Info::display(), window->winId()) == -1) +#if defined(Q_OS_UNIX) && defined(SPNAV_FOUND) + if (spnav_x11_open(QX11Info::display(), window->winId()) == -1) { Base::Console().Log("Couldn't connect to spacenav daemon\n"); - else - { + } else { Base::Console().Log("Connected to spacenav daemon\n"); spaceballPresent = true; - } -#endif -#endif -#ifdef _USE_3DCONNEXION_SDK -#ifdef Q_OS_WIN + #if QT_VERSION >= 0x050000 + static auto evFilter( [](void *msg, long *result){ + auto inst(dynamic_cast(QApplication::instance())); + if (inst) { + return inst->xcbEventFilter(msg, result); + } else { + return false; + } + } ); + qApp->installNativeEventFilter(new Gui::RawInputEventFilter(evFilter)); + #endif // #if QT_VERSION >= 0x050000 + } + +#elif defined(Q_OS_WIN) && defined(_USE_3DCONNEXION_SDK) spaceballPresent = Is3dmouseAttached(); if (spaceballPresent) { @@ -123,9 +123,8 @@ void Gui::GUIApplicationNativeEventAware::initSpaceball(QMainWindow *window) } else { Base::Console().Log("3Dconnexion device not attached.\n"); } -#endif // #ifdef Q_OS_WIN -//mac -#ifdef Q_OS_MACX + +#elif defined(Q_OS_MACX) && defined(_USE_3DCONNEXION_SDK) OSStatus err; /* make sure the framework is installed */ if (InstallConnexionHandlers == NULL) @@ -157,8 +156,7 @@ void Gui::GUIApplicationNativeEventAware::initSpaceball(QMainWindow *window) Base::Console().Log("3Dconnexion driver initialized. Client ID: %d\n", tdxClientID); spaceballPresent = true; -#endif -#endif // _USE_3DCONNEXION_SDK +#endif // Platform switch Spaceball::MotionEvent::MotionEventType = QEvent::registerEventType(); Spaceball::ButtonEvent::ButtonEventType = QEvent::registerEventType(); @@ -238,7 +236,7 @@ bool Gui::GUIApplicationNativeEventAware::setOSIndependentMotionData() temp = motionDataArray[4]; motionDataArray[4] = -motionDataArray[5]; motionDataArray[5] = -temp; -#elif _USE_3DCONNEXION_SDK +#elif defined(_USE_3DCONNEXION_SDK) motionDataArray[0] = -motionDataArray[0]; motionDataArray[3] = -motionDataArray[3]; #else @@ -377,8 +375,99 @@ void Gui::GUIApplicationNativeEventAware::importSettings() } } +#if defined(Q_OS_UNIX) + +#if QT_VERSION >= 0x050000 + +bool Gui::GUIApplicationNativeEventAware::xcbEventFilter(void *message, long *result) +{ +#if defined(SPNAV_FOUND) + spnav_event navEvent; + + // Qt4 used XEvents in native event filters, but Qt5 changed to XCB. The + // SpaceNavigator API only works with XEvent, so we need to construct a + // temporary XEvent with just enough information for spnav_x11_event() + auto xcb_ev(static_cast(message)); + if ((xcb_ev->response_type & 0x7F) == XCB_CLIENT_MESSAGE) { + XClientMessageEvent xev; + + xev.type = ClientMessage; + xev.message_type = xcb_ev->type; + memcpy(xev.data.b, xcb_ev->data.data8, sizeof(xev.data.b)); + xev.serial = 0; // These are just to squash warnings... + xev.send_event = 0; + xev.display = 0; + xev.window = 0; + xev.format = 0; + + if (!spnav_x11_event(reinterpret_cast(&xev), &navEvent)) { + return false; + } + } else { + return false; + } + // navEvent is now initialised + + auto currentWidget(focusWidget()); + if (!currentWidget) { + currentWidget = mainWindow; + } + + switch (navEvent.type) { + case SPNAV_EVENT_MOTION: + { + motionDataArray[0] = navEvent.motion.x; + motionDataArray[1] = navEvent.motion.y; + motionDataArray[2] = navEvent.motion.z; + motionDataArray[3] = navEvent.motion.rx; + motionDataArray[4] = navEvent.motion.ry; + motionDataArray[5] = navEvent.motion.rz; + + setOSIndependentMotionData(); + + importSettings(); + + auto motionEvent(new Spaceball::MotionEvent()); + + motionEvent->setTranslations( motionDataArray[0], + motionDataArray[1], + motionDataArray[2] ); + motionEvent->setRotations( motionDataArray[3], + motionDataArray[4], + motionDataArray[5] ); + + postEvent(currentWidget, motionEvent); + return true; + } + + case SPNAV_EVENT_BUTTON: + { + auto buttonEvent(new Spaceball::ButtonEvent()); + buttonEvent->setButtonNumber(navEvent.button.bnum); + if (navEvent.button.press) { + buttonEvent->setButtonStatus(Spaceball::BUTTON_PRESSED); + } else { + buttonEvent->setButtonStatus(Spaceball::BUTTON_RELEASED); + } + + postEvent(currentWidget, buttonEvent); + return true; + } + + default: + Base::Console().Log("Unknown spaceball event\n"); + return true; + } // end switch (navEvent.type) { + +#else + Q_UNUSED(message); + Q_UNUSED(result); + return false; +#endif // if/else defined(SPNAV_FOUND) +} + +#else // if QT_VERSION >= 0x050000 -#ifdef Q_WS_X11 bool Gui::GUIApplicationNativeEventAware::x11EventFilter(XEvent *event) { #ifdef SPNAV_FOUND @@ -512,6 +601,8 @@ bool Gui::GUIApplicationNativeEventAware::x11EventFilter(XEvent *event) return false; #endif // SPNAV_FOUND } -#endif // Q_WS_X11 +#endif // if/else QT_VERSION >= 0x050000 + +#endif // Q_OS_UNIX #include "moc_GuiApplicationNativeEventAware.cpp" diff --git a/src/Gui/GuiApplicationNativeEventAware.h b/src/Gui/GuiApplicationNativeEventAware.h index 13e54b94a2..1b6fe04a97 100644 --- a/src/Gui/GuiApplicationNativeEventAware.h +++ b/src/Gui/GuiApplicationNativeEventAware.h @@ -32,21 +32,35 @@ class QMainWindow; +#if defined(Q_OS_UNIX) + #include + #undef Bool + #undef CursorShape + #undef Expose + #undef KeyPress + #undef KeyRelease + #undef FocusIn + #undef FocusOut + #undef FontChange + #undef None + #undef Status + #undef Unsorted + #undef False + #undef True + #undef Complex + #include -#ifdef _USE_3DCONNEXION_SDK - -#ifdef Q_OS_WIN +#elif defined(Q_OS_WIN) && defined(_USE_3DCONNEXION_SDK) #include "3Dconnexion/MouseParameters.h" #include #include //#define _WIN32_WINNT 0x0501 //target at least windows XP - #include -#endif // Q_OS_WIN -#ifdef Q_OS_MACX +#elif defined(Q_OS_MACX) && defined(_USE_3DCONNEXION_SDK) + #include #include // Note that InstallConnexionHandlers will be replaced with @@ -59,9 +73,7 @@ extern UInt16 RegisterConnexionClient(UInt32 signature, UInt8 *name, UInt16 mode UInt32 mask) __attribute__((weak_import)); extern void UnregisterConnexionClient(UInt16 clientID) __attribute__((weak_import)); extern void CleanupConnexionHandlers(void) __attribute__((weak_import)); -#endif // Q_OS_MACX - -#endif // _USE_3DCONNEXION_SDK +#endif // Platform switch namespace Gui { @@ -82,7 +94,7 @@ namespace Gui private: EventFilter eventFilter; }; -#endif +#endif // if QT_VERSION >= 0x050000 class GUIApplicationNativeEventAware : public QApplication { @@ -102,10 +114,14 @@ namespace Gui float convertPrefToSensitivity(int value); // For X11 -#ifdef Q_WS_X11 +#ifdef Q_OS_UNIX public: + #if QT_VERSION >= 0x050000 + bool xcbEventFilter(void *message, long *result); + #else bool x11EventFilter(XEvent *event); -#endif // Q_WS_X11 + #endif // if/else QT_VERSION >= 0x050000 +#endif // Q_OS_UNIX #ifdef _USE_3DCONNEXION_SDK // For Windows @@ -168,7 +184,7 @@ namespace Gui #endif// Q_OS_MACX #endif // _USE_3DCONNEXION_SDK - }; -} + }; // end class GUIApplicationNativeEventAware +} // end namespace Gui #endif // GUIAPPLICATIONNATIVEEVENTAWARE_H