On Fri, 2002-08-02 at 19:38, Dom Lachowicz wrote:
> Does anyone have a copy of this patch? Sam's archives are down.

Attached.

Jesper

// FV_Cursor.cpp
/* Part of AbiWord.
 *
 * Author: Mikael Nordell ([EMAIL PROTECTED])
 * !!! Not yet released for public consumption!!!
 * !!! Don NOT CVS commit this                !!!
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  
 * 02111-1307, USA.
 */
 
#include "fv_Cursor.h"

#include "ut_assert.h"
#include "ut_timer.h"
#include "ut_debugmsg.h"
#include "gr_Graphics.h"
#include "fp_Run.h"
#include "fp_Line.h"
#include "fl_BlockLayout.h"
#include "fv_View.h"


// Since this is not-committed code, and this is only for
// development and debugging purposes, I felt it acceptable
// (read appropriate) to use the real, suppported by all our
// current compilers, datatype 'bool'. Note that this will be
// gone before commit.
const bool bDebugMsg_setCurrentDocPos	= false;
const bool bDebugMsg_setDocPos			= false;
const bool bDebugBeepOnBlink			= false;

//////////////////////////////////////////////////////////////////
//
// DOCUMENT POSITIONS
//
// PT_DocPosition is "byte offset" within the document.
//
// fl_BlockLayout::getPosition() returns DocPos of the line
// that this block belongs to (close enough explanation I think,
// but feel free to fill in/rewrite).
//
// FV_View::getPoint() returns the "insert point" in DocPos.
// This *will* probably go away, since FV_View should get this from
// FV_Cursor.
//
// fp_Run::getBlockOffset() returns offset for this run from its
// fl_BlockLayout in DocPos units.
//
// COORDINATE SYSTEMS - all in "display units/pixels".
// This was something that I had to research (since this is not mentioned
// anywhere else AFAIK) and it _might_ not be 100% correct.
// If so, please fix the comments.
//
// - fp_Run::getX()						fp_Line relative x.
// - fp_Line::getX()					fl_BlockLayout relative x.
// - fp_Run::findPointCoords()			fp_Container (fp_Column) relative.
// - fp_Line::getOffsets()				fp_Container (fp_Column) relative.
// - fl_BlockLayout::findPointCoords()	fp_Container (fp_Column) relative.
//
// - fp_Run::mapXYToPosition() wants run-relative x coord.
//
//

class FV_Cursor_impl
{
public:
	FV_Cursor_impl(FV_Cursor& owner, FV_View& view, FL_DocLayout& layout)
	:	m_layout(layout),
		m_caret(owner, view),
		m_docPos(0),
		m_nStickyX(0),
		m_xPoint(0),
		m_yPoint(0),
		m_nPointHeight(0),
		m_bBOL(UT_FALSE),
		m_bEOL(UT_FALSE)
	{ }

	void	updateInternal();
	// The 'bEOL' argument is needed since IP (Insert Position) might
	// be at BOL at line two while the _cursor_ is at EOL at line 1.
	// Think about it for a while, you'll get it.
	fp_Run*			setCurrentDocPos(	PT_DocPosition dp,
										UT_Bool bEOL = UT_FALSE);
	fp_Run*			getCurrentRun();
	PT_DocPosition	clampToDocument(PT_DocPosition dp);

	FL_DocLayout&	m_layout;		// The layout for the view
	FV_Caret		m_caret;		// The (possibly blinking) gfx caret
	PT_DocPosition	m_docPos;		// Absolute DocPos of IP/Caret
	UT_uint32		m_nStickyX;		// fp_Container (fp_Column) relative
	UT_sint32		m_xPoint;		// fp_Container (fp_Column) relative
	UT_sint32		m_yPoint;		// fp_Container (fp_Column) relative
	UT_sint32		m_nPointHeight;	// Height of char at IP
	UT_Bool			m_bBOL;			// self explanatory
	UT_Bool			m_bEOL;			// self explanatory
};


void FV_Cursor_impl::updateInternal()
{
	fp_Run* pRun = setCurrentDocPos(m_docPos, m_bEOL);
	if (!pRun || !pRun->getLine() || !pRun->getBlock())
	{
		m_bBOL = UT_FALSE;
		m_bEOL = UT_FALSE;
		m_nStickyX = 0;
	}
	else
	{
		if (!pRun->isFirstRunOnLine())
		{
			m_bBOL = UT_FALSE;
		}

		if (!pRun->isLastRunOnLine())
		{
			m_bEOL = UT_FALSE;
		}
	}
}

// returns the run it got set to
fp_Run* FV_Cursor_impl::setCurrentDocPos(PT_DocPosition docPos, UT_Bool bEOL)
{
	if (!docPos /* || docPos == m_docPos */)
	{
		return 0;
	}

	fl_BlockLayout* pBlock = m_layout.findBlockAtPosition(docPos);

	UT_ASSERT(pBlock);

	if (!pBlock)
	{
		// What to do?! Internal error!
		// Should we crash here, or is it nicer to let the user continue?
		return 0;
	}

	UT_sint32 nPosX;
	UT_sint32 nPosY;
	UT_sint32 nPtHeight;

	fp_Run* pRun =
		pBlock->findPointCoords(docPos		/* [in]  */,
								m_bEOL		/* [in]  */,
								nPosX		/* [out] */,
								nPosY		/* [out] */,
								nPtHeight	/* [out] */ );

	// If we don't get an fp_Run for a DocPos something is severely broken.
	// What to do?!
	UT_ASSERT(pRun);

	if (pRun)
	{
		if (bDebugMsg_setCurrentDocPos)
		{
			UT_DEBUGMSG(("%s(%d): setCurrentDocPos(%d), EOL=%d\n",
						__FILE__, __LINE__, docPos, (int)bEOL));
		}
		m_xPoint		= nPosX;
		m_yPoint		= nPosY;
		m_nPointHeight	= nPtHeight;
		m_docPos		= docPos;
	}

	return pRun;
}

fp_Run* FV_Cursor_impl::getCurrentRun()
{
	return setCurrentDocPos(m_docPos, m_bEOL);
}

PT_DocPosition FV_Cursor_impl::clampToDocument(PT_DocPosition dp)
{
	PT_DocPosition		dpMin;
	PT_DocPosition		dpMax;
	const PD_Document*	pDoc = m_layout.getDocument();
	
	UT_ASSERT(pDoc);

	if (!pDoc ||
		!pDoc->getBounds(UT_FALSE, dpMin) ||
		!pDoc->getBounds(UT_TRUE, dpMax))
	{
		// Internal error. What to do? Panic!
		// When in trouble, when in doubt, run in circles, scream and shout.
		return 0;
	}

	dp = MyMin(dp, dpMax);
	dp = MyMax(dp, dpMin);

	return dp;
}


//////////////////////////////////////////////////////////////////

FV_Cursor::FV_Cursor(FV_View& view, FL_DocLayout& layout)
:	m_pimpl(new FV_Cursor_impl(*this, view, layout))
{
}

FV_Cursor::~FV_Cursor()
{
	delete m_pimpl;
}

fp_Run* FV_Cursor::getCurrentRun()
{
	return m_pimpl->getCurrentRun();
}

fp_Line* FV_Cursor::getCurrentLine()
{
	fp_Run* pRun = getCurrentRun();
	return pRun ? pRun->getLine() : 0;
}

// fl_BlockLayout for current DocPos
fl_BlockLayout*	FV_Cursor::getCurrentBlockLayout()
{
	fp_Line* pLine = getCurrentLine();
	return pLine ? pLine->getBlock() : 0;
}

PT_DocPosition FV_Cursor::getDocPos() const
{
	return m_pimpl->m_docPos;
}

UT_sint32 FV_Cursor::getContainerRelativeX() const
{
	return m_pimpl->m_xPoint;
}

UT_sint32 FV_Cursor::getContainerRelativeY() const
{
	return m_pimpl->m_yPoint;
}

UT_sint32 FV_Cursor::getPointHeight() const
{
	return m_pimpl->m_nPointHeight;
}


void FV_Cursor::setDocPos(PT_DocPosition dp, UT_Bool bEOL)
{
	if (bDebugMsg_setDocPos)
	{
		UT_DEBUGMSG(("%s(%d): setDocPos(%d)\n", __FILE__, __LINE__, dp));
	}

	dp = m_pimpl->clampToDocument(dp);

	if (m_pimpl->m_docPos != dp)
	{
		disable();
		m_pimpl->m_docPos = dp;
		m_pimpl->setCurrentDocPos(dp, bEOL);
		enable();
	}
}

// painting
void FV_Cursor::disable()
{
	m_pimpl->m_caret.disable();
}

void FV_Cursor::enable()
{
	m_pimpl->m_caret.enable();
}

void FV_Cursor::setBlink(UT_Bool bBlink)
{
	m_pimpl->m_caret.setBlink(bBlink);
}


//////////////////////////////////////////////////////////////////
// movement commands

