Bug 449734 part 4 - Add nsIWidget::ReparentNativeWidget() to handle reparenting of top-level widgets. r=roc a=blocking2.0:betaN

This commit is contained in:
Mats Palmgren 2010-09-18 13:28:50 +02:00
parent 34b76f12ed
commit ecf868198c
19 changed files with 212 additions and 87 deletions

View File

@ -1100,6 +1100,8 @@ nsEventStatus nsViewManager::HandleEvent(nsView* aView, nsGUIEvent* aEvent)
void nsViewManager::ReparentChildWidgets(nsIView* aView, nsIWidget *aNewWidget)
{
NS_PRECONDITION(aNewWidget, "");
if (aView->HasWidget()) {
// Check to see if the parent widget is the
// same as the new parent. If not then reparent
@ -1107,14 +1109,19 @@ void nsViewManager::ReparentChildWidgets(nsIView* aView, nsIWidget *aNewWidget)
// to do for the view and its descendants
nsIWidget* widget = aView->GetWidget();
nsIWidget* parentWidget = widget->GetParent();
// Toplevel widgets should not be reparented!
if (parentWidget && parentWidget != aNewWidget) {
if (parentWidget) {
// Child widget
if (parentWidget != aNewWidget) {
#ifdef DEBUG
nsresult rv =
#endif
widget->SetParent(aNewWidget);
NS_ASSERTION(NS_SUCCEEDED(rv), "SetParent failed!");
}
} else {
// Toplevel widget (popup, dialog, etc)
widget->ReparentNativeWidget(aNewWidget);
}
return;
}

View File

@ -112,9 +112,10 @@ typedef nsEventStatus (* EVENT_CALLBACK)(nsGUIEvent *event);
#define NS_NATIVE_TSF_DISPLAY_ATTR_MGR 102
#endif
// 36762512-d533-4884-9ac3-4ada8594146c
#define NS_IWIDGET_IID \
{ 0xe1dda370, 0xdf16, 0x4c92, \
{ 0x9b, 0x86, 0x4b, 0xd9, 0xcf, 0xff, 0x4e, 0xb1 } }
{ 0x36762512, 0xd533, 0x4884, \
{ 0x9a, 0xc3, 0x4a, 0xda, 0x85, 0x94, 0x14, 0x6c } }
/*
* Window shadow styles
@ -1264,7 +1265,14 @@ class nsIWidget : public nsISupports {
CreatePuppetWidget();
#endif
/**
* Reparent this widget's native widget.
* @param aNewParent the native widget of aNewParent is the new native
* parent widget
*/
NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent) = 0;
protected:
// keep the list of children. We also keep track of our siblings.
// The ownership model is as follows: parent holds a strong ref to
// the first element of the list, and each element holds a strong

View File

@ -257,6 +257,13 @@ nsWindow::SetParent(nsIWidget *aNewParent)
return NS_OK;
}
NS_IMETHODIMP
nsWindow::ReparentNativeWidget(nsIWidget *aNewParent)
{
NS_PRECONDITION(aNewParent, "");
return NS_OK;
}
nsIWidget*
nsWindow::GetParent()
{

View File

@ -163,6 +163,7 @@ public:
LayerManager* GetLayerManager();
gfxASurface* GetThebesSurface();
NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent);
protected:
void BringToFront();
nsWindow *FindTopLevel();

View File

@ -23,7 +23,7 @@
* Paul Ashford <arougthopher@lizardland.net>
* Sergei Dolgov <sergei_d@fi.tartu.ee>
* Fredrik Holmqvist <thesuckiestemail@yahoo.se>
* Mats Palmgren <mats.palmgren@bredband.net>
* Mats Palmgren <matspal@gmail.com>
*
* 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
@ -396,6 +396,13 @@ void nsWindow::InitEvent(nsGUIEvent& event, nsPoint* aPoint)
event.time = PR_IntervalNow();
}
NS_IMETHODIMP nsWindow::ReparentNativeWidget(nsIWidget* aNewParent)
{
NS_PRECONDITION(aNewParent, "");
return NS_OK;
}
//-------------------------------------------------------------------------
//
// Invokes callback and ProcessEvent method on Event Listener object

View File

@ -160,7 +160,7 @@ public:
void InitEvent(nsGUIEvent& event, nsPoint* aPoint = nsnull);
NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent);
protected:
static PRBool EventIsInsideWindow(nsWindow* aWindow, nsPoint pos) ;

View File

@ -406,6 +406,7 @@ public:
void PaintQD();
NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent);
protected:
PRBool ReportDestroyEvent();

