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