Null out weak pointers when they become invalid. b=479749 r=josh sr=roc

This commit is contained in:
Steven Michaud 2009-03-09 11:59:29 -05:00
Родитель ebb622ed2b
Коммит 7472c08540
3 изменённых файлов: 44 добавлений и 11 удалений

Просмотреть файл

@ -736,7 +736,6 @@ NS_IMETHODIMP nsChildView::Destroy()
[mView widgetDestroyed]; [mView widgetDestroyed];
nsBaseWidget::OnDestroy();
nsBaseWidget::Destroy(); nsBaseWidget::Destroy();
ReportDestroyEvent(); ReportDestroyEvent();
@ -744,6 +743,8 @@ NS_IMETHODIMP nsChildView::Destroy()
TearDownView(); TearDownView();
nsBaseWidget::OnDestroy();
return NS_OK; return NS_OK;
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
@ -2942,7 +2943,7 @@ NSEvent* gLastDragEvent = nil;
static const PRInt32 sShadowInvalidationInterval = 100; static const PRInt32 sShadowInvalidationInterval = 100;
- (void)maybeInvalidateShadow - (void)maybeInvalidateShadow
{ {
if ([mWindow isOpaque] || ![mWindow hasShadow]) if (!mWindow || [mWindow isOpaque] || ![mWindow hasShadow])
return; return;
PRIntervalTime now = PR_IntervalNow(); PRIntervalTime now = PR_IntervalNow();
@ -2963,7 +2964,7 @@ static const PRInt32 sShadowInvalidationInterval = 100;
- (void)invalidateShadow - (void)invalidateShadow
{ {
if (!mNeedsShadowInvalidation) if (!mWindow || !mNeedsShadowInvalidation)
return; return;
[mWindow invalidateShadow]; [mWindow invalidateShadow];
mNeedsShadowInvalidation = NO; mNeedsShadowInvalidation = NO;
@ -3659,6 +3660,9 @@ static nsEventStatus SendGeckoMouseEnterOrExitEvent(PRBool isTrusted,
{ {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK; NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
if (!mWindow)
return;
// Work around an Apple bug that causes the OS to continue sending // Work around an Apple bug that causes the OS to continue sending
// mouseMoved events to a window for a while after it's been miniaturized. // mouseMoved events to a window for a while after it's been miniaturized.
// This may be related to a similar problem with popup windows (bmo bug // This may be related to a similar problem with popup windows (bmo bug
@ -4173,10 +4177,13 @@ static nsEventStatus SendGeckoMouseEnterOrExitEvent(PRBool isTrusted,
{ {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL;
if (!mWindow)
return nil;
WindowDataMap* windowMap = [WindowDataMap sharedWindowDataMap]; WindowDataMap* windowMap = [WindowDataMap sharedWindowDataMap];
TopLevelWindowData* windowData = [windowMap dataForWindow:mWindow]; TopLevelWindowData* windowData = [windowMap dataForWindow:mWindow];
if (mWindow && !windowData) if (!windowData)
{ {
windowData = [[TopLevelWindowData alloc] initWithWindow:mWindow]; windowData = [[TopLevelWindowData alloc] initWithWindow:mWindow];
[windowMap setData:windowData forWindow:mWindow]; // takes ownership [windowMap setData:windowData forWindow:mWindow]; // takes ownership

Просмотреть файл

@ -118,6 +118,25 @@ nsCocoaWindow::nsCocoaWindow()
} }
// Under unusual circumstances, an nsCocoaWindow object can be destroyed
// before the nsChildView objects it contains are destroyed. But this will
// invalidate the (weak) mWindow variable in these nsChildView objects
// before their own destructors have been called. So we need to null-out
// this variable in our nsChildView objects as we're destroyed. This helps
// resolve bmo bug 479749.
static void TellNativeViewsGoodbye(NSView *aNativeView)
{
if (!aNativeView)
return;
if ([aNativeView respondsToSelector:@selector(setNativeWindow:)])
[(NSView<mozView>*)aNativeView setNativeWindow:nil];
NSArray *immediateSubviews = [aNativeView subviews];
int count = [immediateSubviews count];
for (int i = 0; i < count; ++i)
TellNativeViewsGoodbye((NSView *)[immediateSubviews objectAtIndex:i]);
}
nsCocoaWindow::~nsCocoaWindow() nsCocoaWindow::~nsCocoaWindow()
{ {
NS_OBJC_BEGIN_TRY_ABORT_BLOCK; NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
@ -128,12 +147,15 @@ nsCocoaWindow::~nsCocoaWindow()
childWindow->mParent = nsnull; childWindow->mParent = nsnull;
} }
if (mWindow && mWindowMadeHere) { if (mWindow) {
// we want to unhook the delegate here because we don't want events TellNativeViewsGoodbye([mWindow contentView]);
// sent to it after this object has been destroyed if (mWindowMadeHere) {
[mWindow setDelegate:nil]; // we want to unhook the delegate here because we don't want events
[mWindow autorelease]; // sent to it after this object has been destroyed
[mDelegate autorelease]; [mWindow setDelegate:nil];
[mWindow autorelease];
[mDelegate autorelease];
}
} }
NS_IF_RELEASE(mPopupContentView); NS_IF_RELEASE(mPopupContentView);
@ -429,8 +451,8 @@ NS_IMETHODIMP nsCocoaWindow::Destroy()
if (mPopupContentView) if (mPopupContentView)
mPopupContentView->Destroy(); mPopupContentView->Destroy();
nsBaseWidget::OnDestroy();
nsBaseWidget::Destroy(); nsBaseWidget::Destroy();
nsBaseWidget::OnDestroy();
return NS_OK; return NS_OK;
} }

Просмотреть файл

@ -256,6 +256,10 @@ NS_METHOD nsBaseWidget::Destroy()
// Just in case our parent is the only ref to us // Just in case our parent is the only ref to us
nsCOMPtr<nsIWidget> kungFuDeathGrip(this); nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
// Clear the device context's mWidget field -- otherwise it may get accessed
// after it's been deleted. See bug 479749.
if (mContext)
mContext->Init(nsnull);
// disconnect from the parent // disconnect from the parent
nsIWidget *parent = GetParent(); nsIWidget *parent = GetParent();
if (parent) { if (parent) {