// I know, it's bad form to use macros. But since all of these are
// just forwarders, and I wanted some reporting...
#if 1
#define THIS_REPORTER_(fn)	UT_DEBUGMSG(("FV_Cursor::"#fn"\n"))
#define FV_CURSOR_DEF_FWD_FUN_(fn)			\
	void FV_Cursor::fn() {					\
		THIS_REPORTER_(fn);					\
		_do_movement(_ ## fn);	\
	}

FV_CURSOR_DEF_FWD_FUN_(up)
FV_CURSOR_DEF_FWD_FUN_(down)
FV_CURSOR_DEF_FWD_FUN_(left)
FV_CURSOR_DEF_FWD_FUN_(right)
FV_CURSOR_DEF_FWD_FUN_(pageUp)
FV_CURSOR_DEF_FWD_FUN_(pageDown)
FV_CURSOR_DEF_FWD_FUN_(home)
FV_CURSOR_DEF_FWD_FUN_(end)
FV_CURSOR_DEF_FWD_FUN_(wordLeft)
FV_CURSOR_DEF_FWD_FUN_(wordRight)

#undef FV_CURSOR_DEF_FWD_FUN_
#undef THIS_REPORTER_

#else

void FV_Cursor::up()		{	_do_movement(_up);			}
void FV_Cursor::down()		{	_do_movement(_down);		}
void FV_Cursor::left()		{	_do_movement(_left);		}
void FV_Cursor::right()		{	_do_movement(_right);		}
void FV_Cursor::pageUp()	{	_do_movement(_pageUp);		}
void FV_Cursor::pageDown()	{	_do_movement(_pageDown);	}
void FV_Cursor::home()		{	_do_movement(_home);		}
void FV_Cursor::end()		{	_do_movement(_end);			}
void FV_Cursor::wordLeft()	{	_do_movement(_wordLeft);	}
void FV_Cursor::wordRight()	{	_do_movement(_wordRight);	}

#endif

//////////////////////////////////////////////////////////////////
// accessors

UT_Bool FV_Cursor::isAtEOL() const
{
	return m_pimpl->m_bEOL;
}

UT_Bool FV_Cursor::isAtBOL() const
{
	return m_pimpl->m_bBOL;
}


//////////////////////////////////////////////////////////////////
// protected default handlers
// When we entered these, we KNOW that
// 1. We have a valid fp_Run pointer.
// 2. That run is on a fp_Line.

void FV_Cursor::_up()
{
	fp_Line* pLine = _getPrevLine();
	if (!pLine || pLine->isEmpty())
	{
		// beep?
		return;
	}

	// now we need to find X-offset in display/layout coords,
	// save that as stickyX, find closest x-pos from the
	// previous line, find DocPos for that x-pos, and set
	// our 'm_docPos' to the found value.

	if (!_getStickyX())
	{
		_setStickyX(getContainerRelativeX());
	}

	fp_Run* pNewRun = _getRunAtColumnOffset(*pLine, _getStickyX());
	UT_ASSERT(pNewRun);

	UT_Bool bBOL = UT_FALSE;	// dummy
	UT_Bool bEOL = UT_FALSE;	// dummy
	const UT_sint32 nRunRelativeX = _containerToLineX(*pLine, _getStickyX()) -
									pNewRun->getX();
	pNewRun->mapXYToPosition(	nRunRelativeX,
								0,					// unused arg
								m_pimpl->m_docPos,
								bBOL,
								bEOL);
}

void FV_Cursor::_down()
{
	fp_Line* pLine = _getNextLine();
	if (!pLine || pLine->isEmpty())
	{
		// beep?
		return;
	}

	// now we need to find X-offset in display/layout coords,
	// save that as stickyX, find closest x-pos from the
	// next line, find DocPos for that x-pos, and set
	// our 'm_docPos' to the found value.

	if (!_getStickyX())
	{
		_setStickyX(getContainerRelativeX());
	}

	fp_Run* pNewRun = _getRunAtColumnOffset(*pLine, _getStickyX());
	UT_ASSERT(pNewRun);

	UT_Bool bBOL = UT_FALSE;	// dummy
	UT_Bool bEOL = UT_FALSE;	// dummy
	const UT_sint32 nRunRelativeX = _containerToLineX(*pLine, _getStickyX()) -
									pNewRun->getX();
	pNewRun->mapXYToPosition(	nRunRelativeX,
								0,					// unused arg
								m_pimpl->m_docPos,
								bBOL,
								bEOL);
}

void FV_Cursor::_left()
{
	PT_DocPosition	dpMin;
	PD_Document*	pDoc = m_pimpl->m_layout.getDocument();
	UT_ASSERT(pDoc);
	if (!pDoc || !pDoc->getBounds(UT_FALSE, dpMin))
	{
		// Internal error. What to do?
		return;
	}

	UT_ASSERT(getDocPos() >= dpMin);

	if (getDocPos() == dpMin)
	{
		// Already at BOD
		return;
	}

	if (isAtBOL())
	{
		UT_ASSERT(getCurrentRun()->isFirstRunOnLine());

		fp_Line* pLine = _getPrevLine();
		if (!pLine)
		{
			// we're already at the first line.
			// beep?
			return;
		}
	}

	_setStickyX(0);
	setDocPos(getDocPos() - 1);
}

void FV_Cursor::_right()
{
	if (isAtEOL())
	{
		// EOL here means that the Caret is at EOL, but IP/DocPos
		// is really before the first character of the next line.
		UT_ASSERT(getCurrentRun()->isFirstRunOnLine());

		_setBOL();			// don't change docPos!
		return;
	}

	_setStickyX(0);
	setDocPos(getDocPos() + 1);
}

void FV_Cursor::_pageUp()
{
	UT_ASSERT(("C'mon, implement me!" == 0));
}

void FV_Cursor::_pageDown()
{
	UT_ASSERT(("C'mon, implement me!" == 0));
}

void FV_Cursor::_home()
{
#if 1
	if (isAtBOL())
#else
	// the following is the same as IsAtBOL()
	if (getCurrentRun()->isFirstRunOnLine() &&
		getCurrentRun()->getBlockOffset() +
		getCurrentBlockLayout()->getPosition() == m_pimpl->m_docPos)
#endif
	{
		return;
	}
	_setStickyX(0);
	setDocPos(getCurrentLine()->getFirstRun()->getBlockOffset() +
		getCurrentBlockLayout()->getPosition());
	_setBOL();
}

void FV_Cursor::_end()
{
	if (isAtEOL())
	{
		return;
	}
	_setStickyX(0);
	// Note that the usage of 'getCurrentRun()->getLength()' gets us to the
	// first DocPos _after_ that run. This is correct, and not an oversight.
	setDocPos(getCurrentLine()->getLastRun()->getBlockOffset() +
		getCurrentBlockLayout()->getPosition() +
		getCurrentRun()->getLength());
	_setEOL();
}

void FV_Cursor::_wordLeft()
{
	UT_ASSERT(("C'mon, implement me!" == 0));
	// This is hairy. You'll have to look at FV_View::_getDocPosFromPoint
	// to even get a basic grip on it.
	// Look into the switch FV_DOCPOS_BOW;
}

void FV_Cursor::_wordRight()
{
	UT_ASSERT(("C'mon, implement me!" == 0));
	// This is hairy. You'll have to look at FV_View::_getDocPosFromPoint
	// to even get a basic grip on it.
	// Look into the switch FV_DOCPOS_EOW;
}

// end of overridables
//////////////////////////////////////////////////////////////////

void FV_Cursor::_updateInternal()
{
	m_pimpl->updateInternal();
}

void FV_Cursor::_setEOL(UT_Bool bEOL)
{
	m_pimpl->m_bEOL = bEOL;
	if (bEOL)
	{
		_setStickyX(0);
		_setBOL(UT_FALSE);
	}
}

void FV_Cursor::_setBOL(UT_Bool bBOL)
{
	m_pimpl->m_bBOL = bBOL;
	if (bBOL)
	{
		_setStickyX(0);
		_setEOL(UT_FALSE);
	}
}

void FV_Cursor::_setStickyX(UT_sint32 x)
{
	m_pimpl->m_nStickyX = x;
}

UT_sint32 FV_Cursor::_getStickyX()
{
	return m_pimpl->m_nStickyX;
}

fp_Line* FV_Cursor::_getPrevLine()
{
	fl_BlockLayout* pBlockLayout = getCurrentBlockLayout();
	
	UT_ASSERT(pBlockLayout);
	
	return pBlockLayout ?
				pBlockLayout->findPrevLineInDocument(getCurrentLine()) :
				0;
}

fp_Line* FV_Cursor::_getNextLine()
{
	fl_BlockLayout* pBlockLayout = getCurrentBlockLayout();
	
	UT_ASSERT(pBlockLayout);
	
	return pBlockLayout ?
				pBlockLayout->findNextLineInDocument(getCurrentLine()) :
				0;
}


//////////////////////////////////////////////////////////////////
// private (implementation specific) methods

// helper function

UT_sint32 FV_Cursor::_containerToLineX(	const fp_Line& line,
										UT_sint32 containerX)
{
	UT_ASSERT(!line.isEmpty());

	fp_Container* pContainer = line.getContainer();
	UT_ASSERT(pContainer);

	if (!pContainer)
	{
		// WHAT THE...?!
		return 0;
	}

	// transpose the fp_Column relative x to fp_Line relative.
	UT_sint32 xOffs;
	UT_sint32 yOffs;
	pContainer->getOffsets(&line, xOffs, yOffs);
	return containerX - xOffs;
}

// 'x' is in fp_Container (fp_Column) relative coords.
// With legal input, this function returns either the correct run or, if
// that's not found, the last run. It returns 0 if no line is given.
fp_Run* FV_Cursor::_getRunAtColumnOffset(const fp_Line& line, UT_sint32 x)
{
	x = _containerToLineX(line, x);

	fp_Run* pRun = line.getFirstRun();
	fp_Run* pEnd = line.getLastRun();

	UT_ASSERT(pRun);
	UT_ASSERT(pEnd);

	// Current X might be on an indented line. stickyX is then
	// to the left of current run.
	if (x >= pRun->getX())
	{
		for (; pRun != pEnd; pRun = pRun->getNext())
		{
			UT_ASSERT(x >= pRun->getX());

			if (x >= pRun->getX() &&
				x < pRun->getX() + pRun->getWidth())
			{
				break;
			}
		}
	}

	return pRun;
}

UT_Bool	FV_Cursor::_isRelativeMovementAllowed()
{
	// Implementation detail: If we have a currentBlockLayout, we also
	// have a currentLine and a currentRun.
	// If implementation changes, theis must be reviewed.
	return	getCurrentBlockLayout() && !getCurrentLine()->isEmpty();
}

void FV_Cursor::_do_movement(void (FV_Cursor::*pmfn)())
{
	UT_ASSERT(pmfn);
	UT_ASSERT(getCurrentRun());

	if (_isRelativeMovementAllowed())
	{
		FV_CursorDisabler disabler(*this);

		(this->*pmfn)();

		// If this assert triggers it's a sign that we have
		// a SERIOUS bug!
		UT_ASSERT(getCurrentRun());

		_updateInternal();
	}
}


//////////////////////////////////////////////////////////////////
// implementation of class FV_Caret

FV_Caret::FV_Caret(FV_Cursor& cursor, FV_View& view)
:	m_cursor(cursor),
	m_view(view),
	m_pAutoCursorTimer(0),
	m_nDisableCount(1),
	m_bCursorBlink(UT_TRUE/*UT_FALSE*/),
	m_bCursorIsOn(UT_FALSE)
{
}

FV_Caret::~FV_Caret()
{
	delete m_pAutoCursorTimer;
}

void FV_Caret::enable()
{
	// If it isn't disabled by the time we get this call, something is wrong.
	UT_ASSERT(m_nDisableCount);

	UT_DEBUGMSG(("FV_Caret::enable() , count = %d\n", m_nDisableCount));

	if (--m_nDisableCount)
	{
		return;
	}

	// Caret should never be "on" when in disabled state. Let's assert so.
	UT_ASSERT(!m_bCursorIsOn);

	// Always start out with the caret in drawn state
	if (!m_bCursorIsOn)
	{
		_blink();
	}

	if (m_bCursorBlink)
	{
		if (!m_pAutoCursorTimer && !_createTimer())
		{
			// TODO How should we report this error?
			UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
			return;
		}

		m_pAutoCursorTimer->set(AUTO_DRAW_POINT);
		m_pAutoCursorTimer->start();
	}

	// Caret should always be "on" when leaving enable().
	UT_ASSERT(m_bCursorIsOn);	// post condition
}

void FV_Caret::disable()
{
	UT_DEBUGMSG(("FV_Caret::disable(), count = %d\n", m_nDisableCount));

	if (!m_nDisableCount++)
	{
		if (m_pAutoCursorTimer)
		{
			m_pAutoCursorTimer->stop();
		}

		if (m_bCursorIsOn)
		{
			_blink();
		}
	}

	// Caret should never be "on" when leaving enable().
	UT_ASSERT(!m_bCursorIsOn);	// post condition
}

void FV_Caret::setBlink(UT_Bool bBlink)
{
	m_bCursorBlink = bBlink;
}


// This is just to have an _instant_ report of what the caret class think
// is the carets state. A higher pitch beep (1500 Hz) means the class
// think it's drawing a caret, a lower pitch beep (1000 Hz) means it
// thinks it's erasing the caret.
// It will _probably_ go away before committing. But on the other hand,
// this code could be of use when adding another platform.
#ifdef UT_DEBUG

#ifdef _WIN32
extern "C" __declspec(dllimport) int __stdcall Beep(unsigned long dwFreq, unsigned long dwDuration);
#else	// _WIN32
void Beep(UT_uint32 freq, UT_uint32 duration)
{
	UT_UNUSED(freq);
	UT_UNUSED(duration);
}
#endif	// _WIN32
#endif	// UT_DEBUG


void FV_Caret::_blink()
{
	// toggle this as soon as possible, since timer blinks can possibly
	// interfere with calls from enable()/disable().
	// Since there's no synchronizing mechanism in XP, use a local
	// (auto/stack) variable.
	const UT_Bool bTurnCursorOn = !m_bCursorIsOn;

	fp_Line* pCurrLine = m_cursor.getCurrentLine();

	if (m_view.getWindowHeight() <= 0 ||
		!m_view.isSelectionEmpty() ||
		!pCurrLine ||
		!m_cursor.getPointHeight())
	{
		return;
	}

	GR_Graphics* pG = m_view.getGraphics();
	
	if (!pG)
	{
		return;
	}

	UT_sint32 xPageOffs;
	UT_sint32 yPageOffs;
	m_view.
		getPageScreenOffsets(	pCurrLine->getContainer()->getPage(),
								xPageOffs,
								yPageOffs);
	const UT_uint32 x		= m_cursor.getContainerRelativeX() + xPageOffs;
	const UT_uint32 yMin	= m_cursor.getContainerRelativeY() + yPageOffs;
	const UT_uint32 yMax	= yMin + m_cursor.getPointHeight();

	UT_DEBUGMSG(("caret at %d,%d (%d,%d), docpos: %d\n",
				x, yMin, x - xPageOffs, yMin - yPageOffs,
				m_cursor.getDocPos()));

#ifdef UT_DEBUG
// This is just to have an _instant_ report of what the caret class think
// is the carets state. A higher pitch beep (1500 Hz) means the class
// think it's drawing a caret, a lower pitch beep (1000 Hz) means it
// thinks it's erasing the caret.
// It will _probably_ go away before committing. But on the other hand,
// this code could be of use when adding another platform.
	if (bDebugBeepOnBlink)
	{
		Beep(bTurnCursorOn ? 1500 : 1000, 20);
	}
#endif

	UT_RGBColor clr(255,255,255);
	pG->setColor(clr);
	pG->xorLine(x-1, yMin, x-1, yMax);
	pG->xorLine(x  , yMin, x  , yMax);

	m_bCursorIsOn = !m_bCursorIsOn;
}


// This is really the only legal (C++ language-wise) function type
// we can use for callbacks as we do them now.
void FV_Caret_CursorTimerCallback(UT_Timer* pTimer)
{
	UT_ASSERT(pTimer);

	if (!pTimer)
	{
		// If we get no timer, things are really bad.
		return;
	}

	FV_Caret* pCaret = static_cast<FV_Caret*>(pTimer->getInstanceData());
	UT_ASSERT(pCaret);
	
	FV_Caret::callbackHelper::_callback(*pCaret);
}

UT_Bool FV_Caret::_createTimer()
{
	if (m_pAutoCursorTimer)
	{
		return UT_FALSE;
	}

	m_pAutoCursorTimer =
		UT_Timer::static_constructor(FV_Caret_CursorTimerCallback,
									this,
									m_view.getGraphics());

	return m_pAutoCursorTimer != 0;
}

// FV_Cursor.h
/* Part of the AbiWord.
 *
 * Author: Mikael Nordell ([EMAIL PROTECTED])
 * !!! Not yet released for public consumption!!!
 * !!! Don NOT CVS commit this                !!!
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  
 * 02111-1307, USA.
 */
 
#ifndef FV_CURSOR_H
#define FV_CURSOR_H

#include "ut_types.h"
#include "pt_types.h"

// fwd. decl.
class FV_View;
class fp_Line;
class fp_Run;
class UT_Timer;
class FL_DocLayout;
class fl_BlockLayout;
class FV_Caret;


class FV_Cursor
{
public:
	FV_Cursor(FV_View& view, FL_DocLayout& layout);
	~FV_Cursor();

	// the following accessors returns' are related to current DocPos.
	fp_Run*			getCurrentRun();		// returns 0 if no current run
	fp_Line*		getCurrentLine();		// returns 0 if no current line
	fl_BlockLayout*	getCurrentBlockLayout();// BlockLayout for current DocPos
	PT_DocPosition	getDocPos() const;
	UT_sint32		getContainerRelativeX() const;
	UT_sint32		getContainerRelativeY() const;
	UT_sint32		getPointHeight() const;

	// The bEOL argument is needed since a document position
	// can have IP at either EOL line 1 or BOL line 2.
	void			setDocPos(PT_DocPosition dp, UT_Bool bEOL = UT_FALSE);

	// should this really be in the public part of the interface?
	// It returns the display/layout x-position of IP in
	// fp_Container (fp_Column) relative coordinate system.
	UT_uint32		getDisplayX();

	// The user interface for FV_Caret.
	void disable();				// visibly no-op if cursor already is drawn
	void enable();				// visibly no-op if cursor already is erased
	void setBlink(UT_Bool bBlink);	// Tells it wether to "blink" or not.

	// these are the move commands for the cursor.
	void up();			// Implemented. Seems to work OK.
	void down();		// Implemented. Seems to work OK.
	void left();		// Implemented. Seems to work OK.
	void right();		// Implemented. Seems to work OK.
	void pageUp();		// Not implemented yet!
	void pageDown();	// Not implemented yet!
	void home();		// Implemented. Seems to work OK.
	void end();			// Implemented. Seems to work OK.
	void wordLeft();	// Not implemented yet!
	void wordRight();	// Not implemented yet!

	UT_Bool isAtEOL() const;
	UT_Bool isAtBOL() const;	// This might be dropped or put in protected.

protected:
	// These are the [relative] movement handlers for the cursor.
	// They are free for any derived classes to override and implement
	// other behaviour. No calling of baseclass' version is needed.
	virtual void _up();
	virtual void _down();
	virtual void _left();
	virtual void _right();
	virtual void _pageUp();
	virtual void _pageDown();
	virtual void _home();
	virtual void _end();
	virtual void _wordLeft();
	virtual void _wordRight();

	// interface for derived classes
	void		_updateInternal();
	void		_setEOL(UT_Bool bEOL = UT_TRUE);
	void		_setBOL(UT_Bool bBOL = UT_TRUE);
	void		_setStickyX(UT_sint32 x);	// 0 is non-sticky
	UT_sint32	_getStickyX();				// 0 is non-sticky
	fp_Line*	_getPrevLine();				// realtive current DocPos
	fp_Line*	_getNextLine();				// realtive current DocPos

	// Coordinate system conversion
	UT_sint32	_containerToLineX(const fp_Line& line, UT_sint32 containerX);

	// Returns closest match.
	//	x < first run on line returns first run on line.
	//	x > last  run on line returns last  run on line.
	fp_Run*		_getRunAtColumnOffset(const fp_Line& line, UT_sint32 x);

private:
	FV_Cursor(const FV_Cursor& rhs);		// no impl.
	void operator=(const FV_Cursor& rhs);	// no impl.

	UT_Bool		_isRelativeMovementAllowed();
	void		_do_movement(void (FV_Cursor::*pmfn)());

	// Since this class uses some hairy stuff inside, depends upon
	// more than a few other classes, and has changed rather frequently
	// during development, I decided to use the 'pimpl' idiom.
	// This might (will?) change before the release of this class.
	class FV_Cursor_impl* m_pimpl;
};



//////////////////////////////////////////////////////////////////
// The following class is used internally by FV_Cursor
// It should possibly (probably) be moved into its own file(s), but for
// now, during development, it's left here due to the close relationship
// with FV_Cursor.

class FV_Caret
{
public:
	FV_Caret(FV_Cursor& cursor, FV_View& view);
	~FV_Caret();

	void enable();
	void disable();

	UT_Bool isEnabled() const { return m_nDisableCount == 0; }

	void setBlink(UT_Bool bBlink);

	class callbackHelper
	{
		// This [inner] class is here for two reasons.
		// 1. To inhibit any function but the one in the
		//    friend declaration to make the caret blink.
		// 2. To display how friendship actually can strengthen
		//    encapsulation (compared to giving this free function
		//    friendship to the class FV_Caret)..
		friend void FV_Caret_CursorTimerCallback(UT_Timer* pTimer);
		static void _callback(FV_Caret& caret)
		{ if (caret.isEnabled()) { caret._blink(); } }
	};

private:
	friend callbackHelper;

	FV_Caret(const FV_Caret& rhs);			// no impl.
	void operator=(const FV_Caret& rhs);	// no impl.

	void	_blink();
	UT_Bool	_createTimer();

	FV_Cursor&			m_cursor;
	FV_View&			m_view;
	UT_Timer*			m_pAutoCursorTimer;
	// without interlocked inc/dec the best we can do is to use volatile...
	volatile UT_uint32	m_nDisableCount;
	UT_Bool				m_bCursorBlink;
	UT_Bool				m_bCursorIsOn;
};


class FV_CursorDisabler
{
public:
	FV_CursorDisabler(FV_Cursor& cursor)
	:	m_cursor(cursor)
	{
		// The reson for using 'cursor' rather than 'm_cursor' is that this
		// approach uses less memory (RAM) accesses.
		cursor.disable();
	}
	~FV_CursorDisabler() { m_cursor.enable(); }
private:
	FV_Cursor& m_cursor;
};


#endif	// FV_CURSOR_H

--- ap_Win32Frame.cpp   Thu May 18 11:01:12 2000
+++ \AbiWord\abi\src\wp\ap\win\ap_Win32Frame.cpp        Mon May 22 17:54:22 2000
@@ -173,6 +173,10 @@
                return UT_IE_IMPORTERROR;
        }
 
