I think the remaining two big obstacles on the path to something that could be called 'a fairly clean core design' are inset locking ('IL') and the 'distributed' cursor ('DC').
The currently 'distributed' cursor (i.e. one 'slice' of a (virtual) global cursor per LyXText plus some optional MathCursor 'tail') alone prevents inset unification ('IU') and the locking comes with a lot of ugly code and leads to poretty hackish code in LyXText::dispatch and InsetText::dispatch. The missing IU means that I can't e.g. nest a proper InsetText within mathed which mean I either have to duplicate code or cannot implement some features. Definitely Not Nice. Unfortunately, both IL and DC are tied closely together with implementation spread over all the 'real core' files (text.C, insets/*). So I figured that's not worth trying a long shot. But I think we could have a small steps conversion along the following lines: 1. create some class GlobalCursor holding a stack of TextCursors [completely non-intrusive]. 2. create a GlobalCursor BufferView::buildCursor() function which build such a thing from the slices in BufferView's text and its relevant children using the locking inset information [still c n-i] 3. create a GlobalCursor BufferView::buildCursorXY() function which build such a thing from a given x,y position using the locking inset information [still c n-i] 4. create a Global::cursor dispatch after the model of MathCursor::dispatch [still c n-i] 5. use buildCursor().dispatch() instead of getLyXText()->dispatch() in the default branch of BufferView::Pimpl::dispatch() [That's the fun part but should not be that hard] 6. Simplify the structure of InsetText::localDispatch by removing most of the special RESULT handling (locking and unlocking is done in the GlobalCursor::dispatch). The result should be just a big switch. [7. Try to let InsetText::localDispatch use LyXText::dispatch in almost all cases] 8. Move logical ownership of TextCursor slices from LyXText to GlobalCursor. [lots of work but straightforward] 9. Move TextCursor slices data physically. We now have all the cursor related data and all the locking in GlobalCursor. 10. Remove inset locking. The stack already has all data, so an 'unlock' amounts to a 'pop' and most 'locks' to a 'push' and some won't be needed anymore. [11. Try to figure out a common base of data for GlobalCursor and MathCursor... 12. 13. ...] We can stop after any point without any penalty. Opinions? Andre'