Index: src/Cursor.h
===================================================================
--- src/Cursor.h	(Revision 18737)
+++ src/Cursor.h	(Arbeitskopie)
@@ -86,9 +86,9 @@
 	DocIterator selectionBegin() const;
 	/// access start of selection
 	DocIterator selectionEnd() const;
+	/// FIXME: document this
+	bool selHandle(bool selecting);
 	///
-	bool selHandle(bool selecting);
-	//
 	docstring selectionAsString(bool label) const;
 	///
 	docstring currentState();
@@ -194,6 +194,8 @@
 	
 	///
 	DispatchResult disp_;
+	///
+	DocIterator const & beforeDispatchCursor() { return beforeDispatchCursor_; }
 	
 private:
 	/**
@@ -225,8 +227,8 @@
 	/// y position before dispatch started
 	int beforeDispY_;
 	/// position before dispatch started
-	size_t beforeDispDepth_;
-		
+	DocIterator beforeDispatchCursor_;
+
 private:
 
 	//
@@ -296,6 +298,7 @@
 	bool isInside(Inset const *);
 
 	/// make sure cursor position is valid
+	/// FIXME: It does a subset of fixIfBroken. Maybe merge them?
 	void normalize();
 	/// mark current cursor trace for redraw
 	void touch();
@@ -328,7 +331,14 @@
 };
 
 
+/**
+ * Notifies all insets which appear in old, but not in cur. Make
+ * Sure that the cursor old is valid, i.e. als inset pointer
+ * point to valid insets! Use Cursor::fixIfBroken if necessary.
+ */
+bool notifyCursorLeaves(DocIterator const & old, Cursor & cur);
 
+
 } // namespace lyx
 
 #endif // LYXLCURSOR_H
Index: src/insets/Inset.h
===================================================================
--- src/insets/Inset.h	(Revision 18743)
+++ src/insets/Inset.h	(Arbeitskopie)
@@ -528,7 +528,6 @@
  *  It can be forward-declared and passed as a function argument without
  *  having to expose Inset.h.
  */
-
 class Inset_code {
 	Inset::Code val_;
 public:
Index: src/mathed/MathMacro.h
===================================================================
--- src/mathed/MathMacro.h	(Revision 18737)
+++ src/mathed/MathMacro.h	(Arbeitskopie)
@@ -48,6 +48,8 @@
 	/// target pos when we enter the inset from the right by pressing "Left"
 	bool idxLast(Cursor &) const;
 	///
+	bool idxUpDown(Cursor & cur, bool up) const;
+	///
 	virtual bool notifyCursorLeaves(Cursor &);
 	///
 	docstring name() const;
Index: src/mathed/MathMacro.cpp
===================================================================
--- src/mathed/MathMacro.cpp	(Revision 18737)
+++ src/mathed/MathMacro.cpp	(Arbeitskopie)
@@ -254,6 +254,22 @@
 }
 
 
+bool MathMacro::idxUpDown(Cursor & cur, bool up) const
+{
+	if (up) {
+		if (cur.idx() == 0)
+			return false;
+		--cur.idx();
+	} else {
+		if (cur.idx() >= nargs() - 1)
+			return false;
+		++cur.idx();
+	}
+	cur.pos() = cell(cur.idx()).x2pos(cur.x_target());
+	return true;
+}
+
+
 bool MathMacro::notifyCursorLeaves(Cursor & cur)
 {
 	cur.updateFlags(Update::Force);
Index: src/mathed/InsetMathNest.cpp
===================================================================
--- src/mathed/InsetMathNest.cpp	(Revision 18742)
+++ src/mathed/InsetMathNest.cpp	(Arbeitskopie)
@@ -546,36 +546,34 @@
 		}
 		break;
 
+	case LFUN_DOWN:
 	case LFUN_UP:
 		cur.updateFlags(Update::Decoration | Update::FitCursor);
-	case LFUN_UP_SELECT:
-		// FIXME Tried to use clearTargetX and macroModeClose, crashed on cur.up()
+	case LFUN_DOWN_SELECT: 
+	case LFUN_UP_SELECT: {
+		// close active macro
 		if (cur.inMacroMode()) {
-			// Make Helge happy
 			cur.macroModeClose();
 			break;
 		}
-		cur.selHandle(cmd.action == LFUN_UP_SELECT);
-		if (!cur.upDownInMath(true))
+		
+		// FIXME: what is this doing?
+		bool select = cmd.action == LFUN_DOWN_SELECT ||
+			cmd.action == LFUN_UP_SELECT;
+		cur.selHandle(select);
+		
+		// go up/down
+		bool up = cmd.action == LFUN_UP || cmd.action == LFUN_UP_SELECT;
+		bool successful = cur.upDownInMath(up);
+		if (successful) {
+			// notify left insets and give them chance to set update flags
+			lyx::notifyCursorLeaves(cur.beforeDispatchCursor(), cur);
+			cur.fixIfBroken();
+		}	else
 			cur.undispatched();
-		// fixes bug 1598. Please check!
-		cur.normalize();
 		break;
+	}
 