+       // TMN: This is both ugly and dangeruous, but since it's already done
+       // and apparently accepted I did my part trying to clean it up... <sigh>
+       AP_FrameData* pData = static_cast<AP_FrameData*>(m_pData);
+
        GR_Win32Graphics*                       pG                                     
         = 0;
        FL_DocLayout*                           pDocLayout                             
 = 0;
        AV_View*                                        pView                          
         = 0;
@@ -268,22 +272,26 @@
        ****************************************************************/
        
        // switch to new view, cleaning up previous settings
-       if (static_cast<AP_FrameData*>(m_pData)->m_pDocLayout)
+       if (pData->m_pDocLayout)
        {
-               pOldDoc = 
static_cast<AP_FrameData*>(m_pData)->m_pDocLayout->getDocument();
+               pOldDoc = pData->m_pDocLayout->getDocument();
        }
 
-       REPLACEP(static_cast<AP_FrameData*>(m_pData)->m_pG, pG);
-       REPLACEP(static_cast<AP_FrameData*>(m_pData)->m_pDocLayout, pDocLayout);
+       REPLACEP(pData->m_pG, pG);
+       REPLACEP(pData->m_pDocLayout, pDocLayout);
        if (pOldDoc != m_pDoc)
        {
                UNREFP(pOldDoc);
        }
 
        {
-               const AV_Focus prevFocus = m_pView ? m_pView->getFocus() : 
AV_FOCUS_NONE;
+               AV_View* pPrevView = m_pView;
+               const AV_Focus prevFocus = pPrevView ? pPrevView->getFocus() : 
+AV_FOCUS_NONE;
                REPLACEP(m_pView, pView);
-               m_pView->setFocus(prevFocus);
+               if (pPrevView)
+               {
+                       m_pView->focusChange(prevFocus);
+               }
        }
 
        REPLACEP(m_pScrollObj, pScrollObj);
