The attached patch attempts to address the underlying cause of bug 6522. My other fixes all have problems, which trace to the fact that we are calling updateBuffer()---what used to be called updateLabels()---before we are really ready to do so. The patch also does something we've been wanting to do for a while anyway, namely, bring some sense to the whole updateLabels() nightmare.
The patch introduces an argument to DispatchResult that tracks whether we need to update the Buffer. This reduces the number of updateBuffer calls to six or seven from a whole lot more than that, and some of these can still go, too. Ideally, we'd like one such call, at the end of the dispatch() process, but that doesn't seem entirely likely.
I don't think this will introduce instability, as delaying the call to updateBuffer() shouldn't have ill effects. I'll guess, though, that there are some missing updates in here, but these can easily enough be fixed. In any event, it is essential. What caused 6522 will cause other problems.
Please, please have a look at this. I'd particularly appreciate it if people could look at the things marked "FIXME audit updateBuffer calls". These are the ones that can still go, or that I'm not sure can go.
Richard
Index: src/Cursor.h =================================================================== --- src/Cursor.h (revision 33676) +++ src/Cursor.h (working copy) @@ -229,6 +229,10 @@ void dispatched(); /// Set which update should be done void updateFlags(Update::flags f); + /// + void needBufferUpdate(bool u); + /// + bool needBufferUpdate() const; /** * don't call update() when done * Index: src/insets/InsetBibitem.cpp =================================================================== --- src/insets/InsetBibitem.cpp (revision 33684) +++ src/insets/InsetBibitem.cpp (working copy) @@ -93,8 +93,6 @@ "it will be changed to %2$s."), new_key, key)); } setParam("key", key); - - buffer().updateBuffer(); } Index: src/insets/Inset.cpp =================================================================== --- src/insets/Inset.cpp (revision 33681) +++ src/insets/Inset.cpp (working copy) @@ -233,13 +233,7 @@ return getLayout().forceLTR(); } -void Inset::initView() -{ - if (isLabeled()) - buffer().updateBuffer(); -} - docstring Inset::toolTip(BufferView const &, int, int) const { return docstring(); Index: src/insets/Inset.h =================================================================== --- src/insets/Inset.h (revision 33679) +++ src/insets/Inset.h (working copy) @@ -124,7 +124,7 @@ * * \sa isLabeled() **/ - virtual void initView(); + virtual void initView() {}; /// \return true if this inset is labeled. virtual bool isLabeled() const { return false; } Index: src/insets/InsetFloat.cpp =================================================================== --- src/insets/InsetFloat.cpp (revision 33676) +++ src/insets/InsetFloat.cpp (working copy) @@ -152,7 +152,7 @@ setNewLabel(); if (params_.type != params.type) { params_.type = params.type; - buffer().updateBuffer(); + cur.needBufferUpdate(); } break; } Index: src/insets/InsetLabel.cpp =================================================================== --- src/insets/InsetLabel.cpp (revision 33676) +++ src/insets/InsetLabel.cpp (working copy) @@ -97,10 +97,6 @@ } } buffer().undo().endUndoGroup(); - - // We need an update of the Buffer reference cache. This is achieved by - // updateBuffer(). - buffer().updateBuffer(); } @@ -205,6 +201,7 @@ } if (p["name"] != params()["name"]) updateCommand(p["name"]); + cur.needBufferUpdate(); break; } Index: src/insets/InsetCommand.cpp =================================================================== --- src/insets/InsetCommand.cpp (revision 33676) +++ src/insets/InsetCommand.cpp (working copy) @@ -102,7 +102,6 @@ void InsetCommand::setParams(InsetCommandParams const & p) { p_ = p; - initView(); } @@ -144,6 +143,8 @@ cur.noUpdate(); else setParams(p); + if (isLabeled()) + cur.needBufferUpdate(); break; } Index: src/BufferView.cpp =================================================================== --- src/BufferView.cpp (revision 33682) +++ src/BufferView.cpp (working copy) @@ -408,6 +408,8 @@ << ", singlepar = " << (flags & Update::SinglePar) << "] buffer: " << &buffer_); + // FIXME Does this really need doing here? It's done in updateBuffer, and + // if the Buffer doesn't need updating, then do the macros? buffer_.updateMacros(); // Now do the first drawing step if needed. This consists on updating @@ -912,7 +914,6 @@ setCursor(backcur.asDocIterator(&buffer_)); buffer_.errors("Class Switch"); - buffer_.updateBuffer(); } /** Return the change status at cursor position, taking in account the @@ -1185,6 +1186,7 @@ // It is then better to make sure that all dialogs are in sync with // current document settings. dr.update(Update::Force | Update::FitCursor); + dr.needBufferUpdate(); break; } @@ -1196,6 +1198,7 @@ buffer_.params().makeDocumentClass(); updateDocumentClass(oldClass); dr.update(Update::Force | Update::FitCursor); + dr.needBufferUpdate(); break; } @@ -1213,6 +1216,7 @@ buffer_.params().makeDocumentClass(); updateDocumentClass(oldClass); dr.update(Update::Force | Update::FitCursor); + dr.needBufferUpdate(); break; } @@ -1236,6 +1240,7 @@ buffer_.params().makeDocumentClass(); updateDocumentClass(oldDocClass); dr.update(Update::Force | Update::FitCursor); + dr.needBufferUpdate(); break; } @@ -1252,6 +1257,7 @@ buffer_.params().makeDocumentClass(); updateDocumentClass(oldClass); dr.update(Update::Force | Update::FitCursor); + dr.needBufferUpdate(); break; } @@ -1262,6 +1268,7 @@ dr.setMessage(_("No further undo information")); else dr.update(Update::Force | Update::FitCursor); + dr.needBufferUpdate(); break; case LFUN_REDO: @@ -1271,6 +1278,7 @@ dr.setMessage(_("No further redo information")); else dr.update(Update::Force | Update::FitCursor); + dr.needBufferUpdate(); break; case LFUN_FONT_STATE: @@ -1403,6 +1411,7 @@ case LFUN_CHANGES_MERGE: if (findNextChange(this) || findPreviousChange(this)) { dr.update(Update::Force | Update::FitCursor); + dr.needBufferUpdate(); showDialog("changes"); } break; @@ -1416,6 +1425,7 @@ buffer_.text().acceptOrRejectChanges(cur, Text::ACCEPT); // FIXME: Move this LFUN to Buffer so that we don't have to do this: dr.update(Update::Force | Update::FitCursor); + dr.needBufferUpdate(); break; case LFUN_ALL_CHANGES_REJECT: @@ -1428,6 +1438,7 @@ buffer_.text().acceptOrRejectChanges(cur, Text::REJECT); // FIXME: Move this LFUN to Buffer so that we don't have to do this: dr.update(Update::Force | Update::FitCursor); + dr.needBufferUpdate(); break; case LFUN_WORD_FIND_FORWARD: @@ -1482,6 +1493,7 @@ } } replace(this, cmd, has_deleted); + dr.needBufferUpdate(); break; } @@ -1720,6 +1732,7 @@ cur = savecur; cur.fixIfBroken(); dr.update(Update::Force); + dr.needBufferUpdate(); if (iterations >= max_iter) { dr.setError(true); @@ -1838,6 +1851,7 @@ FuncRequest fr(LFUN_INSET_MODIFY, cmd.argument()); inset->dispatch(cur, fr); dr.update(Update::SinglePar | Update::FitCursor); + dr.needBufferUpdate(); break; } @@ -2227,7 +2241,9 @@ d->cursor_ = cur; - buffer_.updateBuffer(); + // FIXME audit updateBuffer calls. + // I think this can go. It should, anyway. + // buffer_.updateBuffer(); buffer_.changed(true); return true; } Index: src/Text2.cpp =================================================================== --- src/Text2.cpp (revision 33676) +++ src/Text2.cpp (working copy) @@ -231,7 +231,7 @@ pit_type undopit = undoSpan(end - 1); recUndo(cur, start, undopit - 1); setLayout(start, end, layout); - cur.buffer()->updateBuffer(); + cur.needBufferUpdate(); } @@ -290,7 +290,7 @@ } // this handles the counter labels, and also fixes up // depth values for follow-on (child) paragraphs - cur.buffer()->updateBuffer(); + cur.needBufferUpdate(); } Index: src/mathed/InsetMathGrid.cpp =================================================================== --- src/mathed/InsetMathGrid.cpp (revision 33676) +++ src/mathed/InsetMathGrid.cpp (working copy) @@ -1336,10 +1336,9 @@ cell(i).append(grid.cell(grid.index(r, c))); } cur.clearSelection(); // bug 393 - // FIXME audit setBuffer/updateBuffer calls + // FIXME audit setBuffer calls cur.inset().setBuffer(*buffer_); - // FIXME audit setBuffer/updateBuffer calls - cur.buffer()->updateBuffer(); + cur.needBufferUpdate(); cur.finishUndo(); break; } Index: src/mathed/InsetMathHull.cpp =================================================================== --- src/mathed/InsetMathHull.cpp (revision 33679) +++ src/mathed/InsetMathHull.cpp (working copy) @@ -552,10 +552,6 @@ if (label.empty()) { delete label_[row]; label_[row] = dummy_pointer; - // We need an update of the Buffer reference cache. - // This is achieved by updateBuffer(). - if (buffer_) - buffer().updateBuffer(); } else { if (buffer_) label_[row]->updateCommand(label); @@ -578,14 +574,6 @@ if (nonum_[row] && label_[row]) { delete label_[row]; label_[row] = 0; - if (!buffer_) { - // The buffer is set at the end of readInset. - // When parsing the inset, buffer_ is 0. - return; - } - // We need an update of the Buffer reference cache. - // This is achieved by updateBuffer(). - buffer().updateBuffer(); } } @@ -1242,6 +1230,8 @@ bool const align = cur.bv().buffer().params().use_amsmath == BufferParams::package_on; mutate(align ? hullAlign : hullEqnArray); + // mutate() may change labels and such. + cur.needBufferUpdate(); cur.idx() = nrows() * ncols() - 1; cur.pos() = cur.lastpos(); } @@ -1259,6 +1249,7 @@ numbered(row, !old); cur.message(old ? _("No number") : _("Number")); + cur.needBufferUpdate(); break; } @@ -1268,6 +1259,7 @@ bool old = numbered(r); cur.message(old ? _("No number") : _("Number")); numbered(r, !old); + cur.needBufferUpdate(); break; } @@ -1329,6 +1321,7 @@ } else if (numbered(row(cur.idx()))) { cur.recordUndoInset(); numbered(row(cur.idx()), false); + cur.needBufferUpdate(); } else { InsetMathGrid::doDispatch(cur, cmd); return; @@ -1363,6 +1356,7 @@ label_[r]->initView(); } } + cur.needBufferUpdate(); break; } InsetMathGrid::doDispatch(cur, cmd); @@ -1387,6 +1381,7 @@ if (cur.pos() > cur.lastpos()) cur.pos() = cur.lastpos(); + cur.needBufferUpdate(); // FIXME: find some more clever handling of the selection, // i.e. preserve it. cur.clearSelection(); Index: src/mathed/InsetMathRef.cpp =================================================================== --- src/mathed/InsetMathRef.cpp (revision 33676) +++ src/mathed/InsetMathRef.cpp (working copy) @@ -214,7 +214,7 @@ if (createInsetMath_fromDialogStr( from_utf8(InsetCommand::params2string("ref", icp)), ar)) { *this = *ar[0].nucleus()->asRefInset(); - // FIXME audit setBuffer/updateBuffer calls + // FIXME audit setBuffer calls setBuffer(buf); } } Index: src/mathed/InsetMathNest.cpp =================================================================== --- src/mathed/InsetMathNest.cpp (revision 33676) +++ src/mathed/InsetMathNest.cpp (working copy) @@ -564,8 +564,7 @@ } cur.niceInsert(topaste, parseflg, false); cur.clearSelection(); // bug 393 - // FIXME audit setBuffer/updateBuffer calls - cur.buffer()->updateBuffer(); + cur.needBufferUpdate(); cur.finishUndo(); break; } @@ -577,8 +576,7 @@ // Prevent stale position >= size crash // Probably not necessary anymore, see eraseSelection (gb 2005-10-09) cur.normalize(); - // FIXME audit setBuffer/updateBuffer calls - cur.buffer()->updateBuffer(); + cur.needBufferUpdate(); break; case LFUN_COPY: @@ -988,8 +986,7 @@ cur.posBackward(); cur.pushBackward(*cur.nextInset()); cur.niceInsert(save_selection); - // FIXME audit setBuffer/updateBuffer calls - cur.buffer()->updateBuffer(); + cur.needBufferUpdate(); #else if (currentMode() == Inset::TEXT_MODE) { cur.recordUndoSelection(); @@ -1203,8 +1200,7 @@ if (createInsetMath_fromDialogStr(cmd.argument(), ar)) { cur.recordUndoSelection(); cur.insert(ar); - // FIXME audit setBuffer/updateBuffer calls - cur.buffer()->updateBuffer(); + cur.needBufferUpdate(); } else cur.undispatched(); break; Index: src/DispatchResult.h =================================================================== --- src/DispatchResult.h (revision 33676) +++ src/DispatchResult.h (working copy) @@ -24,7 +24,7 @@ public: /// DispatchResult() : dispatched_(false), error_(false), - update_(Update::None) {} + update_(Update::None), need_buf_update_(false) {} /// DispatchResult(bool disp, Update::flags f) : dispatched_(disp), error_(false), update_(f) {} @@ -44,6 +44,10 @@ Update::flags update() const { return update_; } /// void update(Update::flags f) { update_ = f; } + /// + bool needBufferUpdate() const { return need_buf_update_; } + /// + void needBufferUpdate(bool u) { need_buf_update_ = u; } private: /// was the event fully dispatched? bool dispatched_; @@ -53,6 +57,8 @@ Update::flags update_; /// docstring message_; + /// + bool need_buf_update_; }; Index: src/TextMetrics.cpp =================================================================== --- src/TextMetrics.cpp (revision 33676) +++ src/TextMetrics.cpp (working copy) @@ -414,6 +414,7 @@ LYXERR(Debug::INFO, "MacroContext not initialised!" << " Going through the buffer again and hope" << " the context is better then."); + // FIXME audit updateBuffer calls bv_->buffer().updateBuffer(); parPos = text_->macrocontextPosition(); LASSERT(!parPos.empty(), /**/); Index: src/lyxfind.cpp =================================================================== --- src/lyxfind.cpp (revision 33676) +++ src/lyxfind.cpp (working copy) @@ -194,7 +194,6 @@ ++num; } - buf.updateBuffer(); bv->putSelectionAt(doc_iterator_begin(&buf), 0, false); if (num) buf.markDirty(); Index: src/Text.cpp =================================================================== --- src/Text.cpp (revision 33676) +++ src/Text.cpp (working copy) @@ -717,10 +717,9 @@ break; // the character couldn't be deleted physically due to change tracking } - cur.buffer()->updateBuffer(); - // A singlePar update is not enough in this case. cur.updateFlags(Update::Force); + cur.needBufferUpdate(); // This check is necessary. Otherwise the new empty paragraph will // be deleted automatically. And it is more friendly for the user! @@ -1294,7 +1293,7 @@ cur.clearSelection(); setCursorIntern(cur, begPit, begPos); cur.updateFlags(Update::Force); - cur.buffer()->updateBuffer(); + cur.needBufferUpdate(); } @@ -1445,7 +1444,7 @@ cur.recordUndo(ATOMIC_UNDO, prevcur.pit()); mergeParagraph(bufparams, cur.text()->paragraphs(), prevcur.pit()); - cur.buffer()->updateBuffer(); + cur.needBufferUpdate(); setCursorIntern(cur, prevcur.pit(), prevcur.pos()); cur.updateFlags(Update::Force); return true; @@ -1473,7 +1472,7 @@ cur.top().forwardPos(); if (was_inset) - cur.buffer()->updateBuffer(); + cur.needBufferUpdate(); else cur.checkBufferStructure(); needsUpdate = true; @@ -1549,7 +1548,7 @@ } if (needsUpdate) { - cur.buffer()->updateBuffer(); + cur.needBufferUpdate(); setCursorIntern(cur, prevcur.pit(), prevcur.pos()); } @@ -1589,7 +1588,7 @@ bool const was_inset = cur.paragraph().isInset(cur.pos()); cur.paragraph().eraseChar(cur.pos(), cur.buffer()->params().trackChanges); if (was_inset) - cur.buffer()->updateBuffer(); + cur.needBufferUpdate(); else cur.checkBufferStructure(); } @@ -1645,9 +1644,7 @@ cur.pit() = min(cur.lastpit(), spit); cur.pos() = min(cur.lastpos(), spos); } else - // this is the least that needs to be done (bug 6003) - // in the above case, pasteParagraphList handles this - cur.buffer()->updateBuffer(); + cur.needBufferUpdate(); // Ensure the current language is set correctly (bug 6292) cur.text()->setCursor(cur, cur.pit(), cur.pos()); Index: src/frontends/qt4/TocWidget.cpp =================================================================== --- src/frontends/qt4/TocWidget.cpp (revision 33683) +++ src/frontends/qt4/TocWidget.cpp (working copy) @@ -315,13 +315,7 @@ { current_type_ = typeCO->itemData(index).toString(); updateView(); - // In Qt 4.6.x, we can end up here programmatically, when the - // model is rebuilt. But the Buffer may not be ready for us to - // reset focus, start the cursor, etc. So we check to see if the - // combo box has focus. It will, if the user has changed the - // value. - if (typeCO->hasFocus()) - gui_view_.setFocus(); + gui_view_.setFocus(); } Index: src/frontends/qt4/GuiView.cpp =================================================================== --- src/frontends/qt4/GuiView.cpp (revision 33676) +++ src/frontends/qt4/GuiView.cpp (working copy) @@ -1757,7 +1757,10 @@ docstring str2; Buffer * buf = loadDocument(fullname); if (buf) { - buf->updateBuffer(); + // FIXME audit updateBuffer calls + // I don't think this is needed, since it will be done in setBuffer(). + // Someone please check. + // buf->updateBuffer(); setBuffer(buf); buf->errors("Parse"); str2 = bformat(_("Document %1$s opened."), disp_fn); @@ -1806,7 +1809,10 @@ Buffer * buf = lv->loadDocument(lyxfile); if (!buf) return false; - buf->updateBuffer(); + // FIXME audit updateBuffer calls + // I don't think this is needed, since it will be done in setBuffer(). + // Someone please check. + // buf->updateBuffer(); lv->setBuffer(buf); buf->errors("Parse"); } else { @@ -2669,7 +2675,11 @@ // This makes insertion of citations and references in the child work, // when the target is in the parent or another child document. child->setParent(&buffer); - child->masterBuffer()->updateBuffer(); + + // FIXME audit updateBuffer calls + // I don't think this is needed, since it will be called in + // setBuffer(). + // child->masterBuffer()->updateBuffer(); setBuffer(child); if (parsed) child->errors("Parse"); @@ -2717,7 +2727,13 @@ buf = theBufferList().getBuffer(s); else if (s.exists()) { buf = loadDocument(s); - buf->updateBuffer(); + if (!buf) + return false; + // FIXME audit updateBuffer calls + // I don't think this is needed. loadDocument() calls + // setBuffer(), which calls updateBuffer(). + // Someone please check. + // buf->updateBuffer(); buf->errors("Parse"); } else { message(bformat( Index: src/frontends/qt4/GuiApplication.cpp =================================================================== --- src/frontends/qt4/GuiApplication.cpp (revision 33676) +++ src/frontends/qt4/GuiApplication.cpp (working copy) @@ -1072,6 +1072,8 @@ BufferView * bv = current_view_->currentBufferView(); if (bv) { + if (dr.needBufferUpdate()) + bv->buffer().updateBuffer(); // BufferView::update() updates the ViewMetricsInfo and // also initializes the position cache for all insets in // (at least partially) visible top-level paragraphs. Index: src/CutAndPaste.cpp =================================================================== --- src/CutAndPaste.cpp (revision 33676) +++ src/CutAndPaste.cpp (working copy) @@ -242,6 +242,8 @@ InsetLabel * lab = labels[i]; docstring const oldname = lab->getParam("name"); lab->updateCommand(oldname, false); + // We need to update the buffer reference cache. + cur.needBufferUpdate(); docstring const newname = lab->getParam("name"); if (oldname == newname) continue; @@ -258,7 +260,7 @@ static_cast<InsetMathHull &>(*itt); // this is necessary to prevent an uninitialized // buffer when the RefInset is in a MathBox. - // FIXME audit setBuffer/updateBuffer calls + // FIXME audit setBuffer calls mi.setBuffer(const_cast<Buffer &>(buffer)); if (mi.asRefInset()->getTarget() == oldname) mi.asRefInset()->changeTarget(newname); @@ -273,6 +275,8 @@ InsetCommand & lab = static_cast<InsetCommand &>(*it); docstring const oldname = lab.getParam("name"); lab.updateCommand(oldname, false); + // We need to update the buffer reference cache. + cur.needBufferUpdate(); docstring const newname = lab.getParam("name"); if (oldname == newname) break; @@ -287,7 +291,7 @@ static_cast<InsetMathHull &>(*itt); // this is necessary to prevent an uninitialized // buffer when the RefInset is in a MathBox. - // FIXME audit setBuffer/updateBuffer calls + // FIXME audit setBuffer calls mi.setBuffer(const_cast<Buffer &>(buffer)); if (mi.asRefInset()->getTarget() == oldname) mi.asRefInset()->changeTarget(newname); @@ -299,6 +303,8 @@ case INCLUDE_CODE: { InsetInclude & inc = static_cast<InsetInclude &>(*it); inc.updateCommand(); + // We need to update the list of included files. + cur.needBufferUpdate(); break; } @@ -307,6 +313,8 @@ InsetCommand & bib = static_cast<InsetCommand &>(*it); docstring const oldkey = bib.getParam("key"); bib.updateCommand(oldkey, false); + // We need to update the buffer reference cache. + cur.needBufferUpdate(); docstring const newkey = bib.getParam("key"); if (oldkey == newkey) break; @@ -345,6 +353,8 @@ text, 0, 1, _("&Add"), _("&Don't Add")) != 0) break; lyx::dispatch(FuncRequest(LFUN_BRANCH_ADD, name)); + // We need to update the list of branches. + cur.needBufferUpdate(); break; } @@ -775,7 +785,7 @@ // need a valid cursor. (Lgb) cur.clearSelection(); - cur.buffer()->updateBuffer(); + cur.needBufferUpdate(); // tell tabular that a recent copy happened dirtyTabularStack(false); @@ -953,7 +963,7 @@ boost::tie(ppp, endpit) = pasteSelectionHelper(cur, parlist, docclass, errorList); - cur.buffer()->updateBuffer(); + cur.needBufferUpdate(); cur.clearSelection(); text->setCursor(cur, ppp.first, ppp.second); } Index: src/Text3.cpp =================================================================== --- src/Text3.cpp (revision 33676) +++ src/Text3.cpp (working copy) @@ -485,7 +485,7 @@ recUndo(cur, pit, pit + 1); cur.finishUndo(); pars_.swap(pit, pit + 1); - cur.buffer()->updateBuffer(); + cur.needBufferUpdate(); needsUpdate = true; ++cur.pit(); break; @@ -496,7 +496,7 @@ recUndo(cur, pit - 1, pit); cur.finishUndo(); pars_.swap(pit, pit - 1); - cur.buffer()->updateBuffer(); + cur.needBufferUpdate(); --cur.pit(); needsUpdate = true; break; @@ -522,7 +522,7 @@ par.params().startOfAppendix(start); // we can set the refreshing parameters now - cur.buffer()->updateBuffer(); + cur.needBufferUpdate(); break; } @@ -1577,7 +1577,7 @@ cur.posForward(); // Some insets are numbered, others are shown in the outline pane so // let's update the labels and the toc backend. - bv->buffer().updateBuffer(); + cur.needBufferUpdate(); break; case LFUN_TABULAR_INSERT: @@ -1631,7 +1631,7 @@ // date metrics. FuncRequest cmd_caption(LFUN_CAPTION_INSERT); doInsertInset(cur, cur.text(), cmd_caption, true, false); - bv->buffer().updateBuffer(); + cur.needBufferUpdate(); cur.updateFlags(Update::Force); // FIXME: When leaving the Float (or Wrap) inset we should // delete any empty paragraph left above or below the @@ -2072,26 +2072,26 @@ case LFUN_OUTLINE_UP: outline(OutlineUp, cur); setCursor(cur, cur.pit(), 0); - cur.buffer()->updateBuffer(); + cur.needBufferUpdate(); needsUpdate = true; break; case LFUN_OUTLINE_DOWN: outline(OutlineDown, cur); setCursor(cur, cur.pit(), 0); - cur.buffer()->updateBuffer(); + cur.needBufferUpdate(); needsUpdate = true; break; case LFUN_OUTLINE_IN: outline(OutlineIn, cur); - cur.buffer()->updateBuffer(); + cur.needBufferUpdate(); needsUpdate = true; break; case LFUN_OUTLINE_OUT: outline(OutlineOut, cur); - cur.buffer()->updateBuffer(); + cur.needBufferUpdate(); needsUpdate = true; break; Index: src/Cursor.cpp =================================================================== --- src/Cursor.cpp (revision 33676) +++ src/Cursor.cpp (working copy) @@ -388,6 +388,16 @@ beforeDispatchCursor_ = safe.beforeDispatchCursor_; } buffer()->undo().endUndoGroup(); + + if (needBufferUpdate()) { + // FIXME audit updateBuffer calls + // I think this could probably be removed, and we could let it + // happen back in GuiApplication::dispatch(), where it happens + // for the other dispatch() branches. But I'm a little worried + // about what happens if needBufferUpdate() doesn't get reset. + buffer()->updateBuffer(); + needBufferUpdate(false); + } } @@ -1267,6 +1277,7 @@ ++pos(); inset().setBuffer(bv_->buffer()); inset().initView(); + needBufferUpdate(); } @@ -1309,6 +1320,8 @@ text()->insertInset(*this, inset0); inset0->setBuffer(bv_->buffer()); inset0->initView(); + if (inset0->isLabeled()) + needBufferUpdate(); } } @@ -1350,7 +1363,7 @@ cap::eraseSelection(*this); cell().insert(pos(), ar); pos() += ar.size(); - // FIXME audit setBuffer/updateBuffer calls + // FIXME audit setBuffer calls inset().setBuffer(bv_->buffer()); } @@ -2110,6 +2123,18 @@ } +void Cursor::needBufferUpdate(bool u) +{ + disp_.needBufferUpdate(u); +} + + +bool Cursor::needBufferUpdate() const +{ + return disp_.needBufferUpdate(); +} + + void Cursor::noUpdate() { disp_.update(Update::None); Index: src/Undo.cpp =================================================================== --- src/Undo.cpp (revision 33676) +++ src/Undo.cpp (working copy) @@ -428,7 +428,6 @@ // Adapt the new material to current buffer. buffer_.setBuffersForInsets(); // FIXME This shouldn't be here. - buffer_.updateBuffer(); return true; } Index: src/Buffer.cpp =================================================================== --- src/Buffer.cpp (revision 33676) +++ src/Buffer.cpp (working copy) @@ -2006,6 +2006,7 @@ branch->setSelected(func.action == LFUN_BRANCH_ACTIVATE); dr.setError(false); dr.update(Update::Force); + dr.needBufferUpdate(); } break; } @@ -2040,8 +2041,10 @@ } } - if (success) + if (success) { dr.update(Update::Force); + dr.needBufferUpdate(); + } break; } @@ -2167,8 +2170,10 @@ Language const * newL = languages.getLanguage(argument); if (!newL || oldL == newL) break; - if (oldL->rightToLeft() == newL->rightToLeft() && !isMultiLingual()) + if (oldL->rightToLeft() == newL->rightToLeft() && !isMultiLingual()) { changeLanguage(oldL, newL); + dr.needBufferUpdate(); + } break; }