Thanks for the intensive testing, Helge!

Helge Hafting wrote:
> void lyx::BufferView::updateScrollbar() Updating scrollbar: height: 1175 curr 
> par: 905 default height 32
> scrolling: one event posted
> void lyx::BufferView::scrollDocView(int)[ value = 259297]
> void lyx::BufferView::updateScrollbar() Updating scrollbar: height: 1175 curr 
> par: 905 default height 32
> scrolling: one event posted

This output shows the problem: all scroll events are posted
even when the xsever hasn't finishes the last one.

One way to fix this is to replace the flush() call with
QApplication::syncX(), then on each event LyX is waiting
for the xserver, but this gives bad scroll performance.

Attached a patch which also checks if the x11-queue is empty
(<2: page down doesn't work with <1 -> the patch becomes more
and more a hack).

When you run with -dbg 8 you will see the how full the
x11 queue is. Here it is never more than 1 event in the queue,
seems this is the reason why I coudn't reproduce your scrolling
bug. I hope you see numbers bigger than 1.

What for a linux distro is on your system? Maybe it is the xserver
configuration.

Peter
Index: src/frontends/qt4/GuiWorkArea.cpp
===================================================================
--- src/frontends/qt4/GuiWorkArea.cpp   (Revision 18433)
+++ src/frontends/qt4/GuiWorkArea.cpp   (Arbeitskopie)
@@ -54,6 +54,10 @@
 int const CursorWidth = 1;
 #endif
 
+#ifdef Q_WS_X11
+#include <QX11Info>
+extern "C" int XEventsQueued(Display *display, int mode);
+#endif
 
 using std::endl;
 using std::string;
@@ -63,6 +67,17 @@
 
 namespace lyx {
 
+#ifdef Q_WS_X11
+bool xEventsProcessed() { 
+       QApplication::flush();
+       int events = XEventsQueued(QX11Info::display(), 0 /* QueuedAlready */) 
== 0;
+       LYXERR(Debug::GUI) << "X11 queue " << events << "  \n";
+       return events < 2;
+}
+#else
+bool xEventsProcessed() { return true; }
+#endif
+
 using support::FileName;
 
 /// return the LyX key state from Qt's
@@ -190,8 +205,11 @@
 
        // Initialize the vertical Scroll Bar
        QObject::connect(verticalScrollBar(), SIGNAL(actionTriggered(int)),
-               this, SLOT(adjustViewWithScrollBar(int)));
+               this, SLOT(generateLyxScrollEvent()));
+       QObject::connect(verticalScrollBar(), SIGNAL(sliderReleased()),
+               this, SLOT(lyxScrollEvent()));
 
+
        // disable context menu for the scrollbar
        verticalScrollBar()->setContextMenuPolicy(Qt::NoContextMenu);
 
@@ -211,6 +229,53 @@
 }
 
 
+
+class LyxScrollEvent : public QEvent
+{
+public:
+       LyxScrollEvent() : QEvent(QEvent::Type(id)) 
+       {}
+       static int id;
+       static bool locked;
+};
+
+// Qt doc: user event type between 1000 and 65535
+int LyxScrollEvent::id = 31415;
+bool LyxScrollEvent::locked = false;
+
+
+class LyxKeyEvent : public QKeyEvent
+{
+public:
+       LyxKeyEvent(QKeyEvent * e) : 
+         QKeyEvent(QEvent::Type(id), e->key(), 
+                               e->modifiers(), e->text(), e->isAutoRepeat(), 
e->count())
+       {}
+       static int id;
+       static bool locked;
+};
+
+int LyxKeyEvent::id = 27182;
+bool LyxKeyEvent::locked = false;
+
+
+
+bool GuiWorkArea::event(QEvent * event)
+{
+       if (event->type() == LyxKeyEvent::id) {
+               lyxKeyEvent(dynamic_cast<LyxKeyEvent*>(event));
+               LyxKeyEvent::locked = false;
+               return true;
+       } else if (event->type() == LyxScrollEvent::id) {
+               lyxScrollEvent();
+               LyxScrollEvent::locked = false;
+               return true;
+       } else {
+               return QAbstractScrollArea::event(event);
+       }
+}
+
+
 void GuiWorkArea::setScrollbarParams(int h, int scroll_pos, int 
scroll_line_step)
 {
        if (verticalScrollBarPolicy() != Qt::ScrollBarAlwaysOn)
@@ -231,12 +296,30 @@
 }
 
 
-void GuiWorkArea::adjustViewWithScrollBar(int)
+void GuiWorkArea::lyxScrollEvent()
 {
        scrollBufferView(verticalScrollBar()->sliderPosition());
 }
 
 