@@ -300,14 +308,15 @@
        // views, like we do for all the other objects.  We also do not
        // allocate the TopRuler, LeftRuler here; that is done as the frame is
        // created.
-       if (static_cast<AP_FrameData*>(m_pData)->m_pTopRuler)
-               static_cast<AP_FrameData*>(m_pData)->m_pTopRuler->setView(pView, 
iZoom);
-       if (static_cast<AP_FrameData*>(m_pData)->m_pLeftRuler)
-               static_cast<AP_FrameData*>(m_pData)->m_pLeftRuler->setView(pView, 
iZoom);
-       static_cast<AP_FrameData*>(m_pData)->m_pStatusBar->setView(pView);
+       if (pData->m_pTopRuler)
+               pData->m_pTopRuler->setView(pView, iZoom);
+       if (pData->m_pLeftRuler)
+               pData->m_pLeftRuler->setView(pView, iZoom);
 
-       pView->setInsertMode(static_cast<AP_FrameData*>(m_pData)->m_bInsertMode);
-    ((FV_View *) m_pView)->setShowPara(((AP_FrameData*)m_pData)->m_bShowPara);
+       pData->m_pStatusBar->setView(pView);
+
+       pView->setInsertMode(pData->m_bInsertMode);
+    static_cast<FV_View*>(m_pView)->setShowPara(pData->m_bShowPara);
 
        RECT r;
        GetClientRect(hwnd, &r);
@@ -322,11 +331,12 @@
        if (point != 0)
                ((FV_View *) m_pView)->moveInsPtTo(point);
 
-       if (static_cast<AP_FrameData*>(m_pData)->m_pTopRuler)
-               static_cast<AP_FrameData*>(m_pData)->m_pTopRuler->draw(NULL);
-       if (static_cast<AP_FrameData*>(m_pData)->m_pLeftRuler)
-               static_cast<AP_FrameData*>(m_pData)->m_pLeftRuler->draw(NULL);
-       static_cast<AP_FrameData*>(m_pData)->m_pStatusBar->draw();
+       if (pData->m_pTopRuler)
+               pData->m_pTopRuler->draw(NULL);
+       if (pData->m_pLeftRuler)
+               pData->m_pLeftRuler->draw(NULL);
+
+       pData->m_pStatusBar->draw();
 
        return UT_OK;
 
@@ -341,7 +351,7 @@
        
        // change back to prior document
        UNREFP(m_pDoc);
-       m_pDoc = static_cast<AP_FrameData*>(m_pData)->m_pDocLayout->getDocument();
+       m_pDoc = pData->m_pDocLayout->getDocument();
 
        return UT_IE_ADDLISTENERERROR;
 }
--- fv_View.cpp Fri May 19 11:01:14 2000
+++ \AbiWord\abi\src\text\fmt\xp\fv_View.cpp    Mon May 22 17:50:02 2000
@@ -52,9 +52,18 @@
 #include "ap_TopRuler.h"
 #include "ap_LeftRuler.h"
 #include "ap_Prefs.h"
+#include "fv_Cursor.h"
 
 #include "sp_spell.h"
 
+// moved definition to header file fv_View.h
+//#define ABW_CURSOR_EXTERNAL_CLASS
+
+#ifndef ABW_CURSOR_EXTERNAL_CLASS
+#define        FV_CursorDisabler //
+#endif
+
+
 /****************************************************************/
 
 class _fmtPair
@@ -76,8 +85,12 @@
 
 
 FV_View::FV_View(XAP_App * pApp, void* pParentData, FL_DocLayout* pLayout)