View File

@ -24,7 +24,7 @@
* Mark Mentovai <mark@moxienet.com>
* Håkan Waara <hwaara@gmail.com>
* Stuart Morgan <stuart.morgan@alumni.case.edu>
* Mats Palmgren <mats.palmgren@bredband.net>
* Mats Palmgren <matspal@gmail.com>
* Thomas K. Dyas <tdyas@zecador.org>
*
* Alternatively, the contents of this file may be used under the terms of
@ -926,9 +926,6 @@ nsChildView::SetParent(nsIWidget* aNewParent)
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
NS_ENSURE_ARG(aNewParent);
NSView<mozView>* newParentView =
(NSView*)aNewParent->GetNativeData(NS_NATIVE_WIDGET);
NS_ENSURE_TRUE(newParentView, NS_ERROR_FAILURE);
if (mOnDestroyCalled)
return NS_OK;
@ -939,12 +936,34 @@ nsChildView::SetParent(nsIWidget* aNewParent)
// remove us from our existing parent
if (mParentWidget)
mParentWidget->RemoveChild(this);
// we hold a ref to mView, so this is safe
[mView removeFromSuperview];
nsresult rv = ReparentNativeWidget(aNewParent);
if (NS_SUCCEEDED(rv))
mParentWidget = aNewParent;
// add us to the new parent
aNewParent->AddChild(this);
mParentWidget = aNewParent;
mParentWidget->AddChild(this);
return NS_OK;
NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT;
}
NS_IMETHODIMP
nsChildView::ReparentNativeWidget(nsIWidget* aNewParent)
{
NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT;
NS_PRECONDITION(aNewParent, "");
if (mOnDestroyCalled)
return NS_OK;
NSView<mozView>* newParentView =
(NSView*)aNewParent->GetNativeData(NS_NATIVE_WIDGET);
NS_ENSURE_TRUE(newParentView, NS_ERROR_FAILURE);
// we hold a ref to mView, so this is safe
[mView removeFromSuperview];
mParentView = newParentView;
[mParentView addSubview:mView];
return NS_OK;

View File

@ -298,6 +298,7 @@ public:
void SetPopupWindowLevel();
NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent);
protected:
nsresult CreateNativeWindow(const NSRect &aRect,

View File

@ -307,6 +307,11 @@ static unsigned int WindowMaskForBorderStyle(nsBorderStyle aBorderStyle)
return mask;
}
NS_IMETHODIMP nsCocoaWindow::ReparentNativeWidget(nsIWidget* aNewParent)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
// If aRectIsFrameRect, aRect specifies the frame rect of the new window.
// Otherwise, aRect.x/y specify the position of the window's frame relative to
// the bottom of the menubar and aRect.width/height specify the size of the

View File

