]> git.lyx.org Git - lyx.git/blobdiff - src/frontends/qt4/GuiWorkArea.cpp
Do not compute caret geometry when we are not ready to do so.
[lyx.git] / src / frontends / qt4 / GuiWorkArea.cpp
index 18c25caac5f109656f8de7bf593e72f2dc56884f..95cff6d5ec30f8c7d8de4903e3750115022cff16 100644 (file)
@@ -133,26 +133,30 @@ public:
                x_(0), caret_width_(0)
        {}
 
-       void draw(QPainter & painter)
+       /* Draw the caret. Parameter \c horiz_offset is not 0 when there
+        * has been horizontal scrolling in current row
+        */
+       void draw(QPainter & painter, int horiz_offset)
        {
                if (!rect_.isValid())
                        return;
 
-               int y = rect_.top();
-               int l = x_ - rect_.left();
-               int r = rect_.right() - x_;
-               int bot = rect_.bottom();
+               int const x = x_ - horiz_offset;
+               int const y = rect_.top();
+               int const l = x_ - rect_.left();
+               int const r = rect_.right() - x_;
+               int const bot = rect_.bottom();
 
                // draw vertical line
-               painter.fillRect(x_, y, caret_width_, rect_.height(), color_);
+               painter.fillRect(x, y, caret_width_, rect_.height(), color_);
 
                // draw RTL/LTR indication
                painter.setPen(color_);
                if (l_shape_) {
                        if (rtl_)
-                               painter.drawLine(x_, bot, x_ - l, bot);
+                               painter.drawLine(x, bot, x - l, bot);
                        else
-                               painter.drawLine(x_, bot, x_ + caret_width_ + r, bot);
+                               painter.drawLine(x, bot, x + caret_width_ + r, bot);
                }
 
                // draw completion triangle
@@ -160,11 +164,11 @@ public:
                        int m = y + rect_.height() / 2;
                        int d = TabIndicatorWidth - 1;
                        if (rtl_) {
-                               painter.drawLine(x_ - 1, m - d, x_ - 1 - d, m);
-                               painter.drawLine(x_ - 1, m + d, x_ - 1 - d, m);
+                               painter.drawLine(x - 1, m - d, x - 1 - d, m);
+                               painter.drawLine(x - 1, m + d, x - 1 - d, m);
                        } else {
-                               painter.drawLine(x_ + caret_width_, m - d, x_ + caret_width_ + d, m);
-                               painter.drawLine(x_ + caret_width_, m + d, x_ + caret_width_ + d, m);
+                               painter.drawLine(x + caret_width_, m - d, x + caret_width_ + d, m);
+                               painter.drawLine(x + caret_width_, m + d, x + caret_width_ + d, m);
                        }
                }
        }
@@ -235,13 +239,27 @@ SyntheticMouseEvent::SyntheticMouseEvent()
 
 
 GuiWorkArea::Private::Private(GuiWorkArea * parent)
