diff --git a/widget/src/mac/nsAppShell.cpp b/widget/src/mac/nsAppShell.cpp index 251e2d21eafc..7c2bfd726077 100644 --- a/widget/src/mac/nsAppShell.cpp +++ b/widget/src/mac/nsAppShell.cpp @@ -84,6 +84,15 @@ NS_IMETHODIMP nsAppShell::Create(int* argc, char ** argv) mMacSink = auto_ptr( new nsMacMessageSink() ); nsIToolkit* toolkit = mToolkit.get(); mMacPump = auto_ptr( new nsMacMessagePump(static_cast(toolkit), mMacSink.get()) ); + mMacMemoryCushion = auto_ptr( new nsMacMemoryCushion() ); + + if (!mMacSink.get() || !mMacPump.get() || !mMacMemoryCushion.get()) + return NS_ERROR_OUT_OF_MEMORY; + + OSErr err = mMacMemoryCushion->Init(nsMacMemoryCushion::kMemoryReserveSize); + if (err != noErr) + return NS_ERROR_FAILURE; + return NS_OK; } @@ -97,6 +106,7 @@ NS_IMETHODIMP nsAppShell::Run(void) if (!mMacPump.get()) return NS_ERROR_NOT_INITIALIZED; + mMacMemoryCushion->StartRepeating(); mMacPump->StartRunning(); mMacPump->DoMessagePump(); diff --git a/widget/src/mac/nsAppShell.h b/widget/src/mac/nsAppShell.h index 8b0140437eab..21918a8930fd 100644 --- a/widget/src/mac/nsAppShell.h +++ b/widget/src/mac/nsAppShell.h @@ -41,6 +41,7 @@ using std::auto_ptr; class nsMacMessagePump; class nsMacMessageSink; +class nsMacMemoryCushion; class nsIToolkit; @@ -57,7 +58,8 @@ class nsAppShell : public nsIAppShell nsDispatchListener *mDispatchListener; // note: we don't own this, but it can be NULL nsCOMPtr mToolkit; auto_ptr mMacPump; - auto_ptr mMacSink; //€€€ this will be COM, so use scc's COM_auto_ptr + auto_ptr mMacSink; // this will be COM, so use scc's COM_auto_ptr + auto_ptr mMacMemoryCushion; PRBool mExitCalled; static PRBool mInitializedToolbox; }; diff --git a/widget/src/mac/nsToolkit.cpp b/widget/src/mac/nsToolkit.cpp index e824e742c75e..78b0ce15863f 100644 --- a/widget/src/mac/nsToolkit.cpp +++ b/widget/src/mac/nsToolkit.cpp @@ -30,7 +30,8 @@ #include "nsIEventQueue.h" #include "nsIEventQueueService.h" #include "nsIServiceManager.h" - +#include "nsIImageManager.h" +#include "nsGfxCIID.h" //#define MAC_PL_EVENT_TWEAKING @@ -38,6 +39,7 @@ static NS_DEFINE_CID(kEventQueueCID, NS_EVENTQUEUE_CID); static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); +static NS_DEFINE_IID(kImageManagerCID, NS_IMAGEMANAGER_CID); static nsMacNSPREventQueueHandler* gEventQueueHandler = nsnull; @@ -285,3 +287,70 @@ NS_METHOD NS_GetCurrentToolkit(nsIToolkit* *aResult) return rv; } +#pragma mark - + +Handle nsMacMemoryCushion::sMemoryReserve; + +nsMacMemoryCushion::nsMacMemoryCushion() +{ +} + +nsMacMemoryCushion::~nsMacMemoryCushion() +{ + ::SetGrowZone(nsnull); + if (sMemoryReserve) + ::DisposeHandle(sMemoryReserve); +} + + +OSErr nsMacMemoryCushion::Init(Size reserveSize) +{ + sMemoryReserve = ::NewHandle(reserveSize); + if (sMemoryReserve == nsnull) + return ::MemError(); + + ::SetGrowZone(NewGrowZoneProc(GrowZoneProc)); + return noErr; +} + + +void nsMacMemoryCushion::RepeatAction(const EventRecord &aMacEvent) +{ + if (!RecoverMemoryReserve(kMemoryReserveSize)) + { + nsMemory::HeapMinimize(); + + // until imglib implements nsIMemoryPressureObserver (bug 46337) + // manually flush the imglib cache here + nsCOMPtr imageManager = do_GetService(kImageManagerCID); + if (imageManager) + { + imageManager->FlushCache(); + } + } +} + + +Boolean nsMacMemoryCushion::RecoverMemoryReserve(Size reserveSize) +{ + if (!sMemoryReserve) return true; // not initted yet + if (*sMemoryReserve != nsnull) return true; // everything is OK + + ::ReallocateHandle(sMemoryReserve, reserveSize); + if (::MemError() != noErr) return false; + return true; +} + +pascal long nsMacMemoryCushion::GrowZoneProc(Size amountNeeded) +{ + long freedMem = 0; + + if (sMemoryReserve && *sMemoryReserve && sMemoryReserve != ::GZSaveHnd()) + { + freedMem = ::GetHandleSize(sMemoryReserve); + ::EmptyHandle(sMemoryReserve); + } + + return freedMem; +} + diff --git a/widget/src/mac/nsToolkit.h b/widget/src/mac/nsToolkit.h index 075d7433cc3b..cf4691cc6613 100644 --- a/widget/src/mac/nsToolkit.h +++ b/widget/src/mac/nsToolkit.h @@ -101,5 +101,40 @@ protected: }; +// class for low memory detection and handling +class nsMacMemoryCushion : public Repeater +{ +public: + + enum { + kMemoryReserveSize = 32 * 1024 // 32k memory reserve + }; + + nsMacMemoryCushion(); + ~nsMacMemoryCushion(); + + OSErr Init(Size reserveSize); + + + void RepeatAction(const EventRecord &aMacEvent); + +protected: + + // allocate or recover the memory reserve. Returns true on success + Boolean RecoverMemoryReserve(Size reserveSize); + +public: + + static pascal long GrowZoneProc(Size amountNeeded); + + +protected: + + static Handle sMemoryReserve; + +}; + + + #endif // TOOLKIT_H