From 48ccf5abefce9ecac2b3212c662af6fc3511cfb0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Fri, 2 Dec 2005 15:06:14 +0000 Subject: [PATCH] Some work to get modal/floating windows back: * B_{FLOATING|MODAL}_ALL_WINDOW_FEEL now works as expected * reintroduced the concepts of subsets of modal/floating windows - does only work correctly for subset "all" window feels. * RootLayer::_SetFront() now deals correctly with modal windows * renamed RootLayer *WindowLayer() methods to *Window() git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15282 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/servers/app/Desktop.cpp | 8 +- src/servers/app/RootLayer.cpp | 127 +++++++++++++++++++++----------- src/servers/app/RootLayer.h | 8 +- src/servers/app/WindowLayer.cpp | 88 ++++++++++++++++------ src/servers/app/WindowLayer.h | 10 +++ 5 files changed, 171 insertions(+), 70 deletions(-) diff --git a/src/servers/app/Desktop.cpp b/src/servers/app/Desktop.cpp index 580130aa5a..fed925451c 100644 --- a/src/servers/app/Desktop.cpp +++ b/src/servers/app/Desktop.cpp @@ -626,7 +626,7 @@ Desktop::ShowWindow(WindowLayer* window) return; } - fRootLayer->ShowWindowLayer(window); + fRootLayer->ShowWindow(window); // If the mouse cursor is directly over the newly visible window, // we'll send a fake mouse moved message to the window, so that @@ -659,7 +659,7 @@ Desktop::HideWindow(WindowLayer* window) return; } - fRootLayer->HideWindowLayer(window); + fRootLayer->HideWindow(window); } @@ -692,7 +692,7 @@ Desktop::_ChangeWindowWorkspaces(WindowLayer* window, uint32 oldWorkspaces, // window is on this workspace, is it anymore? if (!workspaces_on_workspace(i, newWorkspaces)) { if (i == CurrentWorkspace()) - RootLayer()->RemoveWindowLayer(window); + RootLayer()->RemoveWindow(window); else fWorkspaces[i].RemoveWindow(window); } @@ -700,7 +700,7 @@ Desktop::_ChangeWindowWorkspaces(WindowLayer* window, uint32 oldWorkspaces, // window was not on this workspace, is it now? if (workspaces_on_workspace(i, newWorkspaces)) { if (i == CurrentWorkspace()) - RootLayer()->AddWindowLayer(window); + RootLayer()->AddWindow(window); else fWorkspaces[i].AddWindow(window); } diff --git a/src/servers/app/RootLayer.cpp b/src/servers/app/RootLayer.cpp index 49a3ead65a..2d4c7837a8 100644 --- a/src/servers/app/RootLayer.cpp +++ b/src/servers/app/RootLayer.cpp @@ -205,29 +205,73 @@ RootLayer::SetFocus(WindowLayer* focus) } +/*! + \brief Tries to move the specified window to the front of the screen. + + If there are any modal windows on this screen, it might not actually + become the frontmost window, though, as modal windows stay in front + of their subset. +*/ void -RootLayer::_SetFront(WindowLayer* windowLayer, BRegion& update) +RootLayer::_SetFront(WindowLayer* window, BRegion& update) { - if (windowLayer == NULL) { + if (window == NULL) { fBack = NULL; fFront = NULL; return; } - if (!windowLayer->SupportsFront() && fFront != NULL) + if (!window->SupportsFront() && fFront != NULL) return; - BRegion previous = windowLayer->FullVisible(); + BRegion previous = window->FullVisible(); + WindowLayer* frontmost = window->Frontmost(); - _RemoveChildFromList(windowLayer); - _AddChildToList(windowLayer); + _RemoveChildFromList(window); - windowLayer->GetOnScreenRegion(update); + if (frontmost != NULL && frontmost->IsModal()) { + // all modal windows follow their subsets to the front + // (ie. they are staying in front of them, but they are + // not supposed to change their order because of that) + + WindowLayer* nextModal; + for (WindowLayer* modal = frontmost; modal != NULL ; modal = nextModal) { + nextModal = (WindowLayer*)modal->NextLayer(); + + if (nextModal == frontmost) { + // since we're adding the modal windows to the end of the list + // we're traversing, we must stop when we've reached the initial + // starting point again + nextModal = NULL; + } else if (nextModal != NULL + && (!nextModal->IsModal() || !nextModal->HasInSubset(window))) + nextModal = NULL; + + previous.Include(&modal->FullVisible()); + WindowLayer* modalFrontmost = modal->Frontmost(); + + _RemoveChildFromList(modal); + _AddChildToList(modal, modalFrontmost); + + BRegion modalRegion; + modal->GetOnScreenRegion(modalRegion); + // TODO: this is not what we want, we'd want the new visible region + update.Include(&modalRegion); + } + } + + _AddChildToList(window, frontmost); + + BRegion windowRegion; + window->GetOnScreenRegion(windowRegion); + // TODO: this is not what we want, we'd want the new visible region + + update.Include(&windowRegion); update.Exclude(&previous); - fFront = windowLayer; + _UpdateFront(); - if (windowLayer == fBack || fBack == NULL) + if (window == fBack || fBack == NULL) _UpdateBack(); } @@ -280,19 +324,20 @@ RootLayer::_UpdateFronts() void -RootLayer::ActivateWindow(WindowLayer* windowLayer) +RootLayer::ActivateWindow(WindowLayer* window) { BAutolock _(fAllRegionsLock); BRegion changed; - _SetFront(windowLayer, changed); + _SetFront(window, changed); // TODO: if this window has any floating windows, add them here MarkForRebuild(changed); TriggerRebuild(); - _SetFocus(windowLayer, changed); + _SetFocus(Front(), changed); + _WindowsChanged(changed); MarkForRedraw(changed); TriggerRedraw(); @@ -336,32 +381,32 @@ RootLayer::SendBehindWindow(WindowLayer* windowLayer, WindowLayer* behindOf) void -RootLayer::AddWindowLayer(WindowLayer* windowLayer) +RootLayer::AddWindow(WindowLayer* window) { - STRACE(("AddWindowLayer(%p \"%s\")\n", windowLayer, windowLayer->Name())); + STRACE(("AddWindowLayer(%p \"%s\")\n", window, window->Name())); - if (windowLayer->SupportsFront()) - _AddChildToList(windowLayer); + if (window->SupportsFront()) + _AddChildToList(window, window->Frontmost((WindowLayer*)FirstChild())); else - _AddChildToList(windowLayer, Back()); + _AddChildToList(window, Back()); - windowLayer->SetRootLayer(this); + window->SetRootLayer(this); - if (!windowLayer->IsHidden()) - ActivateWindow(windowLayer); + if (!window->IsHidden()) + ActivateWindow(window); } void -RootLayer::RemoveWindowLayer(WindowLayer* windowLayer) +RootLayer::RemoveWindow(WindowLayer* window) { - if (!windowLayer->IsHidden()) - HideWindowLayer(windowLayer); + if (!window->IsHidden()) + HideWindow(window); - _RemoveChildFromList(windowLayer); + _RemoveChildFromList(window); - LayerRemoved(windowLayer); - windowLayer->SetRootLayer(NULL); + LayerRemoved(window); + window->SetRootLayer(NULL); } @@ -467,15 +512,15 @@ RootLayer::SetWorkspace(int32 index, Workspace::Private& previousWorkspace, void -RootLayer::HideWindowLayer(WindowLayer* windowLayer) +RootLayer::HideWindow(WindowLayer* window) { BAutolock _(fAllRegionsLock); - BRegion changed = windowLayer->FullVisible(); - windowLayer->Hide(); + BRegion changed = window->FullVisible(); + window->Hide(); _UpdateFronts(); - if (dynamic_cast(windowLayer->TopLayer()) != NULL) + if (dynamic_cast(window->TopLayer()) != NULL) fWorkspacesLayer = NULL; // TODO: if this window has any floating windows, remove them here @@ -483,7 +528,7 @@ RootLayer::HideWindowLayer(WindowLayer* windowLayer) MarkForRebuild(changed); TriggerRebuild(); - if (windowLayer == Focus()) + if (window == Focus()) _SetFocus(Front(), changed); _WindowsChanged(changed); @@ -493,34 +538,34 @@ RootLayer::HideWindowLayer(WindowLayer* windowLayer) void -RootLayer::ShowWindowLayer(WindowLayer* windowLayer, bool toFront) +RootLayer::ShowWindow(WindowLayer* window, bool toFront) { - STRACE(("ShowWindowLayer(%p)\n", windowLayer)); + STRACE(("ShowWindowLayer(%p)\n", window)); - if (!windowLayer->IsHidden()) + if (!window->IsHidden()) return; BAutolock _(fAllRegionsLock); - windowLayer->Show(); - BRegion changed = windowLayer->FullVisible(); + window->Show(); + BRegion changed = window->FullVisible(); if (toFront) - _SetFront(windowLayer, changed); + _SetFront(window, changed); else _UpdateFront(); // TODO: if this window has any floating windows, remove them here // TODO: support FFM - if (Front() == windowLayer || Focus() == NULL) - _SetFocus(windowLayer, changed); + if (Front() == window || Focus() == NULL) + _SetFocus(window, changed); _WindowsChanged(changed); MarkForRedraw(changed); TriggerRedraw(); - if (dynamic_cast(windowLayer->TopLayer()) != NULL) - fWorkspacesLayer = windowLayer->TopLayer(); + if (dynamic_cast(window->TopLayer()) != NULL) + fWorkspacesLayer = window->TopLayer(); } diff --git a/src/servers/app/RootLayer.h b/src/servers/app/RootLayer.h index 010b6e6e10..8c5bfb3d36 100644 --- a/src/servers/app/RootLayer.h +++ b/src/servers/app/RootLayer.h @@ -54,8 +54,8 @@ class RootLayer : public Layer { virtual void ScrollBy(float x, float y) { /* not allowed */ } - void HideWindowLayer(WindowLayer* windowLayer); - void ShowWindowLayer(WindowLayer* windowLayer, bool toFront = true); + void HideWindow(WindowLayer* window); + void ShowWindow(WindowLayer* window, bool toFront = true); void MoveWindowBy(WindowLayer* window, float x, float y); void ResizeWindowBy(WindowLayer* window, float x, float y); @@ -100,8 +100,8 @@ class RootLayer : public Layer { thread_id LockingThread() { return fAllRegionsLock.LockingThread(); } - void AddWindowLayer(WindowLayer* windowLayer); - void RemoveWindowLayer(WindowLayer* windowLayer); + void AddWindow(WindowLayer* window); + void RemoveWindow(WindowLayer* window); private: bool _SetFocus(WindowLayer* focus, BRegion& update); diff --git a/src/servers/app/WindowLayer.cpp b/src/servers/app/WindowLayer.cpp index 198564b4ba..459aef4262 100644 --- a/src/servers/app/WindowLayer.cpp +++ b/src/servers/app/WindowLayer.cpp @@ -5,6 +5,7 @@ * Author: DarkWyrm * Adi Oanca * Stephan Aßmus + * Axel Dörfler, axeld@pinc-software.de */ @@ -714,27 +715,6 @@ WindowLayer::SetFeel(window_feel feel) // having modal windows with B_AVOID_FRONT or B_AVOID_FOCUS doesn't // make that much sense, so we filter those flags out on demand fWindowFlags &= ~ValidWindowFlags(fFeel); - - // TODO: this shouldn't be necessary, but we'll see :) - - // floating and modal windows must appear in every workspace where - // their main window is present. Thus their fWorkspaces will be set to - // '0x0' and they will be made visible when needed. - switch (fFeel) { - case B_MODAL_APP_WINDOW_FEEL: - break; - case B_MODAL_SUBSET_WINDOW_FEEL: - case B_FLOATING_APP_WINDOW_FEEL: - case B_FLOATING_SUBSET_WINDOW_FEEL: - fWorkspaces = 0x0UL; - break; - case B_MODAL_ALL_WINDOW_FEEL: - case B_FLOATING_ALL_WINDOW_FEEL: - fWorkspaces = 0xffffffffUL; - break; - case B_NORMAL_WINDOW_FEEL: - break; - } } @@ -768,6 +748,72 @@ WindowLayer::IsFloating() const } +/*! + \brief Returns the windows that's in front of the frontmost position + this window can get. + Returns NULL is this window can be the frontmost window. +*/ +WindowLayer* +WindowLayer::Frontmost(WindowLayer* first) +{ + if (fFeel == B_FLOATING_ALL_WINDOW_FEEL) + return NULL; + + if (first == NULL) + first = (WindowLayer*)NextLayer(); + + for (WindowLayer* window = first; window != NULL; + window = (WindowLayer*)window->NextLayer()) { + if (window->IsHidden()) + continue; + + // no one can be in front of a floating all window + if (window->Feel() == B_FLOATING_ALL_WINDOW_FEEL) + return window; + + if (fFeel == B_NORMAL_WINDOW_FEEL + && window->HasInSubset(this)) + return window; + } + + return NULL; +} + + + +bool +WindowLayer::AddToSubset(WindowLayer* window) +{ + if (fFeel == B_FLOATING_ALL_WINDOW_FEEL + || fFeel == B_MODAL_ALL_WINDOW_FEEL) + return true; + + return fSubsets.AddItem(window); +} + + +void +WindowLayer::RemoveFromSubset(WindowLayer* window) +{ + if (fFeel == B_FLOATING_ALL_WINDOW_FEEL + || fFeel == B_MODAL_ALL_WINDOW_FEEL) + return; + + fSubsets.RemoveItem(window); +} + + +bool +WindowLayer::HasInSubset(WindowLayer* window) +{ + if (fFeel == B_FLOATING_ALL_WINDOW_FEEL + || fFeel == B_MODAL_ALL_WINDOW_FEEL) + return true; + + return fSubsets.HasItem(window); +} + + click_type WindowLayer::_ActionFor(const BMessage *msg) const { diff --git a/src/servers/app/WindowLayer.h b/src/servers/app/WindowLayer.h index a337a6e1f5..0979c44ad2 100644 --- a/src/servers/app/WindowLayer.h +++ b/src/servers/app/WindowLayer.h @@ -5,6 +5,7 @@ * Author: DarkWyrm * Adi Oanca * Stephan Aßmus + * Axel Dörfler, axeld@pinc-software.de */ #ifndef WINDOW_LAYER_H #define WINDOW_LAYER_H @@ -13,6 +14,7 @@ #include "Decorator.h" #include "Layer.h" +#include #include #include @@ -113,6 +115,12 @@ class WindowLayer : public Layer { bool IsModal() const; bool IsFloating() const; + WindowLayer* Frontmost(WindowLayer* first = NULL); + + bool AddToSubset(WindowLayer* window); + void RemoveFromSubset(WindowLayer* window); + bool HasInSubset(WindowLayer* window); + void RequestClientRedraw(const BRegion& invalid); void SetTopLayer(Layer* layer); @@ -153,6 +161,8 @@ class WindowLayer : public Layer { bool fIsFocus; + BObjectList fSubsets; + bool fIsClosing; bool fIsMinimizing; bool fIsZooming;