-: p(parent), buffer_view_(0), lyx_view_(0),
-  caret_(0), caret_visible_(false),
-  need_resize_(false), preedit_lines_(1),
-  last_pixel_ratio_(1.0),
-  completer_(new GuiCompleter(p, p)), dialog_mode_(false), shell_escape_(false),
-  read_only_(false), clean_(true), externally_modified_(false)
-{
+: p(parent), buffer_view_(0), lyx_view_(0), caret_(0),
+  caret_visible_(false), need_resize_(false), preedit_lines_(1),
+  last_pixel_ratio_(1.0), completer_(new GuiCompleter(p, p)),
+  dialog_mode_(false), shell_escape_(false), read_only_(false),
+  clean_(true), externally_modified_(false)
+{
+/* Qt on macOS and Wayland does not respect the
+ * Qt::WA_OpaquePaintEvent attribute and resets the widget backing
+ * store at each update. Therefore, we use our own backing store in
+ * these two cases. */
+#if QT_VERSION >= 0x050000
+       use_backingstore_ = guiApp->platformName() == "cocoa"
+               || guiApp->platformName().contains("wayland");
+#else
+#  ifdef Q_OS_MAC
+       use_backingstore_ = true;
+#  else
+       use_backingstore_ = false;
+#  endif
+#endif
+
        int const time = QApplication::cursorFlashTime() / 2;
        if (time > 0) {
                caret_timeout_.setInterval(time);
@@ -425,12 +443,16 @@ void GuiWorkArea::startBlinkingCaret()
        if (view().busy())
                return;
 
-       Point p;
-       int h = 0;
-       d->buffer_view_->caretPosAndHeight(p, h);
-       // Don't start blinking if the cursor isn't on screen.
-       if (!d->buffer_view_->cursorInView(p, h))
-               return;
+       // we cannot update geometry if not ready and we do not need to if
+       // caret is not in view.
+       if (!d->buffer_view_->buffer().undo().activeUndoGroup()) {
+               Point p;
+               int h = 0;
+               d->buffer_view_->caretPosAndHeight(p, h);
+               // Don't start blinking if the cursor isn't on screen.
+               if (!d->buffer_view_->cursorInView(p, h))
+                       return;
+       }
 
        d->showCaret();
 
@@ -593,6 +615,11 @@ void GuiWorkArea::Private::resizeBufferView()
 
 void GuiWorkArea::Private::updateCaretGeometry()
 {
+       // we cannot update geometry if not ready and we do not need to if
+       // caret is not in view.
+       if (buffer_view_->buffer().undo().activeUndoGroup())
+               return;
+
        Point point;
        int h = 0;
        buffer_view_->caretPosAndHeight(point, h);
@@ -621,11 +648,6 @@ void GuiWorkArea::Private::updateCaretGeometry()
                && !completer_->inlineVisible();
        caret_visible_ = true;
 
-       //int cur_x = buffer_view_->getPos(cur).x_;
-       // We may have decided to slide the cursor row so that caret
-       // is visible.
-       point.x_ -= buffer_view_->horizScrollOffset();
-
        caret_->update(point.x_, point.y_, h, l_shape, isrtl, completable);
 }
 
@@ -636,7 +658,7 @@ void GuiWorkArea::Private::showCaret()
                return;
 
        updateCaretGeometry();
-       p->viewport()->update(caret_->rect());
+       p->viewport()->update();
 }
 
 
@@ -647,7 +669,7 @@ void GuiWorkArea::Private::hideCaret()
 
        caret_visible_ = false;
        //if (!qApp->focusWidget())
-               p->viewport()->update(caret_->rect());
+               p->viewport()->update();
 }
 
 
@@ -1258,6 +1280,41 @@ void GuiWorkArea::Private::paintPreeditText(GuiPainter & pain)
 }
 
 
+void GuiWorkArea::Private::resetScreen()
+{
+       if (use_backingstore_) {
+               int const pr = p->pixelRatio();
+               screen_ = QImage(static_cast<int>(pr * p->viewport()->width()),
+                                static_cast<int>(pr * p->viewport()->height()),
+                                QImage::Format_ARGB32_Premultiplied);
+#  if QT_VERSION >= 0x050000
+               screen_.setDevicePixelRatio(pr);
+#  endif
+       }
+}
+
+
+QPaintDevice * GuiWorkArea::Private::screenDevice()
+{
+       if (use_backingstore_)
+               return &screen_;
+       else
+               return p->viewport();
+}
+
+
+void GuiWorkArea::Private::updateScreen(QRectF const & rc)
+{
+       if (use_backingstore_) {
+               QPainter qpain(p->viewport());
+               double const pr = p->pixelRatio();
+               QRectF const rcs = QRectF(rc.x() * pr, rc.y() * pr,
+                                         rc.width() * pr, rc.height() * pr);
+               qpain.drawImage(rc, screen_, rcs);
+       }
+}
+
+
 void GuiWorkArea::paintEvent(QPaintEvent * ev)
 {
        // Do not trigger the painting machinery if we are not ready (see
@@ -1293,7 +1350,7 @@ void GuiWorkArea::paintEvent(QPaintEvent * ev)
 
        // and the caret
        if (d->caret_visible_)
-               d->caret_->draw(pain);
+               d->caret_->draw(pain, d->buffer_view_->horizScrollOffset());
 
        d->updateScreen(ev->rect());