diff --git a/src/Gui/3Dconnexion/GuiApplicationNativeEventAwareLinux.cpp b/src/Gui/3Dconnexion/GuiApplicationNativeEventAwareLinux.cpp new file mode 100644 index 0000000000..044a444950 --- /dev/null +++ b/src/Gui/3Dconnexion/GuiApplicationNativeEventAwareLinux.cpp @@ -0,0 +1,49 @@ + /* +Implementation by Torsten Sadowski 2018 + */ + +#include "GuiApplicationNativeEventAware.h" +#include "SpaceballEvent.h" +#include + +#if defined(SPNAV_FOUND) + #include +#endif + +void Gui::GUIApplicationNativeEventAware::pollSpacenav() +{ + spnav_event ev; + while(spnav_poll_event(&ev)) + { + QWidget *currentWidget = this->focusWidget(); + if (!currentWidget) + return; + if (!setOSIndependentMotionData()) return; + importSettings(); + switch (ev.type) + { + case SPNAV_EVENT_MOTION: + { + Spaceball::MotionEvent *motionEvent = new Spaceball::MotionEvent(); + motionEvent->setTranslations(ev.motion.x, ev.motion.y, ev.motion.z); + motionEvent->setRotations(ev.motion.rx, ev.motion.ry, ev.motion.rz); + this->postEvent(currentWidget, motionEvent); + break; + } + case SPNAV_EVENT_BUTTON: + { + Spaceball::ButtonEvent *buttonEvent = new Spaceball::ButtonEvent(); + buttonEvent->setButtonNumber(ev.button.bnum); + if (ev.button.press) + { + buttonEvent->setButtonStatus(Spaceball::BUTTON_PRESSED); + } + else + { + buttonEvent->setButtonStatus(Spaceball::BUTTON_RELEASED); + } + break; + } + } + } +} diff --git a/src/Gui/CMakeLists.txt b/src/Gui/CMakeLists.txt index 3bd96e01a6..9604f710ed 100644 --- a/src/Gui/CMakeLists.txt +++ b/src/Gui/CMakeLists.txt @@ -106,12 +106,6 @@ 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} @@ -119,12 +113,6 @@ IF(SPNAV_FOUND) list(APPEND FreeCADGui_LIBS ${SPNAV_LIBRARIES} ) - find_package(X11 QUIET) - if (X11_FOUND) - list(APPEND FreeCADGui_LIBS - ${X11_X11_LIB} - ) - endif(X11_FOUND) ENDIF(SPNAV_FOUND) IF(OCULUS_FOUND) @@ -208,6 +196,13 @@ SET(FreeCADGui_SDK_SRCS SOURCE_GROUP("3D connexion SDK" FILES ${FreeCADGui_SDK_SRCS}) endif(FREECAD_USE_3DCONNEXION AND APPLE) +if(UNIX AND NOT APPLE) +SET(FreeCADGui_SDK_SRCS + 3Dconnexion/GuiApplicationNativeEventAwareLinux.cpp +) +SOURCE_GROUP("3D connexion SDK" FILES ${FreeCADGui_SDK_SRCS}) +endif(UNIX AND NOT APPLE) + set(Gui_MOC_HDRS Action.h ActionFunction.h diff --git a/src/Gui/GuiApplicationNativeEventAware.cpp b/src/Gui/GuiApplicationNativeEventAware.cpp index b30f4477bf..78ba28a591 100644 --- a/src/Gui/GuiApplicationNativeEventAware.cpp +++ b/src/Gui/GuiApplicationNativeEventAware.cpp @@ -31,11 +31,10 @@ #include "SpaceballEvent.h" #include "Application.h" #if defined(Q_OS_LINUX) && defined(SPNAV_FOUND) - #include #include #if QT_VERSION >= 0x050000 - #include + #include #undef Bool #undef CursorShape #undef Expose @@ -98,23 +97,16 @@ void Gui::GUIApplicationNativeEventAware::initSpaceball(QMainWindow *window) mainWindow = window; #if defined(Q_OS_LINUX) && defined(SPNAV_FOUND) - if (spnav_x11_open(QX11Info::display(), window->winId()) == -1) { + if (spnav_open() == -1) { Base::Console().Log("Couldn't connect to spacenav daemon\n"); } else { Base::Console().Log("Connected to spacenav daemon\n"); spaceballPresent = true; #if QT_VERSION >= 0x050000 - static auto evFilter( [](void *msg, long *result){ - Q_UNUSED(result); - auto inst(dynamic_cast(QApplication::instance())); - if (inst) { - return inst->xcbEventFilter(static_cast(msg)); - } else { - return false; - } - } ); - qApp->installNativeEventFilter(new Gui::RawInputEventFilter(evFilter)); + QTimer* SpacenavPollTimer = new QTimer(this); + connect(SpacenavPollTimer, &QTimer::timeout, this, &GUIApplicationNativeEventAware::pollSpacenav); + SpacenavPollTimer->start(20); #endif // #if QT_VERSION >= 0x050000 } @@ -179,6 +171,7 @@ void Gui::GUIApplicationNativeEventAware::initSpaceball(QMainWindow *window) bool Gui::GUIApplicationNativeEventAware::processSpaceballEvent(QObject *object, QEvent *event) { + std::cout << "Gui::GUIApplicationNativeEventAware::processSpaceballEvent" << std::endl; if (!activeWindow()) { qDebug("No active window\n"); return true; @@ -390,232 +383,4 @@ void Gui::GUIApplicationNativeEventAware::importSettings() } } -#if defined(Q_OS_LINUX) - -#if QT_VERSION >= 0x050000 - -bool Gui::GUIApplicationNativeEventAware::xcbEventFilter(const xcb_client_message_event_t *xcb_ev) -{ -#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() - 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(xcb_ev); - return false; -#endif // if/else defined(SPNAV_FOUND) -} - -#else // if QT_VERSION >= 0x050000 - -bool Gui::GUIApplicationNativeEventAware::x11EventFilter(XEvent *event) -{ -#ifdef SPNAV_FOUND - /* - First we check if we have a motion flush event: - - If there are unprocessed motion events we are in a flooding situation. - In that case we wait with generating a Spaceball event. - - A motion event counter of 0 indicates that FreeCAD is ready to process - the event. A Spaceball event, using the saved motion data, is posted. - */ - static Display* display = QX11Info::display(); - static Atom motion_flush_event = XInternAtom(display, "FCMotionFlushEvent", false); - static int nMotionEvents = 0; - - QWidget *currentWidget = this->focusWidget(); - if (!currentWidget) - currentWidget = mainWindow; - - if (event->type == ClientMessage) - { - Atom message_type = event->xclient.message_type; - - if (message_type == motion_flush_event) - { - nMotionEvents--; - if (nMotionEvents == 0) - { - importSettings(); - - Spaceball::MotionEvent *motionEvent = new Spaceball::MotionEvent(); - - motionEvent->setTranslations(motionDataArray[0], motionDataArray[1], motionDataArray[2]); - motionEvent->setRotations(motionDataArray[3], motionDataArray[4], motionDataArray[5]); - - this->postEvent(currentWidget, motionEvent); - } - - return true; - } // XEvent: motion_flush_event - } // XEvent: ClientMessage - - /* - From here on we deal with spacenav events only: - - motion: The event data is saved and a self addressed flush event - is sent through the window system (XEvent). - In the case of an event flooding, the motion data is added up. - - button: A Spaceball event is posted (QInputEvent). - */ - spnav_event navEvent; - if (!spnav_x11_event(event, &navEvent)) - return false; - - if (navEvent.type == SPNAV_EVENT_MOTION) - { - /* - If the motion data of the preceding event has not been processed - through posting an Spaceball event (flooding situation), - the motion data provided by the incoming event is added to the saved data. - */ - int dx, dy, dz, drx, dry, drz; - - if (nMotionEvents == 0) - { - dx = 0; - dy = 0; - dz = 0; - drx = 0; - dry = 0; - drz = 0; - } - else - { - dx = motionDataArray[0]; - dy = motionDataArray[1]; - dz = motionDataArray[2]; - drx = motionDataArray[3]; - dry = motionDataArray[4]; - drz = motionDataArray[5]; - } - - 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; - - if (!setOSIndependentMotionData()) return false; - - motionDataArray[0] += dx; - motionDataArray[1] += dy; - motionDataArray[2] += dz; - motionDataArray[3] += drx; - motionDataArray[4] += dry; - motionDataArray[5] += drz; - - /* - Send a self addressed flush event through the window system. This will - trigger a Spaceball event if FreeCAD is ready to do so. - */ - nMotionEvents++; - XClientMessageEvent flushEvent; - - flushEvent.display = display; - flushEvent.window = event->xclient.window; - flushEvent.type = ClientMessage; - flushEvent.format = 8; - flushEvent.message_type = motion_flush_event; - - XSendEvent (display, flushEvent.window, False, 0, (XEvent*)&flushEvent); // siehe spnavd, False, 0 - - return true; - } - - if (navEvent.type == SPNAV_EVENT_BUTTON) - { - Spaceball::ButtonEvent *buttonEvent = new Spaceball::ButtonEvent(); - buttonEvent->setButtonNumber(navEvent.button.bnum); - if (navEvent.button.press) - buttonEvent->setButtonStatus(Spaceball::BUTTON_PRESSED); - else - buttonEvent->setButtonStatus(Spaceball::BUTTON_RELEASED); - this->postEvent(currentWidget, buttonEvent); - return true; - } - - Base::Console().Log("Unknown spaceball event\n"); - return true; -#else - Q_UNUSED(event); - return false; -#endif // SPNAV_FOUND -} -#endif // if/else QT_VERSION >= 0x050000 - -#endif // Q_OS_LINUX - #include "moc_GuiApplicationNativeEventAware.cpp" diff --git a/src/Gui/GuiApplicationNativeEventAware.h b/src/Gui/GuiApplicationNativeEventAware.h index 3d5f845e30..3f13e04632 100644 --- a/src/Gui/GuiApplicationNativeEventAware.h +++ b/src/Gui/GuiApplicationNativeEventAware.h @@ -26,17 +26,10 @@ #define GUIAPPLICATIONNATIVEEVENTAWARE_H #include -#if QT_VERSION >= 0x050000 -#include -#endif class QMainWindow; -#if defined(Q_OS_LINUX) && QT_VERSION >= 0x050000 - #include - #include - -#elif defined(Q_OS_WIN) && defined(_USE_3DCONNEXION_SDK) +#if defined(Q_OS_WIN) && defined(_USE_3DCONNEXION_SDK) #include "3Dconnexion/MouseParameters.h" #include @@ -44,6 +37,7 @@ class QMainWindow; //#define _WIN32_WINNT 0x0501 //target at least windows XP #include +#include #elif defined(Q_OS_MACX) && defined(_USE_3DCONNEXION_SDK) @@ -63,25 +57,6 @@ extern void CleanupConnexionHandlers(void) __attribute__((weak_import)); namespace Gui { -#if QT_VERSION >= 0x050000 - class RawInputEventFilter : public QAbstractNativeEventFilter - { - public: - typedef bool (*EventFilter)(void *message, long *result); - RawInputEventFilter(EventFilter filter) : eventFilter(filter) { - } - virtual ~RawInputEventFilter() { - } - - virtual bool nativeEventFilter(const QByteArray & /*eventType*/, void *message, long *result) { - return eventFilter(message, result); - } - - private: - EventFilter eventFilter; - }; -#endif // if QT_VERSION >= 0x050000 - class GUIApplicationNativeEventAware : public QApplication { Q_OBJECT @@ -99,19 +74,31 @@ namespace Gui void importSettings(); float convertPrefToSensitivity(int value); -// For X11 #ifdef Q_OS_LINUX public: - #if QT_VERSION >= 0x050000 - bool xcbEventFilter(const xcb_client_message_event_t *message); - #else - bool x11EventFilter(XEvent *event); - #endif // if/else QT_VERSION >= 0x050000 + void pollSpacenav(); #endif // Q_OS_LINUX #ifdef _USE_3DCONNEXION_SDK // For Windows #ifdef Q_OS_WIN + class RawInputEventFilter : public QAbstractNativeEventFilter + { + public: + typedef bool (*EventFilter)(void *message, long *result); + RawInputEventFilter(EventFilter filter) : eventFilter(filter) { + } + virtual ~RawInputEventFilter() { + } + + virtual bool nativeEventFilter(const QByteArray & /*eventType*/, void *message, long *result) { + return eventFilter(message, result); + } + + private: + EventFilter eventFilter; + }; + public: static bool Is3dmouseAttached(); diff --git a/src/Gui/Quarter/SpaceNavigatorDevice.cpp b/src/Gui/Quarter/SpaceNavigatorDevice.cpp index 14fe49e871..3e2ac3ffd6 100644 --- a/src/Gui/Quarter/SpaceNavigatorDevice.cpp +++ b/src/Gui/Quarter/SpaceNavigatorDevice.cpp @@ -47,7 +47,6 @@ #include "NativeEvent.h" #ifdef HAVE_SPACENAV_LIB -#include #include #endif //HAVE_SPACENAV_LIB @@ -91,7 +90,7 @@ SpaceNavigatorDevice::SpaceNavigatorDevice() #ifdef HAVE_SPACENAV_LIB PRIVATE(this)->hasdevice = - spnav_x11_open(QX11Info::display(), PRIVATE(this)->windowid) == -1 ? false : true; + spnav_open() == -1 ? false : true; // FIXME: Use a debugmessage mechanism instead? (20101020 handegar) if (!PRIVATE(this)->hasdevice) { @@ -108,7 +107,7 @@ SpaceNavigatorDevice::SpaceNavigatorDevice(QuarterWidget *quarter) : #ifdef HAVE_SPACENAV_LIB PRIVATE(this)->hasdevice = - spnav_x11_open(QX11Info::display(), PRIVATE(this)->windowid) == -1 ? false : true; + spnav_open() == -1 ? false : true; // FIXME: Use a debugmessage mechanism instead? (20101020 handegar) if (!PRIVATE(this)->hasdevice) { @@ -136,7 +135,7 @@ SpaceNavigatorDevice::translateEvent(QEvent * event) XEvent * xev = ce->getEvent(); spnav_event spev; - if(spnav_x11_event(xev, &spev)) { + if(spnav_event(xev, &spev)) { if(spev.type == SPNAV_EVENT_MOTION) { // Add rotation const float axislen = sqrt(spev.motion.rx*spev.motion.rx +