commit c6771569384edc1e100d427365d6a4976bc5bd95
Author: Jean-Marc Lasgouttes <lasgout...@lyx.org>
Date:   Sat Nov 25 12:31:11 2017 +0100

    Use a backing store on macOS
    
    Qt on macOS does not respect the Qt::WA_OpaquePaintEvent attribute and
    clears the widget backing store at each update. Therefore, we use our
    own backing store in this case.
    
    This restores a simplified version of the code that was removed at 06253dfe.
    
    (cherry picked from commit 2316435f2fd2da28c70e1b251b852d3bf6d8011a)
---
 src/frontends/qt4/GuiWorkArea.cpp       |   11 ++++++-
 src/frontends/qt4/GuiWorkArea_Private.h |   44 +++++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+), 2 deletions(-)

diff --git a/src/frontends/qt4/GuiWorkArea.cpp 
b/src/frontends/qt4/GuiWorkArea.cpp
index c4463e3..6df7e4e 100644
--- a/src/frontends/qt4/GuiWorkArea.cpp
+++ b/src/frontends/qt4/GuiWorkArea.cpp
@@ -306,6 +306,7 @@ void GuiWorkArea::init()
                        generateSyntheticMouseEvent();
                });
 
+       d->resetScreen();
        // With Qt4.5 a mouse event will happen before the first paint event
        // so make sure that the buffer view has an up to date metrics.
        d->buffer_view_->resize(viewport()->width(), viewport()->height());
@@ -1246,12 +1247,15 @@ void GuiWorkArea::paintEvent(QPaintEvent * ev)
        // LYXERR(Debug::PAINTING, "paintEvent begin: x: " << rc.x()
        //      << " y: " << rc.y() << " w: " << rc.width() << " h: " << 
rc.height());
 
-       if (d->need_resize_ || pixelRatio() != d->last_pixel_ratio_)
+       if (d->need_resize_ || pixelRatio() != d->last_pixel_ratio_) {
+               d->resetScreen();
                d->resizeBufferView();
+       }
 
        d->last_pixel_ratio_ = pixelRatio();
 
-       GuiPainter pain(viewport(), pixelRatio());
+       GuiPainter pain(d->screenDevice(), pixelRatio());
+
        d->buffer_view_->draw(pain, d->caret_visible_);
 
        // The preedit text, if needed
@@ -1260,6 +1264,9 @@ void GuiWorkArea::paintEvent(QPaintEvent * ev)
        // and the caret
        if (d->caret_visible_)
                d->caret_->draw(pain);
+
+       d->updateScreen(ev->rect());
+
        ev->accept();
 }
 
diff --git a/src/frontends/qt4/GuiWorkArea_Private.h 
b/src/frontends/qt4/GuiWorkArea_Private.h
index de20397..83012fa 100644
--- a/src/frontends/qt4/GuiWorkArea_Private.h
+++ b/src/frontends/qt4/GuiWorkArea_Private.h
@@ -20,6 +20,14 @@
 #include <QMouseEvent>
 #include <QTimer>
 
+#ifdef Q_OS_MAC
+/* Qt on macOS 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 this case */
+#define LYX_BACKINGSTORE 1
+#include <QPainter>
+#endif
+
 namespace lyx {
 
 class Buffer;
@@ -99,6 +107,38 @@ struct GuiWorkArea::Private
 
        void paintPreeditText(GuiPainter & pain);
 
+       void resetScreen() {
+#ifdef LYX_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
+#endif
+       }
+
+       QPaintDevice * screenDevice() {
+#ifdef LYX_BACKINGSTORE
+               return &screen_;
+#else
+               return p->viewport();
+#endif
+       }
+
+#ifdef LYX_BACKINGSTORE
+       void updateScreen(QRectF const & rc) {
+               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);
+       }
+#else
+       void updateScreen(QRectF const & ) {}
+#endif
+
        ///
        GuiWorkArea * p;
        ///
@@ -106,6 +146,10 @@ struct GuiWorkArea::Private
        ///
        GuiView * lyx_view_;
 
+#ifdef LYX_BACKINGSTORE
+       ///
+       QImage screen_;
+#endif
        ///
        CaretWidget * caret_;
        /// is the caret currently displayed

Reply via email to