Fixup 5202d44e: make caret geometry update lazy

Instead of working around crashes in update of caret geometry, only
request it as needed. The actual computation will take place just
before painting the caret.

It might be that this is overkill and that caret geometry should be
updated unconditionally. One would have to to some timing while idle to
ascertain that.

Fixes bug #11912.
This commit is contained in:
Jean-Marc Lasgouttes 2020-09-07 15:45:30 +02:00
parent 6a5f1f380e
commit c1f8c6c26d
2 changed files with 28 additions and 6 deletions

View File

@ -243,7 +243,7 @@ GuiWorkArea::Private::Private(GuiWorkArea * parent)
caret_visible_(false), need_resize_(false), preedit_lines_(1), caret_visible_(false), need_resize_(false), preedit_lines_(1),
last_pixel_ratio_(1.0), completer_(new GuiCompleter(p, p)), last_pixel_ratio_(1.0), completer_(new GuiCompleter(p, p)),
dialog_mode_(false), shell_escape_(false), read_only_(false), 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 on macOS and Wayland does not respect the
* Qt::WA_OpaquePaintEvent attribute and resets the widget backing * 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 // update caret position, because otherwise it has to wait until
// the blinking interval is over // the blinking interval is over
d->updateCaretGeometry(); d->resetCaret();
LYXERR(Debug::WORKAREA, "WorkArea::redraw screen"); LYXERR(Debug::WORKAREA, "WorkArea::redraw screen");
viewport()->update(); viewport()->update();
@ -587,7 +587,7 @@ void GuiWorkArea::Private::resizeBufferView()
buffer_view_->resize(p->viewport()->width(), p->viewport()->height()); buffer_view_->resize(p->viewport()->width(), p->viewport()->height());
if (caret_in_view) if (caret_in_view)
buffer_view_->scrollToCursor(); buffer_view_->scrollToCursor();
updateCaretGeometry(); resetCaret();
// Update scrollbars which might have changed due different // Update scrollbars which might have changed due different
// BufferView dimension. This is especially important when the // 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() void GuiWorkArea::Private::updateCaretGeometry()
{ {
// we cannot update geometry if not ready and we do not need to if // 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_->completionAvailable()
&& !completer_->popupVisible() && !completer_->popupVisible()
&& !completer_->inlineVisible(); && !completer_->inlineVisible();
caret_visible_ = true;
caret_->update(point.x_, point.y_, h, l_shape, isrtl, completable); caret_->update(point.x_, point.y_, h, l_shape, isrtl, completable);
needs_caret_geometry_update_ = false;
} }
void GuiWorkArea::Private::showCaret() void GuiWorkArea::Private::showCaret()
{ {
if (caret_visible_) if (caret_visible_)
return; return;
updateCaretGeometry(); resetCaret();
p->viewport()->update(); p->viewport()->update();
} }
@ -1359,8 +1371,14 @@ void GuiWorkArea::paintEvent(QPaintEvent * ev)
d->paintPreeditText(pain); d->paintPreeditText(pain);
// and the caret // 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->caret_->draw(pain, d->buffer_view_->horizScrollOffset());
}
d->updateScreen(ev->rect()); d->updateScreen(ev->rect());

View File

@ -85,6 +85,8 @@ struct GuiWorkArea::Private
/// ///
void dispatch(FuncRequest const & cmd0); 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 /// recompute the shape and position of the caret
void updateCaretGeometry(); void updateCaretGeometry();
/// show the caret if it is not visible /// show the caret if it is not visible
@ -169,6 +171,8 @@ struct GuiWorkArea::Private
bool clean_; bool clean_;
/// ///
bool externally_modified_; bool externally_modified_;
///
bool needs_caret_geometry_update_;
}; // GuiWorkArea }; // GuiWorkArea