@ -842,6 +842,8 @@ nsWindow::SetParent(nsIWidget *aNewParent)
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_ASSERTION(!mTransientParent, "child widget with transient parent");
nsCOMPtr<nsIWidget> kungFuDeathGrip = this;
mParent->RemoveChild(this);
@ -856,50 +858,104 @@ nsWindow::SetParent(nsIWidget *aNewParent)
return NS_OK;
}
NS_ABORT_IF_FALSE(!GDK_WINDOW_OBJECT(mGdkWindow)->destroyed,
"destroyed GdkWindow with widget");
nsWindow* newParent = static_cast<nsWindow*>(aNewParent);
GdkWindow* newParentWindow = NULL;
GtkWidget* newContainer = NULL;
if (aNewParent) {
aNewParent->AddChild(this);
newParentWindow = newParent->mGdkWindow;
if (newParentWindow) {
newContainer = get_gtk_widget_for_gdk_window(newParentWindow);
}
ReparentNativeWidget(aNewParent);
} else {
// aNewParent is NULL, but reparent to a hidden window to avoid
// destroying the GdkWindow and its descendants.
// An invisible container widget is needed to hold descendant
// GtkWidgets.
newContainer = EnsureInvisibleContainer();
newParentWindow = newContainer->window;
GtkWidget* newContainer = EnsureInvisibleContainer();
GdkWindow* newParentWindow = newContainer->window;
ReparentNativeWidgetInternal(aNewParent, newContainer, newParentWindow,
oldContainer);
}
return NS_OK;
}
if (!newContainer) {
NS_IMETHODIMP
nsWindow::ReparentNativeWidget(nsIWidget* aNewParent)
{
NS_PRECONDITION(aNewParent, "");
NS_ASSERTION(!mIsDestroyed, "");
NS_ASSERTION(!static_cast<nsWindow*>(aNewParent)->mIsDestroyed, "");
GtkWidget* oldContainer = GetMozContainerWidget();
if (!oldContainer) {
// The GdkWindows have been destroyed so there is nothing else to
// reparent.
NS_ABORT_IF_FALSE(GDK_WINDOW_OBJECT(mGdkWindow)->destroyed,
"live GdkWindow with no widget");
return NS_OK;
}
NS_ABORT_IF_FALSE(!GDK_WINDOW_OBJECT(mGdkWindow)->destroyed,
"destroyed GdkWindow with widget");
nsWindow* newParent = static_cast<nsWindow*>(aNewParent);
GdkWindow* newParentWindow = newParent->mGdkWindow;
GtkWidget* newContainer = NULL;
if (newParentWindow) {
newContainer = get_gtk_widget_for_gdk_window(newParentWindow);
}
if (mTransientParent) {
GtkWindow* topLevelParent =
GTK_WINDOW(gtk_widget_get_toplevel(newContainer));
gtk_window_set_transient_for(GTK_WINDOW(mShell), topLevelParent);
mTransientParent = topLevelParent;
if (mWindowGroup) {
g_object_unref(G_OBJECT(mWindowGroup));
mWindowGroup = NULL;
}
if (mTransientParent->group) {
gtk_window_group_add_window(mTransientParent->group,
GTK_WINDOW(mShell));
mWindowGroup = mTransientParent->group;
g_object_ref(G_OBJECT(mWindowGroup));
}
else if (GTK_WINDOW(mShell)->group) {
gtk_window_group_remove_window(GTK_WINDOW(mShell)->group,
GTK_WINDOW(mShell));
}
}
ReparentNativeWidgetInternal(aNewParent, newContainer, newParentWindow,
oldContainer);
return NS_OK;
}
void
nsWindow::ReparentNativeWidgetInternal(nsIWidget* aNewParent,
GtkWidget* aNewContainer,
GdkWindow* aNewParentWindow,
GtkWidget* aOldContainer)
{
if (!aNewContainer) {
// The new parent GdkWindow has been destroyed.
NS_ABORT_IF_FALSE(!newParentWindow ||
GDK_WINDOW_OBJECT(newParentWindow)->destroyed,
NS_ABORT_IF_FALSE(!aNewParentWindow ||
GDK_WINDOW_OBJECT(aNewParentWindow)->destroyed,
"live GdkWindow with no widget");
Destroy();
} else {
if (newContainer != oldContainer) {
NS_ABORT_IF_FALSE(!GDK_WINDOW_OBJECT(newParentWindow)->destroyed,
if (aNewContainer != aOldContainer) {
NS_ABORT_IF_FALSE(!GDK_WINDOW_OBJECT(aNewParentWindow)->destroyed,
"destroyed GdkWindow with widget");
SetWidgetForHierarchy(mGdkWindow, oldContainer, newContainer);
SetWidgetForHierarchy(mGdkWindow, aOldContainer, aNewContainer);
}
gdk_window_reparent(mGdkWindow, newParentWindow, mBounds.x, mBounds.y);
if (!mIsTopLevel) {
gdk_window_reparent(mGdkWindow, aNewParentWindow, mBounds.x,
mBounds.y);
}
}
nsWindow* newParent = static_cast<nsWindow*>(aNewParent);
PRBool parentHasMappedToplevel =
newParent && newParent->mHasMappedToplevel;
if (mHasMappedToplevel != parentHasMappedToplevel) {
SetHasMappedToplevel(parentHasMappedToplevel);
}
return NS_OK;
}
NS_IMETHODIMP

View File

@ -332,11 +332,17 @@ public:
static already_AddRefed<gfxASurface> GetSurfaceForGdkDrawable(GdkDrawable* aDrawable,
const nsIntSize& aSize);
NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent);
#ifdef ACCESSIBILITY
static PRBool sAccessibilityEnabled;
#endif
protected:
// Helper for SetParent and ReparentNativeWidget.
void ReparentNativeWidgetInternal(nsIWidget* aNewParent,
GtkWidget* aNewContainer,
GdkWindow* aNewParentWindow,
GtkWidget* aOldContainer);
nsCOMPtr<nsIWidget> mParent;
// Is this a toplevel window?
PRPackedBool mIsTopLevel;

View File

@ -2797,6 +2797,14 @@ NS_IMETHODIMP nsWindow::DispatchEvent(nsGUIEvent* event, nsEventStatus& aStatus)
//-----------------------------------------------------------------------------
NS_IMETHODIMP nsWindow::ReparentNativeWidget(nsIWidget* aNewParent)
{
NS_PRECONDITION(aNewParent, "");
return NS_ERROR_NOT_IMPLEMENTED;
}
//-----------------------------------------------------------------------------
PRBool nsWindow::DispatchWindowEvent(nsGUIEvent* event)
{
nsEventStatus status;

View File

@ -214,10 +214,10 @@ public:
PRBool* aLEDState);
NS_IMETHOD DispatchEvent(nsGUIEvent* event,
nsEventStatus& aStatus);
NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent);
// nsWindow
static void ReleaseGlobals();
protected:
// from nsBaseWidget
virtual void OnDestroy();

View File

@ -21,7 +21,7 @@
* are Copyright (C) 2001 the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Mats Palmgren <mats.palmgren@bredband.net>
* Mats Palmgren <matspal@gmail.com>
* Masayuki Nakano <masayuki@d-toybox.com>
* Romashin Oleg <romaxa@gmail.com>
* Vladimir Vukicevic <vladimir@pobox.com>
@ -391,35 +391,32 @@ NS_IMETHODIMP
nsWindow::SetParent(nsIWidget *aNewParent)
{
NS_ENSURE_ARG_POINTER(aNewParent);
if (aNewParent) {
nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
nsIWidget* parent = GetParent();
if (parent) {
parent->RemoveChild(this);
}
if (aNewParent) {
ReparentNativeWidget(aNewParent);
aNewParent->AddChild(this);
return NS_OK;
}
if (mWidget) {
mWidget->setParentItem(0);
}
return NS_OK;
}
NS_IMETHODIMP
nsWindow::ReparentNativeWidget(nsIWidget *aNewParent)
{
NS_PRECONDITION(aNewParent, "");
MozQWidget* newParent = static_cast<MozQWidget*>(aNewParent->GetNativeData(NS_NATIVE_WINDOW));
NS_ASSERTION(newParent, "Parent widget has a null native window handle");
if (mWidget) {
mWidget->setParentItem(newParent);
}
aNewParent->AddChild(this);
return NS_OK;
}
nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
nsIWidget* parent = GetParent();
if (parent)
parent->RemoveChild(this);
if (mWidget)
mWidget->setParentItem(0);
return NS_OK;
}

View File

@ -231,6 +231,7 @@ public:
// called to check and see if a widget's dimensions are sane
PRBool AreBoundsSane(void);
NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent);
protected:
nsCOMPtr<nsIWidget> mParent;
// Is this a toplevel window?

View File

@ -1018,38 +1018,37 @@ NS_IMETHODIMP nsWindow::SetParent(nsIWidget *aNewParent)
{
mParent = aNewParent;
if (aNewParent) {
nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
nsIWidget* parent = GetParent();
if (parent) {
parent->RemoveChild(this);
}
if (aNewParent) {
ReparentNativeWidget(aNewParent);
aNewParent->AddChild(this);
return NS_OK;
}
if (mWnd) {
// If we have no parent, SetParent should return the desktop.
VERIFY(::SetParent(mWnd, nsnull));
}
return NS_OK;
}
NS_IMETHODIMP
nsWindow::ReparentNativeWidget(nsIWidget* aNewParent)
{
NS_PRECONDITION(aNewParent, "");
mParent = aNewParent;
if (mWindowType == eWindowType_popup) {
return NS_OK;
}
HWND newParent = (HWND)aNewParent->GetNativeData(NS_NATIVE_WINDOW);
NS_ASSERTION(newParent, "Parent widget has a null native window handle");
if (newParent && mWnd) {
::SetParent(mWnd, newParent);
}
aNewParent->AddChild(this);
return NS_OK;
}
nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
nsIWidget* parent = GetParent();
if (parent) {
parent->RemoveChild(this);
}
if (mWnd) {
// If we have no parent, SetParent should return the desktop.
VERIFY(::SetParent(mWnd, nsnull));
}
return NS_OK;
}

View File

@ -272,6 +272,7 @@ public:
void SetTaskbarPreview(nsITaskbarWindowPreview *preview) { mTaskbarPreview = do_GetWeakReference(preview); }
#endif
NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent);
protected:
/**

View File

@ -185,6 +185,7 @@ public:
mBorderStyle & eBorderStyle_title);
}
NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent) = 0;
/**
* Use this when GetLayerManager() returns a BasicLayerManager
* (nsBaseWidget::GetLayerManager() does). This sets up the widget's