Bug 1936164 - Don't reparent widgets when moving views around. r=tnikkel,layout-reviewers
This wasn't done consistently (otherwise bug 1936194 wouldn't have worked). Now that we recreate the popups when needed, we can rely on that instead of reparenting the widget. Popups are the only type of widget we should ever reparent, as other widgets are created at the top level which can't be moved around. Differential Revision: https://phabricator.services.mozilla.com/D232202
This commit is contained in:
@@ -616,53 +616,6 @@ void nsViewManager::DispatchEvent(WidgetGUIEvent* aEvent, nsView* aView,
|
|||||||
*aStatus = nsEventStatus_eIgnore;
|
*aStatus = nsEventStatus_eIgnore;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recursively reparent widgets if necessary
|
|
||||||
|
|
||||||
void nsViewManager::ReparentChildWidgets(nsView* aView, nsIWidget* aNewWidget) {
|
|
||||||
MOZ_ASSERT(aNewWidget, "null widget");
|
|
||||||
|
|
||||||
if (nsIWidget* widget = aView->GetWidget()) {
|
|
||||||
// Check to see if the parent widget is the
|
|
||||||
// same as the new parent. If not then reparent
|
|
||||||
// the widget, otherwise there is nothing more
|
|
||||||
// to do for the view and its descendants
|
|
||||||
if (widget->GetParent() != aNewWidget) {
|
|
||||||
widget->SetParent(aNewWidget);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Need to check each of the views children to see
|
|
||||||
// if they have a widget and reparent it.
|
|
||||||
|
|
||||||
for (nsView* kid = aView->GetFirstChild(); kid; kid = kid->GetNextSibling()) {
|
|
||||||
ReparentChildWidgets(kid, aNewWidget);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reparent a view and its descendant views widgets if necessary
|
|
||||||
|
|
||||||
void nsViewManager::ReparentWidgets(nsView* aView, nsView* aParent) {
|
|
||||||
MOZ_ASSERT(aParent, "Must have a parent");
|
|
||||||
MOZ_ASSERT(aView, "Must have a view");
|
|
||||||
|
|
||||||
// Quickly determine whether the view has pre-existing children or a
|
|
||||||
// widget. In most cases the view will not have any pre-existing
|
|
||||||
// children when this is called. Only in the case
|
|
||||||
// where a view has been reparented by removing it from
|
|
||||||
// a reinserting it into a new location in the view hierarchy do we
|
|
||||||
// have to consider reparenting the existing widgets for the view and
|
|
||||||
// it's descendants.
|
|
||||||
if (aView->HasWidget() || aView->GetFirstChild()) {
|
|
||||||
nsIWidget* parentWidget = aParent->GetNearestWidget(nullptr);
|
|
||||||
if (parentWidget) {
|
|
||||||
ReparentChildWidgets(aView, parentWidget);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
NS_WARNING("Can not find a widget for the parent view");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void nsViewManager::InsertChild(nsView* aParent, nsView* aChild,
|
void nsViewManager::InsertChild(nsView* aParent, nsView* aChild,
|
||||||
nsView* aSibling, bool aAfter) {
|
nsView* aSibling, bool aAfter) {
|
||||||
MOZ_ASSERT(nullptr != aParent, "null ptr");
|
MOZ_ASSERT(nullptr != aParent, "null ptr");
|
||||||
@@ -682,7 +635,6 @@ void nsViewManager::InsertChild(nsView* aParent, nsView* aChild,
|
|||||||
// insert at end of document order, i.e., before first view
|
// insert at end of document order, i.e., before first view
|
||||||
// this is the common case, by far
|
// this is the common case, by far
|
||||||
aParent->InsertChild(aChild, nullptr);
|
aParent->InsertChild(aChild, nullptr);
|
||||||
ReparentWidgets(aChild, aParent);
|
|
||||||
} else {
|
} else {
|
||||||
// insert at beginning of document order, i.e., after last view
|
// insert at beginning of document order, i.e., after last view
|
||||||
nsView* kid = aParent->GetFirstChild();
|
nsView* kid = aParent->GetFirstChild();
|
||||||
@@ -693,7 +645,6 @@ void nsViewManager::InsertChild(nsView* aParent, nsView* aChild,
|
|||||||
}
|
}
|
||||||
// prev is last view or null if there are no children
|
// prev is last view or null if there are no children
|
||||||
aParent->InsertChild(aChild, prev);
|
aParent->InsertChild(aChild, prev);
|
||||||
ReparentWidgets(aChild, aParent);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
nsView* kid = aParent->GetFirstChild();
|
nsView* kid = aParent->GetFirstChild();
|
||||||
@@ -707,11 +658,9 @@ void nsViewManager::InsertChild(nsView* aParent, nsView* aChild,
|
|||||||
if (aAfter) {
|
if (aAfter) {
|
||||||
// insert after 'kid' in document order, i.e. before in view order
|
// insert after 'kid' in document order, i.e. before in view order
|
||||||
aParent->InsertChild(aChild, prev);
|
aParent->InsertChild(aChild, prev);
|
||||||
ReparentWidgets(aChild, aParent);
|
|
||||||
} else {
|
} else {
|
||||||
// insert before 'kid' in document order, i.e. after in view order
|
// insert before 'kid' in document order, i.e. after in view order
|
||||||
aParent->InsertChild(aChild, kid);
|
aParent->InsertChild(aChild, kid);
|
||||||
ReparentWidgets(aChild, aParent);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -309,8 +309,6 @@ class nsViewManager final {
|
|||||||
static void CollectVMsForWillPaint(nsView* aView, nsViewManager* aParentVM,
|
static void CollectVMsForWillPaint(nsView* aView, nsViewManager* aParentVM,
|
||||||
nsTArray<RefPtr<nsViewManager>>& aVMs);
|
nsTArray<RefPtr<nsViewManager>>& aVMs);
|
||||||
|
|
||||||
void ReparentChildWidgets(nsView* aView, nsIWidget* aNewWidget);
|
|
||||||
void ReparentWidgets(nsView* aView, nsView* aParent);
|
|
||||||
void InvalidateWidgetArea(nsView* aWidgetView,
|
void InvalidateWidgetArea(nsView* aWidgetView,
|
||||||
const nsRegion& aDamagedRegion);
|
const nsRegion& aDamagedRegion);
|
||||||
|
|
||||||
|
|||||||
@@ -2306,7 +2306,7 @@ void nsWindow::OnGeckoViewReady() {
|
|||||||
acc->OnReady();
|
acc->OnReady();
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsWindow::DidChangeParent(nsIWidget*) {
|
void nsWindow::DidClearParent(nsIWidget*) {
|
||||||
// if we are now in the toplevel window's hierarchy, schedule a redraw
|
// if we are now in the toplevel window's hierarchy, schedule a redraw
|
||||||
if (FindTopLevel() == nsWindow::TopWindow()) {
|
if (FindTopLevel() == nsWindow::TopWindow()) {
|
||||||
RedrawAll();
|
RedrawAll();
|
||||||
|
|||||||
@@ -158,7 +158,7 @@ class nsWindow final : public nsBaseWidget {
|
|||||||
const LayoutDeviceIntRect& aRect,
|
const LayoutDeviceIntRect& aRect,
|
||||||
InitData* aInitData) override;
|
InitData* aInitData) override;
|
||||||
void Destroy() override;
|
void Destroy() override;
|
||||||
void DidChangeParent(nsIWidget* aNewParent) override;
|
void DidClearParent(nsIWidget*) override;
|
||||||
float GetDPI() override;
|
float GetDPI() override;
|
||||||
double GetDefaultScaleInternal() override;
|
double GetDefaultScaleInternal() override;
|
||||||
void Show(bool aState) override;
|
void Show(bool aState) override;
|
||||||
|
|||||||
@@ -469,7 +469,7 @@ class nsChildView final : public nsBaseWidget {
|
|||||||
|
|
||||||
nsCocoaWindow* GetAppWindowWidget() const;
|
nsCocoaWindow* GetAppWindowWidget() const;
|
||||||
|
|
||||||
void DidChangeParent(nsIWidget*) override;
|
void DidClearParent(nsIWidget*) override;
|
||||||
|
|
||||||
mozilla::widget::TextInputHandler* GetTextInputHandler() {
|
mozilla::widget::TextInputHandler* GetTextInputHandler() {
|
||||||
return mTextInputHandler;
|
return mTextInputHandler;
|
||||||
|
|||||||
@@ -249,7 +249,7 @@ nsChildView::~nsChildView() {
|
|||||||
// mGeckoChild are used throughout the ChildView class to tell if it's safe
|
// mGeckoChild are used throughout the ChildView class to tell if it's safe
|
||||||
// to use a ChildView object.
|
// to use a ChildView object.
|
||||||
[mView widgetDestroyed]; // Safe if mView is nil.
|
[mView widgetDestroyed]; // Safe if mView is nil.
|
||||||
SetParent(nullptr);
|
ClearParent();
|
||||||
TearDownView(); // Safe if called twice.
|
TearDownView(); // Safe if called twice.
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -524,23 +524,15 @@ void nsChildView::Show(bool aState) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Change the parent of this widget
|
// Change the parent of this widget
|
||||||
void nsChildView::DidChangeParent(nsIWidget*) {
|
void nsChildView::DidClearParent(nsIWidget*) {
|
||||||
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
|
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
|
||||||
|
|
||||||
if (mOnDestroyCalled) {
|
if (mOnDestroyCalled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
|
|
||||||
|
|
||||||
// we hold a ref to mView, so this is safe
|
// we hold a ref to mView, so this is safe
|
||||||
[mView removeFromSuperview];
|
[mView removeFromSuperview];
|
||||||
mParentView = mParent
|
|
||||||
? (NSView<mozView>*)mParent->GetNativeData(NS_NATIVE_WIDGET)
|
|
||||||
: nullptr;
|
|
||||||
if (mParentView) {
|
|
||||||
[mParentView addSubview:mView];
|
|
||||||
}
|
|
||||||
|
|
||||||
NS_OBJC_END_TRY_IGNORE_BLOCK;
|
NS_OBJC_END_TRY_IGNORE_BLOCK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -715,29 +715,6 @@ bool nsWindow::WidgetTypeSupportsAcceleration() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsWindow::DidChangeParent(nsIWidget* aOldParent) {
|
|
||||||
LOG("nsWindow::DidChangeParent new parent %p -> %p\n", aOldParent, mParent);
|
|
||||||
if (!mParent) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* newParent = static_cast<nsWindow*>(mParent);
|
|
||||||
if (mIsDestroyed || newParent->IsDestroyed()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!IsTopLevelWidget()) {
|
|
||||||
GdkWindow* window = GetToplevelGdkWindow();
|
|
||||||
GdkWindow* parentWindow = newParent->GetToplevelGdkWindow();
|
|
||||||
gdk_window_reparent(window, parentWindow, 0, 0);
|
|
||||||
SetHasMappedToplevel(newParent->mHasMappedToplevel);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
GtkWindow* newParentWidget = GTK_WINDOW(newParent->GetGtkWidget());
|
|
||||||
GtkWindowSetTransientFor(GTK_WINDOW(mShell), newParentWidget);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void InitPenEvent(WidgetMouseEvent& aGeckoEvent, GdkEvent* aEvent) {
|
static void InitPenEvent(WidgetMouseEvent& aGeckoEvent, GdkEvent* aEvent) {
|
||||||
// Find the source of the event
|
// Find the source of the event
|
||||||
GdkDevice* device = gdk_event_get_source_device(aEvent);
|
GdkDevice* device = gdk_event_get_source_device(aEvent);
|
||||||
|
|||||||
@@ -338,7 +338,6 @@ class nsWindow final : public nsBaseWidget {
|
|||||||
void SetTransparencyMode(TransparencyMode aMode) override;
|
void SetTransparencyMode(TransparencyMode aMode) override;
|
||||||
TransparencyMode GetTransparencyMode() override;
|
TransparencyMode GetTransparencyMode() override;
|
||||||
void SetInputRegion(const InputRegion&) override;
|
void SetInputRegion(const InputRegion&) override;
|
||||||
void DidChangeParent(nsIWidget* aOldParent) override;
|
|
||||||
|
|
||||||
nsresult SynthesizeNativeMouseEvent(LayoutDeviceIntPoint aPoint,
|
nsresult SynthesizeNativeMouseEvent(LayoutDeviceIntPoint aPoint,
|
||||||
NativeMouseMessage aNativeMessage,
|
NativeMouseMessage aNativeMessage,
|
||||||
|
|||||||
@@ -426,22 +426,20 @@ void nsBaseWidget::BaseCreate(nsIWidget* aParent, widget::InitData* aInitData) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsIWidget::SetParent(nsIWidget* aNewParent) {
|
void nsIWidget::ClearParent() {
|
||||||
|
if (!mParent) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
nsCOMPtr<nsIWidget> kungFuDeathGrip = this;
|
nsCOMPtr<nsIWidget> kungFuDeathGrip = this;
|
||||||
nsCOMPtr<nsIWidget> oldParent = mParent;
|
nsCOMPtr<nsIWidget> oldParent = mParent;
|
||||||
if (mParent) {
|
oldParent->RemoveFromChildList(this);
|
||||||
mParent->RemoveFromChildList(this);
|
mParent = nullptr;
|
||||||
}
|
DidClearParent(oldParent);
|
||||||
mParent = aNewParent;
|
|
||||||
if (mParent) {
|
|
||||||
mParent->AddToChildList(this);
|
|
||||||
}
|
|
||||||
DidChangeParent(oldParent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsIWidget::RemoveAllChildren() {
|
void nsIWidget::RemoveAllChildren() {
|
||||||
while (nsCOMPtr<nsIWidget> kid = mLastChild) {
|
while (nsCOMPtr<nsIWidget> kid = mLastChild) {
|
||||||
kid->SetParent(nullptr);
|
kid->ClearParent();
|
||||||
MOZ_ASSERT(kid != mLastChild);
|
MOZ_ASSERT(kid != mLastChild);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -513,14 +513,8 @@ class nsIWidget : public nsISupports {
|
|||||||
*/
|
*/
|
||||||
bool Destroyed() const { return mOnDestroyCalled; }
|
bool Destroyed() const { return mOnDestroyCalled; }
|
||||||
|
|
||||||
/**
|
/** Clear the widget's parent. */
|
||||||
* Reparent a widget
|
void ClearParent();
|
||||||
*
|
|
||||||
* Change the widget's parent. Null parents are allowed.
|
|
||||||
*
|
|
||||||
* @param aNewParent new parent
|
|
||||||
*/
|
|
||||||
void SetParent(nsIWidget* aNewParent);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the parent Widget of this Widget or nullptr if this is a
|
* Return the parent Widget of this Widget or nullptr if this is a
|
||||||
@@ -531,8 +525,8 @@ class nsIWidget : public nsISupports {
|
|||||||
*/
|
*/
|
||||||
nsIWidget* GetParent() const { return mParent; }
|
nsIWidget* GetParent() const { return mParent; }
|
||||||
|
|
||||||
/** Gets called when mParent changes after creation. */
|
/** Gets called when mParent is cleared. */
|
||||||
virtual void DidChangeParent(nsIWidget* aOldParent) {}
|
virtual void DidClearParent(nsIWidget* aOldParent) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the top level Widget of this Widget
|
* Return the top level Widget of this Widget
|
||||||
|
|||||||
@@ -760,7 +760,7 @@ nsresult nsWindow::Create(nsIWidget* aParent, const LayoutDeviceIntRect& aRect,
|
|||||||
void nsWindow::Destroy() {
|
void nsWindow::Destroy() {
|
||||||
for (uint32_t i = 0; i < mChildren.Length(); ++i) {
|
for (uint32_t i = 0; i < mChildren.Length(); ++i) {
|
||||||
// why do we still have children?
|
// why do we still have children?
|
||||||
mChildren[i]->SetParent(nullptr);
|
mChildren[i]->ClearParent();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mParent) mParent->mChildren.RemoveElement(this);
|
if (mParent) mParent->mChildren.RemoveElement(this);
|
||||||
|
|||||||
@@ -1441,13 +1441,11 @@ void nsWindow::DissociateFromNativeWindow() {
|
|||||||
mPrevWndProc.reset();
|
mPrevWndProc.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void nsWindow::DidChangeParent(nsIWidget*) {
|
void nsWindow::DidClearParent(nsIWidget*) {
|
||||||
if (mWindowType == WindowType::Popup || !mWnd) {
|
if (mWindowType == WindowType::Popup || !mWnd) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
HWND newParent =
|
::SetParent(mWnd, nullptr);
|
||||||
mParent ? (HWND)mParent->GetNativeData(NS_NATIVE_WINDOW) : nullptr;
|
|
||||||
::SetParent(mWnd, newParent);
|
|
||||||
RecreateDirectManipulationIfNeeded();
|
RecreateDirectManipulationIfNeeded();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -195,7 +195,7 @@ class nsWindow final : public nsBaseWidget {
|
|||||||
void Destroy() override;
|
void Destroy() override;
|
||||||
float GetDPI() override;
|
float GetDPI() override;
|
||||||
double GetDefaultScaleInternal() override;
|
double GetDefaultScaleInternal() override;
|
||||||
void DidChangeParent(nsIWidget* aOldParent) override;
|
void DidClearParent(nsIWidget* aOldParent) override;
|
||||||
int32_t LogToPhys(double aValue);
|
int32_t LogToPhys(double aValue);
|
||||||
mozilla::DesktopToLayoutDeviceScale GetDesktopToDeviceScale() override {
|
mozilla::DesktopToLayoutDeviceScale GetDesktopToDeviceScale() override {
|
||||||
if (mozilla::widget::WinUtils::IsPerMonitorDPIAware()) {
|
if (mozilla::widget::WinUtils::IsPerMonitorDPIAware()) {
|
||||||
|
|||||||
Reference in New Issue
Block a user