-	case LFUN_DOWN:
-		cur.updateFlags(Update::Decoration | Update::FitCursor);
-	case LFUN_DOWN_SELECT:
-		if (cur.inMacroMode()) {
-			cur.macroModeClose();
-			break;
-		}
-		cur.selHandle(cmd.action == LFUN_DOWN_SELECT);
-		if (!cur.upDownInMath(false))
-			cur.undispatched();
-		// fixes bug 1598. Please check!
-		cur.normalize();
-		break;
-
 	case LFUN_MOUSE_DOUBLE:
 	case LFUN_MOUSE_TRIPLE:
 	case LFUN_WORD_SELECT:
Index: src/Text3.cpp
===================================================================
--- src/Text3.cpp	(Revision 18737)
+++ src/Text3.cpp	(Arbeitskopie)
@@ -512,24 +512,27 @@
 		break;
 
 	case LFUN_UP:
-	case LFUN_UP_SELECT: {
-		//lyxerr << "handle LFUN_UP[SEL]:\n" << cur << endl;
-		needsUpdate |= cur.selHandle(cmd.action == LFUN_UP_SELECT);
-		bool const successful = cur.upDownInText(true, needsUpdate);
-		if (!successful)
-			cur.undispatched();
-		if (cur.selection())
-			saveSelection(cur);
-		break;
-	}
-
+	case LFUN_UP_SELECT:
 	case LFUN_DOWN:
 	case LFUN_DOWN_SELECT: {
 		//lyxerr << "handle LFUN_DOWN[SEL]:\n" << cur << endl;
-		needsUpdate |= cur.selHandle(cmd.action == LFUN_DOWN_SELECT);
-		bool const successful = cur.upDownInText(false, needsUpdate);
-		if (!successful)
+		bool select = cmd.action == LFUN_DOWN_SELECT || 
+			cmd.action == LFUN_UP_SELECT;
+		needsUpdate |= cur.selHandle(select);
+		
+		// move cursor up/down
+		bool up = cmd.action == LFUN_UP_SELECT || cmd.action == LFUN_UP;
+		bool const successful = cur.upDownInText(up, needsUpdate);
+		if (successful) {
+			// notify insets which were left and get their update flags 
+			cur.updateFlags(Update::None);
+			notifyCursorLeaves(cur.beforeDispatchCursor(), cur);
+			cur.fixIfBroken();
+			needsUpdate |= cur.disp_.update() & Update::Force;
+		} else
 			cur.undispatched();
+		
+		// save new selection
 		if (cur.selection())
 			saveSelection(cur);
 		break;
Index: src/Cursor.cpp
===================================================================
--- src/Cursor.cpp	(Revision 18737)
+++ src/Cursor.cpp	(Arbeitskopie)
@@ -301,8 +301,7 @@
 	
 	// store some values to be used inside of the handlers
 	getPos(beforeDispX_, beforeDispY_);
-	beforeDispDepth_ = depth();
-	
+	beforeDispatchCursor_ = *this;
 	for (; depth(); pop()) {
 		LYXERR(Debug::DEBUG) << "Cursor::dispatch: cmd: "
 			<< cmd0 << endl << *this << endl;
@@ -319,6 +318,7 @@
 		if (disp_.dispatched())
 			break;
 	}
+	
 	// it completely to get a 'bomb early' behaviour in case this
 	// object will be used again.
 	if (!disp_.dispatched()) {
@@ -326,6 +326,10 @@
 		operator=(safe);
 		disp_.update(Update::None);
 		disp_.dispatched(false);
+	} else {
+		// restore the previous one because nested Cursor::dispatch calls
+		// are possible which would change it
+		beforeDispatchCursor_ = safe.beforeDispatchCursor_;
 	}
 }
 
@@ -1183,7 +1187,8 @@
 	// if we cannot move up/down inside this inset anymore
 	if (x_target_ == -1)
 		setTargetX(xo);
-	else if (xo - textTargetOffset() != x_target() && depth() == beforeDispDepth_) {
+	else if (xo - textTargetOffset() != x_target() && 
+					 depth() == beforeDispatchCursor_.depth()) {
 		// In text mode inside the line (not left or right) possibly set a new target_x,
 		// but only if we are somewhere else than the previous target-offset.
 		
@@ -1483,4 +1488,24 @@
 }
 
 
+bool notifyCursorLeaves(DocIterator const & old, Cursor & cur)
+{
+	// find inset in common
+	size_type i;
+	for (i = 0; i < old.depth() && i < cur.depth(); ++i) {
+		if (&old.inset() != &cur.inset())
+			break;
+	}
+	
+	// notify everything on top of the common part in old cursor,
+	// but stop if the inset claims the cursor to be invalid now
+	for (;  i < old.depth(); ++i) {
+		if (old[i].inset().notifyCursorLeaves(cur))
+			return true;
+	}
+	
+	return false;
+}
+
+
 } // namespace lyx
