From 7b8b3e38a1b9ff4d733266a4f3fe0f8fb041da01 Mon Sep 17 00:00:00 2001 From: Jean-Marc Lasgouttes Date: Fri, 8 Sep 2017 16:55:11 +0200 Subject: [PATCH] Do the actual drawing in the paint event Historically, because of two-stage drawing, LyX has been painting on a Pixmap, and this pixmap is copied to screen at paint event time. Now that we have three-stage drawing, it is possible to delay the painting to actual paint event and avoid the intermediate Pixmap. Known bug: the cursor is never erased. --- src/frontends/qt4/GuiWorkArea.cpp | 55 ++++++++----------------- src/frontends/qt4/GuiWorkArea_Private.h | 29 ------------- 2 files changed, 17 insertions(+), 67 deletions(-) diff --git a/src/frontends/qt4/GuiWorkArea.cpp b/src/frontends/qt4/GuiWorkArea.cpp index ea6423ac85..8ce598583e 100644 --- a/src/frontends/qt4/GuiWorkArea.cpp +++ b/src/frontends/qt4/GuiWorkArea.cpp @@ -246,7 +246,7 @@ SyntheticMouseEvent::SyntheticMouseEvent() GuiWorkArea::Private::Private(GuiWorkArea * parent) -: p(parent), screen_(0), buffer_view_(0), lyx_view_(0), +: p(parent), buffer_view_(0), lyx_view_(0), cursor_visible_(false), cursor_(0), need_resize_(false), schedule_redraw_(false), preedit_lines_(1), pixel_ratio_(1.0), @@ -299,7 +299,6 @@ void GuiWorkArea::init() d->cursor_timeout_.setInterval(500); } - 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()); @@ -313,10 +312,11 @@ void GuiWorkArea::init() setFrameStyle(QFrame::NoFrame); updateWindowTitle(); - viewport()->setAutoFillBackground(false); + //viewport()->setAutoFillBackground(false); // We don't need double-buffering nor SystemBackground on // the viewport because we have our own backing pixmap. - viewport()->setAttribute(Qt::WA_NoSystemBackground); + //viewport()->setAttribute(Qt::WA_NoSystemBackground); + viewport()->setAttribute(Qt::WA_OpaquePaintEvent); setFocusPolicy(Qt::StrongFocus); @@ -344,7 +344,6 @@ GuiWorkArea::~GuiWorkArea() try { d->buffer_view_->buffer().workAreaManager().remove(this); } catch(...) {} - delete d->screen_; delete d->buffer_view_; delete d->cursor_; // Completer has a QObject parent and is thus automatically destroyed. @@ -491,8 +490,7 @@ void GuiWorkArea::redraw(bool update_metrics) } LYXERR(Debug::WORKAREA, "WorkArea::redraw screen"); - d->updateScreen(); - update(0, 0, viewport()->width(), viewport()->height()); + viewport()->update(); /// \warning: scrollbar updating *must* be done after the BufferView is drawn /// because \c BufferView::updateScrollbar() is called in \c BufferView::draw(). @@ -591,7 +589,7 @@ void GuiWorkArea::Private::resizeBufferView() buffer_view_->resize(p->viewport()->width(), p->viewport()->height()); if (cursor_in_view) buffer_view_->scrollToCursor(); - updateScreen(); + p->viewport()->update(); // Update scrollbars which might have changed due different // BufferView dimension. This is especially important when the @@ -1176,20 +1174,12 @@ void GuiWorkArea::resizeEvent(QResizeEvent * ev) } -void GuiWorkArea::Private::update(int x, int y, int w, int h) -{ - p->viewport()->update(x, y, w, h); -} - - void GuiWorkArea::paintEvent(QPaintEvent * ev) { - QRectF const rc = ev->rect(); // LYXERR(Debug::PAINTING, "paintEvent begin: x: " << rc.x() // << " y: " << rc.y() << " w: " << rc.width() << " h: " << rc.height()); if (d->needResize()) { - d->resetScreen(); d->resizeBufferView(); if (d->cursor_visible_) { d->hideCursor(); @@ -1197,29 +1187,14 @@ void GuiWorkArea::paintEvent(QPaintEvent * ev) } } - QPainter pain(viewport()); - double const pr = pixelRatio(); - QRectF const rcs = QRectF(rc.x() * pr, rc.y() * pr, rc.width() * pr, rc.height() * pr); + GuiPainter pain(viewport(), pixelRatio()); + d->buffer_view_->draw(pain); - if (lyxrc.use_qimage) { - QImage const & image = static_cast(*d->screen_); - pain.drawImage(rc, image, rcs); - } else { - QPixmap const & pixmap = static_cast(*d->screen_); - pain.drawPixmap(rc, pixmap, rcs); - } d->cursor_->draw(pain); ev->accept(); } -void GuiWorkArea::Private::updateScreen() -{ - GuiPainter pain(screen_, p->pixelRatio()); - buffer_view_->draw(pain); -} - - void GuiWorkArea::Private::showCursor(int x, int y, int h, bool l_shape, bool rtl, bool completable) { @@ -1229,9 +1204,8 @@ void GuiWorkArea::Private::showCursor(int x, int y, int h, // We can't use redraw() here because this would trigger a infinite // recursive loop with showCursor(). buffer_view_->resize(p->viewport()->width(), p->viewport()->height()); - updateScreen(); + p->viewport()->update(); updateScrollbar(); - p->viewport()->update(QRect(0, 0, p->viewport()->width(), p->viewport()->height())); schedule_redraw_ = false; // Show the cursor immediately after the update. hideCursor(); @@ -1255,6 +1229,10 @@ void GuiWorkArea::Private::removeCursor() void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e) { +//FIXME Broken Feature !! +// I do not think that we are supposed to paint inside this event. Shall we +// just let TextMetrics::breakRow add this to the relevant Row object? +#if 0 QString const & commit_string = e->commitString(); docstring const & preedit_string = qstring_to_ucs4(e->preeditString()); @@ -1290,7 +1268,7 @@ void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e) } d->buffer_view_->updateMetrics(); - d->updateScreen(); + viewport()->update(); // FIXME: shall we use real_current_font here? (see #10478) FontInfo font = d->buffer_view_->cursor().getFont().fontInfo(); FontMetrics const & fm = theFontMetrics(font); @@ -1299,7 +1277,7 @@ void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e) int cur_y = d->cursor_->rect().bottom(); // redraw area of preedit string. - update(0, cur_y - height, viewport()->width(), + viewport()->update(0, cur_y - height, viewport()->width(), (height + 1) * d->preedit_lines_); if (preedit_string.empty()) { @@ -1387,8 +1365,9 @@ void GuiWorkArea::inputMethodEvent(QInputMethodEvent * e) } // update the preedit string screen area. - update(0, cur_y - d->preedit_lines_*height, viewport()->width(), + viewport()->update(0, cur_y - d->preedit_lines_*height, viewport()->width(), (height + 1) * d->preedit_lines_); +#endif // Don't forget to accept the event! e->accept(); diff --git a/src/frontends/qt4/GuiWorkArea_Private.h b/src/frontends/qt4/GuiWorkArea_Private.h index 76b05c0d36..42597172b1 100644 --- a/src/frontends/qt4/GuiWorkArea_Private.h +++ b/src/frontends/qt4/GuiWorkArea_Private.h @@ -92,10 +92,6 @@ struct GuiWorkArea::Private { Private(GuiWorkArea *); - /// update the passed area. - void update(int x, int y, int w, int h); - /// - void updateScreen(); /// void resizeBufferView(); @@ -123,34 +119,9 @@ struct GuiWorkArea::Private return need_resize_ || p->pixelRatio() != pixel_ratio_; } - void resetScreen() - { - delete screen_; - pixel_ratio_ = p->pixelRatio(); - if (lyxrc.use_qimage) { - QImage *x = - new QImage(static_cast(pixel_ratio_ * p->viewport()->width()), - static_cast(pixel_ratio_ * p->viewport()->height()), - QImage::Format_ARGB32_Premultiplied); -#if QT_VERSION >= 0x050000 - x->setDevicePixelRatio(pixel_ratio_); -#endif - screen_ = x; - } else { - QPixmap *x = - new QPixmap(static_cast(pixel_ratio_ * p->viewport()->width()), - static_cast(pixel_ratio_ * p->viewport()->height())); -#if QT_VERSION >= 0x050000 - x->setDevicePixelRatio(pixel_ratio_); -#endif - screen_ = x; - } - } /// GuiWorkArea * p; /// - QPaintDevice * screen_; - /// BufferView * buffer_view_; /// GuiView * lyx_view_;