From a5615e40a21f647e9a0737b0b4af6e12198081de Mon Sep 17 00:00:00 2001 From: Josh Aas Date: Mon, 21 Nov 2011 15:15:38 -0500 Subject: [PATCH] Bug 90268: Part 1, improve support for re-parenting native widgets. r=roc r=karlt --- widget/public/nsIWidget.h | 14 +++++++++++--- widget/src/cocoa/nsChildView.mm | 28 +++++++++++++++------------ widget/src/gtk2/nsWindow.cpp | 12 +++++++++--- widget/src/xpwidgets/nsBaseWidget.cpp | 15 ++++++++++++++ widget/src/xpwidgets/nsBaseWidget.h | 1 + 5 files changed, 52 insertions(+), 18 deletions(-) diff --git a/widget/public/nsIWidget.h b/widget/public/nsIWidget.h index 93aaa4281e5..833d78de298 100644 --- a/widget/public/nsIWidget.h +++ b/widget/public/nsIWidget.h @@ -118,8 +118,8 @@ typedef nsEventStatus (* EVENT_CALLBACK)(nsGUIEvent *event); #endif #define NS_IWIDGET_IID \ - { 0x32966f95, 0x89e0, 0x447a, \ - { 0x91, 0x8d, 0x58, 0x53, 0xd6, 0x99, 0x4a, 0x72 } } + { 0xEAAF1019, 0x0CD8, 0x4DD8, \ + { 0xBE, 0xB9, 0x8D, 0x8D, 0xEB, 0x52, 0xFC, 0xF6 } } /* * Window shadow styles @@ -356,6 +356,14 @@ class nsIWidget : public nsISupports { nsWidgetInitData *aInitData = nsnull, bool aForceUseIWidgetParent = false) = 0; + /** + * Set the event callback for a widget. If a device context is not + * provided then the existing device context will remain, it will + * not be nulled out. + */ + NS_IMETHOD SetEventCallback(EVENT_CALLBACK aEventFunction, + nsDeviceContext *aContext) = 0; + /** * Attach to a top level widget. * @@ -398,7 +406,7 @@ class nsIWidget : public nsISupports { /** * Reparent a widget * - * Change the widgets parent + * Change the widget's parent. Null parents are allowed. * * @param aNewParent new parent */ diff --git a/widget/src/cocoa/nsChildView.mm b/widget/src/cocoa/nsChildView.mm index f8cdcfbc395..fdf16af495b 100644 --- a/widget/src/cocoa/nsChildView.mm +++ b/widget/src/cocoa/nsChildView.mm @@ -705,26 +705,30 @@ nsChildView::SetParent(nsIWidget* aNewParent) { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; - NS_ENSURE_ARG(aNewParent); - if (mOnDestroyCalled) return NS_OK; - // make sure we stay alive nsCOMPtr kungFuDeathGrip(this); - // remove us from our existing parent - if (mParentWidget) + if (mParentWidget) { mParentWidget->RemoveChild(this); + } - nsresult rv = ReparentNativeWidget(aNewParent); - if (NS_SUCCEEDED(rv)) - mParentWidget = aNewParent; + if (aNewParent) { + ReparentNativeWidget(aNewParent); + } else { + [mView removeFromSuperview]; + mParentView = nil; + } + + mParentWidget = aNewParent; + + if (mParentWidget) { + mParentWidget->AddChild(this); + } - // add us to the new parent - mParentWidget->AddChild(this); return NS_OK; - + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; } @@ -744,7 +748,7 @@ nsChildView::ReparentNativeWidget(nsIWidget* aNewParent) // we hold a ref to mView, so this is safe [mView removeFromSuperview]; - mParentView = newParentView; + mParentView = newParentView; [mParentView addSubview:mView]; return NS_OK; diff --git a/widget/src/gtk2/nsWindow.cpp b/widget/src/gtk2/nsWindow.cpp index 612345b2f25..f3d2d4fe1e2 100644 --- a/widget/src/gtk2/nsWindow.cpp +++ b/widget/src/gtk2/nsWindow.cpp @@ -897,15 +897,17 @@ nsWindow::GetDPI() NS_IMETHODIMP nsWindow::SetParent(nsIWidget *aNewParent) { - if (mContainer || !mGdkWindow || !mParent) { - NS_NOTREACHED("nsWindow::SetParent - reparenting a non-child window"); + if (mContainer || !mGdkWindow) { + NS_NOTREACHED("nsWindow::SetParent called illegally"); return NS_ERROR_NOT_IMPLEMENTED; } NS_ASSERTION(!mTransientParent, "child widget with transient parent"); nsCOMPtr kungFuDeathGrip = this; - mParent->RemoveChild(this); + if (mParent) { + mParent->RemoveChild(this); + } mParent = aNewParent; @@ -1002,6 +1004,10 @@ nsWindow::ReparentNativeWidgetInternal(nsIWidget* aNewParent, NS_ABORT_IF_FALSE(!gdk_window_is_destroyed(aNewParentWindow), "destroyed GdkWindow with widget"); SetWidgetForHierarchy(mGdkWindow, aOldContainer, aNewContainer); + + if (aOldContainer == gInvisibleContainer) { + CheckDestroyInvisibleContainer(); + } } if (!mIsTopLevel) { diff --git a/widget/src/xpwidgets/nsBaseWidget.cpp b/widget/src/xpwidgets/nsBaseWidget.cpp index a0639ea3887..f76f3c52188 100644 --- a/widget/src/xpwidgets/nsBaseWidget.cpp +++ b/widget/src/xpwidgets/nsBaseWidget.cpp @@ -250,6 +250,21 @@ nsBaseWidget::CreateChild(const nsIntRect &aRect, return nsnull; } +NS_IMETHODIMP +nsBaseWidget::SetEventCallback(EVENT_CALLBACK aEventFunction, + nsDeviceContext *aContext) +{ + mEventCallback = aEventFunction; + + if (aContext) { + NS_IF_RELEASE(mContext); + mContext = aContext; + NS_ADDREF(mContext); + } + + return NS_OK; +} + // Attach a view to our widget which we'll send events to. NS_IMETHODIMP nsBaseWidget::AttachViewToTopLevel(EVENT_CALLBACK aViewEventFunction, diff --git a/widget/src/xpwidgets/nsBaseWidget.h b/widget/src/xpwidgets/nsBaseWidget.h index 8d685fec885..bfa0c62777a 100644 --- a/widget/src/xpwidgets/nsBaseWidget.h +++ b/widget/src/xpwidgets/nsBaseWidget.h @@ -165,6 +165,7 @@ public: nsDeviceContext *aContext, nsWidgetInitData *aInitData = nsnull, bool aForceUseIWidgetParent = false); + NS_IMETHOD SetEventCallback(EVENT_CALLBACK aEventFunction, nsDeviceContext *aContext); NS_IMETHOD AttachViewToTopLevel(EVENT_CALLBACK aViewEventFunction, nsDeviceContext *aContext); virtual ViewWrapper* GetAttachedViewPtr(); NS_IMETHOD SetAttachedViewPtr(ViewWrapper* aViewWrapper);