-:      AV_View(pApp, pParentData),
-       m_bCursorIsOn(UT_FALSE)
+:      AV_View(pApp, pParentData)
+#ifdef ABW_CURSOR_EXTERNAL_CLASS
+       ,m_pCursor(new FV_Cursor(*this, *pLayout))
+#else
+       ,m_iPointHeight(0)
+#endif
 {
        m_pLayout = pLayout;
        m_pDoc = pLayout->getDocument();
@@ -85,16 +98,21 @@
 //     UT_ASSERT(m_pG->queryProperties(GR_Graphics::DGP_SCREEN));
 
        m_iInsPoint = 0;
-       m_iPointHeight = 0;
        m_bPointEOL = UT_FALSE;
        m_bSelection = UT_FALSE;
 //     m_bPointAP = UT_FALSE;
        m_pAutoScrollTimer      = NULL;
-       m_pAutoCursorTimer  = NULL;
-        m_pParentData = pParentData;
        
+#ifdef ABW_CURSOR_EXTERNAL_CLASS
+       UT_Bool bCursorBlink;
+       if (pApp->getPrefsValueBool(AP_PREF_KEY_CursorBlink, &bCursorBlink))
+       {
+               m_pCursor->setBlink(bCursorBlink);
+       }
+#else
        // initialize prefs cache
        pApp->getPrefsValueBool(AP_PREF_KEY_CursorBlink, &m_bCursorBlink);
+#endif
 
        // initialize prefs listener
        pApp->getPrefs()->addListener( _prefsListener, this );
@@ -130,8 +148,11 @@
        // remove prefs listener
        m_pApp->getPrefs()->removeListener( _prefsListener, this );
 
+#ifdef ABW_CURSOR_EXTERNAL_CLASS
+       delete m_pCursor;
+#endif
+
        DELETEP(m_pAutoScrollTimer);
-       DELETEP(m_pAutoCursorTimer);
        
        FREEP(_m_findNextString);
        
@@ -146,33 +167,20 @@
        switch(focus)
        {
        case AV_FOCUS_HERE:
+               _enableCursor();
                if (isSelectionEmpty())
                {
                        _fixInsertionPointCoords();
-                       _drawInsertionPoint();
                }
                else
                {
                        _drawSelection();
                }
-                m_pApp->rememberFocussedFrame( m_pParentData);
                break;
        case AV_FOCUS_NEARBY:
                if (isSelectionEmpty())
                {
                        _fixInsertionPointCoords();
-                       _drawInsertionPoint();
-               }
-               else
-               {
-                       _drawSelection();
-               }
-               break;
-       case AV_FOCUS_MODELESS:
-               if (isSelectionEmpty())
-               {
-                       _fixInsertionPointCoords();
-                       _drawInsertionPoint();
                }
                else
                {
@@ -180,11 +188,8 @@
                }
                break;
        case AV_FOCUS_NONE:
-               if (isSelectionEmpty())
-               {
-                       _eraseInsertionPoint();
-               }
-               else
+               _disableCursor();
+               if (!isSelectionEmpty())
                {
                        if (!m_bSelection)
                        {
@@ -475,6 +480,11 @@
        PT_DocPosition curPos = getPoint();
        UT_ASSERT(curPos != m_iSelectionAnchor);
        _setPoint(m_iSelectionAnchor);
+
+#ifdef ABW_CURSOR_EXTERNAL_CLASS
+       m_pCursor->setDocPos(m_iSelectionAnchor);
+#endif
+
        m_iSelectionAnchor = curPos;
 }
        
@@ -487,10 +497,10 @@
 
        UT_ASSERT(!isSelectionEmpty());
        
-       PT_DocPosition curPos = getPoint();
+       const PT_DocPosition curPos = getPoint();
        
        UT_ASSERT(curPos != m_iSelectionAnchor);
-       UT_Bool bForwardSelection = (m_iSelectionAnchor < curPos);
+       const UT_Bool bForwardSelection = (m_iSelectionAnchor < curPos);
        
        if (bForward != bForwardSelection)
        {
@@ -972,26 +982,36 @@
 void FV_View::moveInsPtTo(FV_DocPos dp)
 {
        if (!isSelectionEmpty())
+       {
                _clearSelection();
-       else
-               _eraseInsertionPoint();
+       }
        
        PT_DocPosition iPos = _getDocPos(dp);
 
        if (iPos != getPoint())
        {
-               UT_Bool bPointIsValid = (getPoint() >= _getDocPos(FV_DOCPOS_BOD));
+               const UT_Bool bPointIsValid = getPoint() >= _getDocPos(FV_DOCPOS_BOD);
                if (bPointIsValid)
                        _clearIfAtFmtMark(getPoint());
        }
 
        _setPoint(iPos, (dp == FV_DOCPOS_EOL));
 
-       if (!_ensureThatInsertionPointIsOnScreen())
+#ifdef ABW_CURSOR_EXTERNAL_CLASS
+       switch (dp)
        {
-               _fixInsertionPointCoords();
-               _drawInsertionPoint();
+               case FV_DOCPOS_BOL:
+                       m_pCursor->home();
+                       break;
+               case FV_DOCPOS_EOL:
+                       m_pCursor->end();
+                       break;
+               default:
+                       m_pCursor->setDocPos(iPos);
        }
+#endif // ABW_CURSOR_EXTERNAL_CLASS
+
+       _updateInsertionPoint();
 
        notifyListeners(AV_CHG_MOTION);
 }
@@ -1001,10 +1021,22 @@
        if (dp != getPoint())
                _clearIfAtFmtMark(getPoint());
 
-       _setPoint(dp, /* (dp == FV_DOCPOS_EOL) */ UT_FALSE);  // is this bool correct?
+       // is this bool correct?
+       // TMN: No I don't think so.
+       _setPoint(dp, /* (dp == FV_DOCPOS_EOL) */ UT_FALSE);
+
+#ifdef ABW_CURSOR_EXTERNAL_CLASS
+       m_pCursor->setDocPos(dp);
+#endif
        
        _fixInsertionPointCoords();
+
+#ifdef ABW_CURSOR_EXTERNAL_CLASS
+       cmdScroll(AV_SCROLLCMD_LINEDOWN, (UT_uint32) (m_yPoint + 
+m_pCursor->getPointHeight()/2 - m_iWindowHeight/2));
+#else
        cmdScroll(AV_SCROLLCMD_LINEDOWN, (UT_uint32) (m_yPoint + m_iPointHeight/2 - 
m_iWindowHeight/2));
+#endif
+
        cmdScroll(AV_SCROLLCMD_LINERIGHT, (UT_uint32) (m_xPoint - m_iWindowWidth/2));
        notifyListeners(AV_CHG_MOTION);
 }
@@ -1012,15 +1044,37 @@
 
 void FV_View::cmdCharMotion(UT_Bool bForward, UT_uint32 count)
 {
+       FV_CursorDisabler disabler(*m_pCursor);
+
        if (!isSelectionEmpty())
        {
+               --count;
                _moveToSelectionEnd(bForward);
                // Note: _moveToSelectionEnd() clears the selection
                //       but does not redraw the insertion point.
-               _drawInsertionPoint();
        }
 
-       PT_DocPosition iPoint = getPoint();
+       const PT_DocPosition iPoint = getPoint();
+
+#ifdef ABW_CURSOR_EXTERNAL_CLASS
+
+       if (iPoint != m_pCursor->getDocPos()) {
+               UT_DEBUGMSG(("%s(%d): iPoint != m_pCursor->getDocPos()\n", __FILE__, 
+__LINE__));
+       }
+
+       if (bForward)
+       {
+               for (UT_uint32 i=0; i<count; ++i)
+                       m_pCursor->right();
+       }
+       else
+       {
+               for (UT_uint32 i=0; i<count; ++i)
+                       m_pCursor->left();
+       }
+#endif // ABW_CURSOR_EXTERNAL_CLASS
+
+//     if (!_charMotion(bForward, count))
        if (!_charMotion(bForward, count))
        {
                _setPoint(iPoint);
@@ -1051,6 +1105,8 @@
 {
        UT_Bool bResult;
 
+       FV_CursorDisabler disabler(*m_pCursor);
+
        if (!isSelectionEmpty())
        {
                m_pDoc->beginUserAtomicGlob();
@@ -1060,8 +1116,6 @@
        } 
        else 
        {
-               _eraseInsertionPoint();
-
                UT_Bool bOverwrite = (!m_bInsertMode && !bForce);
 
                if (bOverwrite)
@@ -1081,27 +1135,21 @@
 
        _generalUpdate();
 
-       if (!_ensureThatInsertionPointIsOnScreen())
-       {
-               _fixInsertionPointCoords();
-               _drawInsertionPoint();
-       }
+       _updateInsertionPoint();
 
        return bResult;
 }
 
 void FV_View::insertSectionBreak(void)
 {
+       FV_CursorDisabler disabler(*m_pCursor);
+
        m_pDoc->beginUserAtomicGlob();
 
        if (!isSelectionEmpty())
        {
                _deleteSelection();
        }
-       else
-       {
-               _eraseInsertionPoint();
-       }
 
        // insert a new paragraph with the same attributes/properties
        // as the previous (or none if the first paragraph in the section).
@@ -1115,27 +1163,21 @@
 
        _generalUpdate();
 
-       if (!_ensureThatInsertionPointIsOnScreen())
-       {
-               _fixInsertionPointCoords();
-               _drawInsertionPoint();
-       }
+       _updateInsertionPoint();
 }
 
 void FV_View::insertParagraphBreak(void)
 {
        UT_Bool bDidGlob = UT_FALSE;
 
+       FV_CursorDisabler disabler(*m_pCursor);
+
        if (!isSelectionEmpty())
        {
                bDidGlob = UT_TRUE;
                m_pDoc->beginUserAtomicGlob();
                _deleteSelection();
        }
-       else
-       {
-               _eraseInsertionPoint();
-       }
 
        // insert a new paragraph with the same attributes/properties
        // as the previous (or none if the first paragraph in the section).
@@ -1147,11 +1189,7 @@
 
        _generalUpdate();
 
-       if (!_ensureThatInsertionPointIsOnScreen())
-       {
-               _fixInsertionPointCoords();
-               _drawInsertionPoint();
-       }
+       _updateInsertionPoint();
 }
 
 UT_Bool FV_View::setStyle(const XML_Char * style)
@@ -1190,11 +1228,6 @@
        if (bCharStyle)
        {
                // set character-level style
-               if (isSelectionEmpty())
-               {
-                       _eraseInsertionPoint();
-               }
-
                _clearIfAtFmtMark(getPoint());  // TODO is this correct ??
                _eraseSelection();
                 
@@ -1203,8 +1236,6 @@
        else
        {
                // set block-level style
-               _eraseInsertionPoint();
-
                _clearIfAtFmtMark(getPoint());  // TODO is this correct ??
 
                // NB: clear explicit props at both block and char levels
@@ -1216,7 +1247,6 @@
        if (isSelectionEmpty())
        {
                _fixInsertionPointCoords();
-               _drawInsertionPoint();
        }
        return bRet;
 }
@@ -1409,10 +1439,7 @@
 {
        UT_Bool bRet;
 
-       if (isSelectionEmpty())
-       {
-               _eraseInsertionPoint();
-       }
+       FV_CursorDisabler disabler(*m_pCursor);
 
        PT_DocPosition posStart = getPoint();
        PT_DocPosition posEnd = posStart;
@@ -1438,7 +1465,6 @@
        if (isSelectionEmpty())
        {
                _fixInsertionPointCoords();
-               _drawInsertionPoint();
        }
 
        return bRet;
@@ -1616,9 +1642,9 @@
 {
        UT_Bool bRet;
 
-       _clearIfAtFmtMark(getPoint());
+       FV_CursorDisabler disabler(*m_pCursor);
 
-       _eraseInsertionPoint();
+       _clearIfAtFmtMark(getPoint());
 
        PT_DocPosition posStart = getPoint();
        PT_DocPosition posEnd = posStart;
@@ -1642,7 +1668,6 @@
        if (isSelectionEmpty())
        {
                _fixInsertionPointCoords();
-               _drawInsertionPoint();
        }
 
        return bRet;
@@ -1908,7 +1933,6 @@
        _generalUpdate();
 
        _fixInsertionPointCoords();
-       _drawInsertionPoint();
 }
 
 /*
@@ -1929,15 +1953,7 @@
 
        UT_uint32 selLength = labs(m_iInsPoint - m_iSelectionAnchor);
 
-       PT_DocPosition low;
-       if (m_iInsPoint > m_iSelectionAnchor)
-       {
-               low = m_iSelectionAnchor;
-       }
-       else
-       {
-               low = m_iInsPoint;
-       }
+       const PT_DocPosition low = UT_MIN(m_iInsPoint, m_iSelectionAnchor);
        
        // get the current block the insertion point is in
        fl_BlockLayout * block = m_pLayout->findBlockAtPosition(low);
@@ -1973,17 +1989,15 @@
   const XML_Char ** props_in = NULL;
   const XML_Char * currentfont;
   
+       FV_CursorDisabler disabler(*m_pCursor);
+
        if (!isSelectionEmpty())
        {
                _deleteSelection();
 
                _generalUpdate();
 
-               if (!_ensureThatInsertionPointIsOnScreen())
-               {
-                       _fixInsertionPointCoords();
-                       _drawInsertionPoint();
-               }
+               _updateInsertionPoint();
        }
        else
        {
@@ -1999,7 +2013,6 @@
                currentfont = UT_getAttribute("font-family",props_in);
                properties[1] = currentfont;
 
-               _eraseInsertionPoint();
                UT_uint32 amt = count;
                UT_uint32 posCur = getPoint();
                UT_uint32 nposCur = getPoint();
@@ -2051,16 +2064,29 @@
                _generalUpdate();
                free(props_in);
 
-               if (!_ensureThatInsertionPointIsOnScreen())
-               {
-                       _fixInsertionPointCoords();
-                       _drawInsertionPoint();
-               }
+               _updateInsertionPoint();
        }
 }
 
 void FV_View::_moveInsPtNextPrevLine(UT_Bool bNext)
 {
+#ifdef ABW_CURSOR_EXTERNAL_CLASS
+       if (bNext)
+       {
+               m_pCursor->down();
+       }
+       else
+       {
+               m_pCursor->up();
+       }
+
+       _setPoint(m_pCursor->getDocPos(), m_pCursor->isAtEOL());
+
+       _updateInsertionPoint();
+
+#else  // ABW_CURSOR_EXTERNAL_CLASS
+//#endif       // ABW_CURSOR_EXTERNAL_CLASS
+
        UT_sint32 xPoint;
        UT_sint32 yPoint;
        UT_sint32 iPointHeight, iLineHeight;
@@ -2191,7 +2217,6 @@
        if (bNOOP)
        {
                // cannot move.  should we beep?
-               _drawInsertionPoint();
                return;
        }
 
@@ -2215,14 +2240,13 @@
 
        _setPoint(iNewPoint, bEOL);
 
-       if (!_ensureThatInsertionPointIsOnScreen())
-       {
-               _fixInsertionPointCoords();
-               _drawInsertionPoint();
-       }
+       _updateInsertionPoint();
 
        // this is the only place where we override changes to m_xPointSticky 
        m_xPointSticky = xOldSticky;
+
+#endif // ABW_CURSOR_EXTERNAL_CLASS
+
 }
 
 UT_Bool FV_View::_ensureThatInsertionPointIsOnScreen(void)
@@ -2243,12 +2267,22 @@
                cmdScroll(AV_SCROLLCMD_LINEUP, (UT_uint32) (-(m_yPoint)));
                bRet = UT_TRUE;
        }
+#ifdef ABW_CURSOR_EXTERNAL_CLASS
+       else if (((UT_uint32) (m_yPoint + m_pCursor->getPointHeight())) >= 
+((UT_uint32) m_iWindowHeight))
+       {
+               cmdScroll(AV_SCROLLCMD_LINEDOWN, (UT_uint32)(m_yPoint + 
+m_pCursor->getPointHeight() - m_iWindowHeight));
+               bRet = UT_TRUE;
+       }
+
+#else
        else if (((UT_uint32) (m_yPoint + m_iPointHeight)) >= ((UT_uint32) 
m_iWindowHeight))
        {
                cmdScroll(AV_SCROLLCMD_LINEDOWN, (UT_uint32)(m_yPoint + m_iPointHeight 
- m_iWindowHeight));
                bRet = UT_TRUE;
        }
 
+#endif
+
        /*
                TODO: we really ought to try to do better than this.  
        */
@@ -2297,6 +2331,20 @@
        PT_DocPosition iNewPoint = pPage->getFirstLastPos(UT_TRUE);
        _setPoint(iNewPoint, UT_FALSE);
 
+#ifdef ABW_CURSOR_EXTERNAL_CLASS
+       if (bNext)
+       {
+               m_pCursor->pageDown();
+       }
+       else
+       {
+               m_pCursor->pageUp();
+       }
+       // TMN: Remove when PgUp/PgDn is handled
+       m_pCursor->setDocPos(iNewPoint);
+
+#endif // ABW_CURSOR_EXTERNAL_CLASS
+
        // explicit vertical scroll to top of page
        UT_sint32 iPageOffset;
        getPageYOffset(pPage, iPageOffset);
@@ -2317,32 +2365,45 @@
        }
 
        // also allow implicit horizontal scroll, if needed
-       if (!_ensureThatInsertionPointIsOnScreen() && !bVScroll)
+       if (!bVScroll)
        {
-               _fixInsertionPointCoords();
-               _drawInsertionPoint();
+               _updateInsertionPoint();
        }
 }
 
 void FV_View::warpInsPtNextPrevPage(UT_Bool bNext)
 {
        if (!isSelectionEmpty())
+       {
                _moveToSelectionEnd(bNext);
-       else
-               _eraseInsertionPoint();
+       }
 
        _resetSelection();
        _clearIfAtFmtMark(getPoint());
        _moveInsPtNextPrevPage(bNext);
+
+#ifdef ABW_CURSOR_EXTERNAL_CLASS
+       if (bNext)
+       {
+               m_pCursor->pageDown();
+       }
+       else
+       {
+               m_pCursor->pageUp();
+       }
+#endif // ABW_CURSOR_EXTERNAL_CLASS
+
        notifyListeners(AV_CHG_MOTION);
 }
 
 void FV_View::warpInsPtNextPrevLine(UT_Bool bNext)
 {
+       FV_CursorDisabler disabler(*m_pCursor);
+
        if (!isSelectionEmpty())
+       {
                _moveToSelectionEnd(bNext);
-       else
-               _eraseInsertionPoint();
+       }
 
        _resetSelection();
        _clearIfAtFmtMark(getPoint());
@@ -2352,6 +2413,8 @@
 
 void FV_View::extSelNextPrevLine(UT_Bool bNext)
 {
+       FV_CursorDisabler disabler(*m_pCursor);
+
        if (isSelectionEmpty())
        {
                _setSelectionAnchor();
@@ -2360,7 +2423,6 @@
                if (isSelectionEmpty())
                {
                        _fixInsertionPointCoords();
-                       _drawInsertionPoint();
                }
                else
                {
@@ -2383,7 +2445,6 @@
                {
                        _resetSelection();
                        _fixInsertionPointCoords();
-                       _drawInsertionPoint();
                }
        }
 
@@ -2394,7 +2455,6 @@
 {
        if (isSelectionEmpty())
        {
-               _eraseInsertionPoint();
                _setSelectionAnchor();
                _charMotion(bForward, count);
        }
@@ -2405,6 +2465,11 @@
                if (_charMotion(bForward, count) == UT_FALSE)
                {
                        _setPoint(iOldPoint);
+
+#ifdef ABW_CURSOR_EXTERNAL_CLASS
+                       m_pCursor->setDocPos(iOldPoint);
+#endif
+
                        return;
                }
                
@@ -2423,7 +2488,6 @@
        {
                _resetSelection();
                _fixInsertionPointCoords();
-               _drawInsertionPoint();
        }
        else
        {
@@ -2439,14 +2503,7 @@
 
        _extSelToPos(iPos);
 
-       if (!_ensureThatInsertionPointIsOnScreen())
-       {
-               if (isSelectionEmpty())
-               {
-                       _fixInsertionPointCoords();
-                       _drawInsertionPoint();
-               }
-       }
+       _updateInsertionPoint();
 
        notifyListeners(AV_CHG_MOTION);
 }
@@ -2476,7 +2533,6 @@
                if (!pView->_ensureThatInsertionPointIsOnScreen())
                {
                        pView->_fixInsertionPointCoords();
-//                     pView->_drawInsertionPoint();
                }
        }
        else
@@ -2770,24 +2826,18 @@
        
 UT_Bool FV_View::findNext(const UT_UCSChar * find, UT_Bool matchCase, UT_Bool * 
bDoneEntireDocument)
 {
+       FV_CursorDisabler disabler(*m_pCursor);
+
         if (!isSelectionEmpty())
        {
                _clearSelection();
        }
-       else
-       {
-               _eraseInsertionPoint();
-       }
 
        UT_Bool bRes = _findNext(find, matchCase, bDoneEntireDocument);
 
        if (isSelectionEmpty())
        {
-               if (!_ensureThatInsertionPointIsOnScreen())
-               {
-                       _fixInsertionPointCoords();
-                       _drawInsertionPoint();
-               }
+               _updateInsertionPoint();
        }
        else
        {
@@ -2834,6 +2884,11 @@
                if (foundAt != -1)
                {
                        _setPoint(block->getPosition(UT_FALSE) + offset + foundAt);
+
+#ifdef ABW_CURSOR_EXTERNAL_CLASS
+                       m_pCursor->setDocPos(block->getPosition(UT_FALSE) + offset + 
+foundAt);
+#endif
+
                        _setSelectionAnchor();
                        _charMotion(UT_TRUE, UT_UCS_strlen(find));
 
@@ -2991,6 +3046,8 @@
 
 UT_Bool FV_View::findAgain()
 {
+       FV_CursorDisabler disabler(*m_pCursor);
+
        if (_m_findNextString && *_m_findNextString)
        {
                UT_Bool bRes = findNext(_m_findNextString, _m_matchCase, NULL);
@@ -3016,11 +3073,7 @@
        
        if (isSelectionEmpty())
        {
-               if (!_ensureThatInsertionPointIsOnScreen())
-               {
-                       _fixInsertionPointCoords();
-                       _drawInsertionPoint();
-               }
+               _updateInsertionPoint();
        }
        else
        {
@@ -3045,10 +3098,6 @@
                {
                        _deleteSelection();
                }
-               else
-               {
-                       _eraseInsertionPoint();
-               }
 
                // if we have a string with length, do an insert, else let it hang
                // from the delete above
@@ -3145,6 +3194,10 @@
          TODO WRONG! WRONG! WRONG! will get each view on the document.
        */
        notifyListeners(AV_CHG_TYPING | AV_CHG_FMTCHAR | AV_CHG_FMTBLOCK);
+
+#ifdef ABW_CURSOR_EXTERNAL_CLASS
+       m_pCursor->setDocPos(getPoint());
+#endif
 }
 
 UT_uint32 FV_View::findReplaceAll(const UT_UCSChar * find, const UT_UCSChar * replace,
@@ -3182,11 +3235,7 @@
        
        if (isSelectionEmpty())
        {
-               if (!_ensureThatInsertionPointIsOnScreen())
-               {
-                       _fixInsertionPointCoords();
-                       _drawInsertionPoint();
-               }
+               _updateInsertionPoint();
        }
        else
        {
@@ -3359,20 +3408,25 @@
        if (iNewPoint == iOldPoint)
                return;
 
+       FV_CursorDisabler disabler(*m_pCursor);
+
        if (isSelectionEmpty())
        {
-               _eraseInsertionPoint();
                _clearIfAtFmtMark(getPoint());
                _setSelectionAnchor();
        }
 
        _setPoint(iNewPoint);
+
+#ifdef ABW_CURSOR_EXTERNAL_CLASS
+       m_pCursor->setDocPos(iNewPoint);
+#endif
+
        _extSel(iOldPoint);
        
        if (isSelectionEmpty())
        {
                _resetSelection();
-               _drawInsertionPoint();
        }
 
        notifyListeners(AV_CHG_MOTION);
@@ -3387,10 +3441,12 @@
        UT_sint32 xClick, yClick;
        fp_Page* pPage = _getPageForXY(xPos, yPos, xClick, yClick);
 
+       // This disabler is probably not needed here. It won't harm
+       // [noticable/much] though.
+       FV_CursorDisabler disabler(*m_pCursor);
+
        if (!isSelectionEmpty())
                _clearSelection();
-       else
-               _eraseInsertionPoint();
        
        PT_DocPosition pos;
        UT_Bool bBOL = UT_FALSE;
@@ -3402,8 +3458,12 @@
                _clearIfAtFmtMark(getPoint());
        
        _setPoint(pos, bEOL);
+
+#ifdef ABW_CURSOR_EXTERNAL_CLASS
+       m_pCursor->setDocPos(pos, bEOL);
+#endif
+
        _fixInsertionPointCoords();
-       _drawInsertionPoint();
 
        notifyListeners(AV_CHG_MOTION);
 }
@@ -3426,7 +3486,7 @@
        }
 
        yoff = y - m_yScrollOffset;
-       xoff = fl_PAGEVIEW_MARGIN_Y - m_xScrollOffset;
+       xoff = fl_PAGEVIEW_MARGIN_X - m_xScrollOffset;
 }
 
 void FV_View::getPageYOffset(fp_Page* pThePage, UT_sint32& yoff)
@@ -3474,6 +3534,8 @@
 {
        UT_ASSERT(iPos1 < iPos2);
        
+       FV_CursorDisabler disabler(*m_pCursor);
+
        fp_Run* pRun1;
        fp_Run* pRun2;
        UT_sint32 xoff;
@@ -3676,100 +3738,32 @@
 
 void FV_View::_fixInsertionPointCoords()
 {
+#ifdef ABW_CURSOR_EXTERNAL_CLASS
+       UT_uint32 nDummyPointHeight;
+       _findPositionCoords(m_pCursor->getDocPos(), m_bPointEOL, m_xPoint, m_yPoint, 
+nDummyPointHeight, NULL, NULL);
+
+       // TMN: This call is possibly redundant
+       m_pCursor->setDocPos(getPoint(), m_bPointEOL);
+
+#else
        _findPositionCoords(getPoint(), m_bPointEOL, m_xPoint, m_yPoint, 
m_iPointHeight, NULL, NULL);
 
        // hang onto this for _moveInsPtNextPrevLine()
        m_xPointSticky = m_xPoint + m_xScrollOffset - fl_PAGEVIEW_MARGIN_X;
+
+#endif
 }
 
 void FV_View::_updateInsertionPoint()
 {
-       if (isSelectionEmpty())
-       {
-               _eraseInsertionPoint();
+       FV_CursorDisabler disabler(*m_pCursor);
 
                if (!_ensureThatInsertionPointIsOnScreen())
                {
                        _fixInsertionPointCoords();
-                       _drawInsertionPoint();
-               }
        }
 }
 
-void FV_View::_xorInsertionPoint()
-{
-       if (m_iPointHeight > 0)
-       {
-               UT_RGBColor clr(255,255,255);
-
-               m_pG->setColor(clr);
-               m_pG->xorLine(m_xPoint-1, m_yPoint, m_xPoint-1, m_yPoint + 
m_iPointHeight);
-               m_pG->xorLine(m_xPoint, m_yPoint, m_xPoint, m_yPoint + m_iPointHeight);
-       }
-}
-
-void FV_View::_eraseInsertionPoint()
-{
-       if (m_pAutoCursorTimer) 
-               m_pAutoCursorTimer->stop();
-       
-       if (!isSelectionEmpty() || !m_bCursorIsOn)
-       {
-               return;
-       }
-
-       _xorInsertionPoint();
-}
-
-void FV_View::_drawInsertionPoint()
-{
-       if(m_focus==AV_FOCUS_NONE)
-               return;
-       if (m_bCursorBlink && (m_focus==AV_FOCUS_HERE || m_focus==AV_FOCUS_MODELESS) )
-       {
-               if (m_pAutoCursorTimer == NULL) {
-                       m_pAutoCursorTimer = 
UT_Timer::static_constructor(_autoDrawPoint, this, m_pG);
-                       m_pAutoCursorTimer->set(AUTO_DRAW_POINT);
-               }
-
-               m_pAutoCursorTimer->start();
-       }
-
-       m_bCursorIsOn = UT_TRUE;
-
-       if (m_iWindowHeight <= 0)
-       {
-               return;
-       }
-       
-       if (!isSelectionEmpty())
-       {
-               return;
-       }
-       
-       _xorInsertionPoint();
-}
-
-void FV_View::_autoDrawPoint(UT_Timer * pTimer)
-{
-       UT_ASSERT(pTimer);
-
-       FV_View * pView = (FV_View *) pTimer->getInstanceData();
-       UT_ASSERT(pView);
-
-       if (pView->m_iWindowHeight <= 0)
-       {
-               return;
-       }
-       
-       if (!pView->isSelectionEmpty())
-       {
-               return;
-       }
-       pView->_xorInsertionPoint();
-       pView->m_bCursorIsOn = !pView->m_bCursorIsOn;
-}
-
 void FV_View::setXScrollOffset(UT_sint32 v)
 {
        UT_sint32 dx = v - m_xScrollOffset;
@@ -3842,6 +3836,8 @@
 {
        xxx_UT_DEBUGMSG(("FV_View::draw_1: [page %ld]\n",page));
 
+       FV_CursorDisabler disabler(*m_pCursor);
+
        da->pG = m_pG;
        fp_Page* pPage = m_pLayout->getNthPage(page);
        if (pPage)
@@ -3877,6 +3873,8 @@
                                 x,y,width,height,bClip,
                                 m_yScrollOffset,m_iWindowHeight));
 
+       FV_CursorDisabler disabler(*m_pCursor);
+
        // this can happen when the frame size is decreased and
        // only the toolbars show...
        if ((m_iWindowWidth <= 0) || (m_iWindowHeight <= 0))
@@ -4068,7 +4066,6 @@
        if (!bDirtyRunsOnly)
        {
                _fixInsertionPointCoords();
-               _drawInsertionPoint();
        }
 
        if (bClip)
@@ -4099,7 +4096,7 @@
        UT_Bool bVertical = UT_FALSE;
        UT_Bool bHorizontal = UT_FALSE;
        
-       _eraseInsertionPoint(); 
+       FV_CursorDisabler disabler(*m_pCursor);
 
        docHeight = m_pLayout->getHeight();
        
@@ -4170,12 +4167,9 @@
                yoff = 0;
        }
 
-       UT_Bool bRedrawPoint = UT_TRUE;
-       
        if (bVertical && (yoff != m_yScrollOffset))
        {
                sendVerticalScrollEvent(yoff);
-               bRedrawPoint = UT_FALSE;
        }
 
        if (xoff < 0)
@@ -4186,12 +4180,6 @@
        if (bHorizontal && (xoff != m_xScrollOffset))
        {
                sendHorizontalScrollEvent(xoff);
-               bRedrawPoint = UT_FALSE;
-       }
-
-       if (bRedrawPoint)
-       {
-               _drawInsertionPoint();
        }
 }
 
@@ -4217,9 +4205,9 @@
 
 void FV_View::cmdSelect(UT_sint32 xPos, UT_sint32 yPos, FV_DocPos dpBeg, FV_DocPos 
dpEnd)
 {
-       warpInsPtToXY(xPos, yPos);
+       FV_CursorDisabler disabler(*m_pCursor);
 
-       _eraseInsertionPoint();
+       warpInsPtToXY(xPos, yPos);
 
        PT_DocPosition iPosLeft = _getDocPos(dpBeg, UT_FALSE);
        PT_DocPosition iPosRight = _getDocPos(dpEnd, UT_FALSE);
@@ -4235,10 +4223,13 @@
        
        _setPoint(iPosRight);
 
+#ifdef ABW_CURSOR_EXTERNAL_CLASS
+       m_pCursor->setDocPos(iPosRight);
+#endif
+
        if (iPosLeft == iPosRight)
        {
                _fixInsertionPointCoords();
-               _drawInsertionPoint();
                return;
        }
 
@@ -4256,6 +4247,10 @@
        m_iInsPoint = pt;
        m_bPointEOL = bEOL;
 
+// TMN: I don't know if the following call will be needed or not.
+// Just in case someone wants to test, I leave it here for now.
+//     m_pCursor->setDocPos(pt, bEOL);
+
        _checkPendingWord();
 }
 
@@ -4279,6 +4274,21 @@
        }
 }
 
+void FV_View::_disableCursor()
+{
+#ifdef ABW_CURSOR_EXTERNAL_CLASS
+       m_pCursor->disable();
+#endif
+}
+
+void FV_View::_enableCursor()
+{
+#ifdef ABW_CURSOR_EXTERNAL_CLASS
+       m_pCursor->enable();
+#endif
+}
+
+
 UT_uint32 FV_View::_getDataCount(UT_uint32 pt1, UT_uint32 pt2)
 {
        UT_ASSERT(pt2>=pt1);
@@ -4359,10 +4369,12 @@
 
 void FV_View::cmdUndo(UT_uint32 count)
 {
+       FV_CursorDisabler disabler(*m_pCursor);
+
        if (!isSelectionEmpty())
+       {
                _clearSelection();
-       else
-               _eraseInsertionPoint();
+       }
 
        m_pDoc->undoCmd(count);
 
@@ -4370,54 +4382,48 @@
        
        notifyListeners(AV_CHG_DIRTY);
        
-       if (isSelectionEmpty())
-       {
-               if (!_ensureThatInsertionPointIsOnScreen())
-               {
-                       _fixInsertionPointCoords();
-                       _drawInsertionPoint();
-               }
-       }
+       _updateInsertionPoint();
 }
 
 void FV_View::cmdRedo(UT_uint32 count)
 {
+       FV_CursorDisabler disabler(*m_pCursor);
+
        if (!isSelectionEmpty())
+       {
                _clearSelection();
-       else
-               _eraseInsertionPoint();
+       }
 
        m_pDoc->redoCmd(count);
 
        _generalUpdate();
        
-       if (isSelectionEmpty())
-       {
-               if (!_ensureThatInsertionPointIsOnScreen())
-               {
-                       _fixInsertionPointCoords();
-                       _drawInsertionPoint();
-               }
-       }
+       _updateInsertionPoint();
 }
 
 UT_Error FV_View::cmdSave(void)
 {
-  UT_Error tmpVar;
-  tmpVar = m_pDoc->save();
-  if (!tmpVar)
+  const UT_Error saveError = m_pDoc->save();
+
+  if (!saveError)
+  {
       notifyListeners(AV_CHG_SAVE);
-  return tmpVar;
+  }
+
+  return saveError;
 }
 
 
 UT_Error FV_View::cmdSaveAs(const char * szFilename, int ieft)
 {
-  UT_Error tmpVar;
-  tmpVar = m_pDoc->saveAs(szFilename, ieft);
-  if (!tmpVar)
+  const UT_Error saveError = m_pDoc->saveAs(szFilename, ieft);
+
+  if (!saveError)
+  {
       notifyListeners(AV_CHG_SAVE);
-  return tmpVar;
+  }
+
+  return saveError;
 }
 
 
@@ -4435,7 +4441,6 @@
        _generalUpdate();
        
        _fixInsertionPointCoords();
-       _drawInsertionPoint();
 }
 
 void FV_View::getDocumentRangeOfCurrentSelection(PD_DocumentRange * pdr)
@@ -4489,6 +4494,8 @@
        // be a selection to paste when get there.  this is sort of
        // back door hack and should probably be re-thought.
        
+       // TMN: I agree. X11 code have NO business in XP code.
+
        // set UAG markers around everything that the actual paste does
        // so that undo/redo will treat it as one step.
        
@@ -4505,10 +4512,12 @@
 {
        // internal portion of paste operation.
        
+       FV_CursorDisabler disabler(*m_pCursor);
+
        if (!isSelectionEmpty())
+       {
                _deleteSelection();
-       else
-               _eraseInsertionPoint();
+       }
 
        _clearIfAtFmtMark(getPoint());
        PD_DocumentRange dr(m_pDoc,getPoint(),getPoint());
@@ -4516,18 +4525,15 @@
 
        _generalUpdate();
        
-       if (!_ensureThatInsertionPointIsOnScreen())
-       {
-               _fixInsertionPointCoords();
-               _drawInsertionPoint();
-       }
+       _updateInsertionPoint();
 }
 
 UT_Bool FV_View::setSectionFormat(const XML_Char * properties[])
 {
        UT_Bool bRet;
 
-       _eraseInsertionPoint();
+       FV_CursorDisabler disabler(*m_pCursor);
+
        _clearIfAtFmtMark(getPoint());
 
        PT_DocPosition posStart = getPoint();
@@ -4548,7 +4554,6 @@
        if (isSelectionEmpty())
        {
                _fixInsertionPointCoords();
-               _drawInsertionPoint();
        }
 
        return bRet;
@@ -4686,6 +4691,8 @@
                NULL, NULL
        };
 
+       FV_CursorDisabler disabler(*m_pCursor);
+
        if (!isSelectionEmpty())
        {
                m_pDoc->beginUserAtomicGlob();
@@ -4695,17 +4702,12 @@
        }
        else
        {
-               _eraseInsertionPoint();
                bResult = m_pDoc->insertObject(getPoint(), PTO_Field, attributes, 
NULL);
        }
 
        _generalUpdate();
 
-       if (!_ensureThatInsertionPointIsOnScreen())
-       {
-               _fixInsertionPointCoords();
-               _drawInsertionPoint();
-       }
+       _updateInsertionPoint();
 
        return bResult;
 }
@@ -4729,10 +4731,6 @@
                m_pDoc->beginUserAtomicGlob();
                _deleteSelection();
        }
-       else
-       {
-               _eraseInsertionPoint();
-       }
 
        /*
          First, find a unique name for the data item.
@@ -4756,11 +4754,7 @@
 
        _generalUpdate();
 
-       if (!_ensureThatInsertionPointIsOnScreen())
-       {
-               _fixInsertionPointCoords();
-               _drawInsertionPoint();
-       }
+       _updateInsertionPoint();
 
        return errorCode;
 }
@@ -4889,9 +4883,19 @@
        // TODO selection region.
        
        if (pxPos)
+       {
                *pxPos = m_xPoint;
+       }
+
        if (pyPos)
+       {
+#ifdef ABW_CURSOR_EXTERNAL_CLASS
+               *pyPos = m_yPoint + m_pCursor->getPointHeight();
+#else
                *pyPos = m_yPoint + m_iPointHeight;
+#endif
+       }
+
        return emc;
 }
 
@@ -5096,6 +5100,15 @@
        FV_View *pView = (FV_View *)data;
        UT_Bool b;
        UT_ASSERT(data && pPrefs);
+
+#ifdef ABW_CURSOR_EXTERNAL_CLASS
+       UT_Bool bCursorBlink;
+       if (pPrefs->getPrefsValueBool(AP_PREF_KEY_CursorBlink, &b))
+       {
+               pView->m_pCursor->setBlink(b);
+               pView->_updateInsertionPoint();
+       }
+#else
        if ( pPrefs->getPrefsValueBool(AP_PREF_KEY_CursorBlink, &b) && b != 
pView->m_bCursorBlink )
        {
                UT_DEBUGMSG(("FV_View::_prefsListener m_bCursorBlink=%s 
m_bCursorIsOn=%s\n",
@@ -5114,6 +5127,7 @@
 
                pView->_updateInsertionPoint();
        }
+#endif
 }
 
 /******************************************************
@@ -5222,4 +5236,4 @@
         m_bShowPara = bShowPara;
         draw();
     }
-};
+}
--- fv_View.h   Thu May 18 11:01:12 2000
+++ \AbiWord\abi\src\text\fmt\xp\fv_View.h      Mon May 22 17:15:26 2000
@@ -31,6 +31,9 @@
 // number of milliseconds between cursor blinks
 const int AUTO_DRAW_POINT = 600;
 
+// Define if we're using the FV_Cursor class
+#define ABW_CURSOR_EXTERNAL_CLASS
+
 class FL_DocLayout;
 class fl_DocListener;
 class fl_BlockLayout;
@@ -46,9 +49,10 @@
 class XAP_App;
 class XAP_Prefs;
 class UT_AlphaHashTable;
+class FV_Cursor;
 
 
-typedef enum _FVDocPos
+enum FV_DocPos
 {
        FV_DOCPOS_BOB, FV_DOCPOS_EOB,   // block
        FV_DOCPOS_BOD, FV_DOCPOS_EOD,   // document
@@ -56,13 +60,13 @@
        FV_DOCPOS_BOL, FV_DOCPOS_EOL,   // line
        FV_DOCPOS_BOS, FV_DOCPOS_EOS,   // sentence
        FV_DOCPOS_BOW, FV_DOCPOS_EOW_MOVE, FV_DOCPOS_EOW_SELECT // word
-} FV_DocPos;
+};
 
-typedef enum _FVJumpTarget
+enum FV_JumpTarget
 {
        FV_JUMPTARGET_PAGE,                             // beginning of page
        FV_JUMPTARGET_LINE                              // beginning of line
-} FV_JumpTarget;
+};
                
 struct fv_ChangeState
 {
@@ -97,7 +101,7 @@
        ~FV_View();
 
        inline GR_Graphics*             getGraphics(void) const { return m_pG; }
-       inline UT_uint32                getPoint(void) const { return m_iInsPoint; }
+       inline PT_DocPosition   getPoint(void) const { return m_iInsPoint; }
        inline UT_uint32                getSelectionAnchor(void) const { return 
m_bSelection? m_iSelectionAnchor : m_iInsPoint; }
 
        virtual void focusChange(AV_Focus focus);
@@ -273,11 +277,8 @@
        void                            _setSelectionAnchor(void);
        void                            _deleteSelection(void);
        UT_Bool                         _insertFormatPair(const XML_Char * szName, 
const XML_Char * properties[]);
-       void                            _eraseInsertionPoint();
-       void                            _drawInsertionPoint();
        void                            _updateInsertionPoint();
        void                            _fixInsertionPointCoords();
-       void                            _xorInsertionPoint();
        void                            _drawSelection();
        void                            _swapSelectionOrientation(void);
        void                            _extSel(UT_uint32 iOldPoint);
@@ -287,7 +288,6 @@
        UT_UCSChar *            _lookupSuggestion(fl_BlockLayout* pBL, fl_PartOfBlock* 
pPOB, UT_uint32 ndx);
 
        static void                     _autoScroll(UT_Timer * pTimer);
-       static void                     _autoDrawPoint(UT_Timer * pTimer);
 
        // localize handling of insertion point logic
        void                            _setPoint(UT_uint32 pt, UT_Bool bEOL = 
UT_FALSE);
@@ -298,14 +298,20 @@
 
        void                            _checkPendingWord(void);
 
+       // fl_BlockLayout seems to need these. Check if it can be removed!
+       void                            _disableCursor();
+       void                            _enableCursor();
 
 
        PT_DocPosition          m_iInsPoint;
        UT_sint32                       m_xPoint;
        UT_sint32                       m_yPoint;
+
+#ifndef ABW_CURSOR_EXTERNAL_CLASS
        UT_uint32                       m_iPointHeight;
 
        UT_sint32                       m_xPointSticky;         // used only for 
_moveInsPtNextPrevLine() 
+#endif
 
        UT_Bool                         m_bPointVisible;
        UT_Bool                         m_bPointEOL;
@@ -313,7 +319,6 @@
        FL_DocLayout*           m_pLayout;
        PD_Document*            m_pDoc;
        GR_Graphics*            m_pG;
-        void *                  m_pParentData;
 
     PT_DocPosition             m_iSelectionAnchor;
     PT_DocPosition             m_iSelectionLeftAnchor;
@@ -325,8 +330,6 @@
        UT_sint32                       m_xLastMouse;
        UT_sint32                       m_yLastMouse;
 
-       UT_Timer *                      m_pAutoCursorTimer;
-       UT_Bool                         m_bCursorIsOn;
        UT_Bool                         m_bCursorBlink;
        
        fv_ChangeState          m_chg;
@@ -355,7 +358,16 @@
        // prefs listener - to change cursor blink on/off (and possibly others)
        static void _prefsListener( XAP_App *, XAP_Prefs *, UT_AlphaHashTable *, void 
*);
 
+private:
+       // Not that FV_View can be copied, since its baseclass is non-copyable,
+       // but this puts this "documentation" closer to the user.
+       FV_View(const FV_View&);                // no impl.
+       void operator=(const FV_View&); // no impl.
+
     UT_Bool             m_bShowPara;
+
+       // By ptr to minimize compile-time dependencies
+       FV_Cursor*      m_pCursor;
 };
 
 #endif /* FV_VIEW_H */
--- fl_BlockLayout.cpp  Thu May 18 11:01:12 2000
+++ \AbiWord\abi\src\text\fmt\xp\fl_BlockLayout.cpp     Mon May 22 14:23:28 2000
@@ -879,7 +879,11 @@
        return m_pDoc->getBlockBuf(m_sdh, pgb);
 }
 
-fp_Run* fl_BlockLayout::findPointCoords(PT_DocPosition iPos, UT_Bool bEOL, UT_sint32& 
x, UT_sint32& y, UT_sint32& height)
+fp_Run* fl_BlockLayout::findPointCoords(PT_DocPosition iPos,
+                                                                               
+UT_Bool                 bEOL,
+                                                                               
+UT_sint32&              x,
+                                                                               
+UT_sint32&              y,
+                                                                               
+UT_sint32&              height)
 {
        // find the run which has this position inside it.
 
@@ -901,34 +905,35 @@
                UT_uint32 iWhere = pRun->containsOffset(iRelOffset);
                if (FP_RUN_JUSTAFTER == iWhere)
                {
-                      if(pRun->getNext())
+                       fp_Run* pNextRun = pRun->getNext();
+                       if (bEOL)
                       {
-                           if(pRun->getNext()->containsOffset(iRelOffset) == 
FP_RUN_INSIDE)
+                               const fp_Line* pNextLine = pNextRun ? 
+pNextRun->getLine() : 0;
+
+                               if (pNextLine != pRun->getLine())
                            {
                                  pRun->findPointCoords(iRelOffset, x, y, height);
-                                 return pRun->getNext();
-                           }
-                      }
+                                       return pRun;
                }
-               if (FP_RUN_INSIDE == iWhere)
+
+                               if (pNextRun)
                {
                        pRun->findPointCoords(iRelOffset, x, y, height);        
-                       return pRun;
+                                       return pNextRun;
+                               }
                }
-               else if (bEOL && (FP_RUN_JUSTAFTER == iWhere))
+                       if (pNextRun &&
+                               pNextRun->containsOffset(iRelOffset) == FP_RUN_INSIDE)
                {
-                       fp_Run* pNext = pRun->getNext();
-                       fp_Line* pNextLine = NULL;
-
-                       if (pNext)
-                               pNextLine = pNext->getLine();
-
-                       if (pNextLine != pRun->getLine())
+                               pNextRun->findPointCoords(iRelOffset, x, y, height);
+                               return pNextRun;
+                       }
+               }
+               if (FP_RUN_INSIDE == iWhere)
                        {
                                pRun->findPointCoords(iRelOffset, x, y, height);
                                return pRun;
                        }
-               }
                
                pRun = pRun->getNext();
        }
@@ -940,7 +945,7 @@
                if ((FP_RUN_JUSTAFTER == iWhere))
                {
                        fp_Run* nextRun = pRun->getNext();
-                       if (nextRun)
+                       if (nextRun && nextRun->canContainPoint())
                        {
                                nextRun->lookupProperties();
                                nextRun->findPointCoords(iRelOffset, x, y, height);
@@ -1561,7 +1566,7 @@
                        {
                                bUpdateScreen = UT_TRUE;
                                if (pView)
-                                       pView->_eraseInsertionPoint();
+                                       pView->_disableCursor();
                        }
 
                        _updateSquiggle(pPOB);
@@ -1577,7 +1582,7 @@
        if (bUpdateScreen && pView)
        {
                pView->updateScreen();
-               pView->_drawInsertionPoint();
+               pView->_enableCursor();
        }
 }
 
@@ -1658,7 +1663,7 @@
                                                FV_View* pView = m_pLayout->getView();
 
                                                if (pView)
-                                                       pView->_eraseInsertionPoint();
+                                                       pView->_disableCursor();
                                        }
 
                                        // squiggle it
@@ -2465,20 +2470,6 @@
                                delete pNuke;
                        }
 
-#if 0                
-                       //BUG: Code from Mike that crashes hard
-
-                       UT_ASSERT(pRun);
-
-                       m_pFirstRun = pRun;
-
-                       // then link what's left
-                       m_pFirstRun->insertIntoRunListAfterThis(*pLastRun);
-
-
-#else
-                       //BUG: Quick and Dirty Replacement Code
-
                        m_pFirstRun = pRun;
 
                        //then link what's left
@@ -2488,7 +2479,6 @@
                        {
                                m_pFirstRun->setPrev(pLastRun);
                        }
-#endif
                        
                }
                else
@@ -3329,7 +3319,10 @@
        if (pView)
        {
                pView->_resetSelection();
+#if 0
+               // TMN: Can really a FmtMark change DocPos?!
                pView->_setPoint(pcrfm->getPosition());
+#endif
                pView->notifyListeners(AV_CHG_FMTCHAR);
        }
 
@@ -3357,7 +3350,11 @@
        if (pView)
        {
                pView->_resetSelection();
+#if 0
+               // TMN: If addition of a FmtMark can't change
+               // cursor DocPos, neither can removal of one.
                pView->_setPoint(pcrfm->getPosition());
+#endif
                pView->notifyListeners(AV_CHG_FMTCHAR);
        }
 
@@ -3541,6 +3538,6 @@
        if (bUpdate && pView)
        {
                pView->updateScreen();
-               pView->_drawInsertionPoint();
+               pView->_enableCursor();
        }
 }

Reply via email to