Ok, it took a lot more effort than I thought it would, but I got
revert to work when you have multiple views of the same document open.
As a side effect, I implemented reference counting in XAD_Document,
along with two new macros -- REFP and UNREFP -- for managing
references on reference-counted object. So -- now that XAD_Document
is reference counted, the memory management of XAD_Document's is much
nicer when there are multiple frames with the same document.
The rest of the patch has to do with making sure all frames with refer
to a particular document object are changed to a new document object
when a document is reverted to its on-disk version. To do this, I had
to patch platform-specific code. I've patches all three versions --
Unix, BeOS and Win32 -- but I've only tested the Unix version. Sorry,
I've got only Linux installed on my home machine at the moment. The
other two should work fine, but, like I said, they're untested.
The patch is attached.
-- Matt Kimball mkimball@xmission.com--YZ5djTAD1cGYuMQK Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="abiword-multiwin.patch"
diff -ur ../abi-0.5.5/src/af/util/xp/ut_types.h ./src/af/util/xp/ut_types.h --- ../abi-0.5.5/src/af/util/xp/ut_types.h Thu Apr 22 13:11:15 1999 +++ ./src/af/util/xp/ut_types.h Sat May 1 21:08:00 1999 @@ -94,6 +94,8 @@ #define FREEP(p) do { if (p) free((void *)p); (p)=NULL; } while (0) #define DELETEP(p) do { if (p) delete(p); (p)=NULL; } while (0) +#define REFP(p) ((p)->ref(), (p)) +#define UNREFP(p) do { if (p) (p)->unref(); (p)=NULL; } while (0) #define CLONEP(p,q) do { FREEP(p); if (q && *q) UT_cloneString(p,q); } while (0) #define NrElements(a) ((sizeof(a)/sizeof(a[0]))) diff -ur ../abi-0.5.5/src/af/util/xp/ut_vector.cpp ./src/af/util/xp/ut_vector.cpp --- ../abi-0.5.5/src/af/util/xp/ut_vector.cpp Wed Mar 31 08:42:39 1999 +++ ./src/af/util/xp/ut_vector.cpp Sat May 1 21:08:00 1999 @@ -237,3 +237,18 @@ ::qsort(m_pEntries, m_iCount, sizeof(void*), compar); } +UT_Bool UT_Vector::copy(UT_Vector *pVec) +{ + clear(); + + for (UT_uint32 i=0; i < pVec->m_iCount; i++) + { + UT_sint32 err; + + err = addItem(pVec->m_pEntries[i]); + if(err == -1) + return err; + } + + return 0; +} diff -ur ../abi-0.5.5/src/af/util/xp/ut_vector.h ./src/af/util/xp/ut_vector.h --- ../abi-0.5.5/src/af/util/xp/ut_vector.h Tue Apr 6 14:19:03 1999 +++ ./src/af/util/xp/ut_vector.h Sat May 1 21:08:00 1999 @@ -52,6 +52,8 @@ void clear(); void qsort(int (*compar)(const void *, const void *)); + UT_Bool copy(UT_Vector *pVec); + protected: UT_uint32 calcNewSpace(); UT_sint32 grow(UT_uint32); diff -ur ../abi-0.5.5/src/af/xap/xp/xad_Document.cpp ./src/af/xap/xp/xad_Document.cpp --- ../abi-0.5.5/src/af/xap/xp/xad_Document.cpp Mon Dec 7 10:12:57 1998 +++ ./src/af/xap/xp/xad_Document.cpp Sat May 1 21:08:00 1999 @@ -18,16 +18,37 @@ */ +#include "ut_assert.h" #include "xad_Document.h" AD_Document::AD_Document() { + m_iRefCount = 1; m_szFilename = NULL; } AD_Document::~AD_Document() { + UT_ASSERT(m_iRefCount == 0); + // NOTE: let subclass clean up m_szFilename, so it matches the alloc mechanism +} + +void AD_Document::ref(void) +{ + UT_ASSERT(m_iRefCount > 0); + + m_iRefCount++; +} + +void AD_Document::unref(void) +{ + UT_ASSERT(m_iRefCount > 0); + + if (--m_iRefCount == 0) + { + delete this; + } } const char * AD_Document::getFilename(void) const diff -ur ../abi-0.5.5/src/af/xap/xp/xad_Document.h ./src/af/xap/xp/xad_Document.h --- ../abi-0.5.5/src/af/xap/xp/xad_Document.h Tue Apr 6 14:00:19 1999 +++ ./src/af/xap/xp/xad_Document.h Sat May 1 21:08:00 1999 @@ -29,7 +29,8 @@ { public: AD_Document(); - virtual ~AD_Document(); + void ref(void); + void unref(void); const char * getFilename(void) const; @@ -42,6 +43,9 @@ virtual UT_Bool redoCmd(UT_uint32 repeatCount) = 0; protected: + virtual ~AD_Document(); // Use unref() instead. + + int m_iRefCount; const char * m_szFilename; }; diff -ur ../abi-0.5.5/src/af/xap/xp/xap_App.cpp ./src/af/xap/xp/xap_App.cpp --- ../abi-0.5.5/src/af/xap/xp/xap_App.cpp Thu Apr 15 10:56:29 1999 +++ ./src/af/xap/xp/xap_App.cpp Sat May 1 21:08:00 1999 @@ -291,6 +291,43 @@ return UT_TRUE; } +UT_Bool XAP_App::forgetClones(XAP_Frame * pFrame) +{ + UT_ASSERT(pFrame); + + if (pFrame->getViewNumber() == 0) + { + return forgetFrame(pFrame); + } + + UT_Vector vClones; + getClones(&vClones, pFrame); + + for (UT_uint32 i = 0; i < vClones.getItemCount(); i++) + { + XAP_Frame * f = (XAP_Frame *) vClones.getNthItem(i); + forgetFrame(f); + } + + return UT_TRUE; +} + +UT_Bool XAP_App::getClones(UT_Vector *pvClonesCopy, XAP_Frame * pFrame) +{ + UT_ASSERT(pvClonesCopy); + UT_ASSERT(pFrame); + UT_ASSERT(pFrame->getViewNumber() > 0); + + // locate vector of this frame's clones + UT_HashEntry* pEntry = m_hashClones.findEntry(pFrame->getViewKey()); + UT_ASSERT(pEntry); + + UT_Vector * pvClones = (UT_Vector *) pEntry->pData; + UT_ASSERT(pvClones); + + return pvClonesCopy->copy(pvClones); +} + UT_Bool XAP_App::updateClones(XAP_Frame * pFrame) { UT_ASSERT(pFrame); diff -ur ../abi-0.5.5/src/af/xap/xp/xap_App.h ./src/af/xap/xp/xap_App.h --- ../abi-0.5.5/src/af/xap/xp/xap_App.h Tue Mar 23 08:47:48 1999 +++ ./src/af/xap/xp/xap_App.h Sat May 1 21:08:00 1999 @@ -68,6 +68,8 @@ virtual UT_Bool initialize(void); virtual UT_Bool rememberFrame(XAP_Frame * pFrame, XAP_Frame * pCloneOf=(XAP_Frame*)NULL); virtual UT_Bool forgetFrame(XAP_Frame * pFrame); + virtual UT_Bool forgetClones(XAP_Frame * pFrame); + virtual UT_Bool getClones(UT_Vector *pvClonesCopy, XAP_Frame * pFrame); virtual XAP_Frame * newFrame(void) = 0; virtual void reallyExit(void) = 0; diff -ur ../abi-0.5.5/src/af/xap/xp/xap_Frame.cpp ./src/af/xap/xp/xap_Frame.cpp --- ../abi-0.5.5/src/af/xap/xp/xap_Frame.cpp Thu Apr 29 15:15:36 1999 +++ ./src/af/xap/xp/xap_Frame.cpp Sat May 1 21:08:00 1999 @@ -72,7 +72,7 @@ { // only clone a few things m_app = f->m_app; - m_pDoc = f->m_pDoc; + m_pDoc = REFP(f->m_pDoc); m_iUntitled = f->m_iUntitled; // everything else gets recreated @@ -105,8 +105,7 @@ DELETEP(m_pView); DELETEP(m_pViewListener); - if (m_nView==0) - DELETEP(m_pDoc); + UNREFP(m_pDoc); DELETEP(m_pScrollObj); DELETEP(m_pInputModes); diff -ur ../abi-0.5.5/src/text/ptbl/xp/pd_Document.h ./src/text/ptbl/xp/pd_Document.h --- ../abi-0.5.5/src/text/ptbl/xp/pd_Document.h Wed Apr 28 12:54:19 1999 +++ ./src/text/ptbl/xp/pd_Document.h Sat May 1 21:09:23 1999 @@ -58,7 +58,6 @@ { public: PD_Document(); - ~PD_Document(); virtual UT_Bool readFromFile(const char * szFilename, int ieft); virtual UT_Bool newDocument(void); @@ -164,6 +163,8 @@ #endif protected: + ~PD_Document(); + void _setClean(void); void _destroyDataItemData(void); diff -ur ../abi-0.5.5/src/wp/ap/beos/ap_BeOSFrame.cpp ./src/wp/ap/beos/ap_BeOSFrame.cpp --- ../abi-0.5.5/src/wp/ap/beos/ap_BeOSFrame.cpp Thu Apr 29 14:52:11 1999 +++ ./src/wp/ap/beos/ap_BeOSFrame.cpp Sat May 1 21:08:00 1999 @@ -170,7 +170,7 @@ REPLACEP(((AP_FrameData*)m_pData)->m_pG, pG); REPLACEP(((AP_FrameData*)m_pData)->m_pDocLayout, pDocLayout); if (pOldDoc != m_pDoc) { - DELETEP(pOldDoc); + UNREFP(pOldDoc); } REPLACEP(m_pView, pView); @@ -233,7 +233,7 @@ DELETEP(pScrollbarViewListener); // change back to prior document - DELETEP(m_pDoc); + UNREFP(m_pDoc); m_pDoc = ((AP_FrameData*)m_pData)->m_pDocLayout->getDocument(); return UT_FALSE; @@ -414,11 +414,13 @@ goto ReplaceDocument; UT_DEBUGMSG(("ap_Frame: could not open the file [%s]\n",szFilename)); - delete pNewDoc; + UNREFP(pNewDoc); return UT_FALSE; ReplaceDocument: - // NOTE: prior document is bound to ((AP_FrameData*)m_pData)->m_pDocLayout, which gets discarded by subclass + getApp()->forgetClones(this); + + // NOTE: prior document is discarded in _showDocument() m_pDoc = pNewDoc; return UT_TRUE; } @@ -451,6 +453,16 @@ UT_Bool AP_BeOSFrame::loadDocument(const char * szFilename, int ieft) { + UT_Bool bUpdateClones; + UT_Vector vClones; + XAP_App * pApp = getApp(); + + bUpdateClones = (getViewNumber() > 0); + if (bUpdateClones) + { + pApp->getClones(&vClones, this); + } + if (! _loadDocument(szFilename,(IEFileType)ieft)) { // we could not load the document. @@ -460,6 +472,20 @@ return UT_FALSE; } + pApp->rememberFrame(this); + if (bUpdateClones) + { + for (UT_uint32 i = 0; i < vClones.getItemCount(); i++) + { + AP_BeOSFrame * pFrame = (AP_BeOSFrame *) vClones.getNthItem(i); + if(pFrame != this) + { + pFrame->_replaceDocument(m_pDoc); + pApp->rememberFrame(pFrame, this); + } + } + } + return _showDocument(); } @@ -583,4 +609,10 @@ return(m_pbe_DocView); } +UT_Bool AP_BeOSFrame::_replaceDocument(AD_Document * pDoc) +{ + // NOTE: prior document is discarded in _showDocument() + m_pDoc = REFP(pDoc); + return _showDocument(); +} diff -ur ../abi-0.5.5/src/wp/ap/beos/ap_BeOSFrame.h ./src/wp/ap/beos/ap_BeOSFrame.h --- ../abi-0.5.5/src/wp/ap/beos/ap_BeOSFrame.h Sun Apr 11 07:00:02 1999 +++ ./src/wp/ap/beos/ap_BeOSFrame.h Sat May 1 21:08:00 1999 @@ -51,6 +51,7 @@ UT_Bool _showDocument(UT_uint32 zoom=100); static void _scrollFuncX(void * pData, UT_sint32 xoff, UT_sint32 xlimit); static void _scrollFuncY(void * pData, UT_sint32 yoff, UT_sint32 ylimit); + UT_Bool _replaceDocument(AD_Document * pDoc); /* GtkAdjustment * m_pVadj; diff -ur ../abi-0.5.5/src/wp/ap/unix/ap_UnixFrame.cpp ./src/wp/ap/unix/ap_UnixFrame.cpp --- ../abi-0.5.5/src/wp/ap/unix/ap_UnixFrame.cpp Tue Apr 6 14:00:10 1999 +++ ./src/wp/ap/unix/ap_UnixFrame.cpp Sat May 1 21:08:00 1999 @@ -169,7 +169,7 @@ REPLACEP(((AP_FrameData*)m_pData)->m_pDocLayout, pDocLayout); if (pOldDoc != m_pDoc) { - DELETEP(pOldDoc); + UNREFP(pOldDoc); } REPLACEP(m_pView, pView); REPLACEP(m_pScrollObj, pScrollObj); @@ -229,7 +229,7 @@ DELETEP(pScrollbarViewListener); // change back to prior document - DELETEP(m_pDoc); + UNREFP(m_pDoc); m_pDoc = ((AP_FrameData*)m_pData)->m_pDocLayout->getDocument(); return UT_FALSE; @@ -370,11 +370,13 @@ goto ReplaceDocument; UT_DEBUGMSG(("ap_Frame: could not open the file [%s]\n",szFilename)); - delete pNewDoc; + UNREFP(pNewDoc); return UT_FALSE; ReplaceDocument: - // NOTE: prior document is bound to ((AP_FrameData*)m_pData)->m_pDocLayout, which gets discarded by subclass + getApp()->forgetClones(this); + + // NOTE: prior document is discarded in _showDocument() m_pDoc = pNewDoc; return UT_TRUE; } @@ -407,6 +409,16 @@ UT_Bool AP_UnixFrame::loadDocument(const char * szFilename, int ieft) { + UT_Bool bUpdateClones; + UT_Vector vClones; + XAP_App * pApp = getApp(); + + bUpdateClones = (getViewNumber() > 0); + if (bUpdateClones) + { + pApp->getClones(&vClones, this); + } + if (! _loadDocument(szFilename, (IEFileType) ieft)) { // we could not load the document. @@ -416,6 +428,20 @@ return UT_FALSE; } + pApp->rememberFrame(this); + if (bUpdateClones) + { + for (UT_uint32 i = 0; i < vClones.getItemCount(); i++) + { + AP_UnixFrame * pFrame = (AP_UnixFrame *) vClones.getNthItem(i); + if(pFrame != this) + { + pFrame->_replaceDocument(m_pDoc); + pApp->rememberFrame(pFrame, this); + } + } + } + return _showDocument(); } @@ -603,3 +629,10 @@ ((AP_FrameData *)m_pData)->m_pStatusBar->setStatusMessage(szMsg); } +UT_Bool AP_UnixFrame::_replaceDocument(AD_Document * pDoc) +{ + // NOTE: prior document is discarded in _showDocument() + m_pDoc = REFP(pDoc); + + return _showDocument(); +} diff -ur ../abi-0.5.5/src/wp/ap/unix/ap_UnixFrame.h ./src/wp/ap/unix/ap_UnixFrame.h --- ../abi-0.5.5/src/wp/ap/unix/ap_UnixFrame.h Tue Apr 6 14:00:10 1999 +++ ./src/wp/ap/unix/ap_UnixFrame.h Sat May 1 21:08:00 1999 @@ -54,6 +54,7 @@ UT_Bool _showDocument(UT_uint32 iZoom=100); static void _scrollFuncX(void * pData, UT_sint32 xoff, UT_sint32 xlimit); static void _scrollFuncY(void * pData, UT_sint32 yoff, UT_sint32 ylimit); + UT_Bool _replaceDocument(AD_Document * pDoc); GtkAdjustment * m_pVadj; GtkAdjustment * m_pHadj; diff -ur ../abi-0.5.5/src/wp/ap/win/ap_Win32Frame.cpp ./src/wp/ap/win/ap_Win32Frame.cpp --- ../abi-0.5.5/src/wp/ap/win/ap_Win32Frame.cpp Tue Apr 6 14:00:11 1999 +++ ./src/wp/ap/win/ap_Win32Frame.cpp Sat May 1 21:08:00 1999 @@ -224,7 +224,7 @@ REPLACEP(((AP_FrameData*)m_pData)->m_pDocLayout, pDocLayout); if (pOldDoc != m_pDoc) { - DELETEP(pOldDoc); + UNREFP(pOldDoc); } REPLACEP(m_pView, pView); REPLACEP(m_pScrollObj, pScrollObj); @@ -271,7 +271,7 @@ DELETEP(pScrollbarViewListener); // change back to prior document - DELETEP(m_pDoc); + UNREFP(m_pDoc); m_pDoc = ((AP_FrameData*)m_pData)->m_pDocLayout->getDocument(); return UT_FALSE; @@ -550,6 +550,16 @@ UT_Bool AP_Win32Frame::loadDocument(const char * szFilename, int ieft) { + UT_Bool bUpdateClones; + UT_Vector vClones; + XAP_App * pApp = getApp(); + + bUpdateClones = (getViewNumber() > 0); + if (bUpdateClones) + { + pApp->getClones(&vClones, this); + } + if (! _loadDocument(szFilename, (IEFileType) ieft)) { // we could not load the document. @@ -559,6 +569,20 @@ return UT_FALSE; } + pApp->rememberFrame(this); + if (bUpdateClones) + { + for (UT_uint32 i = 0; i < vClones.getItemCount(); i++) + { + AP_Win32Frame * pFrame = (AP_Win32Frame *) vClones.getNthItem(i); + if(pFrame != this) + { + pFrame->_replaceDocument(m_pDoc); + pApp->rememberFrame(pFrame, this); + } + } + } + return _showDocument(); } @@ -930,11 +954,13 @@ goto ReplaceDocument; UT_DEBUGMSG(("ap_Frame: could not open the file [%s]\n",szFilename)); - delete pNewDoc; + UNREFP(pNewDoc); return UT_FALSE; ReplaceDocument: - // NOTE: prior document is bound to ((AP_FrameData*)m_pData)->m_pDocLayout, which gets discarded by subclass + getApp()->forgetClones(this); + + // NOTE: prior document is discarded in _showDocument() m_pDoc = pNewDoc; return UT_TRUE; } @@ -966,4 +992,12 @@ void AP_Win32Frame::setStatusMessage(const char * szMsg) { ((AP_FrameData *)m_pData)->m_pStatusBar->setStatusMessage(szMsg); +} + +UT_Bool AP_Win32Frame::_replaceDocument(AD_Document * pDoc) +{ + // NOTE: prior document is discarded in _showDocument() + m_pDoc = REFP(pDoc); + + return _showDocument(); } diff -ur ../abi-0.5.5/src/wp/ap/win/ap_Win32Frame.h ./src/wp/ap/win/ap_Win32Frame.h --- ../abi-0.5.5/src/wp/ap/win/ap_Win32Frame.h Tue Apr 6 14:00:11 1999 +++ ./src/wp/ap/win/ap_Win32Frame.h Sat May 1 21:08:00 1999 @@ -67,6 +67,8 @@ void _setVerticalScrollInfo(const SCROLLINFO * psi); void _getVerticalScrollInfo(SCROLLINFO * psi); + UT_Bool _replaceDocument(AD_Document * pDoc); + HWND m_hwndTopRuler; HWND m_hwndLeftRuler; HWND m_hwndDeadLowerRight;
--YZ5djTAD1cGYuMQK--