From 490f041717421ff7903c953775efe480a1ac3c1a Mon Sep 17 00:00:00 2001 From: wmayer Date: Tue, 18 Mar 2014 11:27:52 +0100 Subject: [PATCH] + fixes #0001477: Spaceball becomes uncontrollable for large FreeCAD Documnets on X11 (spacenav) --- src/Gui/GuiApplicationNativeEventAware.cpp | 104 ++++++++++++++++++--- 1 file changed, 93 insertions(+), 11 deletions(-) diff --git a/src/Gui/GuiApplicationNativeEventAware.cpp b/src/Gui/GuiApplicationNativeEventAware.cpp index 171fb02cd..1e97f0abd 100644 --- a/src/Gui/GuiApplicationNativeEventAware.cpp +++ b/src/Gui/GuiApplicationNativeEventAware.cpp @@ -311,16 +311,83 @@ void Gui::GUIApplicationNativeEventAware::importSettings() bool Gui::GUIApplicationNativeEventAware::x11EventFilter(XEvent *event) { #ifdef SPNAV_FOUND - spnav_event navEvent; - if (!spnav_x11_event(event, &navEvent)) - return false; + /* + 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; @@ -329,14 +396,29 @@ bool Gui::GUIApplicationNativeEventAware::x11EventFilter(XEvent *event) motionDataArray[5] = navEvent.motion.rz; if (!setOSIndependentMotionData()) return false; - 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); + + 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; }