Bug 311618, Crash [@ QDFlushPortBuffer]. Replumb the flush manager as an XPCOM service so that other components can cancel scheduled flushes when ports are going away. Away goes trouble down the drain. Camino/koko-widget only. r=pink sr=smfr a/1.8=asa
git-svn-id: svn://10.0.0.236/trunk@182170 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
@@ -74,6 +74,10 @@ XPIDLSRCS += nsIPrintSettingsX.idl \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
ifeq (cocoa,$(MOZ_WIDGET_TOOLKIT))
|
||||
XPIDLSRCS += nsIQDFlushManager.idl
|
||||
endif
|
||||
|
||||
ifeq ($(MOZ_GFX_TOOLKIT),windows)
|
||||
XPIDLSRCS += nsIPrintSettingsWin.idl
|
||||
endif
|
||||
|
||||
75
mozilla/gfx/idl/nsIQDFlushManager.idl
Normal file
75
mozilla/gfx/idl/nsIQDFlushManager.idl
Normal file
@@ -0,0 +1,75 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is supposed to avoid exccessive QuickDraw flushes.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mark Mentovai <mark@moxienet.com>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2005
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
%{ C++
|
||||
#include <Carbon/Carbon.h>
|
||||
%}
|
||||
|
||||
native CGrafPtr(CGrafPtr);
|
||||
native RgnHandle(RgnHandle);
|
||||
|
||||
/**
|
||||
* nsIQDFlushManager is responsible for rate-limiting QuickDraw buffer
|
||||
* flushes. Think of it as a plumber in a time of rationing. It's
|
||||
* expected to be used as a singleton doled out by the service manager.
|
||||
*/
|
||||
|
||||
[uuid(40352CE3-9D15-4643-8CBF-71DA61650F13)]
|
||||
interface nsIQDFlushManager : nsISupports
|
||||
{
|
||||
/**
|
||||
* Flushes the port buffer, a la QDFlushPortBuffer. If the buffer has
|
||||
* been flushed too recently, the region to flush is instead added to
|
||||
* the dirty region, and a buffer flush will be scheduled for an
|
||||
* appropriate time.
|
||||
*
|
||||
* @param aPort the QuickDraw port to flush
|
||||
*
|
||||
* @param aRegion the region to flush or mark as dirty
|
||||
*/
|
||||
void flushPortBuffer(in CGrafPtr aPort, in RgnHandle aRegion);
|
||||
|
||||
/**
|
||||
* Cancels a pending flush scheduled by calling flushPortBuffer. This
|
||||
* method is suitable to call when a port is destroyed.
|
||||
*
|
||||
* @param aPort the QuickDraw port to not flush
|
||||
*/
|
||||
void removePort(in CGrafPtr aPort);
|
||||
};
|
||||
@@ -57,6 +57,9 @@
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsUnicodeMappingUtil.h"
|
||||
#include "gfxImageFrame.h"
|
||||
#ifdef MOZ_WIDGET_COCOA
|
||||
#include "nsQDFlushManager.h"
|
||||
#endif
|
||||
|
||||
#include "nsIGenericFactory.h"
|
||||
|
||||
@@ -76,6 +79,9 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsFontEnumeratorMac)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsFontList)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsScreenManagerMac)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(gfxImageFrame)
|
||||
#ifdef MOZ_WIDGET_COCOA
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsQDFlushManager)
|
||||
#endif
|
||||
|
||||
static NS_IMETHODIMP
|
||||
nsScriptableRegionConstructor(nsISupports* aOuter, REFNSIID aIID, void** aResult)
|
||||
@@ -155,7 +161,13 @@ static const nsModuleComponentInfo components[] =
|
||||
{ "windows image frame",
|
||||
GFX_IMAGEFRAME_CID,
|
||||
"@mozilla.org/gfx/image/frame;2",
|
||||
gfxImageFrameConstructor, }
|
||||
gfxImageFrameConstructor, },
|
||||
#ifdef MOZ_WIDGET_COCOA
|
||||
{ NS_QDFLUSHMANAGER_CLASSNAME,
|
||||
NS_QDFLUSHMANAGER_CID,
|
||||
NS_QDFLUSHMANAGER_CONTRACTID,
|
||||
nsQDFlushManagerConstructor },
|
||||
#endif
|
||||
};
|
||||
|
||||
PR_STATIC_CALLBACK(void)
|
||||
|
||||
@@ -38,77 +38,16 @@
|
||||
#include "nsQDFlushManager.h"
|
||||
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsCRT.h"
|
||||
|
||||
class nsQDFlushPort : public nsITimerCallback
|
||||
{
|
||||
// nsQDFlushManager is responsible for maintaining the list of port objects.
|
||||
friend class nsQDFlushManager;
|
||||
|
||||
protected:
|
||||
nsQDFlushPort(CGrafPtr aPort);
|
||||
~nsQDFlushPort();
|
||||
|
||||
void Init(CGrafPtr aPort);
|
||||
void Destroy();
|
||||
void FlushPortBuffer(RgnHandle aRegion);
|
||||
PRInt64 TimeUntilFlush(AbsoluteTime aNow);
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSITIMERCALLBACK
|
||||
|
||||
// To use the display's refresh rate as the update Hz, see
|
||||
// http://developer.apple.com/documentation/Performance/Conceptual/Drawing/Articles/FlushingContent.html .
|
||||
// Here, use a hard-coded 30 Hz instead.
|
||||
static const PRUint32 kRefreshRateHz = 30; // Maximum number of updates
|
||||
// per second
|
||||
|
||||
nsQDFlushPort* mNext; // Next object in list
|
||||
CGrafPtr mPort; // Associated port
|
||||
AbsoluteTime mLastFlushTime; // Last QDFlushPortBuffer call
|
||||
nsCOMPtr<nsITimer> mFlushTimer; // Timer for scheduled flush
|
||||
PRPackedBool mFlushTimerRunning; // Is it?
|
||||
};
|
||||
|
||||
class nsQDFlushObserver : public nsIObserver
|
||||
{
|
||||
// nsQDFlushManager is responsible for creating the observer.
|
||||
friend class nsQDFlushManager;
|
||||
|
||||
protected:
|
||||
nsQDFlushObserver(nsQDFlushManager* aParent);
|
||||
~nsQDFlushObserver();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
nsQDFlushManager* mParent; // Parent object
|
||||
};
|
||||
|
||||
// nsQDFlushManager
|
||||
|
||||
// protected static
|
||||
nsQDFlushManager* nsQDFlushManager::sQDFlushManager = nsnull;
|
||||
nsQDFlushObserver* nsQDFlushManager::sQDFlushObserver = nsnull;
|
||||
|
||||
// nsQDFlushManager() constructor
|
||||
//
|
||||
// If you create your own object, you are responsible for freeing it. Once
|
||||
// freed, it will free the attached port objects.
|
||||
//
|
||||
// If you work through the static object by calling through the static
|
||||
// sQDFlushPortBuffer method, the static object will be created dynamically
|
||||
// at first call and will be freed automatically at shutdown.
|
||||
nsQDFlushManager::nsQDFlushManager()
|
||||
: mPortList(nsnull)
|
||||
{
|
||||
}
|
||||
|
||||
// ~nsQDFlushManager() destructor
|
||||
//
|
||||
// See the note about object creation and destruction in the comment
|
||||
// preceding the constructor.
|
||||
nsQDFlushManager::~nsQDFlushManager()
|
||||
{
|
||||
nsQDFlushPort* port = mPortList;
|
||||
@@ -121,34 +60,6 @@ nsQDFlushManager::~nsQDFlushManager()
|
||||
}
|
||||
}
|
||||
|
||||
// FlushPortBuffer(aPort, aRegion)
|
||||
//
|
||||
// The public entry point for object-based calls. Calls
|
||||
// QDFlushPortBuffer(aPort, aRegion) if aPort hasn't been flushed too
|
||||
// recently. If it has been, calls QDAddRegionToDirtyRegion(aPort, aRegion)
|
||||
// and if no flush has been scheduled, schedules a flush for the appropriate
|
||||
// time.
|
||||
//
|
||||
// public
|
||||
void
|
||||
nsQDFlushManager::FlushPortBuffer(CGrafPtr aPort, RgnHandle aRegion)
|
||||
{
|
||||
CreateOrGetPort(aPort)->FlushPortBuffer(aRegion);
|
||||
}
|
||||
|
||||
// sFlushPortBuffer(aPort, aRegion)
|
||||
//
|
||||
// The public entry point for calls into the static flush manager. Gets
|
||||
// the static object, creating it if necessary, and then calls into
|
||||
// FlushPortBuffer above.
|
||||
//
|
||||
// public static
|
||||
void
|
||||
nsQDFlushManager::sFlushPortBuffer(CGrafPtr aPort, RgnHandle aRegion)
|
||||
{
|
||||
GetStaticQDFlushManager()->FlushPortBuffer(aPort, aRegion);
|
||||
}
|
||||
|
||||
// CreateOrGetPort(aPort)
|
||||
//
|
||||
// Walks through the list of port objects and returns the one corresponding to
|
||||
@@ -203,15 +114,33 @@ nsQDFlushManager::CreateOrGetPort(CGrafPtr aPort)
|
||||
return port;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsQDFlushManager, nsIQDFlushManager)
|
||||
|
||||
// nsIQDFlushManager implementation
|
||||
|
||||
// FlushPortBuffer(aPort, aRegion)
|
||||
//
|
||||
// The public entry point for object-based calls. Calls
|
||||
// QDFlushPortBuffer(aPort, aRegion) if aPort hasn't been flushed too
|
||||
// recently. If it has been, calls QDAddRegionToDirtyRegion(aPort, aRegion)
|
||||
// and if no flush has been scheduled, schedules a flush for the appropriate
|
||||
// time.
|
||||
//
|
||||
// public
|
||||
NS_IMETHODIMP
|
||||
nsQDFlushManager::FlushPortBuffer(CGrafPtr aPort, RgnHandle aRegion)
|
||||
{
|
||||
CreateOrGetPort(aPort)->FlushPortBuffer(aRegion);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// RemovePort(aPort)
|
||||
//
|
||||
// Walks through the list of port objects and removes the one corresponding to
|
||||
// aPort, if it exists.
|
||||
//
|
||||
// Presently unused.
|
||||
//
|
||||
// protected
|
||||
void
|
||||
// public
|
||||
NS_IMETHODIMP
|
||||
nsQDFlushManager::RemovePort(CGrafPtr aPort)
|
||||
{
|
||||
// Traversal is as in CreateOrGetPort.
|
||||
@@ -228,56 +157,11 @@ nsQDFlushManager::RemovePort(CGrafPtr aPort)
|
||||
// mPortList. That makes it easy to snip the old object out by
|
||||
// setting it to the follower.
|
||||
*portPtr = next;
|
||||
return;
|
||||
return NS_OK;
|
||||
}
|
||||
portPtr = &port->mNext;
|
||||
}
|
||||
}
|
||||
|
||||
// GetStaticQDFlushManager()
|
||||
//
|
||||
// Most calls through nsQDFlushManager are expected to be made through
|
||||
// a global object, through the static sQDFlushPort method. Because
|
||||
// constructors and destructors on static objects are distrusted, each
|
||||
// call into sQDFlushPort obtains the static object by calling here.
|
||||
// If the object does not yet exist, it is created. To handle destruction,
|
||||
// a shutdown observer is added. The observer handles teardown of the
|
||||
// static manager object and all attached port objects.
|
||||
//
|
||||
// protected static
|
||||
nsQDFlushManager*
|
||||
nsQDFlushManager::GetStaticQDFlushManager()
|
||||
{
|
||||
if (!sQDFlushManager)
|
||||
{
|
||||
// The static flush manager has not yet been initialized. Create it.
|
||||
sQDFlushManager = new nsQDFlushManager();
|
||||
NS_ASSERTION(sQDFlushManager, "failed to create flush manager");
|
||||
if (!sQDFlushManager)
|
||||
{
|
||||
// Early return, avoid creating a useless observer.
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
// Create a shutdown observer to handle destruction.
|
||||
sQDFlushObserver = new nsQDFlushObserver(sQDFlushManager);
|
||||
NS_ASSERTION(sQDFlushObserver, "failed to create observer");
|
||||
if (sQDFlushObserver)
|
||||
{
|
||||
// register for shutdown
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIObserverService> observerService(
|
||||
do_GetService("@mozilla.org/observer-service;1", &rv));
|
||||
if (NS_SUCCEEDED(rv))
|
||||
{
|
||||
// There's not much we can or should do if this fails.
|
||||
observerService->AddObserver(sQDFlushObserver,
|
||||
NS_XPCOM_SHUTDOWN_OBSERVER_ID, PR_FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sQDFlushManager;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsQDFlushPort
|
||||
@@ -411,31 +295,3 @@ nsQDFlushPort::Notify(nsITimer* aTimer)
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsQDFlushObserver
|
||||
|
||||
nsQDFlushObserver::nsQDFlushObserver(nsQDFlushManager* aParent)
|
||||
: mParent(aParent)
|
||||
{
|
||||
}
|
||||
|
||||
nsQDFlushObserver::~nsQDFlushObserver()
|
||||
{
|
||||
}
|
||||
|
||||
// nsIObserver implementation
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsQDFlushObserver, nsIObserver)
|
||||
|
||||
// Observe(aSubject, aTopic, aData)
|
||||
//
|
||||
// Shutdown callback. Delete static object and any attached port objects.
|
||||
NS_IMETHODIMP
|
||||
nsQDFlushObserver::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
const PRUnichar* aData)
|
||||
{
|
||||
NS_ASSERTION(!nsCRT::strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID,aTopic),
|
||||
"Shutdown observer called with wrong topic\n");
|
||||
delete mParent;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@@ -41,44 +41,69 @@
|
||||
#include "nscore.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIQDFlushManager.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsIObserver.h"
|
||||
|
||||
#include <Carbon/Carbon.h>
|
||||
|
||||
// The expected use is to replace these calls:
|
||||
// ::QDFlushPortBuffer(port, region)
|
||||
// with these:
|
||||
// nsQDFlushManager::sFlushPortBuffer(port,region)
|
||||
// nsCOMPtr<nsIQDFlushManager> qdFlushManager =
|
||||
// do_GetService("@mozilla.org/gfx/qdflushmanager;1");
|
||||
// qdFlushManager->FlushPortBuffer(port, region);
|
||||
// and at port destruction time:
|
||||
// qdFlushManager->RemovePort(port)
|
||||
|
||||
// These subservient classes are defined in nsQDFlushManager.cpp.
|
||||
class nsQDFlushPort;
|
||||
class nsQDFlushObserver;
|
||||
|
||||
class NS_EXPORT nsQDFlushManager
|
||||
class nsQDFlushPort : public nsITimerCallback
|
||||
{
|
||||
// nsQDFlushObserver is responsible for destruction of the static object.
|
||||
friend class nsQDFlushObserver;
|
||||
// nsQDFlushManager is responsible for maintaining the list of port objects.
|
||||
friend class nsQDFlushManager;
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSITIMERCALLBACK
|
||||
|
||||
protected:
|
||||
nsQDFlushPort(CGrafPtr aPort);
|
||||
~nsQDFlushPort();
|
||||
|
||||
void Init(CGrafPtr aPort);
|
||||
void Destroy();
|
||||
void FlushPortBuffer(RgnHandle aRegion);
|
||||
PRInt64 TimeUntilFlush(AbsoluteTime aNow);
|
||||
|
||||
// To use the display's refresh rate as the update Hz, see
|
||||
// http://developer.apple.com/documentation/Performance/Conceptual/Drawing/Articles/FlushingContent.html .
|
||||
// Here, use a hard-coded 30 Hz instead.
|
||||
static const PRUint32 kRefreshRateHz = 30; // Maximum number of updates
|
||||
// per second
|
||||
|
||||
nsQDFlushPort* mNext; // Next object in list
|
||||
CGrafPtr mPort; // Associated port
|
||||
AbsoluteTime mLastFlushTime; // Last QDFlushPortBuffer call
|
||||
nsCOMPtr<nsITimer> mFlushTimer; // Timer for scheduled flush
|
||||
PRPackedBool mFlushTimerRunning; // Is it?
|
||||
};
|
||||
|
||||
class NS_EXPORT nsQDFlushManager : public nsIQDFlushManager
|
||||
{
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIQDFLUSHMANAGER
|
||||
|
||||
public:
|
||||
nsQDFlushManager();
|
||||
~nsQDFlushManager();
|
||||
|
||||
void FlushPortBuffer(CGrafPtr aPort,
|
||||
RgnHandle aRegion);
|
||||
static void sFlushPortBuffer(CGrafPtr aPort,
|
||||
RgnHandle aRegion);
|
||||
|
||||
protected:
|
||||
nsQDFlushPort* CreateOrGetPort(CGrafPtr aPort);
|
||||
void RemovePort(CGrafPtr aPort);
|
||||
|
||||
static nsQDFlushManager* GetStaticQDFlushManager();
|
||||
|
||||
nsQDFlushPort* mPortList; // Head of list
|
||||
|
||||
static nsQDFlushManager* sQDFlushManager; // Static object
|
||||
static nsQDFlushObserver* sQDFlushObserver; // Cleanup for static object
|
||||
};
|
||||
|
||||
// 6F91262A-CF9E-4DDD-AA01-7A1FCCF14281
|
||||
#define NS_QDFLUSHMANAGER_CLASSNAME "QuickDraw Buffer Flusher"
|
||||
#define NS_QDFLUSHMANAGER_CID \
|
||||
{0x6F91262A, 0xCF9E, 0x4DDD, {0xAA, 0x01, 0x7A, 0x1F, 0xCC, 0xF1, 0x42, 0x81}}
|
||||
#define NS_QDFLUSHMANAGER_CONTRACTID "@mozilla.org/gfx/qdflushmanager;1"
|
||||
|
||||
#endif /* nsQDFlushManager_h___ */
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsRenderingContextMac.h"
|
||||
#include "nsDeviceContextMac.h"
|
||||
#include "nsFontMetricsMac.h"
|
||||
@@ -50,9 +51,12 @@
|
||||
#include "nsVoidArray.h"
|
||||
#include "nsGfxCIID.h"
|
||||
#include "nsGfxUtils.h"
|
||||
#include "nsQDFlushManager.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#ifdef MOZ_WIDGET_COCOA
|
||||
#include "nsIQDFlushManager.h"
|
||||
#endif
|
||||
|
||||
#include "plhash.h"
|
||||
|
||||
#include <FixMath.h>
|
||||
@@ -1426,7 +1430,10 @@ nsRenderingContextMac::FlushRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord
|
||||
|
||||
::SetRectRgn(rgn, pinToShort(x), pinToShort(y), pinToShort(x + w), pinToShort(y + h));
|
||||
|
||||
nsQDFlushManager::sFlushPortBuffer(mPort, rgn);
|
||||
nsCOMPtr<nsIQDFlushManager> qdFlushManager =
|
||||
do_GetService("@mozilla.org/gfx/qdflushmanager;1");
|
||||
if (qdFlushManager)
|
||||
qdFlushManager->FlushPortBuffer(mPort, rgn);
|
||||
}
|
||||
#endif
|
||||
return NS_OK;
|
||||
|
||||
@@ -53,10 +53,12 @@
|
||||
#include "nsIEventSink.h"
|
||||
#include "nsIScrollableView.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIServiceManager.h"
|
||||
|
||||
#include "nsCarbonHelpers.h"
|
||||
#include "nsGfxUtils.h"
|
||||
#include "nsMacResources.h"
|
||||
#include "nsIQDFlushManager.h"
|
||||
|
||||
#import "nsCursorManager.h"
|
||||
#import "nsWindowMap.h"
|
||||
@@ -465,6 +467,15 @@ void nsChildView::TearDownView()
|
||||
[(NSView*)responder isDescendantOf:mView])
|
||||
[win makeFirstResponder: [mView superview]];
|
||||
|
||||
GrafPtr curPort = GetChildViewQuickDrawPort();
|
||||
if (curPort)
|
||||
{
|
||||
nsCOMPtr<nsIQDFlushManager> qdFlushManager =
|
||||
do_GetService("@mozilla.org/gfx/qdflushmanager;1");
|
||||
if (qdFlushManager)
|
||||
qdFlushManager->RemovePort(curPort);
|
||||
}
|
||||
|
||||
[mView removeFromSuperviewWithoutNeedingDisplay];
|
||||
[mView release];
|
||||
mView = nil;
|
||||
|
||||
Reference in New Issue
Block a user