Bug 1902315 - Remove other widget z-level fiction. r=win-reviewers,rkraesig,geckoview-reviewers,spohl,m_kato

This comes back to bug 42557 and co. It only does something
half-reasonable on Windows (on macOS we just lie and make z-order
tracking be latest-active tracking), and given we don't use the special
zorder flags elsewhere I'm pretty sure we should be able to just rip
this off... On some DEs like Wayland we can't re-stack toplevel windows.

Differential Revision: https://phabricator.services.mozilla.com/D213602
This commit is contained in:
Emilio Cobos Álvarez 2024-06-19 07:47:36 +00:00
parent b0027fa5ab
commit 6ecd66ed03
24 changed files with 68 additions and 1028 deletions

View File

@ -2441,10 +2441,6 @@ void nsWindow::Resize(double aX, double aY, double aWidth, double aHeight,
if (aRepaint && FindTopLevel() == nsWindow::TopWindow()) RedrawAll();
}
void nsWindow::SetZIndex(int32_t aZIndex) {
ALOG("nsWindow[%p]::SetZIndex %d ignored", (void*)this, aZIndex);
}
void nsWindow::SetSizeMode(nsSizeMode aMode) {
if (aMode == mSizeMode) {
return;

View File

@ -141,57 +141,56 @@ class nsWindow final : public nsBaseWidget {
//
using nsBaseWidget::Create; // for Create signature not overridden here
[[nodiscard]] virtual nsresult Create(nsIWidget* aParent,
nsNativeWidget aNativeParent,
const LayoutDeviceIntRect& aRect,
InitData* aInitData) override;
virtual void Destroy() override;
virtual void SetParent(nsIWidget* aNewParent) override;
virtual nsIWidget* GetParent(void) override;
virtual float GetDPI() override;
virtual double GetDefaultScaleInternal() override;
virtual void Show(bool aState) override;
virtual bool IsVisible() const override;
virtual void ConstrainPosition(DesktopIntPoint&) override;
virtual void Move(double aX, double aY) override;
virtual void Resize(double aWidth, double aHeight, bool aRepaint) override;
virtual void Resize(double aX, double aY, double aWidth, double aHeight,
bool aRepaint) override;
void SetZIndex(int32_t aZIndex) override;
virtual nsSizeMode SizeMode() override { return mSizeMode; }
virtual void SetSizeMode(nsSizeMode aMode) override;
virtual void Enable(bool aState) override;
virtual bool IsEnabled() const override;
virtual void Invalidate(const LayoutDeviceIntRect& aRect) override;
virtual void SetFocus(Raise, mozilla::dom::CallerType aCallerType) override;
virtual LayoutDeviceIntRect GetScreenBounds() override;
virtual LayoutDeviceIntPoint WidgetToScreenOffset() override;
virtual nsresult DispatchEvent(mozilla::WidgetGUIEvent* aEvent,
nsEventStatus& aStatus) override;
[[nodiscard]] nsresult Create(nsIWidget* aParent,
nsNativeWidget aNativeParent,
const LayoutDeviceIntRect& aRect,
InitData* aInitData) override;
void Destroy() override;
void SetParent(nsIWidget* aNewParent) override;
nsIWidget* GetParent(void) override;
float GetDPI() override;
double GetDefaultScaleInternal() override;
void Show(bool aState) override;
bool IsVisible() const override;
void ConstrainPosition(DesktopIntPoint&) override;
void Move(double aX, double aY) override;
void Resize(double aWidth, double aHeight, bool aRepaint) override;
void Resize(double aX, double aY, double aWidth, double aHeight,
bool aRepaint) override;
nsSizeMode SizeMode() override { return mSizeMode; }
void SetSizeMode(nsSizeMode aMode) override;
void Enable(bool aState) override;
bool IsEnabled() const override;
void Invalidate(const LayoutDeviceIntRect& aRect) override;
void SetFocus(Raise, mozilla::dom::CallerType aCallerType) override;
LayoutDeviceIntRect GetScreenBounds() override;
LayoutDeviceIntPoint WidgetToScreenOffset() override;
nsresult DispatchEvent(mozilla::WidgetGUIEvent* aEvent,
nsEventStatus& aStatus) override;
nsEventStatus DispatchEvent(mozilla::WidgetGUIEvent* aEvent);
virtual nsresult MakeFullScreen(bool aFullScreen) override;
nsresult MakeFullScreen(bool aFullScreen) override;
void SetCursor(const Cursor& aDefaultCursor) override;
void* GetNativeData(uint32_t aDataType) override;
virtual nsresult SetTitle(const nsAString& aTitle) override { return NS_OK; }
[[nodiscard]] virtual nsresult GetAttention(int32_t aCycleCount) override {
nsresult SetTitle(const nsAString& aTitle) override { return NS_OK; }
[[nodiscard]] nsresult GetAttention(int32_t aCycleCount) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
TextEventDispatcherListener* GetNativeTextEventDispatcherListener() override;
virtual void SetInputContext(const InputContext& aContext,
const InputContextAction& aAction) override;
virtual InputContext GetInputContext() override;
void SetInputContext(const InputContext& aContext,
const InputContextAction& aAction) override;
InputContext GetInputContext() override;
WindowRenderer* GetWindowRenderer() override;
void NotifyCompositorSessionLost(
mozilla::layers::CompositorSession* aSession) override;
virtual bool NeedsPaint() override;
bool NeedsPaint() override;
virtual bool WidgetPaintsBackground() override;
bool WidgetPaintsBackground() override;
virtual uint32_t GetMaxTouchPoints() const override;
uint32_t GetMaxTouchPoints() const override;
void UpdateZoomConstraints(
const uint32_t& aPresShellId, const ScrollableLayerGuid::ViewID& aViewId,
@ -213,7 +212,7 @@ class nsWindow final : public nsBaseWidget {
void SetCompositorWidgetDelegate(CompositorWidgetDelegate* delegate) override;
virtual void GetCompositorWidgetInitData(
void GetCompositorWidgetInitData(
mozilla::widget::CompositorWidgetInitData* aInitData) override;
mozilla::layers::CompositorBridgeChild* GetCompositorBridgeChild() const;
@ -241,7 +240,7 @@ class nsWindow final : public nsBaseWidget {
void UpdateDynamicToolbarOffset(mozilla::ScreenIntCoord aOffset);
virtual mozilla::ScreenIntMargin GetSafeAreaInsets() const override;
mozilla::ScreenIntMargin GetSafeAreaInsets() const override;
void UpdateSafeAreaInsets(const mozilla::ScreenIntMargin& aSafeAreaInsets);
mozilla::jni::NativeWeakPtr<mozilla::widget::NPZCSupport>

View File

@ -368,7 +368,6 @@ class nsCocoaWindow final : public nsBaseWidget {
void DestroyNativeWindow();
void UpdateBounds();
int32_t GetWorkspaceID();
void SendSetZLevelEvent();
void DoResize(double aX, double aY, double aWidth, double aHeight,
bool aRepaint, bool aConstrainToCurrentScreen);

View File

@ -799,7 +799,6 @@ void nsCocoaWindow::Show(bool aState) {
[mWindow orderFront:nil];
}
NS_OBJC_END_TRY_IGNORE_BLOCK;
SendSetZLevelEvent();
// If our popup window is a non-native context menu, tell the OS (and
// other programs) that a menu has opened. This is how the OS knows to
// close other programs' context menus when ours open.
@ -848,7 +847,6 @@ void nsCocoaWindow::Show(bool aState) {
[mWindow makeKeyAndOrderFront:nil];
}
NS_OBJC_END_TRY_IGNORE_BLOCK;
SendSetZLevelEvent();
}
SetSupportsNativeFullscreen(savedValueForSupportsNativeFullscreen);
} else {
@ -2056,15 +2054,6 @@ bool nsCocoaWindow::DragEvent(unsigned int aMessage,
return false;
}
void nsCocoaWindow::SendSetZLevelEvent() {
if (mWidgetListener) {
nsWindowZ placement = nsWindowZTop;
nsCOMPtr<nsIWidget> actualBelow;
mWidgetListener->ZLevelChanged(true, &placement, nullptr,
getter_AddRefs(actualBelow));
}
}
// Invokes callback and ProcessEvent methods on Event Listener object
nsresult nsCocoaWindow::DispatchEvent(WidgetGUIEvent* event,
nsEventStatus& aStatus) {
@ -2215,7 +2204,6 @@ void nsCocoaWindow::SetFocus(Raise aRaise,
[mWindow deminiaturize:nil];
}
[mWindow makeKeyAndOrderFront:nil];
SendSetZLevelEvent();
}
}

View File

@ -2725,37 +2725,6 @@ void nsWindow::WaylandPopupMoveImpl() {
mPopupMoveToRectParams.mHints, offset.x, offset.y);
}
void nsWindow::SetZIndex(int32_t aZIndex) {
nsIWidget* oldPrev = GetPrevSibling();
nsBaseWidget::SetZIndex(aZIndex);
if (GetPrevSibling() == oldPrev) {
return;
}
// We skip the nsWindows that don't have mGdkWindows.
// These are probably in the process of being destroyed.
if (!mGdkWindow) {
return;
}
if (!GetNextSibling()) {
// We're to be on top.
if (mGdkWindow) {
gdk_window_raise(mGdkWindow);
}
} else {
// All the siblings before us need to be below our widget.
for (nsWindow* w = this; w;
w = static_cast<nsWindow*>(w->GetPrevSibling())) {
if (w->mGdkWindow) {
gdk_window_lower(w->mGdkWindow);
}
}
}
}
void nsWindow::SetSizeMode(nsSizeMode aMode) {
LOG("nsWindow::SetSizeMode %d\n", aMode);

View File

@ -169,7 +169,6 @@ class nsWindow final : public nsBaseWidget {
bool aRepaint) override;
bool IsEnabled() const override;
void SetZIndex(int32_t aZIndex) override;
nsSizeMode SizeMode() override { return mSizeMode; }
void SetSizeMode(nsSizeMode aMode) override;
void GetWorkspaceID(nsAString& workspaceID) override;

View File

@ -170,13 +170,6 @@ void HeadlessWidget::RaiseWindow() {
return;
}
// Raise the window to the top of the stack.
nsWindowZ placement = nsWindowZTop;
nsCOMPtr<nsIWidget> actualBelow;
if (mWidgetListener)
mWidgetListener->ZLevelChanged(true, &placement, nullptr,
getter_AddRefs(actualBelow));
// Deactivate the last active window.
if (activeWindow && activeWindow->mWidgetListener) {
activeWindow->mWidgetListener->WindowDeactivated();

View File

@ -646,51 +646,6 @@ void nsBaseWidget::RemoveChild(nsIWidget* aChild) {
aChild->SetPrevSibling(nullptr);
}
//-------------------------------------------------------------------------
//
// Sets widget's position within its parent's child list.
//
//-------------------------------------------------------------------------
void nsBaseWidget::SetZIndex(int32_t aZIndex) {
// Hold a ref to ourselves just in case, since we're going to remove
// from our parent.
nsCOMPtr<nsIWidget> kungFuDeathGrip(this);
mZIndex = aZIndex;
// reorder this child in its parent's list.
auto* parent = static_cast<nsBaseWidget*>(GetParent());
if (parent) {
parent->RemoveChild(this);
// Scope sib outside the for loop so we can check it afterward
nsIWidget* sib = parent->GetFirstChild();
for (; sib; sib = sib->GetNextSibling()) {
int32_t childZIndex = GetZIndex();
if (aZIndex < childZIndex) {
// Insert ourselves before sib
nsIWidget* prev = sib->GetPrevSibling();
mNextSibling = sib;
mPrevSibling = prev;
sib->SetPrevSibling(this);
if (prev) {
prev->SetNextSibling(this);
} else {
NS_ASSERTION(sib == parent->mFirstChild, "Broken child list");
// We've taken ownership of sib, so it's safe to have parent let
// go of it
parent->mFirstChild = this;
}
PlaceBehind(eZPlacementBelow, sib, false);
break;
}
}
// were we added to the list?
if (!sib) {
parent->AddChild(this);
}
}
}
void nsBaseWidget::GetWorkspaceID(nsAString& workspaceID) {
workspaceID.Truncate();
}

View File

@ -176,10 +176,6 @@ class nsBaseWidget : public nsIWidget, public nsSupportsWeakReference {
void AddChild(nsIWidget* aChild) override;
void RemoveChild(nsIWidget* aChild) override;
void SetZIndex(int32_t aZIndex) override;
void PlaceBehind(nsTopLevelWidgetZPlacement aPlacement, nsIWidget* aWidget,
bool aActivate) override {}
void GetWorkspaceID(nsAString& workspaceID) override;
void MoveToWorkspace(const nsAString& workspaceID) override;
bool IsTiled() const override { return mIsTiled; }

View File

@ -215,12 +215,6 @@ enum nsCursor { ///(normal cursor, usually rendered as an arrow)
eCursorInvalid = eCursorCount + 1
};
enum nsTopLevelWidgetZPlacement { // for PlaceBehind()
eZPlacementBottom = 0, // bottom of the window stack
eZPlacementBelow, // just below another widget
eZPlacementTop // top of the window stack
};
/**
* Before the OS goes to sleep, this topic is notified.
*/
@ -408,10 +402,7 @@ class nsIWidget : public nsISupports {
: mLastChild(nullptr),
mPrevSibling(nullptr),
mOnDestroyCalled(false),
mWindowType(WindowType::Child),
mZIndex(0)
{
mWindowType(WindowType::Child) {
ClearNativeTouchSequence(nullptr);
}
@ -798,30 +789,6 @@ class nsIWidget : public nsISupports {
*/
virtual void ResizeClient(const DesktopRect& aRect, bool aRepaint) = 0;
/**
* Sets the widget's z-index.
*/
virtual void SetZIndex(int32_t aZIndex) = 0;
/**
* Gets the widget's z-index.
*/
int32_t GetZIndex() { return mZIndex; }
/**
* Position this widget just behind the given widget. (Used to
* control z-order for top-level widgets. Get/SetZIndex by contrast
* control z-order for child widgets of other widgets.)
* @param aPlacement top, bottom, or below a widget
* (if top or bottom, param aWidget is ignored)
* @param aWidget widget to place this widget behind
* (only if aPlacement is eZPlacementBelow).
* null is equivalent to aPlacement of eZPlacementTop
* @param aActivate true to activate the widget after placing it
*/
virtual void PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
nsIWidget* aWidget, bool aActivate) = 0;
/**
* Minimize, maximize or normalize the window size.
* Takes a value from nsSizeMode (see nsIWidgetListener.h)
@ -2129,7 +2096,6 @@ class nsIWidget : public nsISupports {
// When Destroy() is called, the sub class should set this true.
bool mOnDestroyCalled;
WindowType mWindowType;
int32_t mZIndex;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIWidget, NS_IWIDGET_IID)

View File

@ -45,12 +45,6 @@ void nsIWidgetListener::DynamicToolbarOffsetChanged(ScreenIntCoord aOffset) {}
void nsIWidgetListener::MacFullscreenMenubarOverlapChanged(
mozilla::DesktopCoord aOverlapAmount) {}
bool nsIWidgetListener::ZLevelChanged(bool aImmediate, nsWindowZ* aPlacement,
nsIWidget* aRequestBelow,
nsIWidget** aActualBelow) {
return false;
}
void nsIWidgetListener::OcclusionStateChanged(bool aIsFullyOccluded) {}
void nsIWidgetListener::WindowActivated() {}

View File

@ -86,17 +86,6 @@ class nsIWidgetListener {
virtual void DynamicToolbarOffsetChanged(mozilla::ScreenIntCoord aOffset);
#endif
/**
* Called when the z-order of the window is changed. Returns true if the
* notification was handled. aPlacement indicates the new z order. If
* placement is nsWindowZRelative, then aRequestBelow should be the
* window to place below. On return, aActualBelow will be set to the
* window actually behind. This generally only applies to Windows.
*/
virtual bool ZLevelChanged(bool aImmediate, nsWindowZ* aPlacement,
nsIWidget* aRequestBelow,
nsIWidget** aActualBelow);
/**
* Called when the macOS titlebar is shown while in fullscreen.
*/

View File

@ -2103,40 +2103,14 @@ void nsWindow::Resize(double aX, double aY, double aWidth, double aHeight,
/**************************************************************
*
* SECTION: Window Z-order and state.
* SECTION: Window state.
*
* nsIWidget::PlaceBehind, nsIWidget::SetSizeMode,
* nsIWidget::ConstrainPosition
* nsIWidget::SetSizeMode, nsIWidget::ConstrainPosition
*
* Z-order, positioning, restore, minimize, and maximize.
* Positioning, restore, minimize, and maximize.
*
**************************************************************/
// Position the window behind the given window
void nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
nsIWidget* aWidget, bool aActivate) {
HWND behind = HWND_TOP;
if (aPlacement == eZPlacementBottom)
behind = HWND_BOTTOM;
else if (aPlacement == eZPlacementBelow && aWidget)
behind = (HWND)aWidget->GetNativeData(NS_NATIVE_WINDOW);
UINT flags = SWP_NOMOVE | SWP_NOREPOSITION | SWP_NOSIZE;
if (!aActivate) flags |= SWP_NOACTIVATE;
if (!CanTakeFocus() && behind == HWND_TOP) {
// Can't place the window to top so place it behind the foreground window
// (as long as it is not topmost)
HWND wndAfter = ::GetForegroundWindow();
if (!wndAfter)
behind = HWND_BOTTOM;
else if (!(GetWindowLongPtrW(wndAfter, GWL_EXSTYLE) & WS_EX_TOPMOST))
behind = wndAfter;
flags |= SWP_NOACTIVATE;
}
::SetWindowPos(mWnd, behind, 0, 0, 0, 0, flags);
}
static UINT GetCurrentShowCmd(HWND aWnd) {
WINDOWPLACEMENT pl;
pl.length = sizeof(pl);
@ -6695,40 +6669,10 @@ void nsWindow::OnWindowPosChanging(WINDOWPOS* info) {
}
}
// enforce local z-order rules
if (!(info->flags & SWP_NOZORDER)) {
HWND hwndAfter = info->hwndInsertAfter;
nsWindow* aboveWindow = 0;
nsWindowZ placement;
if (hwndAfter == HWND_BOTTOM)
placement = nsWindowZBottom;
else if (hwndAfter == HWND_TOP || hwndAfter == HWND_TOPMOST ||
hwndAfter == HWND_NOTOPMOST)
placement = nsWindowZTop;
else {
placement = nsWindowZRelative;
aboveWindow = WinUtils::GetNSWindowPtr(hwndAfter);
}
if (mWidgetListener) {
nsCOMPtr<nsIWidget> actualBelow = nullptr;
if (mWidgetListener->ZLevelChanged(false, &placement, aboveWindow,
getter_AddRefs(actualBelow))) {
if (placement == nsWindowZBottom)
info->hwndInsertAfter = HWND_BOTTOM;
else if (placement == nsWindowZTop)
info->hwndInsertAfter = HWND_TOP;
else {
info->hwndInsertAfter =
(HWND)actualBelow->GetNativeData(NS_NATIVE_WINDOW);
}
}
}
}
// prevent rude external programs from making hidden window visible
if (mWindowType == WindowType::Invisible) info->flags &= ~SWP_SHOWWINDOW;
if (mWindowType == WindowType::Invisible) {
info->flags &= ~SWP_SHOWWINDOW;
}
// When waking from sleep or switching out of tablet mode, Windows 10
// Version 1809 will reopen popup windows that should be hidden. Detect

View File

@ -175,8 +175,6 @@ class nsWindow final : public nsBaseWidget {
void Resize(double aWidth, double aHeight, bool aRepaint) override;
void Resize(double aX, double aY, double aWidth, double aHeight,
bool aRepaint) override;
void PlaceBehind(nsTopLevelWidgetZPlacement aPlacement, nsIWidget* aWidget,
bool aActivate) override;
void SetSizeMode(nsSizeMode aMode) override;
nsSizeMode SizeMode() override;
void GetWorkspaceID(nsAString& workspaceID) override;

View File

@ -300,58 +300,6 @@ NS_IMETHODIMP AppWindow::GetDocShell(nsIDocShell** aDocShell) {
return NS_OK;
}
NS_IMETHODIMP AppWindow::GetZLevel(uint32_t* outLevel) {
nsCOMPtr<nsIWindowMediator> mediator(
do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
if (mediator)
mediator->GetZLevel(this, outLevel);
else
*outLevel = normalZ;
return NS_OK;
}
NS_IMETHODIMP AppWindow::SetZLevel(uint32_t aLevel) {
nsCOMPtr<nsIWindowMediator> mediator(
do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
if (!mediator) return NS_ERROR_FAILURE;
uint32_t zLevel;
mediator->GetZLevel(this, &zLevel);
if (zLevel == aLevel) return NS_OK;
/* refuse to raise a maximized window above the normal browser level,
for fear it could hide newly opened browser windows */
if (aLevel > nsIAppWindow::normalZ && mWindow) {
nsSizeMode sizeMode = mWindow->SizeMode();
if (sizeMode == nsSizeMode_Maximized || sizeMode == nsSizeMode_Fullscreen) {
return NS_ERROR_FAILURE;
}
}
// do it
mediator->SetZLevel(this, aLevel);
PersistentAttributesDirty(PersistentAttribute::Misc, Sync);
nsCOMPtr<nsIDocumentViewer> viewer;
mDocShell->GetDocViewer(getter_AddRefs(viewer));
if (viewer) {
RefPtr<dom::Document> doc = viewer->GetDocument();
if (doc) {
ErrorResult rv;
RefPtr<dom::Event> event =
doc->CreateEvent(u"Events"_ns, dom::CallerType::System, rv);
if (event) {
event->InitEvent(u"windowZLevel"_ns, true, false);
event->SetTrusted(true);
doc->DispatchEvent(*event);
}
}
}
return NS_OK;
}
NS_IMETHODIMP AppWindow::GetChromeFlags(uint32_t* aChromeFlags) {
NS_ENSURE_ARG_POINTER(aChromeFlags);
*aChromeFlags = mChromeFlags;
@ -592,40 +540,6 @@ NS_IMETHODIMP AppWindow::Destroy() {
if (mWindow) mWindow->Show(false);
#endif
#if defined(XP_WIN)
// We need to explicitly set the focus on Windows, but
// only if the parent is visible.
nsCOMPtr<nsIBaseWindow> parent(do_QueryReferent(mParentWindow));
if (parent) {
nsCOMPtr<nsIWidget> parentWidget;
parent->GetMainWidget(getter_AddRefs(parentWidget));
if (parentWidget && parentWidget->IsVisible()) {
bool isParentHiddenWindow = false;
if (appShell) {
bool hasHiddenWindow = false;
appShell->GetHasHiddenWindow(&hasHiddenWindow);
if (hasHiddenWindow) {
nsCOMPtr<nsIBaseWindow> baseHiddenWindow;
nsCOMPtr<nsIAppWindow> hiddenWindow;
appShell->GetHiddenWindow(getter_AddRefs(hiddenWindow));
if (hiddenWindow) {
baseHiddenWindow = do_GetInterface(hiddenWindow);
isParentHiddenWindow = (baseHiddenWindow == parent);
}
}
}
// somebody screwed up somewhere. hiddenwindow shouldn't be anybody's
// parent. still, when it happens, skip activating it.
if (!isParentHiddenWindow) {
parentWidget->PlaceBehind(eZPlacementTop, 0, true);
}
}
}
#endif
RemoveTooltipSupport();
mDOMWindow = nullptr;
@ -1398,13 +1312,13 @@ void AppWindow::SetSpecifiedSize(int32_t aSpecWidth, int32_t aSpecHeight) {
because it's important to load those before one of the misc
attributes (sizemode) and they require extra processing. */
bool AppWindow::UpdateWindowStateFromMiscXULAttributes() {
bool gotState = false;
/* There are no misc attributes of interest to the hidden window.
It's especially important not to try to validate that window's
size or position, because some platforms (Mac OS X) need to
make it visible and offscreen. */
if (mIsHiddenWindow) return false;
if (mIsHiddenWindow) {
return false;
}
nsCOMPtr<dom::Element> windowElement = GetWindowDOMElement();
NS_ENSURE_TRUE(windowElement, false);
@ -1429,10 +1343,9 @@ bool AppWindow::UpdateWindowStateFromMiscXULAttributes() {
if (mChromeFlags & nsIWebBrowserChrome::CHROME_WINDOW_RESIZE) {
mIntrinsicallySized = false;
if (stateString.Equals(SIZEMODE_MAXIMIZED))
sizeMode = nsSizeMode_Maximized;
else
sizeMode = nsSizeMode_Fullscreen;
sizeMode = stateString.Equals(SIZEMODE_MAXIMIZED)
? nsSizeMode_Maximized
: nsSizeMode_Fullscreen;
}
}
}
@ -1451,18 +1364,7 @@ bool AppWindow::UpdateWindowStateFromMiscXULAttributes() {
}
mWindow->SetSizeMode(sizeMode);
}
gotState = true;
// zlevel
windowElement->GetAttr(nsGkAtoms::zlevel, stateString);
if (!stateString.IsEmpty()) {
nsresult errorCode;
int32_t zLevel = stateString.ToInteger(&errorCode);
if (NS_SUCCEEDED(errorCode) && zLevel >= lowestZ && zLevel <= highestZ)
SetZLevel(zLevel);
}
return gotState;
return true;
}
/* Stagger windows of the same type so they don't appear on top of each other.
@ -2086,20 +1988,6 @@ void AppWindow::MaybeSavePersistentMiscAttributes(
aRootElement.SetAttribute(u"gtktiledwindow"_ns,
mWindow->IsTiled() ? u"true"_ns : u"false"_ns,
IgnoreErrors());
if (aPersistString.Find(u"zlevel") >= 0) {
uint32_t zLevel;
nsCOMPtr<nsIWindowMediator> mediator(
do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
if (mediator) {
mediator->GetZLevel(this, &zLevel);
sizeString.Truncate();
sizeString.AppendInt(zLevel);
aRootElement.SetAttr(nsGkAtoms::zlevel, sizeString, IgnoreErrors());
if (aShouldPersist) {
Unused << SetPersistentValue(nsGkAtoms::zlevel, sizeString);
}
}
}
}
void AppWindow::SavePersistentAttributes(
@ -2395,141 +2283,6 @@ void AppWindow::EnableParent(bool aEnable) {
if (parentWidget) parentWidget->Enable(aEnable);
}
// Constrain the window to its proper z-level
bool AppWindow::ConstrainToZLevel(bool aImmediate, nsWindowZ* aPlacement,
nsIWidget* aReqBelow,
nsIWidget** aActualBelow) {
#if 0
/* Do we have a parent window? This means our z-order is already constrained,
since we're a dependent window. Our window list isn't hierarchical,
so we can't properly calculate placement for such a window.
Should we just abort? */
nsCOMPtr<nsIBaseWindow> parentWindow = do_QueryReferent(mParentWindow);
if (parentWindow)
return false;
#endif
nsCOMPtr<nsIWindowMediator> mediator(
do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
if (!mediator) return false;
bool altered;
uint32_t position, newPosition, zLevel;
nsIAppWindow* us = this;
altered = false;
mediator->GetZLevel(this, &zLevel);
// translate from WidgetGUIEvent to nsIWindowMediator constants
position = nsIWindowMediator::zLevelTop;
if (*aPlacement == nsWindowZBottom || zLevel == nsIAppWindow::lowestZ)
position = nsIWindowMediator::zLevelBottom;
else if (*aPlacement == nsWindowZRelative)
position = nsIWindowMediator::zLevelBelow;
if (NS_SUCCEEDED(mediator->CalculateZPosition(
us, position, aReqBelow, &newPosition, aActualBelow, &altered))) {
/* If we were asked to move to the top but constrained to remain
below one of our other windows, first move all windows in that
window's layer and above to the top. This allows the user to
click a window which can't be topmost and still bring mozilla
to the foreground. */
if (altered &&
(position == nsIWindowMediator::zLevelTop ||
(position == nsIWindowMediator::zLevelBelow && aReqBelow == 0)))
PlaceWindowLayersBehind(zLevel + 1, nsIAppWindow::highestZ, 0);
if (*aPlacement != nsWindowZBottom &&
position == nsIWindowMediator::zLevelBottom)
altered = true;
if (altered || aImmediate) {
if (newPosition == nsIWindowMediator::zLevelTop)
*aPlacement = nsWindowZTop;
else if (newPosition == nsIWindowMediator::zLevelBottom)
*aPlacement = nsWindowZBottom;
else
*aPlacement = nsWindowZRelative;
if (aImmediate) {
nsCOMPtr<nsIBaseWindow> ourBase = do_QueryObject(this);
if (ourBase) {
nsCOMPtr<nsIWidget> ourWidget;
ourBase->GetMainWidget(getter_AddRefs(ourWidget));
ourWidget->PlaceBehind(*aPlacement == nsWindowZBottom
? eZPlacementBottom
: eZPlacementBelow,
*aActualBelow, false);
}
}
}
/* CalculateZPosition can tell us to be below nothing, because it tries
not to change something it doesn't recognize. A request to verify
being below an unrecognized window, then, is treated as a request
to come to the top (below null) */
nsCOMPtr<nsIAppWindow> windowAbove;
if (newPosition == nsIWindowMediator::zLevelBelow && *aActualBelow) {
windowAbove = (*aActualBelow)->GetWidgetListener()->GetAppWindow();
}
mediator->SetZPosition(us, newPosition, windowAbove);
}
return altered;
}
/* Re-z-position all windows in the layers from aLowLevel to aHighLevel,
inclusive, to be behind aBehind. aBehind of null means on top.
Note this method actually does nothing to our relative window positions.
(And therefore there's no need to inform WindowMediator we're moving
things, because we aren't.) This method is useful for, say, moving
a range of layers of our own windows relative to windows belonging to
external applications.
*/
void AppWindow::PlaceWindowLayersBehind(uint32_t aLowLevel, uint32_t aHighLevel,
nsIAppWindow* aBehind) {
// step through windows in z-order from top to bottommost window
nsCOMPtr<nsIWindowMediator> mediator(
do_GetService(NS_WINDOWMEDIATOR_CONTRACTID));
if (!mediator) return;
nsCOMPtr<nsISimpleEnumerator> windowEnumerator;
mediator->GetZOrderAppWindowEnumerator(0, true,
getter_AddRefs(windowEnumerator));
if (!windowEnumerator) return;
// each window will be moved behind previousHighWidget, itself
// a moving target. initialize it.
nsCOMPtr<nsIWidget> previousHighWidget;
if (aBehind) {
nsCOMPtr<nsIBaseWindow> highBase(do_QueryInterface(aBehind));
if (highBase) highBase->GetMainWidget(getter_AddRefs(previousHighWidget));
}
// get next lower window
bool more;
while (NS_SUCCEEDED(windowEnumerator->HasMoreElements(&more)) && more) {
uint32_t nextZ; // z-level of nextWindow
nsCOMPtr<nsISupports> nextWindow;
windowEnumerator->GetNext(getter_AddRefs(nextWindow));
nsCOMPtr<nsIAppWindow> nextAppWindow(do_QueryInterface(nextWindow));
nextAppWindow->GetZLevel(&nextZ);
if (nextZ < aLowLevel)
break; // we've processed all windows through aLowLevel
// move it just below its next higher window
nsCOMPtr<nsIBaseWindow> nextBase(do_QueryInterface(nextAppWindow));
if (nextBase) {
nsCOMPtr<nsIWidget> nextWidget;
nextBase->GetMainWidget(getter_AddRefs(nextWidget));
if (nextZ <= aHighLevel)
nextWidget->PlaceBehind(eZPlacementBelow, previousHighWidget, false);
previousHighWidget = nextWidget;
}
}
}
void AppWindow::SetContentScrollbarVisibility(bool aVisible) {
nsCOMPtr<nsPIDOMWindowOuter> contentWin(
do_GetInterface(mPrimaryContentShell));
@ -2927,18 +2680,6 @@ void AppWindow::SizeModeChanged(nsSizeMode aSizeMode) {
FullscreenWillChange(mIsWidgetInFullscreen);
}
// An alwaysRaised (or higher) window will hide any newly opened normal
// browser windows, so here we just drop a raised window to the normal
// zlevel if it's maximized. We make no provision for automatically
// re-raising it when restored.
if (aSizeMode == nsSizeMode_Maximized || aSizeMode == nsSizeMode_Fullscreen) {
uint32_t zLevel;
GetZLevel(&zLevel);
if (zLevel > nsIAppWindow::normalZ) {
SetZLevel(nsIAppWindow::normalZ);
}
}
RecomputeBrowsingContextVisibility();
PersistentAttributesDirty(PersistentAttribute::Misc, Sync);
@ -3086,14 +2827,6 @@ void AppWindow::OSToolbarButtonPressed() {
wbc->SetChromeFlags(chromeFlags);
}
bool AppWindow::ZLevelChanged(bool aImmediate, nsWindowZ* aPlacement,
nsIWidget* aRequestBelow,
nsIWidget** aActualBelow) {
if (aActualBelow) *aActualBelow = nullptr;
return ConstrainToZLevel(aImmediate, aPlacement, aRequestBelow, aActualBelow);
}
void AppWindow::WindowActivated() {
nsCOMPtr<nsIAppWindow> appWindow(this);
@ -3471,14 +3204,6 @@ void AppWindow::WidgetListenerDelegate::OSToolbarButtonPressed() {
holder->OSToolbarButtonPressed();
}
bool AppWindow::WidgetListenerDelegate::ZLevelChanged(
bool aImmediate, nsWindowZ* aPlacement, nsIWidget* aRequestBelow,
nsIWidget** aActualBelow) {
RefPtr<AppWindow> holder = mAppWindow;
return holder->ZLevelChanged(aImmediate, aPlacement, aRequestBelow,
aActualBelow);
}
void AppWindow::WidgetListenerDelegate::WindowActivated() {
RefPtr<AppWindow> holder = mAppWindow;
holder->WindowActivated();

View File

@ -78,40 +78,36 @@ class AppWindow final : public nsIBaseWindow,
// The implementation of non-refcounted nsIWidgetListener, which would hold a
// strong reference on stack before calling AppWindow's
// MOZ_CAN_RUN_SCRIPT methods.
class WidgetListenerDelegate : public nsIWidgetListener {
class WidgetListenerDelegate final : public nsIWidgetListener {
public:
explicit WidgetListenerDelegate(AppWindow* aAppWindow)
: mAppWindow(aAppWindow) {}
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual nsIAppWindow* GetAppWindow() override;
nsIAppWindow* GetAppWindow() override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual mozilla::PresShell* GetPresShell() override;
mozilla::PresShell* GetPresShell() override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual bool WindowMoved(nsIWidget* aWidget, int32_t x, int32_t y,
ByMoveToRect) override;
bool WindowMoved(nsIWidget* aWidget, int32_t x, int32_t y,
ByMoveToRect) override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual bool WindowResized(nsIWidget* aWidget, int32_t aWidth,
int32_t aHeight) override;
bool WindowResized(nsIWidget* aWidget, int32_t aWidth,
int32_t aHeight) override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual bool RequestWindowClose(nsIWidget* aWidget) override;
bool RequestWindowClose(nsIWidget* aWidget) override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual void SizeModeChanged(nsSizeMode sizeMode) override;
void SizeModeChanged(nsSizeMode sizeMode) override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual void MacFullscreenMenubarOverlapChanged(
void MacFullscreenMenubarOverlapChanged(
mozilla::DesktopCoord aOverlapAmount) override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual void OcclusionStateChanged(bool aIsFullyOccluded) override;
void OcclusionStateChanged(bool aIsFullyOccluded) override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual void OSToolbarButtonPressed() override;
void OSToolbarButtonPressed() override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual bool ZLevelChanged(bool aImmediate, nsWindowZ* aPlacement,
nsIWidget* aRequestBelow,
nsIWidget** aActualBelow) override;
void WindowActivated() override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual void WindowActivated() override;
MOZ_CAN_RUN_SCRIPT_BOUNDARY
virtual void WindowDeactivated() override;
void WindowDeactivated() override;
private:
// The lifetime of WidgetListenerDelegate is bound to AppWindow so
@ -163,9 +159,6 @@ class AppWindow final : public nsIBaseWindow,
MOZ_CAN_RUN_SCRIPT void OcclusionStateChanged(bool aIsFullyOccluded);
void RecomputeBrowsingContextVisibility();
MOZ_CAN_RUN_SCRIPT void OSToolbarButtonPressed();
MOZ_CAN_RUN_SCRIPT
bool ZLevelChanged(bool aImmediate, nsWindowZ* aPlacement,
nsIWidget* aRequestBelow, nsIWidget** aActualBelow);
MOZ_CAN_RUN_SCRIPT void WindowActivated();
MOZ_CAN_RUN_SCRIPT void WindowDeactivated();
@ -253,8 +246,6 @@ class AppWindow final : public nsIBaseWindow,
NS_IMETHOD GetHasPrimaryContent(bool* aResult);
void EnableParent(bool aEnable);
bool ConstrainToZLevel(bool aImmediate, nsWindowZ* aPlacement,
nsIWidget* aReqBelow, nsIWidget** aActualBelow);
void PlaceWindowLayersBehind(uint32_t aLowLevel, uint32_t aHighLevel,
nsIAppWindow* aBehind);
void SetContentScrollbarVisibility(bool aVisible);

View File

@ -182,9 +182,6 @@ nsAppShellService::CreateTopLevelWindow(nsIAppWindow* aParent, nsIURI* aUrl,
if (NS_SUCCEEDED(rv)) {
// the addref resulting from this is the owning addref for this window
RegisterTopLevelWindow(*aResult);
nsCOMPtr<nsIAppWindow> parent;
if (aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT) parent = aParent;
(*aResult)->SetZLevel(CalculateWindowZLevel(parent, aChromeMask));
}
return rv;
@ -468,41 +465,6 @@ nsAppShellService::CreateWindowlessBrowser(bool aIsChrome, uint32_t aChromeMask,
return NS_OK;
}
uint32_t nsAppShellService::CalculateWindowZLevel(nsIAppWindow* aParent,
uint32_t aChromeMask) {
uint32_t zLevel;
zLevel = nsIAppWindow::normalZ;
if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_RAISED)
zLevel = nsIAppWindow::raisedZ;
else if (aChromeMask & nsIWebBrowserChrome::CHROME_WINDOW_LOWERED)
zLevel = nsIAppWindow::loweredZ;
#ifdef XP_MACOSX
/* Platforms on which modal windows are always application-modal, not
window-modal (that's just the Mac, right?) want modal windows to
be stacked on top of everyone else.
On Mac OS X, bind modality to parent window instead of app (ala Mac OS 9)
*/
uint32_t modalDepMask =
nsIWebBrowserChrome::CHROME_MODAL | nsIWebBrowserChrome::CHROME_DEPENDENT;
if (aParent && (aChromeMask & modalDepMask)) {
aParent->GetZLevel(&zLevel);
}
#else
/* Platforms with native support for dependent windows (that's everyone
but pre-Mac OS X, right?) know how to stack dependent windows. On these
platforms, give the dependent window the same level as its parent,
so we won't try to override the normal platform behaviour. */
if ((aChromeMask & nsIWebBrowserChrome::CHROME_DEPENDENT) && aParent) {
aParent->GetZLevel(&zLevel);
}
#endif
return zLevel;
}
/*
* Just do the window-making part of CreateTopLevelWindow
*/

View File

@ -62,13 +62,11 @@ void GetWindowType(nsIAppWindow* aWindow, nsString& outType) {
//
nsWindowInfo::nsWindowInfo(nsIAppWindow* inWindow, int32_t inTimeStamp)
: mWindow(inWindow),
mTimeStamp(inTimeStamp),
mZLevel(nsIAppWindow::normalZ) {
: mWindow(inWindow), mTimeStamp(inTimeStamp) {
ReferenceSelf(true, true);
}
nsWindowInfo::~nsWindowInfo() {}
nsWindowInfo::~nsWindowInfo() = default;
// return true if the window described by this WindowInfo has a type
// equal to the given type

View File

@ -24,7 +24,6 @@ struct nsWindowInfo {
nsCOMPtr<nsIAppWindow> mWindow;
int32_t mTimeStamp;
uint32_t mZLevel;
// each struct is in two, independent, circular, doubly-linked lists
nsWindowInfo *mYounger, // next younger in sequence

View File

@ -615,8 +615,7 @@ nsContentTreeOwner::Blur() {
nsCOMPtr<nsIWindowMediator> windowMediator(
do_GetService(kWindowMediatorCID));
if (windowMediator) {
windowMediator->GetZOrderAppWindowEnumerator(
nullptr, true, getter_AddRefs(windowEnumerator));
windowMediator->GetEnumerator(nullptr, getter_AddRefs(windowEnumerator));
}
}

View File

@ -103,14 +103,6 @@ interface nsIAppWindow : nsISupports
*/
void lockAspectRatio(in boolean aShouldLock);
const unsigned long lowestZ = 0;
const unsigned long loweredZ = 4; /* "alwaysLowered" attribute */
const unsigned long normalZ = 5;
const unsigned long raisedZ = 6; /* "alwaysRaised" attribute */
const unsigned long highestZ = 9;
attribute unsigned long zLevel;
attribute uint32_t chromeFlags;
/**

View File

@ -110,76 +110,6 @@ interface nsIWindowMediator: nsISupports
*/
[noscript] void updateWindowTimeStamp(in nsIAppWindow aWindow);
/* z-ordering: */
const unsigned long zLevelTop = 1;
const unsigned long zLevelBottom = 2;
const unsigned long zLevelBelow = 3; // below some window
/** A window wants to be moved in z-order. Calculate whether and how
* it should be constrained. Note this method is advisory only:
* it changes nothing either in WindowMediator's internal state
* or with the window.
* Note it compares the nsIAppWindow to nsIWidgets. A pure interface
* would use all nsIAppWindows. But we expect this to be called from
* callbacks originating in native window code. They are expected to
* hand us comparison values which are pulled from general storage
* in the native widget, and may not correspond to an nsIWidget at all.
* For that reason this interface requires only objects one step
* removed from the native window (nsIWidgets), and its implementation
* must be very understanding of what may be completely invalid
* pointers in those parameters.
*
* @param inWindow the window in question
* @param inPosition requested position
* values: zLevelTop: topmost window. zLevelBottom: bottom.
* zLevelBelow: below ioBelow. (the value of ioBelow will
* be ignored for zLevelTop and Bottom.)
* @param inBelow if inPosition==zLevelBelow, the window
* below which inWindow wants to be placed. Otherwise this
* variable is ignored.
* @param outPosition constrained position, values like inPosition.
* @param outBelow if outPosition==zLevelBelow, the window
* below which inWindow should be placed. Otherwise this
* this value will be null.
* @return PR_TRUE if the position returned is different from
* the position given.
*/
[noscript] boolean calculateZPosition(in nsIAppWindow inWindow,
in unsigned long inPosition,
in nsIWidget inBelow,
out unsigned long outPosition,
out nsIWidget outBelow);
/** A window has been positioned behind another. Inform WindowMediator
* @param inWindow the window in question
* @param inPosition new position. values:
* zLevelTop: topmost window.
* zLevelBottom: bottom.
* zLevelBelow: below inBelow. (inBelow is ignored
* for other values of inPosition.)
* @param inBelow the window inWindow is behind, if zLevelBelow
*/
[noscript] void setZPosition(in nsIAppWindow inWindow,
in unsigned long inPosition,
in nsIAppWindow inBelow);
/** Return the window's Z level (as defined in nsIAppWindow).
* @param aWindow the window in question
* @return aWindow's z level
*/
[noscript] uint32_t getZLevel(in nsIAppWindow aWindow);
/** Set the window's Z level (as defined in nsIAppWindow). The implementation
* will reposition the window as necessary to match its new Z level.
* The implementation will assume a window's Z level to be
* nsIAppWindow::normalZ until it has been informed of a different level.
* @param aWindow the window in question
* @param aZLevel the window's new Z level
*/
[noscript] void setZLevel(in nsIAppWindow aWindow, in uint32_t aZLevel);
/** Register a listener for window status changes.
* keeps strong ref? (to be decided)
* @param aListener the listener to register

View File

@ -43,7 +43,6 @@ nsWindowMediator::nsWindowMediator()
: mOldestWindow(nullptr),
mTopmostWindow(nullptr),
mTimeStamp(0),
mSortingZOrder(false),
mReady(false) {}
nsWindowMediator::~nsWindowMediator() {
@ -379,343 +378,6 @@ nsWindowMediator::UpdateWindowTimeStamp(nsIAppWindow* inWindow) {
return NS_ERROR_FAILURE;
}
/* This method's plan is to intervene only when absolutely necessary.
We will get requests to place our windows behind unknown windows.
For the most part, we need to leave those alone (turning them into
explicit requests to be on top breaks Windows.) So generally we
calculate a change as seldom as possible.
*/
NS_IMETHODIMP
nsWindowMediator::CalculateZPosition(nsIAppWindow* inWindow,
uint32_t inPosition, nsIWidget* inBelow,
uint32_t* outPosition,
nsIWidget** outBelow, bool* outAltered) {
MOZ_RELEASE_ASSERT(NS_IsMainThread());
NS_ENSURE_ARG_POINTER(outBelow);
MOZ_ASSERT(mReady);
NS_ENSURE_STATE(mReady);
*outBelow = nullptr;
if (!inWindow || !outPosition || !outAltered) return NS_ERROR_NULL_POINTER;
if (inPosition != nsIWindowMediator::zLevelTop &&
inPosition != nsIWindowMediator::zLevelBottom &&
inPosition != nsIWindowMediator::zLevelBelow)
return NS_ERROR_INVALID_ARG;
nsWindowInfo* info = mTopmostWindow;
nsIAppWindow* belowWindow = nullptr;
bool found = false;
nsresult result = NS_OK;
*outPosition = inPosition;
*outAltered = false;
if (mSortingZOrder) { // don't fight SortZOrder()
*outBelow = inBelow;
NS_IF_ADDREF(*outBelow);
return NS_OK;
}
uint32_t inZ;
GetZLevel(inWindow, &inZ);
if (inPosition == nsIWindowMediator::zLevelBelow) {
// locate inBelow. use topmost if it can't be found or isn't in the
// z-order list
info = GetInfoFor(inBelow);
if (!info || (info->mYounger != info && info->mLower == info))
info = mTopmostWindow;
else
found = true;
if (!found) {
/* Treat unknown windows as a request to be on top.
Not as it should be, but that's what Windows gives us.
Note we change inPosition, but not *outPosition. This forces
us to go through the "on top" calculation just below, without
necessarily changing the output parameters. */
inPosition = nsIWindowMediator::zLevelTop;
}
}
if (inPosition == nsIWindowMediator::zLevelTop) {
if (mTopmostWindow && mTopmostWindow->mZLevel > inZ) {
// asked for topmost, can't have it. locate highest allowed position.
do {
if (info->mZLevel <= inZ) break;
info = info->mLower;
} while (info != mTopmostWindow);
*outPosition = nsIWindowMediator::zLevelBelow;
belowWindow = info->mHigher->mWindow;
*outAltered = true;
}
} else if (inPosition == nsIWindowMediator::zLevelBottom) {
if (mTopmostWindow && mTopmostWindow->mHigher->mZLevel < inZ) {
// asked for bottommost, can't have it. locate lowest allowed position.
do {
info = info->mHigher;
if (info->mZLevel >= inZ) break;
} while (info != mTopmostWindow);
*outPosition = nsIWindowMediator::zLevelBelow;
belowWindow = info->mWindow;
*outAltered = true;
}
} else {
unsigned long relativeZ;
// check that we're in the right z-plane
if (found) {
belowWindow = info->mWindow;
relativeZ = info->mZLevel;
if (relativeZ > inZ) {
// might be OK. is lower window, if any, lower?
if (info->mLower != info && info->mLower->mZLevel > inZ) {
do {
if (info->mZLevel <= inZ) break;
info = info->mLower;
} while (info != mTopmostWindow);
belowWindow = info->mHigher->mWindow;
*outAltered = true;
}
} else if (relativeZ < inZ) {
// nope. look for a higher window to be behind.
do {
info = info->mHigher;
if (info->mZLevel >= inZ) break;
} while (info != mTopmostWindow);
if (info->mZLevel >= inZ)
belowWindow = info->mWindow;
else
*outPosition = nsIWindowMediator::zLevelTop;
*outAltered = true;
} // else they're equal, so it's OK
}
}
if (NS_SUCCEEDED(result) && belowWindow) {
nsCOMPtr<nsIBaseWindow> base(do_QueryInterface(belowWindow));
if (base)
base->GetMainWidget(outBelow);
else
result = NS_ERROR_NO_INTERFACE;
}
return result;
}
NS_IMETHODIMP
nsWindowMediator::SetZPosition(nsIAppWindow* inWindow, uint32_t inPosition,
nsIAppWindow* inBelow) {
MOZ_RELEASE_ASSERT(NS_IsMainThread());
nsWindowInfo *inInfo, *belowInfo;
if ((inPosition != nsIWindowMediator::zLevelTop &&
inPosition != nsIWindowMediator::zLevelBottom &&
inPosition != nsIWindowMediator::zLevelBelow) ||
!inWindow) {
return NS_ERROR_INVALID_ARG;
}
if (mSortingZOrder) // don't fight SortZOrder()
return NS_OK;
MOZ_ASSERT(mReady);
NS_ENSURE_STATE(mReady);
/* Locate inWindow and unlink it from the z-order list.
It's important we look for it in the age list, not the z-order list.
This is because the former is guaranteed complete, while
now may be this window's first exposure to the latter. */
inInfo = GetInfoFor(inWindow);
if (!inInfo) return NS_ERROR_INVALID_ARG;
// locate inBelow, place inWindow behind it
if (inPosition == nsIWindowMediator::zLevelBelow) {
belowInfo = GetInfoFor(inBelow);
// it had better also be in the z-order list
if (belowInfo && belowInfo->mYounger != belowInfo &&
belowInfo->mLower == belowInfo) {
belowInfo = nullptr;
}
if (!belowInfo) {
if (inBelow)
return NS_ERROR_INVALID_ARG;
else
inPosition = nsIWindowMediator::zLevelTop;
}
}
if (inPosition == nsIWindowMediator::zLevelTop ||
inPosition == nsIWindowMediator::zLevelBottom)
belowInfo = mTopmostWindow ? mTopmostWindow->mHigher : nullptr;
if (inInfo != belowInfo) {
inInfo->Unlink(false, true);
inInfo->InsertAfter(nullptr, belowInfo);
}
if (inPosition == nsIWindowMediator::zLevelTop) mTopmostWindow = inInfo;
return NS_OK;
}
NS_IMETHODIMP
nsWindowMediator::GetZLevel(nsIAppWindow* aWindow, uint32_t* _retval) {
NS_ENSURE_ARG_POINTER(_retval);
*_retval = nsIAppWindow::normalZ;
// This can fail during window destruction.
nsWindowInfo* info = GetInfoFor(aWindow);
if (info) {
*_retval = info->mZLevel;
}
return NS_OK;
}
NS_IMETHODIMP
nsWindowMediator::SetZLevel(nsIAppWindow* aWindow, uint32_t aZLevel) {
MOZ_RELEASE_ASSERT(NS_IsMainThread());
MOZ_ASSERT(mReady);
NS_ENSURE_STATE(mReady);
nsWindowInfo* info = GetInfoFor(aWindow);
NS_ASSERTION(info, "setting z level of unregistered window");
if (!info) return NS_ERROR_FAILURE;
if (info->mZLevel != aZLevel) {
bool lowered = info->mZLevel > aZLevel;
info->mZLevel = aZLevel;
if (lowered)
SortZOrderFrontToBack();
else
SortZOrderBackToFront();
}
return NS_OK;
}
/* Fix potentially out-of-order windows by performing an insertion sort
on the z-order list. The method will work no matter how broken the
list, but its assumed usage is immediately after one window's z level
has been changed, so one window is potentially out of place. Such a sort
is most efficiently done in a particular direction. Use this one
if a window's z level has just been reduced, so the sort is most efficiently
done front to back.
Note it's hardly worth going to all the trouble to write two versions
of this method except that if we choose the inefficient sorting direction,
on slow systems windows could visibly bubble around the window that
was moved.
*/
void nsWindowMediator::SortZOrderFrontToBack() {
nsWindowInfo *scan, // scans list looking for problems
*search, // searches for correct placement for scan window
*prev, // previous search element
*lowest; // bottom-most window in list
bool finished;
if (!mTopmostWindow) // early during program execution there's no z list yet
return; // there's also only one window, so this is not dangerous
mSortingZOrder = true;
/* Step through the list from top to bottom. If we find a window which
should be moved down in the list, move it to its highest legal position. */
do {
finished = true;
lowest = mTopmostWindow->mHigher;
scan = mTopmostWindow;
while (scan != lowest) {
uint32_t scanZ = scan->mZLevel;
if (scanZ < scan->mLower->mZLevel) { // out of order
search = scan->mLower;
do {
prev = search;
search = search->mLower;
} while (prev != lowest && scanZ < search->mZLevel);
// reposition |scan| within the list
if (scan == mTopmostWindow) mTopmostWindow = scan->mLower;
scan->Unlink(false, true);
scan->InsertAfter(nullptr, prev);
// fix actual window order
nsCOMPtr<nsIBaseWindow> base;
nsCOMPtr<nsIWidget> scanWidget;
nsCOMPtr<nsIWidget> prevWidget;
base = do_QueryInterface(scan->mWindow);
if (base) base->GetMainWidget(getter_AddRefs(scanWidget));
base = do_QueryInterface(prev->mWindow);
if (base) base->GetMainWidget(getter_AddRefs(prevWidget));
if (scanWidget)
scanWidget->PlaceBehind(eZPlacementBelow, prevWidget, false);
finished = false;
break;
}
scan = scan->mLower;
}
} while (!finished);
mSortingZOrder = false;
}
// see comment for SortZOrderFrontToBack
void nsWindowMediator::SortZOrderBackToFront() {
nsWindowInfo *scan, // scans list looking for problems
*search, // searches for correct placement for scan window
*lowest; // bottom-most window in list
bool finished;
if (!mTopmostWindow) // early during program execution there's no z list yet
return; // there's also only one window, so this is not dangerous
mSortingZOrder = true;
/* Step through the list from bottom to top. If we find a window which
should be moved up in the list, move it to its lowest legal position. */
do {
finished = true;
lowest = mTopmostWindow->mHigher;
scan = lowest;
while (scan != mTopmostWindow) {
uint32_t scanZ = scan->mZLevel;
if (scanZ > scan->mHigher->mZLevel) { // out of order
search = scan;
do {
search = search->mHigher;
} while (search != lowest && scanZ > search->mZLevel);
// reposition |scan| within the list
if (scan != search && scan != search->mLower) {
scan->Unlink(false, true);
scan->InsertAfter(nullptr, search);
}
if (search == lowest) mTopmostWindow = scan;
// fix actual window order
nsCOMPtr<nsIBaseWindow> base;
nsCOMPtr<nsIWidget> scanWidget;
nsCOMPtr<nsIWidget> searchWidget;
base = do_QueryInterface(scan->mWindow);
if (base) base->GetMainWidget(getter_AddRefs(scanWidget));
if (mTopmostWindow != scan) {
base = do_QueryInterface(search->mWindow);
if (base) base->GetMainWidget(getter_AddRefs(searchWidget));
}
if (scanWidget)
scanWidget->PlaceBehind(eZPlacementBelow, searchWidget, false);
finished = false;
break;
}
scan = scan->mHigher;
}
} while (!finished);
mSortingZOrder = false;
}
NS_IMPL_ISUPPORTS(nsWindowMediator, nsIWindowMediator, nsIObserver,
nsISupportsWeakReference)

View File

@ -56,14 +56,11 @@ class nsWindowMediator : public nsIWindowMediator,
nsresult UnregisterWindow(nsWindowInfo* inInfo);
nsWindowInfo* GetInfoFor(nsIAppWindow* aWindow);
nsWindowInfo* GetInfoFor(nsIWidget* aWindow);
void SortZOrderFrontToBack();
void SortZOrderBackToFront();
nsTArray<nsAppShellWindowEnumerator*> mEnumeratorList;
nsWindowInfo* mOldestWindow;
nsWindowInfo* mTopmostWindow;
int32_t mTimeStamp;
bool mSortingZOrder;
bool mReady;
typedef nsTObserverArray<nsCOMPtr<nsIWindowMediatorListener>> ListenerArray;