home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 February: Technology Seed / Mac Tech Seed Feb '97.toast / OpenDoc 1.2b2c1 / Implementation / Storage / Clipbd.cpp next >
Encoding:
C/C++ Source or Header  |  1997-02-13  |  52.2 KB  |  1,750 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        Clipbd.cpp
  3.  
  4.     Contains:    Implementation for ODClipboard class.
  5.  
  6.     Owned by:    Craig Carper
  7.  
  8.     Copyright:    © 1993 - 1996 by Apple Computer, Inc., all rights reserved.
  9.  
  10.     Change History (most recent first):
  11.  
  12.         <10>     12/9/96    CC        1608906: Call ZeroScrap() immediately when
  13.                                     clipboard is cleared.
  14.                                     1610138: Use scrap counts for clipboard
  15.                                     update ids.
  16.          <9>     9/26/96    CC        1390741 - CloseClipboard: ClearAllPromises,
  17.                                     now unnecessary.  Replaced Externalize with
  18.                                     the more appropriate ResolveAllPromises.
  19.          <8>    20.09.1996    NP        1386078: GetXXXContainer should be
  20.                                     AcquireXXXContainer in StorUtil
  21.          <7>     8/13/96    DM        1362809: use TempSuppressFatalBentoError to
  22.                                     ensure old flag value is restored
  23.          <6>     7/11/96    TJ        Fixed Name of function to check for MacOS 8
  24.          <5>     5/24/96    jpa        1246074: SOM_CATCH --> SOM_TRY..SOM_ENDTRY
  25.          <3>     3/29/96    DM        1296171: suppress fatal Bento container
  26.                                     errors in all clipboard methods
  27.          <2>     3/26/96    CC        1333462: CloseClipboard: ClearAllPromises
  28.                                     if not externalizing the clipboard draft.
  29.  
  30.     To Do:
  31.     • Add a resolvePromises parameter to ExportClipboard (but maybe we need to
  32.         do this all the time).
  33.     • Vincent will add a draft change seed.  The clipboard object can examine
  34.         the seed for the clipboard draft to determine if the clipboard has
  35.         been changed since it was exported (if the clipboard generation is the
  36.         same).
  37.     
  38.     In Progress:
  39.         
  40. */
  41.  
  42. #define VARIABLE_MACROS
  43.  
  44. #define ODClipboard_Class_Source
  45. #include <Clipbd.xih>
  46.  
  47. #ifndef SOM_Module_OpenDoc_StdDefs_defined
  48. #include <StdDefs.xh>
  49. #endif
  50.  
  51. #ifndef _EXCEPT_
  52. #include <Except.h>
  53. #endif
  54.  
  55. #ifndef _ODMEMORY_
  56. #include <ODMemory.h>
  57. #endif
  58.  
  59. #ifndef _CONSTDEF_
  60. #include <ConstDef.h>
  61. #endif
  62.  
  63. #ifndef _PLFMDEF_
  64. #include <PlfmDef.h>
  65. #endif
  66.  
  67. #ifndef _ISOSTR_
  68. #include <ISOStr.h>
  69. #endif
  70.  
  71. #ifndef _ODUTILS_
  72. #include <ODUtils.h>
  73. #endif
  74.  
  75. #ifndef SOM_Module_OpenDoc_StdProps_defined
  76. #include <StdProps.xh>
  77. #endif
  78.  
  79. #ifndef SOM_Module_OpenDoc_StdTypes_defined
  80. #include <StdTypes.xh>
  81. #endif
  82.  
  83. #ifndef SOM_Module_OpenDoc_Foci_defined
  84. #include <Foci.xh>
  85. #endif
  86.  
  87. #ifndef SOM_ODSession_xh
  88. #include <ODSessn.xh>
  89. #endif
  90.  
  91. #ifndef _BENTOSUPPRESS_
  92. #include "BentoSuppress.h"
  93. #endif
  94.  
  95. #ifndef SOM_ODArbitrator_xh
  96. #include <Arbitrat.xh>
  97. #endif
  98.  
  99. #ifndef SOM_ODContainer_xh
  100. #include <ODCtr.xh>
  101. #endif
  102.  
  103. #ifndef SOM_ODDocument_xh
  104. #include <Document.xh>
  105. #endif
  106.  
  107. #ifndef SOM_ODDraft_xh
  108. #include <Draft.xh>
  109. #endif
  110.  
  111. #ifndef SOM_ODStorageSystem_xh
  112. #include <ODStor.xh>
  113. #endif
  114.  
  115. #ifndef SOM_ODStorageUnit_xh
  116. #include <StorageU.xh>
  117. #endif
  118.  
  119. #ifndef SOM_ODTranslation_xh
  120. #include <Translt.xh>
  121. #endif
  122.  
  123. #ifndef SOM_ODTypeList_xh
  124. #include <TypeList.xh>
  125. #endif
  126.  
  127. #ifndef SOM_ODPlatformTypeList_xh
  128. #include <PfTypLs.xh>
  129. #endif
  130.  
  131. #ifndef _LINKDLGS_
  132. #include <LinkDlgs.h>
  133. #endif
  134.  
  135. #ifndef __SCRAP__
  136. #include <Scrap.h>
  137. #endif
  138.  
  139. #ifndef _ODDEBUG_
  140. #include <ODDebug.h>
  141. #endif
  142.  
  143. #ifndef __ERRORS__
  144. #include <Errors.h>
  145. #endif
  146.  
  147. #ifndef _STDTYPIO_
  148. #include <StdTypIO.h>
  149. #endif
  150.  
  151. #ifndef _TEMPOBJ_
  152. #include <TempObj.h>
  153. #endif
  154.  
  155. #ifndef _STORUTIL_
  156. #include <StorUtil.h>
  157. #endif
  158.  
  159. #ifndef _UTILERRS_
  160. #include "UtilErrs.h"
  161. #endif
  162.  
  163. #ifndef __TEXTEDIT__
  164. #include <TextEdit.h>    // for ScrpSTElement
  165. #endif
  166.  
  167. #pragma segment ODClipboard
  168.  
  169. #include "ClipbdB.cpp"    // Platform-independent methods, if any
  170.  
  171. #if ODDebug
  172. #define ODDebugClipboard 0
  173. #undef _REPORT_SCRAP_ERRORS_
  174. #else
  175. #define ODDebugClipboard 0
  176. #undef _REPORT_SCRAP_ERRORS_
  177. #endif
  178.  
  179. #if ODDebugClipboard
  180. // somPrintf must be in the else clause so if stmt is complete [cc]
  181. #define PRINT_CLIP    if ( kODFalse ) ; else somPrintf
  182. #else
  183. #define PRINT_CLIP    if ( kODTrue ) ; else somPrintf
  184. #endif
  185.  
  186. //==============================================================================
  187. // Constants
  188. //==============================================================================
  189.  
  190. const short kInvalidScrapCount = -1;    // Must never match the scrap count!
  191.  
  192. // Mac Scrap state constants
  193. const short kUninitializedScrap = -1;
  194. const short kScrapOnDisk = 0;
  195.  
  196. //==============================================================================
  197. // Function Prototypes
  198. //==============================================================================
  199.  
  200. ODStatic ODULong ApplicationHeapFree();
  201. ODStatic short GetMacScrapCount();
  202. ODStatic ODBoolean IsFrontProcess();
  203. ODStatic void ImportStyledTextType(ODClipboard *somSelf, Environment *ev);
  204. ODStatic OSErr ExportStylType(ODPtr    stxtData);
  205. ODStatic void CloseClipboard(ODClipboard *somSelf, Environment *ev, ODBoolean externalize);
  206. ODStatic void OpenClipboard(ODClipboard *somSelf, Environment *ev);
  207. ODStatic ODBoolean ScrapIsInconsistent();
  208. ODStatic ODBoolean ScrapHasData();
  209. ODStatic ODBoolean ScrapHasType(ODPlatformType type);
  210. ODStatic void ForceZeroScrap();
  211. ODStatic ODBoolean ScrapMemoryAvailable(Size dataSize);
  212. ODStatic OSErr UnloadScrapIfMemLow(Size dataSize);
  213. ODStatic OSErr ClipboardLoadScrap();
  214. ODStatic OSErr ClipboardPutScrap(Size dataSize, ODPlatformType    platformType, ODPtr data);
  215.  
  216. //==============================================================================
  217. // Utility Functions
  218. //==============================================================================
  219.  
  220. //------------------------------------------------------------------------------
  221. // SetOriginalCloneKind
  222. //------------------------------------------------------------------------------
  223.  
  224. static void SetOriginalCloneKind(Environment* ev, ODDraft* draft, ODCloneKind cloneKind)
  225. {
  226.     if ( draft != kODNULL )
  227.     {
  228.         TempODStorageUnit draftProperties = draft->AcquireDraftProperties(ev);
  229.         ODSetULongProp(ev, draftProperties, kODPropOriginalCloneKind, kODULong, (ODULong)cloneKind);
  230.     }
  231. }
  232.  
  233. //------------------------------------------------------------------------------
  234. // GetOriginalDraft
  235. //------------------------------------------------------------------------------
  236. // Returns kODNULL if the original draft is unknown.  This is the case when content
  237. // was placed in the draft without cloning.
  238.  
  239. static ODDraft* GetOriginalDraft(Environment* ev, ODDraft* draft)
  240. {
  241.     TempODStorageUnit    draftProperties = draft->AcquireDraftProperties(ev);
  242.     return (ODDraft*)ODGetULongProp(ev, draftProperties, kODPropOriginalDraft, kODULong);
  243. }
  244.  
  245. //==============================================================================
  246. // ODClipboard
  247. //==============================================================================
  248.  
  249. //------------------------------------------------------------------------------
  250. // ODClipboard::somUninit
  251. //------------------------------------------------------------------------------
  252.  
  253. SOM_Scope void  SOMLINK ODClipboardsomUninit(ODClipboard *somSelf)
  254. {
  255.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  256.     ODClipboardMethodDebug("ODClipboard","somUninit");
  257.     
  258.     TempSuppressFatalBentoError tempSuppress;
  259.     
  260.     Environment *ev = somGetGlobalEnvironment();
  261.  
  262.     // somSelf->DiscardClipboard(ev); 
  263.     // It is incorrect to call methods on somSelf inside somUninit, 
  264.     // a subclass may have already been somUninited.  See OpenDoc Building Code for details.
  265.     // Instead the implementation of DiscardClipboard has been copied here.
  266.     
  267.     // BEGIN copy of DiscardClipboard implementation
  268.     CloseClipboard(somSelf, ev, kODFalse);
  269.     
  270.     ODDisposeHandle(_fContainerHandle);
  271.     _fContainerHandle = (ODHandle) kODNULL;
  272.     // END copy of DiscardClipboard implementation
  273.  
  274.     parent_somUninit(somSelf);
  275. }
  276.  
  277. //------------------------------------------------------------------------------
  278. // ODClipboard::InitClipboard
  279. //------------------------------------------------------------------------------
  280.  
  281. SOM_Scope void  SOMLINK ODClipboardInitClipboard(ODClipboard *somSelf, Environment *ev,
  282.         ODSession* session)
  283. {
  284.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  285.     ODClipboardMethodDebug("ODClipboard","InitClipboard");
  286.  
  287.     TempSuppressFatalBentoError tempSuppress;
  288.  
  289.     /* Moved from somInit. SOM itself sets fields to zero
  290.     _fSession            = (ODSession*) kODNULL;
  291.     _fContainerHandle    = (ODHandle) kODNULL;
  292.     _fContainer            = (ODContainer*) kODNULL;
  293.     _fDocument            = (ODDocument*) kODNULL;
  294.     _fDraft                = (ODDraft*) kODNULL;
  295.     _fSU                = (ODStorageUnit*) kODNULL;
  296.     
  297.     _fOriginalDraft        = (ODDraft*) kODNULL;
  298.     _fExportedLinkSpec    = kODFalse;
  299.  
  300.     _fClonePasteCount    = 0;
  301.     */
  302.     somSelf->InitObject(ev);
  303.             
  304.     _fSession = session;
  305.  
  306.     // fScrapCount is the scrap count associated with the current OpenDoc 
  307.     // clipboard.  If fScrapCount is not equal to the current scrap count,
  308.     // the scrap is newer than the clipboard and must be imported.
  309.     //
  310.     // fLastSynchronizedScrapCount is the scrap count when the OpenDoc
  311.     // clipboard and the scrap were last synchronized.  If fLastSynchronizedScrapCount 
  312.     // is not equal to the current scrap count (and the clipboard is newer 
  313.     // than the scrap), the clipboard has not been written to the scrap.
  314.     //
  315.     // fVirtualScrapCount shadows fScrapCount, and is almost always equal to
  316.     // fScrapCount.  Its value is returned as the update id of the clipboard.
  317.     // It may be different than fScrapCount its necessary to call ZeroScrap 
  318.     // in order to re-write the clipboard.  Callers of GetUpdateID should not
  319.     // get a different result unless the clipboard generation has really changed
  320.     // (either because Clear was called, or because another process changed
  321.     // the scrap).  If ZeroScrap must be called to re-export the clipboard,
  322.     // fVirtualScrapCount is not changed.
  323.     //
  324.     // Initialize fScrapCount to to an invalid value so its not equal
  325.     // to the current scrap count.  This indicates the scrap contains newer
  326.     // data than the OpenDoc clipboard and must be imported. [cc]
  327.     _fScrapCount                    = kInvalidScrapCount;
  328.     _fVirtualScrapCount                = kInvalidScrapCount;
  329.     _fLastSynchronizedScrapCount    = kInvalidScrapCount;    // Not strictly necessary [cc]
  330.     
  331.     _fOriginalCloneKind = kODCloneCopy;
  332. }
  333.  
  334. //------------------------------------------------------------------------------
  335. // ApplicationHeapFree
  336. //------------------------------------------------------------------------------
  337.  
  338. ODStatic ODULong ApplicationHeapFree()
  339. {
  340.     ODULong free;
  341.     THz curZone = GetZone();
  342.     SetZone(ApplicationZone());
  343.     free = FreeMem();
  344.     SetZone(curZone);
  345.     return free;
  346. }
  347.  
  348. //------------------------------------------------------------------------------
  349. // ODClipboard::Purge (OVERRIDE)
  350. //------------------------------------------------------------------------------
  351.  
  352. SOM_Scope ODSize  SOMLINK ODClipboardPurge(ODClipboard *somSelf, Environment *ev,
  353.     ODSize size)
  354. {
  355.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  356.     ODClipboardMethodDebug("ODClipboard","Purge");
  357.     
  358.     ODSize freed = 0;
  359.     ODVolatile(freed);
  360.                         
  361.     SOM_TRY
  362.         TempSuppressFatalBentoError tempSuppress;
  363.  
  364.         Size scrapSize = InfoScrap()->scrapSize;
  365.         short scrapCount = GetMacScrapCount();
  366.         
  367.         if ( InfoScrap()->scrapState > kScrapOnDisk )
  368.         {
  369.             // If the OpenDoc clipboard is newer than the scrap, ZeroScrap will
  370.             // have already been called.  If the OpenDoc clipboard and the scrap
  371.             // are in sync, we can't clear the scrap by calling ZeroScrap and then
  372.             // rewriting the scrap later.  This would change the current scrap
  373.             // count and a container application might mistakenly think its 
  374.             // private scrap was no longer valid.  So, the best we can do is just
  375.             // unload the scrap, which could be slow since it writes a file. [cc]
  376.             
  377.             UnloadScrap();
  378.  
  379.             freed += scrapSize;
  380.  
  381.             #if ODDebugClipboard
  382.                 if ( InfoScrap()->scrapState > kScrapOnDisk )
  383.                     PRINT("ODClipboard::Purge: Scrap unloaded\n");
  384.             #endif
  385.  
  386.             PRINT_CLIP("ODClipboard::Purge: Freed %ld bytes in app heap\n", freed);
  387.         }    
  388.  
  389.         freed += parent_Purge(somSelf, ev, size); // always call parent version of Purge()
  390.  
  391.     SOM_CATCH_ALL
  392.         WARN("Error %ld trying to purge in ODClipboardPurge",ErrorCode());
  393.         SetErrorCode(kODNoError);        // Eat the exception; Purge should not 
  394.                                         // propagate it because clients function
  395.                                         // fine whether memory was purged or not.
  396.     SOM_ENDTRY
  397.  
  398.     return freed;
  399. }
  400.  
  401. //------------------------------------------------------------------------------
  402. // ODClipboard::NewClipboard
  403. //------------------------------------------------------------------------------
  404.  
  405. SOM_Scope void  SOMLINK ODClipboardNewClipboard(ODClipboard *somSelf, Environment *ev)
  406. {
  407.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  408.     ODClipboardMethodDebug("ODClipboard","NewClipboard");
  409.  
  410.     ODStorageUnit* draftProperties = kODNULL;
  411.     
  412.     ODVolatile(draftProperties);
  413.  
  414.     SOM_TRY
  415.         TempSuppressFatalBentoError tempSuppress;
  416.  
  417.         // Create a new clipboard in-memory container
  418.         _fContainerHandle = ODNewHandle(0);
  419.         _fContainer = CreateMemoryContainer(ev, _fSession, _fContainerHandle, kODBentoMemoryContainer);
  420.  
  421.         // Create the root content storage unit
  422.         _fDocument = _fContainer->AcquireDocument(ev, kODDefaultDocument);
  423.         _fDraft = _fDocument->AcquireBaseDraft(ev, kODDPExclusiveWrite);
  424.         _fSU = _fDraft->CreateStorageUnit(ev);
  425.  
  426.         // Store a reference to the content storage unit in the draft properties
  427.         draftProperties = _fDraft->AcquireDraftProperties(ev);
  428.         ODSetStrongSURefProp(ev, draftProperties, kODPropRootPartSU, kODStrongStorageUnitRef, _fSU->GetID(ev));    
  429.         draftProperties->Release(ev);
  430.  
  431.     SOM_CATCH_ALL
  432. #ifdef _REPORT_SCRAP_ERRORS_
  433.         WARN("ODClipboard: Cannot create clipboard - error %ld",ErrorCode());
  434. #endif
  435.         somSelf->DiscardClipboard(ev);
  436.         ODReleaseObject(ev, draftProperties);
  437.     SOM_ENDTRY
  438. }
  439.  
  440. //------------------------------------------------------------------------------
  441. // CloseClipboard
  442. //------------------------------------------------------------------------------
  443. // Close the current clipboard container, without disposing of the container handle.
  444. // If externalize is false, this routine must not, and will not, fail. [cc]
  445.  
  446. ODStatic void CloseClipboard(ODClipboard *somSelf, Environment *ev, ODBoolean externalize)
  447. {
  448.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  449.  
  450.     TempSuppressFatalBentoError tempSuppress;
  451.     
  452.     // Before externalizing the draft, resolve all promises in the root storage unit.
  453.     // Otherwise, externalizing the draft may fail with an iterator-out-of-sync 
  454.     // error because resolving promises may add storage units to the draft's 
  455.     // collection during iteration.  By convention, the only promises should be in 
  456.     // the root storage unit.
  457.  
  458.     if ( externalize )
  459.     {
  460.         if ( _fSU != kODNULL )
  461.             _fSU->ResolveAllPromises(ev);
  462.         if ( _fDraft != kODNULL )
  463.             _fDraft->Externalize(ev);
  464.     }
  465.  
  466.     ODSafeReleaseObject(_fSU);            _fSU = kODNULL;
  467.     ODSafeReleaseObject(_fDraft);        _fDraft = kODNULL;
  468.     ODSafeReleaseObject(_fDocument);    _fDocument = kODNULL;
  469.     ODSafeReleaseObject(_fContainer);    _fContainer = kODNULL;
  470. }
  471.  
  472. //------------------------------------------------------------------------------
  473. // ODClipboard::DiscardClipboard
  474. //------------------------------------------------------------------------------
  475. // This method must not fail. [cc]
  476.  
  477. SOM_Scope void  SOMLINK ODClipboardDiscardClipboard(ODClipboard *somSelf, Environment *ev)
  478. {
  479.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  480.     ODClipboardMethodDebug("ODClipboard","DiscardClipboard");
  481.  
  482.     TRY
  483.     TempSuppressFatalBentoError tempSuppress;
  484.     
  485.     CloseClipboard(somSelf, ev, kODFalse);
  486.     
  487.     ODDisposeHandle(_fContainerHandle);
  488.     _fContainerHandle = (ODHandle) kODNULL;
  489.     
  490.     CATCH_ALL
  491.         // Ignore any errors
  492.     ENDTRY
  493. }
  494.  
  495. //------------------------------------------------------------------------------
  496. // ODClipboard::ImportContent
  497. //------------------------------------------------------------------------------
  498. //
  499. // On entry, assumes the scrap has already been checked for consistency.
  500. // Returns an exception if the scrap can't be loaded into memory.
  501.  
  502. SOM_Scope void  SOMLINK ODClipboardImportContent(ODClipboard *somSelf, Environment *ev)
  503. {
  504.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  505.     ODClipboardMethodDebug("ODClipboard","ImportContent");
  506.     
  507.     ODHandle    hData = kODNULL;
  508.     long        scrapOffset = 0;
  509.     
  510.     ODVolatile(hData);
  511.     
  512.     SOM_TRY
  513.         TempSuppressFatalBentoError tempSuppress;
  514.     
  515.         hData = ODNewHandle(0);
  516.  
  517.         // Because we walk the scrap, it must be loaded in memory.
  518.         THROW_IF_ERROR(ClipboardLoadScrap());
  519.     
  520.         PScrapStuff myScrapStuff = InfoScrap();
  521.         Handle        hScrap = myScrapStuff->scrapHandle;
  522.  
  523.         while ( scrapOffset < myScrapStuff->scrapSize )
  524.         {
  525.             long        scrapTypeLength;
  526.             ResType        theType;
  527.             ODULong        realOffset;
  528.     
  529.             // There is more in the scrap
  530.             theType = *(ResTypePtr)(((long) *hScrap) + scrapOffset);
  531.             scrapTypeLength = GetScrap((Handle) hData, theType, (long*) &realOffset);
  532.             if ( scrapTypeLength < 0 )
  533.                 THROW(scrapTypeLength);
  534.  
  535.             if ( realOffset < scrapOffset )
  536.             {
  537.                 // We tried to read a second occurance of the same resource type
  538.                 // on the scrap.  Since the result of GetScrap is the length
  539.                 // of the first occurance, we can't read the scrap past this point.
  540.                 // So just quit.
  541. #ifdef _REPORT_SCRAP_ERRORS_
  542.                 PRINT("ODClipboard: ImportContent: Duplicate resource on scrap, type = \'%.4s\'\n", &theType);
  543. #endif
  544.                 break;
  545.             }
  546.  
  547.             PRINT_CLIP("Found scrap type \'%.4s\'\n", &theType);
  548.  
  549.             if ( scrapTypeLength > 0 )
  550.             {
  551. #ifdef _REPORT_SCRAP_ERRORS_
  552.                 if ( theType == kODScrapTypeODBentoContainer )
  553.                 {
  554.                     // Internal error
  555.                     WARN("ODClipboard: ImportContent: Reading BentoContainer as scrap type!");
  556.                 }
  557. #endif
  558.                 // Special case: If 'styl' is present, create an 'stxt' if one
  559.                 // isn't also on the scrap
  560.                 if ( theType == 'styl' )
  561.                 {
  562.                     long dummy;
  563.                     if ( GetScrap(nil, 'stxt', &dummy) == noTypeErr )
  564.                         ImportStyledTextType(somSelf, ev);
  565.                 }
  566.                 
  567.                 TempODType theISOType = kODNULL;
  568.                 theISOType = _fSession->GetTranslation(ev)->GetISOTypeFromPlatformType(ev, theType, kODPlatformDataType);
  569.         
  570.                 if ( theISOType != (ODType) kODNULL )
  571.                 {
  572.                     if ( ODSUExistsThenFocus(ev, _fSU, kODPropContents, (ODType) theISOType) )
  573.                     {
  574.                         WARN("ODClipboard: Replacing value on clipboard");
  575.                         _fSU->Remove(ev);
  576.                     }
  577.                     ODSUForceFocus(ev, _fSU, kODPropContents, (ODType) theISOType);
  578.                     ODValue pData = ODLockHandle(hData);
  579.                     StorageUnitSetValue(_fSU, ev, (ODULong) scrapTypeLength, pData);
  580.                     ODUnlockHandle(hData);
  581.                 }
  582.             }
  583.  
  584.             // The length must be EVEN!
  585.             if (scrapTypeLength & 1)
  586.             {
  587.                 scrapTypeLength += 1;
  588.             }
  589.             scrapOffset = realOffset + scrapTypeLength;
  590.         }
  591.  
  592.     SOM_CATCH_ALL
  593.  
  594. #ifdef _REPORT_SCRAP_ERRORS_
  595.         WARN("ODClipboard: ImportContent: Failed with error %ld",ErrorCode());
  596. #endif
  597.         if ( ErrorCode() == memFullErr )
  598.             SetErrorCode(kODErrOutOfMemory);
  599.  
  600.     SOM_ENDTRY
  601.  
  602.     ODDisposeHandle(hData);
  603. }
  604.  
  605. //------------------------------------------------------------------------------
  606. // ODClipboard::PutContentOnPlatformClipboard
  607. //------------------------------------------------------------------------------
  608. //
  609. // Copy values with corresponding platform types onto the desk scrap.
  610. // THROWs an exception if any error occurs, which may cause the desk scrap to
  611. // be only partially updated. The desk scrap requires copying the data in one chunk.
  612.  
  613. SOM_Scope void  SOMLINK ODClipboardPutContentOnPlatformClipboard(ODClipboard *somSelf, Environment *ev)
  614. {
  615.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  616.     ODClipboardMethodDebug("ODClipboard","PutContentOnPlatformClipboard");
  617.     
  618.     ODULong            count;
  619.     ODULong            index;
  620.     ODPlatformType    platformType;
  621.  
  622.     SOM_TRY
  623.         TempSuppressFatalBentoError tempSuppress;
  624.  
  625.         if ( (_fSU == kODNULL) && (_fContainerHandle != kODNULL) )
  626.             OpenClipboard(somSelf, ev);
  627.             
  628.         if ( _fSU )
  629.         {
  630.             _fSU->Focus(ev, kODPropContents, kODPosUndefined, 0, 0, kODPosUndefined);
  631.             count = _fSU->CountValues(ev);
  632.             for (index = 1; index <= count; ++index)
  633.             {
  634.                 _fSU->Focus(ev, kODPropContents, kODPosUndefined, 0, index, kODPosUndefined);
  635.                 TempODType theISOType = _fSU->GetType(ev);
  636.                 platformType = _fSession->GetTranslation(ev)->GetPlatformTypeFromISOType(ev, (ODType) theISOType);
  637.                 if (platformType != (ODPlatformType) kODNULL)
  638.                 {
  639.                     _fSU->Focus(ev, kODPropContents, kODPosUndefined, (ODType) theISOType, 0, kODPosUndefined);
  640.                     Size dataSize = _fSU->GetSize(ev);
  641.  
  642.                     TempODPtr data = kODNULL;
  643.                     data = ODNewPtr(dataSize, kDefaultHeapID);
  644.  
  645.                     StorageUnitGetValue(_fSU, ev, dataSize, (ODValue) data);
  646.     
  647.                     THROW_IF_ERROR(ClipboardPutScrap(dataSize, platformType, data));
  648.  
  649.                     // If styled text ('stxt') was just written to the scrap, also write
  650.                     // 'stly' if a 'TEXT' representation will also be written.
  651.                     if ( platformType == 'stxt' )
  652.                         if ( _fSU->Exists(ev, kODPropContents, kODAppleTEXT, 0) )
  653.                             if ( !_fSU->Exists(ev, kODPropContents, kODApplestyl, 0) )
  654.                                 THROW_IF_ERROR(ExportStylType(data));
  655.                 }
  656.             }
  657.         }
  658.  
  659.     SOM_CATCH_ALL
  660.  
  661.     SOM_ENDTRY
  662. }
  663.  
  664. //------------------------------------------------------------------------------
  665. // ODClipboard::ExportPlatformTypes
  666. //------------------------------------------------------------------------------
  667. //
  668. // Export data of the argument platform types to the host clipboard.
  669. // Since only one ISO type corresponds directly to a platform type (no translation
  670. // is attempted), we just examine each value on the clipboard and check if
  671. // its platform equivalent is present in the argument set.
  672.  
  673.  
  674. SOM_Scope void  SOMLINK ODClipboardExportPlatformTypes(ODClipboard *somSelf, Environment *ev,
  675.     ODPlatformTypeList* typeList)
  676. {
  677.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  678.     ODClipboardMethodDebug("ODClipboard","ExportPlatformTypes");
  679.     
  680.     ODULong    countOfValues;
  681.     ODULong    index;
  682.     ODULong    countToExport;
  683.     
  684.     SOM_TRY
  685.         TempSuppressFatalBentoError tempSuppress;
  686.  
  687.         if ( (_fSU == kODNULL) && (_fContainerHandle != kODNULL) )
  688.             OpenClipboard(somSelf, ev);
  689.             
  690.         if ( _fSU )
  691.         {
  692.             _fSU->Focus(ev, kODPropContents, kODPosUndefined, 0, 0, kODPosUndefined);
  693.             countOfValues = _fSU->CountValues(ev);
  694.             if (typeList != (ODPlatformTypeList*) kODNULL)
  695.                 countToExport = typeList->Count(ev);
  696.             else
  697.                 countToExport = countOfValues;
  698.             
  699.             for (index = 1; (index <= countOfValues) && (countToExport > 0); ++index)
  700.             {
  701.                 _fSU->Focus(ev, kODPropContents, kODPosUndefined, 0, index, kODPosUndefined);
  702.                 TempODType theISOType = _fSU->GetType(ev);
  703.             
  704.                 ODPlatformType platformType = 
  705.                     _fSession->GetTranslation(ev)->GetPlatformTypeFromISOType(ev, (ODType) theISOType);
  706.                 if ( platformType != (ODPlatformType) 0 )
  707.                 {
  708.                     if ((typeList == (ODPlatformTypeList*) kODNULL) || (typeList->Contains(ev, platformType)))
  709.                     {
  710.                         // Put the platform type on the scrap only if its not already there. [cc]
  711.                         long dummy;
  712.                         if ( GetScrap(NULL, platformType, &dummy) == noTypeErr )
  713.                         {
  714.                             _fSU->Focus(ev, kODPropContents, kODPosUndefined, (ODType) theISOType, 0, kODPosUndefined);
  715.                             Size dataSize = _fSU->GetSize(ev);
  716.  
  717.                             TempODPtr data = kODNULL;
  718.                             data = ODNewPtr(dataSize, kDefaultHeapID);
  719.                     
  720.                             StorageUnitGetValue(_fSU, ev, dataSize, (ODValue) data);
  721.                 
  722.                             THROW_IF_ERROR(ClipboardPutScrap(dataSize, platformType, data));
  723.                         }
  724.  
  725.                         if (typeList != (ODPlatformTypeList*) kODNULL)
  726.                             typeList->Remove(ev, platformType);
  727.                         countToExport -= 1;
  728.                     }
  729.                 }
  730.             }
  731.         }
  732.  
  733.     SOM_CATCH_ALL
  734.     
  735.         if ( ErrorCode() == memFullErr )
  736.             SetErrorCode(kODErrOutOfMemory);
  737.  
  738.     SOM_ENDTRY
  739. }
  740.  
  741. //------------------------------------------------------------------------------
  742. // OpenClipboard
  743. //------------------------------------------------------------------------------
  744.  
  745. ODStatic void OpenClipboard(ODClipboard *somSelf, Environment *ev)
  746. {
  747.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  748.  
  749.     ODStorageUnitID    suID;
  750.     
  751.     ODVolatile(somSelf);
  752.     ODVolatile(ev);
  753.  
  754.     TempSuppressFatalBentoError tempSuppress;
  755.  
  756.     if ( _fContainerHandle )
  757.     {
  758.         TRY
  759.             _fContainer = AcquireMemoryContainer(ev, _fSession, _fContainerHandle, kODBentoMemoryContainer);        
  760.             _fDocument = _fContainer->AcquireDocument(ev, kODDefaultDocument);
  761.             _fDraft = _fDocument->AcquireBaseDraft(ev, kODDPExclusiveWrite);
  762.     
  763.             { TempODStorageUnit draftProperties = _fDraft->AcquireDraftProperties(ev);
  764.               suID = ODGetStrongSURefProp(ev, draftProperties, kODPropRootPartSU, kODStrongStorageUnitRef);
  765.             }
  766.     
  767.             _fSU = _fDraft->AcquireStorageUnit(ev, suID);
  768.         CATCH_ALL
  769.             CloseClipboard(somSelf, ev, kODFalse);
  770.             RERAISE;
  771.         ENDTRY
  772.     }
  773. }
  774.  
  775. //------------------------------------------------------------------------------
  776. // ODClipboard::PutClipboardOnPlatformClipboard
  777. //------------------------------------------------------------------------------
  778. //
  779. // This method has the side effect of closing the clipboard container.
  780. // Also note that by externalizing the clipboard draft, all promises are resolved.
  781.  
  782. SOM_Scope void  SOMLINK ODClipboardPutClipboardOnPlatformClipboard(ODClipboard *somSelf, Environment *ev)
  783. {
  784.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  785.     ODClipboardMethodDebug("ODClipboard","PutClipboardOnPlatformClipboard");
  786.  
  787.     SOM_TRY 
  788.  
  789. #if ODDebugClipboard
  790.         long dummy;
  791.         if ( GetScrap(NULL, kODScrapTypeODBentoContainer, &dummy) != noTypeErr )
  792.             PRINT("ODClipboard: PutClipboardOnPlatformClipboard: Clipboard already on scrap!\n");
  793. #endif
  794.  
  795.         TempSuppressFatalBentoError tempSuppress;
  796.  
  797.         // Externalize then close the clipboard container
  798.         CloseClipboard(somSelf, ev, kODTrue);
  799.  
  800.         if ( _fContainerHandle )
  801.         {
  802.             OSErr    error;
  803.             Size    dataSize;
  804.             char    flags;
  805.         
  806.             dataSize = ODGetHandleSize(_fContainerHandle);
  807.  
  808.             THROW_IF_ERROR(UnloadScrapIfMemLow(dataSize));
  809.  
  810.             flags = HGetState((Handle) _fContainerHandle);
  811.             Ptr containerPtr = (Ptr) ODLockHandle(_fContainerHandle);
  812.             error = (OSErr) PutScrap(dataSize, kODScrapTypeODBentoContainer, containerPtr);
  813.             HSetState((Handle) _fContainerHandle, flags);
  814.  
  815. #ifdef _REPORT_SCRAP_ERRORS_
  816.             WASSERTM(error == noErr, "ODClipboard: PutScrap() failed");
  817. #endif
  818.             THROW_IF_ERROR(error);
  819.         }
  820. #ifdef _REPORT_SCRAP_ERRORS_
  821.         else
  822.         {
  823.             // Internal error
  824.             WARN("ODClipboard: PutClipboardOnPlatformClipboard: No Clipboard to export!\n");
  825.         }
  826. #endif
  827.  
  828.     SOM_CATCH_ALL
  829.     
  830. #ifdef _REPORT_SCRAP_ERRORS_
  831.         WARN("ODClipboard: PutClipboardOnPlatformClipboard: Raising exception %d\n", ErrorCode());
  832. #endif
  833.  
  834.     SOM_ENDTRY
  835. }
  836.  
  837. //------------------------------------------------------------------------------
  838. // ODClipboard::ImportClipboard
  839. //------------------------------------------------------------------------------
  840. //
  841. // A bento memory container is always used for data interchange.
  842. // If OpenClipboard throws, its probably because a bad resource of type
  843. // kODScrapTypeODBentoContainer was found on the clipboard (currently error 1012,
  844. // but it may change and there may be others).
  845. // This routine returns:
  846. //        kODFalse, if the platform clipboard does not contain an OpenDoc clipboard;
  847. //        kODTrue, if an OpenDoc clipboard is successfully imported;
  848. //        an exception if an OpenDoc clipboard could not be imported
  849.  
  850. SOM_Scope ODBoolean  SOMLINK ODClipboardImportClipboard(ODClipboard *somSelf, Environment *ev)
  851.     {
  852.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  853.     ODClipboardMethodDebug("ODClipboard","ImportClipboard");
  854.  
  855.     SOM_TRY
  856.     TempSuppressFatalBentoError tempSuppress;
  857.     
  858.     ODHandle    hData = kODNULL;
  859.     Size        dataSize;
  860.     long        dummy;
  861.     
  862.     WASSERTM(_fContainerHandle == (ODHandle) kODNULL, "ODClipboard: fContainerHandle not null");
  863.     WASSERTM(_fContainer == (ODContainer*) kODNULL, "ODClipboard: fContainer not null");
  864.     WASSERTM(_fDocument == (ODDocument*) kODNULL, "ODClipboard: fDocument not null");
  865.     WASSERTM(_fDraft == (ODDraft*) kODNULL, "ODClipboard: fDraft not null");
  866.     WASSERTM(_fSU == (ODStorageUnit*) kODNULL, "ODClipboard: fSU not null");
  867.     
  868.     if ( !ScrapHasType(kODScrapTypeODBentoContainer) )
  869.         return kODFalse;
  870.     
  871.     ODVolatile(hData);
  872.     
  873.     TRY
  874.         hData = ODNewHandle(0);
  875.     
  876.         dataSize = GetScrap((Handle) hData, kODScrapTypeODBentoContainer, &dummy);
  877.         if ( dataSize < 0 )
  878.         {
  879.             if ( dataSize == memFullErr )
  880.                 THROW(kODErrOutOfMemory);
  881.             else
  882.                 THROW(dataSize);
  883.         }
  884.     
  885.         _fContainerHandle = hData;
  886.  
  887.         OpenClipboard(somSelf, ev);
  888.     CATCH_ALL
  889. #ifdef _REPORT_SCRAP_ERRORS_
  890.         WARN("ODClipboard: Cannot import clipboard - error %ld",ErrorCode());
  891. #endif
  892.         _fContainerHandle = kODNULL;
  893.         ODDisposeHandle(hData);
  894.         RERAISE;
  895.     ENDTRY
  896.     
  897.     SOM_CATCH_ALL
  898.     SOM_ENDTRY
  899.     
  900.     return kODTrue;
  901. }
  902.  
  903. //------------------------------------------------------------------------------
  904. // ODClipboard::GetUpdateID
  905. //------------------------------------------------------------------------------
  906.  
  907. SOM_Scope ODUpdateID  SOMLINK ODClipboardGetUpdateID(ODClipboard *somSelf, Environment *ev)
  908. {
  909.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  910.     ODClipboardMethodDebug("ODClipboard","GetUpdateID");
  911.  
  912.     short scrapCount = GetMacScrapCount();
  913.  
  914.     // Unless the scrap is newer than the clipboard, return the "virtual" scrap
  915.     // count (the scrap count when the scrap was imported, or the scrap count
  916.     // after the clipboard was cleared).
  917.     if ( _fScrapCount != scrapCount )
  918.         return scrapCount;
  919.     else
  920.         return _fVirtualScrapCount;
  921. }
  922.  
  923. //------------------------------------------------------------------------------
  924. // ODClipboard::Clear
  925. //------------------------------------------------------------------------------
  926. // This method can only fail if called when the process is in the background.
  927. // Otherwise, its safe to call in a failure handler. [cc]
  928.  
  929. SOM_Scope void  SOMLINK ODClipboardClear(ODClipboard *somSelf, Environment *ev)
  930. {
  931.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  932.     ODClipboardMethodDebug("ODClipboard","Clear");
  933.  
  934.     PRINT_CLIP("ODClipboard::Clear \n");
  935.     
  936.     TempSuppressFatalBentoError tempSuppress;
  937.     
  938.     if ( !IsFrontProcess() )
  939.     {
  940.         ODSetSOMException(ev, kODErrBackgroundClipboardClear);
  941.         return;
  942.     }
  943.     
  944.     // Clear the scrap immediately
  945.     ForceZeroScrap();
  946.     _fScrapCount = _fVirtualScrapCount = GetMacScrapCount();
  947.  
  948. #if ODDebugClipboard
  949.     if ( (_fSU != (ODStorageUnit*) kODNULL) && (_fSU->GetRefCount(ev) != 1) )
  950.         PRINT("ODClipboard::Clear - Storage unit refCount = %d\n", _fSU->GetRefCount(ev));
  951. #endif
  952.     
  953.     somSelf->DiscardClipboard(ev);
  954.     
  955.     PRINT_CLIP("ODClipboard::Clear _fOriginalDraft = kODNULL\n");
  956.     
  957.     _fOriginalDraft = kODNULL;
  958.     _fOriginalCloneKind = kODCloneCopy;
  959.     _fClonePasteCount = 0;
  960. }
  961.  
  962. //------------------------------------------------------------------------------
  963. // ODClipboard::GetContentStorageUnit
  964. //------------------------------------------------------------------------------
  965. //
  966. // If importing from the host clipboard fails, this method returns a new, empty
  967. // storage unit.  No alert is displayed to inform the user.  This method will
  968. // retry importing until Clear() is called.  An exception is returned only if
  969. // an empty clipboard cannot be created.
  970. //
  971. // If this routine is called when the process is in the background, GetScrap()
  972. // will probably return memFullError.  Even if it did return scrap data, the
  973. // data would not be reliable because the forground application might be keeping
  974. // the true clipboard data in a private scrap.  So rather than returning a scrap
  975. // error, just return an empty clipboard.
  976.  
  977. SOM_Scope ODStorageUnit*  SOMLINK ODClipboardGetContentStorageUnit(ODClipboard *somSelf, Environment *ev)
  978. {
  979.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  980.     ODClipboardMethodDebug("ODClipboard","GetContentStorageUnit");
  981.     
  982.     SOM_TRY
  983.     TempSuppressFatalBentoError tempSuppress;
  984.  
  985. #if ODDebugClipboard
  986.     if ( (_fSU != (ODStorageUnit*) kODNULL) && (_fSU->GetRefCount(ev) != 1) )
  987.         PRINT("ODClipboard::GetContentStorageUnit - Storage unit refCount = %d\n", _fSU->GetRefCount(ev));
  988. #endif
  989.  
  990.     short scrapCount = GetMacScrapCount();
  991.     
  992.     if ( _fScrapCount != scrapCount )
  993.     {
  994.         // Import from desk scrap into the OpenDoc clipboard
  995.         PRINT_CLIP("ODClipboard: GetContentStorageUnit: Updating clipboard from scrap\n");
  996.  
  997.         somSelf->DiscardClipboard(ev);
  998.  
  999.         TRY
  1000.             if ( ScrapHasData() )
  1001.             {
  1002.                 if ( !somSelf->ImportClipboard(ev) )
  1003.                 {
  1004.                     somSelf->NewClipboard(ev);
  1005.                     somSelf->ImportContent(ev);
  1006.                 }
  1007.             }
  1008.             else
  1009.             {
  1010.                 somSelf->NewClipboard(ev);
  1011.             }
  1012.             _fScrapCount = _fVirtualScrapCount = _fLastSynchronizedScrapCount = scrapCount;
  1013.         CATCH_ALL
  1014. #ifdef _REPORT_SCRAP_ERRORS_
  1015.             if ( IsFrontProcess() )
  1016.                 WARN("ODClipboard: GetContentStorageUnit: Importing from desk scrap raised exception %d\n", ErrorCode());
  1017. #endif
  1018.             // Importing an OpenDoc clipboard, content, or NewClibpard failed;
  1019.             // just create a new, empty clipboard.  Do not update fScrapCount,
  1020.             // so we will try re-importing again if this clipboard isn't changed. [cc]
  1021.             somSelf->DiscardClipboard(ev);
  1022.             somSelf->NewClipboard(ev);
  1023.         ENDTRY
  1024.         _fOriginalDraft = kODNULL;
  1025.         _fOriginalCloneKind = kODCloneCopy;
  1026.         _fClonePasteCount = 0;
  1027.     }
  1028.     else if ( _fContainerHandle == (ODHandle) kODNULL )
  1029.     {
  1030.         // Open a new clipboard container if a container handle doesn't exist
  1031.         // This case can only happen after an error or after Clear() is called
  1032.         somSelf->NewClipboard(ev);
  1033.         _fOriginalDraft = kODNULL;
  1034.         _fOriginalCloneKind = kODCloneCopy;
  1035.         _fClonePasteCount = 0;
  1036.     }
  1037.     else
  1038.     {
  1039.         // reopen the container handle if necessary.
  1040.         if ( _fContainer == kODNULL )
  1041.             OpenClipboard(somSelf, ev);
  1042.         if ( _fOriginalDraft == kODNULL )
  1043.             _fOriginalDraft = GetOriginalDraft(ev, _fDraft);
  1044.     }
  1045.     
  1046.     SOM_CATCH_ALL
  1047. #ifdef _REPORT_SCRAP_ERRORS_
  1048.         WARN("ODClipboard: GetContentStorageUnit: Raising exception %d\n", ErrorCode());
  1049. #endif
  1050.     SOM_ENDTRY
  1051.  
  1052.     return _fSU;
  1053. }
  1054.  
  1055. //------------------------------------------------------------------------------
  1056. // ODClipboard::ActionDone
  1057. //------------------------------------------------------------------------------
  1058.  
  1059. SOM_Scope ODUpdateID  SOMLINK ODClipboardActionDone(ODClipboard *somSelf, Environment *ev,
  1060.     ODCloneKind cloneKind)
  1061. {
  1062.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  1063.     ODClipboardMethodDebug("ODClipboard","ActionDone");
  1064.  
  1065.     ODUpdateID update = kODUnknownUpdate;
  1066.     
  1067.     SOM_TRY
  1068.         TempSuppressFatalBentoError tempSuppress;
  1069.  
  1070.         // Note that if the clipboard is changed by one OpenDoc document,
  1071.         // and used (via Paste) in another, the sequence of undo, redo, 
  1072.         // and paste actions is separate in each document. That is, the
  1073.         // first document is unaware of the Paste in the second document.
  1074.         // This isn't semantically correct, but doesn't cause errors [cc].
  1075.  
  1076.         if ( (cloneKind == kODCloneCut) || (cloneKind == kODCloneCopy) )
  1077.         {
  1078.             _fOriginalCloneKind = cloneKind;
  1079.             _fClonePasteCount = 0;
  1080.         }
  1081.         else if ( cloneKind == kODClonePaste )
  1082.         {
  1083.             _fClonePasteCount += 1;
  1084.         }
  1085.         else
  1086.             THROW(kODErrIllegalClipboardCloneKind);
  1087.  
  1088.         update = somSelf->GetUpdateID(ev);
  1089.     
  1090.     SOM_CATCH_ALL
  1091.     
  1092.     SOM_ENDTRY
  1093.     
  1094.     return update;
  1095. }
  1096.  
  1097. //------------------------------------------------------------------------------
  1098. // ODClipboard::ActionUndone
  1099. //------------------------------------------------------------------------------
  1100.  
  1101. SOM_Scope void  SOMLINK ODClipboardActionUndone(ODClipboard *somSelf, Environment *ev,
  1102.     ODUpdateID update,
  1103.     ODCloneKind originalCloneKind)
  1104. {
  1105.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  1106.     ODClipboardMethodDebug("ODClipboard","ActionUndone");
  1107.  
  1108.     SOM_TRY
  1109.         TempSuppressFatalBentoError tempSuppress;
  1110.  
  1111.         if ( update == somSelf->GetUpdateID(ev) )
  1112.         {
  1113.             if ( originalCloneKind == kODCloneCut )
  1114.             {
  1115.                 SetOriginalCloneKind(ev, _fDraft, kODCloneCopy);
  1116.             }
  1117.             else if ( originalCloneKind == kODClonePaste )
  1118.             {
  1119.                 _fClonePasteCount -= 1;
  1120.                 if ( (_fClonePasteCount == 0) && (_fOriginalCloneKind == kODCloneCut) )
  1121.                     SetOriginalCloneKind(ev, _fDraft, kODCloneCut);
  1122.             }
  1123.             else if ( originalCloneKind != kODCloneCopy )
  1124.                 THROW(kODErrIllegalClipboardCloneKind);
  1125.         }
  1126.  
  1127.     SOM_CATCH_ALL
  1128.     
  1129.     SOM_ENDTRY
  1130. }
  1131.  
  1132. //------------------------------------------------------------------------------
  1133. // ODClipboard::ActionRedone
  1134. //------------------------------------------------------------------------------
  1135.  
  1136. SOM_Scope void  SOMLINK ODClipboardActionRedone(ODClipboard *somSelf, Environment *ev,
  1137.     ODUpdateID update,
  1138.     ODCloneKind originalCloneKind)
  1139. {
  1140.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  1141.     ODClipboardMethodDebug("ODClipboard","ActionRedone");
  1142.  
  1143.     SOM_TRY
  1144.         TempSuppressFatalBentoError tempSuppress;
  1145.  
  1146.         if ( update == somSelf->GetUpdateID(ev) )
  1147.         {
  1148.             if ( originalCloneKind == kODCloneCut )
  1149.             {
  1150.                 SetOriginalCloneKind(ev, _fDraft, kODCloneCut);
  1151.             }
  1152.             else if ( originalCloneKind == kODClonePaste )
  1153.             {
  1154.                 _fClonePasteCount += 1;
  1155.                 if ( (_fClonePasteCount == 1) )
  1156.                     SetOriginalCloneKind(ev, _fDraft, kODCloneCopy);
  1157.             }
  1158.             else if ( originalCloneKind != kODCloneCopy )
  1159.                 THROW(kODErrIllegalClipboardCloneKind);
  1160.         }
  1161.  
  1162.     SOM_CATCH_ALL
  1163.     
  1164.     SOM_ENDTRY
  1165. }
  1166.  
  1167. //------------------------------------------------------------------------------
  1168. // ODClipboard::SetPlatformClipboard
  1169. //------------------------------------------------------------------------------
  1170.  
  1171. SOM_Scope void  SOMLINK ODClipboardSetPlatformClipboard(ODClipboard *somSelf, Environment *ev,
  1172.     ODPlatformTypeList* typeList)
  1173. {
  1174.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  1175.     ODClipboardMethodDebug("ODClipboard","SetPlatformClipboard");
  1176.     
  1177.     ODPlatformTypeList* requestedTypes = (ODPlatformTypeList*) kODNULL;
  1178.     ODVolatile(requestedTypes);
  1179.     
  1180.     TempSuppressFatalBentoError tempSuppress;
  1181.     
  1182.     short scrapCount = GetMacScrapCount();
  1183.  
  1184.     if ( (_fScrapCount == scrapCount) && (scrapCount != _fLastSynchronizedScrapCount)  )
  1185.     {
  1186.         SOM_TRY
  1187.         
  1188.             if ( _fSU != (ODStorageUnit*) kODNULL )
  1189.             {
  1190.                 if ( typeList )
  1191.                     requestedTypes = _fSession->GetStorageSystem(ev)->CreatePlatformTypeList(ev, typeList);
  1192.  
  1193.                 somSelf->ExportPlatformTypes(ev, requestedTypes);
  1194.             }
  1195.  
  1196.         SOM_CATCH_ALL
  1197.         
  1198.         SOM_ENDTRY
  1199.  
  1200.         if ( requestedTypes )
  1201.             delete requestedTypes;
  1202.     }
  1203. }
  1204.  
  1205. //------------------------------------------------------------------------------
  1206. // ODClipboard::ExportClipboard
  1207. //------------------------------------------------------------------------------
  1208. //
  1209. // Returns a SOM exception if setting the platform clipboard fails.
  1210. // Unfortunately, until the clipboard container is closed its size isn't known.
  1211.  
  1212. SOM_Scope void  SOMLINK ODClipboardExportClipboard(ODClipboard *somSelf, Environment *ev)
  1213. {
  1214.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  1215.     ODClipboardMethodDebug("ODClipboard","ExportClipboard");
  1216.         
  1217.     SOM_TRY 
  1218.         TempSuppressFatalBentoError tempSuppress;
  1219.     
  1220.         short scrapCount = GetMacScrapCount();
  1221.         
  1222. #if ODDebugClipboard
  1223.         PRINT("ODClipboard::ExportClipboard called\n");
  1224.         if ( _fScrapCount == scrapCount )
  1225.         {
  1226.             PRINT("ExportClipboard: OpenDoc clipboard is current\n");
  1227.             if ( scrapCount != _fLastSynchronizedScrapCount )
  1228.                 PRINT("ExportClipboard: Scrap is obsolete\n");
  1229.             else if ( _fExportedLinkSpec && _fSU && !_fSU->Exists(ev, kODPropLinkSpec, kODNULL, 0) )
  1230.                 PRINT("ExportClipboard: Scrap should be re-written to remove link spec\n");
  1231.             else
  1232.                 PRINT("ExportClipboard: Scrap is current\n");
  1233.         }
  1234. #endif
  1235.     
  1236.         ODBoolean needToExport = kODFalse;
  1237.         ODBoolean needToExportToRemoveLinkSpec = kODFalse;
  1238.         if ( _fScrapCount == scrapCount )
  1239.         {
  1240.             if ( scrapCount != _fLastSynchronizedScrapCount )
  1241.             {
  1242.                 needToExport = kODTrue;
  1243.                 _fExportedLinkSpec = _fSU && _fSU->Exists(ev, kODPropLinkSpec, kODNULL, 0);
  1244.             }
  1245.             else if ( _fExportedLinkSpec )
  1246.             {
  1247.                 needToExportToRemoveLinkSpec = _fSU && !_fSU->Exists(ev, kODPropLinkSpec, kODNULL, 0);
  1248.             }
  1249.         }
  1250.     
  1251.         // Immediately after changing the clipboard, _fOriginalDraft won't be set correctly
  1252.         // because the clipboard is not informed when a part is finished writing. [cc]
  1253.         if ( needToExport && (_fOriginalDraft == kODNULL) )
  1254.         {
  1255.             ASSERT(_fDraft != kODNULL, kODErrAssertionFailed);
  1256.             _fOriginalDraft = GetOriginalDraft(ev, _fDraft);
  1257.             WASSERTM(_fOriginalDraft != kODNULL, "Last clipboard change did not clone");
  1258.         }
  1259.     
  1260.         if ( needToExport || needToExportToRemoveLinkSpec )
  1261.         {
  1262.             // Optimistically load the scrap into memory if it was unloaded
  1263.             LoadScrap();
  1264.     
  1265.             TRY
  1266.                 if ( !needToExport )
  1267.                 {
  1268.                     // The clipboard has been exported once already.  We need to
  1269.                     // call ZeroScrap so the clipboard can be written again.
  1270.                     ForceZeroScrap();
  1271.                     _fScrapCount = GetMacScrapCount();
  1272.                 }
  1273.                 
  1274.                 somSelf->PutContentOnPlatformClipboard(ev);
  1275.                 somSelf->PutClipboardOnPlatformClipboard(ev);
  1276.                 
  1277.                 _fLastSynchronizedScrapCount = GetMacScrapCount();
  1278.             CATCH_ALL
  1279.                 // If writing the scrap fails, clear the scrap. [cc]
  1280.                 ForceZeroScrap();
  1281.                 _fScrapCount = GetMacScrapCount();
  1282.  
  1283. #ifdef _REPORT_SCRAP_ERRORS_
  1284.                 PRINT("ODClipboard::ExportClipboard failed; clearing scrap\n");
  1285. #endif
  1286.                 RERAISE;
  1287.             ENDTRY
  1288.  
  1289.             PRINT_CLIP("ODClipboard::ExportClipboard updated the scrap, size is %ld\n", InfoScrap()->scrapSize);
  1290.         }
  1291.     
  1292.         // Exporting was successful
  1293.         if ( needToExportToRemoveLinkSpec )
  1294.             _fExportedLinkSpec = kODFalse;
  1295.  
  1296.     SOM_CATCH_ALL
  1297.         PRINT_CLIP("ODClipboard::ExportClipboard failed!\n");
  1298.     SOM_ENDTRY
  1299.     
  1300.     PRINT_CLIP("ODClipboard::ExportClipboard done, fExportedLinkSpec = %d\n", _fExportedLinkSpec);
  1301. }
  1302.  
  1303. //------------------------------------------------------------------------------
  1304. // ODClipboard::DraftClosing
  1305. //------------------------------------------------------------------------------
  1306. //
  1307. // Forces resolution of promises, and prevents moving content across draft closings
  1308. // via the clipboard. In order to work correctly, parts MUST use BeginClone-EndClone
  1309. // when writing to the clipboard.
  1310.  
  1311. SOM_Scope void  SOMLINK ODClipboardDraftClosing(ODClipboard *somSelf, Environment *ev,
  1312.         ODDraft* draft)
  1313. {
  1314.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  1315.     ODClipboardMethodDebug("ODClipboard","DraftClosing");
  1316.  
  1317.     PRINT_CLIP("ODClipboard::DraftClosing called, draft is %x\n", draft);
  1318.  
  1319.     SOM_TRY
  1320.     TempSuppressFatalBentoError tempSuppress;
  1321.  
  1322.     if ( draft )
  1323.     {
  1324.         // Immediately after changing the clipboard, _fOriginalDraft won't be set correctly
  1325.         // because the clipboard is not informed when a part is finished writing.
  1326.     
  1327.         short scrapCount = GetMacScrapCount();
  1328.         ODBoolean needToExport = (_fScrapCount == scrapCount) && (scrapCount != _fLastSynchronizedScrapCount);
  1329.         if ( needToExport && (_fOriginalDraft == kODNULL) )
  1330.         {
  1331.             ASSERT(_fDraft != kODNULL, kODErrAssertionFailed);
  1332.             _fOriginalDraft = GetOriginalDraft(ev, _fDraft);
  1333.             WASSERTM(_fOriginalDraft != kODNULL, "Last clipboard change did not clone");
  1334.         }
  1335.     
  1336.         PRINT_CLIP("Last draft to change clipboard is %x\n", _fOriginalDraft);
  1337.  
  1338.         if ( _fOriginalDraft == draft )
  1339.         {
  1340.             // Last draft that wrote the clipboard is being closed.
  1341.  
  1342.             PRINT_CLIP("ODClipboard::Draft that last wrote clipboard is closing\n", draft);
  1343.             if ( needToExport ) { PRINT_CLIP("ODClipboard::Clipboard needs exporting\n"); }
  1344.  
  1345.             // If the clipboard container is open, force resolution of promises 
  1346.             // by externalizing the clipboard draft. (If there are unresolved promises, 
  1347.             // the clipboard hasn't be exported yet). Otherwise open the container.
  1348.  
  1349.             if ( _fContainer )
  1350.                 _fDraft->Externalize(ev);
  1351.             else
  1352.                 OpenClipboard(somSelf, ev);
  1353.  
  1354.             // Remove a link spec if present
  1355.             ODSURemoveProperty(ev, _fSU, kODPropLinkSpec);
  1356.  
  1357.             // Check to see if content was cut (not copied) to the clipboard.
  1358.             // If so, change the original clone kind to copy, so any future
  1359.             // paste won't be treated as a move.
  1360.                         
  1361.             if ( GetOriginalCloneKind(ev, _fDraft) == kODCloneCut )
  1362.             {
  1363.                 SetOriginalCloneKind(ev, _fDraft, kODCloneCopy);
  1364.                 
  1365.                 // If the clipboard has already been exported, we can clear the
  1366.                 // scrap now and force exporting again. [cc]
  1367.                 ForceZeroScrap();
  1368.                 _fScrapCount = GetMacScrapCount();
  1369.             }
  1370.  
  1371.             _fOriginalDraft = kODNULL;
  1372.         }
  1373.     }
  1374.     
  1375.     SOM_CATCH_ALL
  1376.     SOM_ENDTRY
  1377. }
  1378.  
  1379. //------------------------------------------------------------------------------
  1380. // ODClipboard::DraftSaved
  1381. //------------------------------------------------------------------------------
  1382. //
  1383.  
  1384. SOM_Scope void  SOMLINK ODClipboardDraftSaved(ODClipboard *somSelf, Environment *ev,
  1385.         ODDraft* draft)
  1386. {
  1387.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  1388.     ODClipboardMethodDebug("ODClipboard","DraftSaved");
  1389.  
  1390.     PRINT_CLIP("ODClipboard::DraftSaved called, draft %08x, orig %08x, fDraft %08x\n", 
  1391.         (long) draft, (long) _fOriginalDraft, (long) _fDraft);
  1392.  
  1393.     SOM_TRY
  1394.     TempSuppressFatalBentoError tempSuppress;
  1395.     
  1396.     if ( draft )
  1397.     {
  1398.         if ( _fOriginalDraft == kODNULL )
  1399.         {
  1400.             if (_fDraft != kODNULL)        // can be null if never accessed
  1401.                 _fOriginalDraft = GetOriginalDraft(ev, _fDraft);
  1402.             PRINT_CLIP("    ODClipboard::DraftSaved orig %08x\n", (long) _fOriginalDraft);
  1403.         }
  1404.  
  1405.         if ( _fOriginalDraft == draft && _fDraft )
  1406.         {
  1407.             // Check to see if content was cut (not copied) to the clipboard.
  1408.             // If so, change the original clone kind to copy, so any future
  1409.             // paste won't be treated as a move.
  1410.  
  1411.             PRINT_CLIP("        ODClipboard::DraftSaved try cut -> copy\n");
  1412.                         
  1413.             if ( GetOriginalCloneKind(ev, _fDraft) == kODCloneCut )
  1414.             {
  1415.                 SetOriginalCloneKind(ev, _fDraft, kODCloneCopy);
  1416.                 PRINT_CLIP("            ODClipboard::DraftSaved perform cut -> copy\n");
  1417.             }
  1418.         }
  1419.     }
  1420.     
  1421.     SOM_CATCH_ALL
  1422.     SOM_ENDTRY
  1423. }
  1424.  
  1425. //------------------------------------------------------------------------------
  1426. // ODClipboard::ShowPasteAsDialog
  1427. //------------------------------------------------------------------------------
  1428.  
  1429. SOM_Scope ODBoolean  SOMLINK ODClipboardShowPasteAsDialog(ODClipboard *somSelf, Environment *ev,
  1430.         ODBoolean canPasteLink,
  1431.         ODPasteAsMergeSetting mergeSetting,
  1432.         ODFacet* facet,
  1433.         ODTypeToken viewType,
  1434.         ODPasteAsResult* result)
  1435. {
  1436.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  1437.     ODClipboardMethodDebug("ODClipboard","ShowPasteAsDialog");
  1438.  
  1439.     ODBoolean returnValue = kODFalse;
  1440.  
  1441.     SOM_TRY
  1442.     TempSuppressFatalBentoError tempSuppress;
  1443.  
  1444.     THROW_IF_NULL(facet, kODErrNullFacetInput);
  1445.     THROW_IF_NULL(result, kODErrNullPasteAsResultInput);
  1446.  
  1447.     ODTypeToken modalFocus = _fSession->Tokenize(ev, kODModalFocus);
  1448.     ODArbitrator* arbitrator = _fSession->GetArbitrator(ev);
  1449.     TempODFrame currentOwner = arbitrator->AcquireFocusOwner(ev, modalFocus);
  1450.  
  1451.     if ( arbitrator->RequestFocus(ev, modalFocus, facet->GetFrame(ev)) )
  1452.     {
  1453.         ODStorageUnit* clipContentSU = somSelf->GetContentStorageUnit(ev);
  1454.     
  1455.         ODBoolean isMove = (GetOriginalCloneKind(ev, clipContentSU->GetDraft(ev)) == kODCloneCut);
  1456.  
  1457.         returnValue = ShowPasteAsDialog(
  1458.                                 canPasteLink, 
  1459.                                 mergeSetting,
  1460.                                 isMove,
  1461.                                 clipContentSU,
  1462.                                 facet, 
  1463.                                 viewType, 
  1464.                                 result);
  1465.  
  1466.         arbitrator->TransferFocus(ev, modalFocus, facet->GetFrame(ev), currentOwner);
  1467.     }
  1468.     else
  1469.     {
  1470.         SysBeep(2);
  1471.     }
  1472.     
  1473.     SOM_CATCH_ALL
  1474.     SOM_ENDTRY
  1475.  
  1476.     return returnValue;
  1477. }
  1478.  
  1479. //==============================================================================
  1480. // Local Functions
  1481. //==============================================================================
  1482.  
  1483. //------------------------------------------------------------------------------
  1484. // GetMacScrapCount
  1485. //------------------------------------------------------------------------------
  1486. //
  1487. // This function returns the identification stamp of the last mac scrap change,
  1488. // NOT the count of items on the scrap!
  1489.  
  1490. ODStatic short GetMacScrapCount()
  1491. {
  1492.     return InfoScrap()->scrapCount;
  1493. }
  1494.  
  1495. //------------------------------------------------------------------------------
  1496. // IsFrontProcess
  1497. //------------------------------------------------------------------------------
  1498.  
  1499. ODStatic ODBoolean IsFrontProcess()
  1500. {
  1501.     ProcessSerialNumber psnFront, psnMine;
  1502.     ODBoolean frontmost;
  1503.  
  1504.     GetFrontProcess(&psnFront);
  1505.     GetCurrentProcess(&psnMine);
  1506.     SameProcess(&psnFront, &psnMine, &frontmost);
  1507.  
  1508.     return frontmost;
  1509. }
  1510.  
  1511. //------------------------------------------------------------------------------
  1512. // ImportStyledTextType
  1513. //------------------------------------------------------------------------------
  1514.  
  1515. ODStatic void ImportStyledTextType(ODClipboard *somSelf, Environment *ev)
  1516. {
  1517.     ODClipboardData *somThis = ODClipboardGetData(somSelf);
  1518.  
  1519.     ODHandle    hndl = kODNULL;
  1520.     ODValue        value;
  1521.     long        dummy;
  1522.  
  1523.     ODVolatile(hndl);
  1524.  
  1525.     SOM_TRY
  1526.     TempSuppressFatalBentoError tempSuppress;
  1527.     
  1528.     // Make sure both 'TEXT' and 'styl' are present
  1529.     ODULong sizeText = GetScrap(nil, 'TEXT', &dummy);
  1530.     ODULong sizeStyl = GetScrap(nil, 'styl', &dummy);
  1531.     
  1532.     if ( (sizeText < 0) || (sizeStyl < 0) )
  1533.         return;
  1534.  
  1535.     if ( ODSUExistsThenFocus(ev, _fSU, kODPropContents, kODApplestxt) )
  1536.     {
  1537. #ifdef _REPORT_SCRAP_ERRORS_
  1538.         WARN("ODClipboard: Replacing value on clipboard");
  1539. #endif
  1540.         _fSU->Remove(ev);
  1541.     }
  1542.     
  1543.     ODSUForceFocus(ev, _fSU, kODPropContents, kODApplestxt);
  1544.  
  1545.     hndl = ODNewHandle(sizeStyl);
  1546.     
  1547.     sizeStyl = GetScrap((Handle) hndl, 'styl', &dummy);
  1548.     if ( sizeStyl < 0 )
  1549.         THROW(sizeStyl);
  1550.  
  1551.     value = (ODValue) ODLockHandle(hndl);
  1552.     StorageUnitSetValue(_fSU, ev, sizeStyl, value);
  1553.     ODUnlockHandle(hndl);
  1554.     ODDisposeHandle(hndl);
  1555.     hndl = kODNULL;
  1556.  
  1557.     hndl = ODNewHandle(sizeText);
  1558.  
  1559.     sizeText = GetScrap((Handle) hndl, 'TEXT', &dummy);
  1560.     if ( sizeText < 0 )
  1561.         THROW(sizeText);
  1562.     
  1563.     value = (ODValue) ODLockHandle(hndl);
  1564.     StorageUnitSetValue(_fSU, ev, sizeText, value);
  1565.  
  1566.     SOM_CATCH_ALL
  1567.         if ( ODSUExistsThenFocus(ev, _fSU, kODPropContents, kODApplestxt) )
  1568.             _fSU->Remove(ev);
  1569.     SOM_ENDTRY
  1570.     
  1571.     ODDisposeHandle(hndl);
  1572. }
  1573.  
  1574. //------------------------------------------------------------------------------
  1575. // ExportStylType
  1576. //------------------------------------------------------------------------------
  1577. //
  1578. // Argument is a pointer to styled text, with begins with a style record.
  1579.  
  1580. ODStatic OSErr ExportStylType(ODPtr    stxtData)
  1581. {
  1582.     Size stylSize = *((short *) stxtData);
  1583.     stylSize = (stylSize * sizeof(ScrpSTElement)) + sizeof(short);
  1584.     
  1585.     return ClipboardPutScrap(stylSize, 'styl', stxtData);
  1586. }
  1587.  
  1588. //------------------------------------------------------------------------------
  1589. // ScrapIsInconsistent
  1590. //------------------------------------------------------------------------------
  1591.  
  1592. ODStatic ODBoolean ScrapIsInconsistent()
  1593. {
  1594.     // Return false if the scrap in an inconsistent state and thus cannot
  1595.     // be read. [cc]
  1596.  
  1597. #if ODDebugClipboard
  1598.     if ( (InfoScrap()->scrapState > 0) && (InfoScrap()->scrapHandle == nil) )
  1599.         PRINT("ODClipboard: Scrap is inconsistent!\n");
  1600. #endif
  1601.  
  1602.     return  ((InfoScrap()->scrapState > 0) && (InfoScrap()->scrapHandle == nil));
  1603.     
  1604. }    
  1605.  
  1606. //------------------------------------------------------------------------------
  1607. // ScrapHasData
  1608. //------------------------------------------------------------------------------
  1609.  
  1610. ODStatic ODBoolean ScrapHasData()
  1611. {
  1612.     // Return true if the scrap size is greater than zero and the scrap is 
  1613.     // in a consistent state. [cc]
  1614.  
  1615.     return ((InfoScrap()->scrapSize > 0) && (!ScrapIsInconsistent()));
  1616. }    
  1617.  
  1618. //------------------------------------------------------------------------------
  1619. // ScrapHasType
  1620. //------------------------------------------------------------------------------
  1621.  
  1622. ODStatic ODBoolean ScrapHasType(ODPlatformType type)
  1623. {
  1624.     long        dummy;
  1625.     Size        dataSize;
  1626.     ODBoolean    result = kODFalse;
  1627.  
  1628.     if ( ScrapHasData() )
  1629.     {
  1630.         dataSize = GetScrap(nil, type, &dummy);
  1631.         if ( dataSize >= 0 )
  1632.             result = kODTrue;
  1633. #ifdef _REPORT_SCRAP_ERRORS_
  1634.         else
  1635.         {
  1636.             if (dataSize != noTypeErr )
  1637.                 WARN("ODClipboard: ScrapHasType: GetScrap() returned error %ld, type = %.4s", dataSize, &type);
  1638.         }
  1639. #endif
  1640.     }
  1641.     
  1642.     return result;
  1643. }
  1644.  
  1645. //------------------------------------------------------------------------------
  1646. // ForceZeroScrap
  1647. //------------------------------------------------------------------------------
  1648.  
  1649. ODStatic void ForceZeroScrap()
  1650. {
  1651.     OSErr err = ZeroScrap();
  1652.     if ( err == nilHandleErr )
  1653.     {
  1654. #ifdef _REPORT_SCRAP_ERRORS_
  1655.         PRINT("ODClipboard: ZeroScrap returned error -109\n");
  1656. #endif
  1657.         // According to Dylan Ashe, if the scrap is inconsistent the best thing to
  1658.         // do is force re-initiaization of the scrap.  Use of this constant to
  1659.         // force re-initiaization will continue to work in MacOS8. [cc]
  1660.         InfoScrap()->scrapState = kUninitializedScrap;
  1661.         ZeroScrap();
  1662.         PRINT_CLIP("ODClipboard: Scrap re-initialized, scrap count is %d\n", GetMacScrapCount());
  1663.     }
  1664. }
  1665.  
  1666. //------------------------------------------------------------------------------
  1667. // ScrapMemoryAvailable
  1668. //------------------------------------------------------------------------------
  1669. //
  1670. // This function ensures than allocating dataSize bytes would still leave
  1671. // a 40K contiguous block free, as recommended by Inside Mac, Memory, 1-43. [cc]
  1672.  
  1673. ODStatic ODBoolean ScrapMemoryAvailable(Size dataSize)
  1674. {
  1675.     const Size kMemCushion = 40*1024;
  1676.     
  1677.     Size totalFree;
  1678.     Size contigFree;
  1679.     
  1680.     PurgeSpace(&totalFree, &contigFree);
  1681.     
  1682.     PRINT_CLIP("Request %ld bytes with %ld available\n", dataSize, contigFree);
  1683.  
  1684.     return (dataSize + kMemCushion) < contigFree;
  1685. }
  1686.  
  1687. //------------------------------------------------------------------------------
  1688. // UnloadScrapIfMemLow
  1689. //------------------------------------------------------------------------------
  1690.  
  1691. ODStatic OSErr UnloadScrapIfMemLow(Size dataSize)
  1692. {
  1693.     OSErr unloadError = noErr;
  1694.     
  1695.     if ( InfoScrap()->scrapState != kScrapOnDisk )
  1696.     {
  1697.         if ( !ScrapMemoryAvailable(dataSize) )
  1698.         {
  1699.             unloadError = UnloadScrap();
  1700.             PRINT_CLIP("ODClipboard: Scrap unloaded with error %d\n", unloadError);
  1701.         }
  1702.     }
  1703.  
  1704.     return unloadError;
  1705. }
  1706.  
  1707. //------------------------------------------------------------------------------
  1708. // ClipboardLoadScrap
  1709. //------------------------------------------------------------------------------
  1710.  
  1711. ODStatic OSErr ClipboardLoadScrap()
  1712. {
  1713.     OSErr loadError = noErr;
  1714.     
  1715.     if ( InfoScrap()->scrapState == kScrapOnDisk )
  1716.     {
  1717.         if ( ScrapMemoryAvailable(InfoScrap()->scrapSize) )
  1718.         {
  1719.             loadError = LoadScrap();
  1720.             PRINT_CLIP("ODClipboard: Scrap loaded with error %d\n", loadError);
  1721.         }
  1722.         else
  1723.         {
  1724.             loadError = kODErrOutOfMemory;
  1725.         }
  1726.     }
  1727.  
  1728.     return loadError;
  1729. }
  1730.  
  1731. //------------------------------------------------------------------------------
  1732. // ClipboardPutScrap
  1733. //------------------------------------------------------------------------------
  1734.  
  1735. ODStatic OSErr ClipboardPutScrap(Size dataSize, ODPlatformType    platformType, ODPtr data)
  1736. {
  1737.     OSErr error = UnloadScrapIfMemLow(dataSize);
  1738.     
  1739.     if ( error == noErr )
  1740.     {
  1741.         error = (OSErr) PutScrap(dataSize, platformType, data);
  1742.  
  1743. #ifdef _REPORT_SCRAP_ERRORS_
  1744.         WASSERTM(error == noErr, "ODClipboard: PutScrap() failed");
  1745. #endif
  1746.     }
  1747.  
  1748.     return error;
  1749. }
  1750.