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();