As I said in my post to bugzilla, this bug seems as if it might be gone.
My office machine has seen it fairly reliably, and now I do not see it
with latest 1.5.svn. I haven't recently tried 1.6.svn, but I expect the
fix is there now, too.
That said, in investigating this bug, I acquired some timing data that
may yet be of interest. Here is what I added to the end of
LyXFunc::dispatch().
default: {
BOOST_ASSERT(lyx_view_);
t.start();
view()->cursor().dispatch(cmd);
lyxerr << t.restart() << " msec 1" << std::endl;
updateFlags = view()->cursor().result().update();
lyxerr << t.restart() << " msec 2" << std::endl;
if (!view()->cursor().result().dispatched())
updateFlags = view()->dispatch(cmd);
lyxerr << t.restart() << " msec 3" << std::endl;
break;
}
}
if (lyx_view_ && view()->buffer()) {
// BufferView::update() updates the ViewMetricsInfo and
// also initializes the position cache for all insets in
// (at least partially) visible top-level paragraphs.
// We will redraw the screen only if needed.
if (view()->update(updateFlags)) {
// Buffer::changed() signals that a repaint is needed.
// The frontend (WorkArea) knows which area to repaint
// thanks to the ViewMetricsInfo updated above.
view()->buffer()->changed();
}
lyxerr << t.restart() << " msec 3.5" << std::endl;
lyx_view_->updateStatusBar();
lyxerr << t.restart() << " msec 4" << std::endl;
// if we executed a mutating lfun, mark the buffer as dirty
if (flag.enabled()
&& !lyxaction.funcHasFlag(action, LyXAction::NoBuffer)
&& !lyxaction.funcHasFlag(action, LyXAction::ReadOnly))
view()->buffer()->markDirty();
lyxerr << t.restart() << " msec 5" << std::endl;
//Do we have a selection?
theSelection().haveSelection(view()->cursor().selection());
lyxerr << t.restart() << " msec 6" << std::endl;
if (view()->cursor().inTexted()) {
lyx_view_->updateLayoutChoice();
lyxerr << t.restart() << " msec 6.5" << std::endl;
}
}
}
lyxerr << t.restart() << " msec 7" << std::endl;
if (!quitting && lyx_view_) {
lyx_view_->updateMenubar();
lyxerr << t.restart() << " msec 8" << std::endl;
lyx_view_->updateToolbars();
lyxerr << t.restart() << " msec 9" << std::endl;
// Some messages may already be translated, so we cannot use _()
sendDispatchMessage(translateIfPossible(getMessage()), cmd);
}
}
You'll see I'm getting (wall) times between the various calls. There are
only a few that reliably take any significant amount of time. One,
obviously, is the repaint, which reports as "msec 3.5". On my machine,
to give you a basis for comparison, that tends to be about 4msec or so,
for just ordinary typing. Obviously, that will continue to be a focus of
work, and I have nothing to say about it.
The call to updateStatusBar() can sometimes take as much as 2 msec, i.e,
half as much as a repaint. It may be that this is an illusion, caused by
the rather verbose status info in the development versions, but someone
who knows this code might have a look at it. It's significant, anyway.
The surprising thing to me was that a LOT of time was spent in this call:
theSelection().haveSelection(view()->cursor().selection());
when e.g. selecting text with Shift-arrow. This tends to run 35-40msec,
minimum, and it's often 80-100msec, and I've seen it go as high as
120msec, roughly 30 times as long as a repaint! The time is all spent in
this call:
qApp->clipboard()->setText(QString(), QClipboard::Selection);
in GuiSelection::haveSelection(). The comments above this call that talk
about how cheap it is seem to be incorrect.
Is there some signal that this is emitting that is causing it to take so
long? The weird thing is that, if you do this
void GuiSelection::haveSelection(bool own)
{
QTime t;
t.start();
if (!qApp->clipboard()->supportsSelection())
return;
lyxerr << t.restart() << "msec check" << std::endl;
// Tell qt that we have a selection by setting a dummy selection.
// We don't use the interface provided by Qt for setting the
// selection for performance reasons (see documentation of
// Selection::put()). Instead we only tell here that we have a
// selection by setting the selection to the empty string.
// The real selection is set in GuiApplication::x11EventFilter when
// an application actually requests it.
// This way calling Selection::have() is cheap and we can do it as
// often as we want.
if (own)
qApp->clipboard()->setText(emp, QClipboard::Selection);
lyxerr << t.restart() << "msec call" << std::endl;
// We don't need to do anything if own = false, as this case is
// handled by QT.
// FIXME (gb): This is wrong. What is missing here is rather a call of
//else
// qApp->clipboard()->clear(QClipboard::Selection);
// Since we do not issue this call we rather implement
// "persistent selections" as far as X is concerned.
}
and watch the times, how long this takes depends upon whether the
selection is within a single paragraph or across a couple paragraphs,
and it can jump as high as 125msec when going from a 2 to a 3 paragraph
selection. That's ridiculous, and puzzling, since the actual call never
changes, but the time spent reliably does.
Anyway, I can't investigate further now. Maybe later.
Richard