diff --git a/src/frontends/qt/GuiWorkArea.cpp b/src/frontends/qt/GuiWorkArea.cpp index dd9d1fd5f3..f323fbc3d9 100644 --- a/src/frontends/qt/GuiWorkArea.cpp +++ b/src/frontends/qt/GuiWorkArea.cpp @@ -243,7 +243,7 @@ GuiWorkArea::Private::Private(GuiWorkArea * parent) 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) + clean_(true), externally_modified_(false), needs_caret_geometry_update_(true) { /* Qt on macOS and Wayland does not respect the * Qt::WA_OpaquePaintEvent attribute and resets the widget backing @@ -487,7 +487,7 @@ void GuiWorkArea::scheduleRedraw(bool update_metrics) // update caret position, because otherwise it has to wait until // the blinking interval is over - d->updateCaretGeometry(); + d->resetCaret(); LYXERR(Debug::WORKAREA, "WorkArea::redraw screen"); viewport()->update(); @@ -587,7 +587,7 @@ void GuiWorkArea::Private::resizeBufferView() buffer_view_->resize(p->viewport()->width(), p->viewport()->height()); if (caret_in_view) buffer_view_->scrollToCursor(); - updateCaretGeometry(); + resetCaret(); // Update scrollbars which might have changed due different // BufferView dimension. This is especially important when the @@ -605,6 +605,17 @@ void GuiWorkArea::Private::resizeBufferView() } +void GuiWorkArea::Private::resetCaret() +{ + // Don't start blinking if the cursor isn't on screen. + if (!buffer_view_->caretInView()) + return; + + needs_caret_geometry_update_ = true; + caret_visible_ = true; +} + + void GuiWorkArea::Private::updateCaretGeometry() { // we cannot update geometry if not ready and we do not need to if @@ -637,18 +648,19 @@ void GuiWorkArea::Private::updateCaretGeometry() && completer_->completionAvailable() && !completer_->popupVisible() && !completer_->inlineVisible(); - caret_visible_ = true; caret_->update(point.x_, point.y_, h, l_shape, isrtl, completable); + needs_caret_geometry_update_ = false; } + void GuiWorkArea::Private::showCaret() { if (caret_visible_) return; - updateCaretGeometry(); + resetCaret(); p->viewport()->update(); } @@ -1359,8 +1371,14 @@ void GuiWorkArea::paintEvent(QPaintEvent * ev) d->paintPreeditText(pain); // and the caret - if (d->caret_visible_) + // FIXME: the code would be a little bit simpler if caret geometry + // was updated unconditionally. Some profiling is required to see + // how expensive this is (especially when idle). + if (d->caret_visible_) { + if (d->needs_caret_geometry_update_) + d->updateCaretGeometry(); d->caret_->draw(pain, d->buffer_view_->horizScrollOffset()); + } d->updateScreen(ev->rect()); diff --git a/src/frontends/qt/GuiWorkArea_Private.h b/src/frontends/qt/GuiWorkArea_Private.h index 6342eaba4a..39130162ad 100644 --- a/src/frontends/qt/GuiWorkArea_Private.h +++ b/src/frontends/qt/GuiWorkArea_Private.h @@ -85,6 +85,8 @@ struct GuiWorkArea::Private /// void dispatch(FuncRequest const & cmd0); + /// Make caret visible and signal that its geometry needs to be updated + void resetCaret(); /// recompute the shape and position of the caret void updateCaretGeometry(); /// show the caret if it is not visible @@ -169,6 +171,8 @@ struct GuiWorkArea::Private bool clean_; /// bool externally_modified_; + /// + bool needs_caret_geometry_update_; }; // GuiWorkArea