+void GuiWorkArea::generateLyxScrollEvent()
+{
+       // This gives the old slow (the scroll bar couldn't follow the mouse)
+       // scrolling on Windows. Is it really better? 
+       // Windows/Qt is here not as fast as X11
+       //lyxScrollEvent();return;
+
+       // multiple scroll events are merged into one
+       if (!LyxScrollEvent::locked && xEventsProcessed()) {
+               LyxScrollEvent::locked = true;
+               LyxScrollEvent* scrollEvent = new LyxScrollEvent;
+               QCoreApplication::postEvent(this, scrollEvent);
+               LYXERR(Debug::GUI) << "scrolling: one event posted" << endl;
+       } else {
+               LYXERR(Debug::GUI) << "scrolling: waiting for processing last 
scrolling event" << endl;
+       }
+}
+
 void GuiWorkArea::dragEnterEvent(QDragEnterEvent * event)
 {
        if (event->mimeData()->hasUrls())
@@ -389,13 +472,14 @@
        int const lines = qApp->wheelScrollLines() * e->delta() / 120;
        verticalScrollBar()->setValue(verticalScrollBar()->value() -
                        lines *  verticalScrollBar()->singleStep());
-       adjustViewWithScrollBar();
+       
+       generateLyxScrollEvent();
 }
 
 
 void GuiWorkArea::generateSyntheticMouseEvent()
 {
-// Set things off to generate the _next_ 'pseudo' event.
+       // Set things off to generate the _next_ 'pseudo' event.
        if (synthetic_mouse_event_.restart_timeout)
                synthetic_mouse_event_.timeout.start();
 
@@ -412,18 +496,32 @@
 }
 
 
+
 void GuiWorkArea::keyPressEvent(QKeyEvent * e)
 {
-       // do nothing if there are other events
-       // (the auto repeated events come too fast)
-       if (e->isAutoRepeat() && QCoreApplication::hasPendingEvents()) {
-               LYXERR(Debug::KEY)      
-                       << BOOST_CURRENT_FUNCTION << endl
-                       << "key ignored" << endl;
-               e->ignore();
-               return;
+       // add here all keys which should be delayed
+       static const int delayed_keys = Qt::Key_PageDown | Qt::Key_PageUp;
+
+       if (e->key() & delayed_keys) {
+               if (!LyxKeyEvent::locked && xEventsProcessed()) {
+                       LyxKeyEvent::locked = true;
+                       QCoreApplication::postEvent(this, new LyxKeyEvent(e));
+                       e->ignore();
+                       LYXERR(Debug::GUI) << "key processing : event queued" 
<< endl;
+               } else {
+                       e->ignore();
+                       LYXERR(Debug::GUI) << "key processing : waiting for 
event processing" << endl;
+               }
+       } else {
+               e->accept();
+               LyxKeyEvent lyxEvent(e);
+               lyxKeyEvent(&lyxEvent);
        }
+}
 
+
+void GuiWorkArea::lyxKeyEvent(LyxKeyEvent * e)
+{
        LYXERR(Debug::KEY) << BOOST_CURRENT_FUNCTION
                << " count=" << e->count()
                << " text=" << fromqstr(e->text())
@@ -436,6 +534,7 @@
        processKeySym(sym, q_key_state(e->modifiers()));
 }
 
+
 void GuiWorkArea::doubleClickTimeout() {
        dc_event_.active = false;
 }
Index: src/frontends/qt4/GuiWorkArea.h
===================================================================
--- src/frontends/qt4/GuiWorkArea.h     (Revision 18433)
+++ src/frontends/qt4/GuiWorkArea.h     (Arbeitskopie)
@@ -25,8 +25,6 @@
 #include <QTimer>
 #include <QPixmap>
 
-#include <queue>
-
 class QWidget;
 class QDragEnterEvent;
 class QDropEvent;
@@ -38,6 +36,8 @@
 
 class GuiView;
 class QLPainter;
+class CursorWidget;
+class LyxKeyEvent;
 
 /// for emulating triple click
 class double_click {
@@ -81,7 +81,6 @@
  * Qt-specific implementation of the work area
  * (buffer view GUI)
 */
-       class CursorWidget;
 class GuiWorkArea : public QAbstractScrollArea, public WorkArea
 {
        Q_OBJECT
@@ -144,15 +143,16 @@
        void inputMethodEvent(QInputMethodEvent * ev);
        /// IM query
        QVariant inputMethodQuery(Qt::InputMethodQuery query) const;
+       /// overwrite QObject function
+       bool event(QEvent * event);
+       ///
+       void lyxKeyEvent(LyxKeyEvent * event);
 
-public Q_SLOTS:
+private Q_SLOTS:
        /// Adjust the LyX buffer view with the position of the scrollbar.
-       /**
-       * The action argument is not used in the the code, it is there
-       * only for the connection to the vertical srollbar signal which
-       * emits an 'int' action.
-       */
-       void adjustViewWithScrollBar(int action = 0);
+       void lyxScrollEvent();
+       /// 
+       void generateLyxScrollEvent();
        /// timer to limit triple clicks
        void doubleClickTimeout();
 

Reply via email to