From 27adb969620d656c8d92dfa608cd85c35f4d37e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Mon, 28 Nov 2005 23:36:59 +0000 Subject: [PATCH] Massive RootLayer & Workspace tearing: * workspace switch and subset windows functionality temporarily removed (away with that mess!). * no more RevealWMState() - we now have methods like ActivateWindow() and SendWindowBehind() that do all the work - just a little cleaner and with less overhead. * Workspace is now a pretty passive class - it only stores configurations of the windows and screens. * added an evil work-around for a locking problem (in RootLayer::_SetFocus()). * I'll plan to move pretty much all of the remaining root layer functionality to Desktop - so that the all regions lock is only held in case clipping regions are affected. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15207 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/servers/app/Desktop.cpp | 255 +--- src/servers/app/Desktop.h | 137 +- src/servers/app/RootLayer.cpp | 974 +++++---------- src/servers/app/RootLayer.h | 149 +-- src/servers/app/ServerApp.cpp | 49 +- src/servers/app/ServerApp.h | 4 - src/servers/app/ServerWindow.cpp | 160 +-- src/servers/app/ServerWindow.h | 6 - src/servers/app/SubWindowList.h | 4 +- src/servers/app/WindowLayer.cpp | 39 +- src/servers/app/WindowLayer.h | 4 + src/servers/app/Workspace.cpp | 1796 +-------------------------- src/servers/app/Workspace.h | 183 +-- src/servers/app/WorkspacesLayer.cpp | 16 +- 14 files changed, 707 insertions(+), 3069 deletions(-) diff --git a/src/servers/app/Desktop.cpp b/src/servers/app/Desktop.cpp index 962da38a1d..c1a3b2ae6b 100644 --- a/src/servers/app/Desktop.cpp +++ b/src/servers/app/Desktop.cpp @@ -98,19 +98,8 @@ KeyboardFilter::Filter(BMessage* message, BHandler** /*_target*/) #endif { STRACE(("Set Workspace %ld\n", key - 1)); - RootLayer* root = fDesktop->RootLayer(); - root->Lock(); - root->SetActiveWorkspace(key - 2); - -#ifdef APPSERVER_ROOTLAYER_SHOW_WORKSPACE_NUMBER - // to draw the current Workspace index on screen. - BRegion region(VisibleRegion()); - fDesktop->GetDrawingEngine()->ConstrainClippingRegion(®ion); - root->Draw(region.Frame()); - fDesktop->GetDrawingEngine()->ConstrainClippingRegion(NULL); -#endif - root->Unlock(); + fDesktop->SetWorkspace(key - 2); return B_SKIP_MESSAGE; } } @@ -188,7 +177,7 @@ Desktop::Init() // TODO: add user identity to the name char name[32]; sprintf(name, "RootLayer %d", 1); - fRootLayer = new ::RootLayer(name, 4, this, GetDrawingEngine()); + fRootLayer = new ::RootLayer(name, this, GetDrawingEngine()); #if TEST_MODE gInputManager->AddStream(new InputServerStream); @@ -436,20 +425,13 @@ Desktop::_ActivateApp(team_id team) int32 windowCount = WindowList().CountItems(); for (int32 i = 0; i < windowCount; ++i) { // is this layer in fact a WindowLayer? - WindowLayer *winBorder = WindowList().ItemAt(i); + WindowLayer *windowLayer = WindowList().ItemAt(i); // if winBorder is valid and not hidden, then we've found our target - if (winBorder != NULL && !winBorder->IsHidden() - && winBorder->App()->ClientTeam() == team) { - if (fRootLayer->Lock()) { - fRootLayer->SetActive(winBorder); - fRootLayer->Unlock(); - - if (fRootLayer->Active() == winBorder) - return B_OK; - - status = B_ERROR; - } + if (windowLayer != NULL && !windowLayer->IsHidden() + && windowLayer->App()->ClientTeam() == team) { + fRootLayer->ActivateWindow(windowLayer); + return B_OK; } } @@ -480,6 +462,19 @@ Desktop::BroadcastToAllApps(int32 code) } +void +Desktop::SetWorkspace(int32 index) +{ + BAutolock _(this); + DesktopSettings settings(this); + + if (index < 0 || index >= settings.WorkspacesCount()) + return; + + fRootLayer->SetWorkspace(index, fWorkspaces[index]); +} + + void Desktop::ScreenChanged(Screen* screen) { @@ -506,204 +501,72 @@ Desktop::ScreenChanged(Screen* screen) void -Desktop::AddWindowLayer(WindowLayer *winBorder) +Desktop::ActivateWindow(WindowLayer* windowLayer) { - if (!winBorder) - return; + fRootLayer->ActivateWindow(windowLayer); +} - int32 feel = winBorder->Feel(); - // we are ServerApp thread, we need to lock RootLayer here. - RootLayer()->Lock(); +void +Desktop::SendBehindWindow(WindowLayer* windowLayer, WindowLayer* front) +{ + fRootLayer->SendBehindWindow(windowLayer, front); +} - // we're playing with window list. lock first. + +void +Desktop::SetWindowWorkspaces(WindowLayer* windowLayer, uint32 workspaces) +{ + BAutolock _(this); + + windowLayer->SetWorkspaces(workspaces); + + // is the window still visible on screen? + bool remove = (workspaces & (1UL << CurrentWorkspace())) == 0; + + if (remove && windowLayer->Parent() != NULL) { + // the window is no longer visible on screen + fRootLayer->RemoveWindowLayer(windowLayer); + } else if (!remove && windowLayer->Parent() == NULL) { + // the window is now visible on screen + fRootLayer->AddWindowLayer(windowLayer); + } +} + + +void +Desktop::AddWindowLayer(WindowLayer *windowLayer) +{ Lock(); - if (fWindowLayerList.HasItem(winBorder)) { + if (fWindowLayerList.HasItem(windowLayer)) { Unlock(); - RootLayer()->Unlock(); debugger("AddWindowLayer: WindowLayer already in Desktop list\n"); return; } - // we have a new window. store a record of it. - fWindowLayerList.AddItem(winBorder); - - // add FLOATING_APP windows to the local list of all normal windows. - // This is to keep the order all floating windows (app or subset) when we go from - // one normal window to another. - if (feel == B_FLOATING_APP_WINDOW_FEEL || feel == B_NORMAL_WINDOW_FEEL) { - WindowLayer *wb = NULL; - int32 count = fWindowLayerList.CountItems(); - int32 feelToLookFor = (feel == B_NORMAL_WINDOW_FEEL ? - B_FLOATING_APP_WINDOW_FEEL : B_NORMAL_WINDOW_FEEL); - - for (int32 i = 0; i < count; i++) { - wb = (WindowLayer *)fWindowLayerList.ItemAt(i); - - if (wb->App()->ClientTeam() == winBorder->App()->ClientTeam() - && wb->Feel() == feelToLookFor) { - // R2: RootLayer comparison is needed. - feel == B_NORMAL_WINDOW_FEEL ? - winBorder->fSubWindowList.AddWindowLayer(wb) : - wb->fSubWindowList.AddWindowLayer(winBorder); - } - } - } - - // add application's list of modal windows. - if (feel == B_MODAL_APP_WINDOW_FEEL) { - winBorder->App()->fAppSubWindowList.AddWindowLayer(winBorder); - } - - // send WindowLayer to be added to workspaces - RootLayer()->AddWindowLayer(winBorder); - - // hey, unlock! + fWindowLayerList.AddItem(windowLayer); Unlock(); - RootLayer()->Unlock(); + RootLayer()->AddWindowLayer(windowLayer); } void -Desktop::RemoveWindowLayer(WindowLayer *winBorder) +Desktop::RemoveWindowLayer(WindowLayer *windowLayer) { - if (!winBorder) - return; - - // we are ServerApp thread, we need to lock RootLayer here. - RootLayer()->Lock(); - - // we're playing with window list. lock first. Lock(); - - // remove from main WindowLayer list. - if (fWindowLayerList.RemoveItem(winBorder)) { - int32 feel = winBorder->Feel(); - - // floating app/subset and modal_subset windows require special atention because - // they are/may_be added to the list of a lot normal windows. - if (feel == B_FLOATING_SUBSET_WINDOW_FEEL - || feel == B_MODAL_SUBSET_WINDOW_FEEL - || feel == B_FLOATING_APP_WINDOW_FEEL) - { - WindowLayer *wb = NULL; - int32 count = fWindowLayerList.CountItems(); - - for (int32 i = 0; i < count; i++) { - wb = (WindowLayer*)fWindowLayerList.ItemAt(i); - - if (wb->Feel() == B_NORMAL_WINDOW_FEEL - && wb->App()->ClientTeam() == winBorder->App()->ClientTeam()) { - // R2: RootLayer comparison is needed. We'll see. - wb->fSubWindowList.RemoveItem(winBorder); - } - } - } - - // remove from application's list - if (feel == B_MODAL_APP_WINDOW_FEEL) { - winBorder->App()->fAppSubWindowList.RemoveItem(winBorder); - } - } else { - Unlock(); - RootLayer()->Unlock(); - debugger("RemoveWindowLayer: WindowLayer not found in Desktop list\n"); - return; - } - - // Tell to winBorder's RootLayer about this. - RootLayer()->RemoveWindowLayer(winBorder); - + fWindowLayerList.RemoveItem(windowLayer); Unlock(); - RootLayer()->Unlock(); -} - -void -Desktop::AddWindowLayerToSubset(WindowLayer *winBorder, WindowLayer *toWindowLayer) -{ - // NOTE: we can safely lock the entire method body, because this method is called from - // RootLayer's thread only. - - // we're playing with window list. lock first. - Lock(); - - if (!winBorder || !toWindowLayer - || !fWindowLayerList.HasItem(winBorder) - || !fWindowLayerList.HasItem(toWindowLayer)) { - Unlock(); - debugger("AddWindowLayerToSubset: NULL WindowLayer or not found in Desktop list\n"); - return; - } - - if ((winBorder->Feel() == B_FLOATING_SUBSET_WINDOW_FEEL - || winBorder->Feel() == B_MODAL_SUBSET_WINDOW_FEEL) - && toWindowLayer->Feel() == B_NORMAL_WINDOW_FEEL - && toWindowLayer->App()->ClientTeam() == winBorder->App()->ClientTeam() - && !toWindowLayer->fSubWindowList.HasItem(winBorder)) { - // add to normal_window's list - toWindowLayer->fSubWindowList.AddWindowLayer(winBorder); - } else { - Unlock(); - debugger("AddWindowLayerToSubset: you must add a subset_window to a normal_window's subset with the same team_id\n"); - return; - } - - // send WindowLayer to be added to workspaces, if not already in there. - RootLayer()->AddSubsetWindowLayer(winBorder, toWindowLayer); - - Unlock(); -} - - -void -Desktop::RemoveWindowLayerFromSubset(WindowLayer *winBorder, WindowLayer *fromWindowLayer) -{ - // NOTE: we can safely lock the entire method body, because this method is called from - // RootLayer's thread only. - - // we're playing with window list. lock first. - Lock(); - - if (!winBorder || !fromWindowLayer - || !fWindowLayerList.HasItem(winBorder) - || !fWindowLayerList.HasItem(fromWindowLayer)) { - Unlock(); - debugger("RemoveWindowLayerFromSubset: NULL WindowLayer or not found in Desktop list\n"); - return; - } - - // remove WindowLayer from workspace, if needed - some other windows may still have it in their subset - RootLayer()->RemoveSubsetWindowLayer(winBorder, fromWindowLayer); - - if (fromWindowLayer->Feel() == B_NORMAL_WINDOW_FEEL) { - //remove from this normal_window's subset. - fromWindowLayer->fSubWindowList.RemoveItem(winBorder); - } else { - Unlock(); - debugger("RemoveWindowLayerFromSubset: you must remove a subset_window from a normal_window's subset\n"); - return; - } - - Unlock(); + RootLayer()->RemoveWindowLayer(windowLayer); } void Desktop::SetWindowLayerFeel(WindowLayer *winBorder, uint32 feel) { - // NOTE: this method is called from RootLayer thread only - - // we're playing with window list. lock first. - Lock(); - - RemoveWindowLayer(winBorder); - winBorder->QuietlySetFeel(feel); - AddWindowLayer(winBorder); - - Unlock(); + // TODO: implement } diff --git a/src/servers/app/Desktop.h b/src/servers/app/Desktop.h index 570ec61655..6744570f31 100644 --- a/src/servers/app/Desktop.h +++ b/src/servers/app/Desktop.h @@ -7,8 +7,8 @@ * Stephan Aßmus * Axel Dörfler, axeld@pinc-software.de */ -#ifndef _DESKTOP_H_ -#define _DESKTOP_H_ +#ifndef DESKTOP_H +#define DESKTOP_H #include "CursorManager.h" @@ -18,6 +18,7 @@ #include "VirtualScreen.h" #include "DesktopSettings.h" #include "MessageLooper.h" +#include "Workspace.h" #include #include @@ -41,87 +42,103 @@ namespace BPrivate { class Desktop : public MessageLooper, public ScreenOwner { - public: - // startup methods + public: Desktop(uid_t userID); - virtual ~Desktop(); + virtual ~Desktop(); - void Init(); + void Init(); - uid_t UserID() const { return fUserID; } - virtual port_id MessagePort() const { return fMessagePort; } + uid_t UserID() const { return fUserID; } + virtual port_id MessagePort() const { return fMessagePort; } - ::EventDispatcher& EventDispatcher() { return fEventDispatcher; } + ::EventDispatcher& EventDispatcher() { return fEventDispatcher; } - void BroadcastToAllApps(int32 code); + void BroadcastToAllApps(int32 code); - // Methods for multiple monitors. - inline Screen* ScreenAt(int32 index) const + // Screen and drawing related methods + + Screen* ScreenAt(int32 index) const { return fActiveScreen; } - inline Screen* ActiveScreen() const + Screen* ActiveScreen() const { return fActiveScreen; } - inline ::RootLayer* RootLayer() const { return fRootLayer; } - inline CursorManager& GetCursorManager() { return fCursorManager; } + ::RootLayer* RootLayer() const { return fRootLayer; } + CursorManager& GetCursorManager() { return fCursorManager; } - void ScreenChanged(Screen* screen); + void ScreenChanged(Screen* screen); - virtual void ScreenRemoved(Screen* screen) {} - virtual void ScreenAdded(Screen* screen) {} - virtual bool ReleaseScreen(Screen* screen) { return false; } + void ScreenRemoved(Screen* screen) {} + void ScreenAdded(Screen* screen) {} + bool ReleaseScreen(Screen* screen) { return false; } - const ::VirtualScreen& VirtualScreen() const { return fVirtualScreen; } - inline DrawingEngine* GetDrawingEngine() const + const ::VirtualScreen& VirtualScreen() const { return fVirtualScreen; } + DrawingEngine* GetDrawingEngine() const { return fVirtualScreen.DrawingEngine(); } - inline ::HWInterface* HWInterface() const + ::HWInterface* HWInterface() const { return fVirtualScreen.HWInterface(); } - // Methods for layer(WindowLayer) manipulation. - void AddWindowLayer(WindowLayer *winBorder); - void RemoveWindowLayer(WindowLayer *winBorder); - void SetWindowLayerFeel(WindowLayer *winBorder, - uint32 feel); - void AddWindowLayerToSubset(WindowLayer *winBorder, - WindowLayer *toWindowLayer); - void RemoveWindowLayerFromSubset(WindowLayer *winBorder, - WindowLayer *fromWindowLayer); + // Workspace methods - WindowLayer* FindWindowLayerByClientToken(int32 token, team_id teamID); - //WindowLayer* FindWindowLayerByServerToken(int32 token); + void SetWorkspace(int32 index); + int32 CurrentWorkspace() + { return fCurrentWorkspace; } + ::Workspace& WorkspaceAt(int32 index) + { return fWorkspaces[index]; } - // get list of registed windows - const BObjectList& WindowList() const; + // WindowLayer methods - void WriteWindowList(team_id team, BPrivate::LinkSender& sender); - void WriteWindowInfo(int32 serverToken, BPrivate::LinkSender& sender); + void ActivateWindow(WindowLayer* window); + void SendBehindWindow(WindowLayer* window, WindowLayer* front); - private: - status_t _ActivateApp(team_id team); - virtual void _GetLooperName(char* name, size_t size); - virtual void _PrepareQuit(); - virtual void _DispatchMessage(int32 code, BPrivate::LinkReceiver &link); + void SetWindowWorkspaces(WindowLayer* window, uint32 workspaces); - private: - friend class DesktopSettings; + void AddWindowLayer(WindowLayer *windowLayer); + void RemoveWindowLayer(WindowLayer *windowLayer); + void SetWindowLayerFeel(WindowLayer *windowLayer, + uint32 feel); - uid_t fUserID; - ::VirtualScreen fVirtualScreen; - DesktopSettings::Private* fSettings; - port_id fMessagePort; - ::EventDispatcher fEventDispatcher; - port_id fInputPort; + WindowLayer* FindWindowLayerByClientToken(int32 token, team_id teamID); + //WindowLayer* FindWindowLayerByServerToken(int32 token); - BLocker fAppListLock; - BList fAppList; + // get list of registed windows + const BObjectList& WindowList() const; - sem_id fShutdownSemaphore; - int32 fShutdownCount; + void WriteWindowList(team_id team, + BPrivate::LinkSender& sender); + void WriteWindowInfo(int32 serverToken, + BPrivate::LinkSender& sender); - BObjectList fWindowLayerList; + private: + status_t _ActivateApp(team_id team); + void _GetLooperName(char* name, size_t size); + void _PrepareQuit(); + void _DispatchMessage(int32 code, + BPrivate::LinkReceiver &link); - ::RootLayer* fRootLayer; - Screen* fActiveScreen; - - CursorManager fCursorManager; + private: + friend class DesktopSettings; + + uid_t fUserID; + ::VirtualScreen fVirtualScreen; + DesktopSettings::Private* fSettings; + port_id fMessagePort; + ::EventDispatcher fEventDispatcher; + port_id fInputPort; + + BLocker fAppListLock; + BList fAppList; + + sem_id fShutdownSemaphore; + int32 fShutdownCount; + + ::Workspace fWorkspaces[32];//kMaxWorkspaces]; + int32 fCurrentWorkspace; + + BObjectList fWindowLayerList; + + ::RootLayer* fRootLayer; + Screen* fActiveScreen; + + CursorManager fCursorManager; }; -#endif // _DESKTOP_H_ +#endif // DESKTOP_H diff --git a/src/servers/app/RootLayer.cpp b/src/servers/app/RootLayer.cpp index a46c8c9413..eef42d03c4 100644 --- a/src/servers/app/RootLayer.cpp +++ b/src/servers/app/RootLayer.cpp @@ -41,36 +41,31 @@ static const float kGoldenProportion = (sqrtf(5.0) - 1.0) / 2.0; #endif -//#define DEBUG_ROOTLAYER +#define DEBUG_ROOT_LAYER #define APPSERVER_ROOTLAYER_SHOW_WORKSPACE_NUMBER -#ifdef DEBUG_ROOTLAYER +#ifdef DEBUG_ROOT_LAYER #define STRACE(a) printf a #else - #define STRACE(a) /* nothing */ + #define STRACE(a) ; #endif -static RGBColor kDefaultWorkspaceColor = RGBColor(51, 102, 152); -static int32 kMaxWorkspaceCount = 32; -RootLayer::RootLayer(const char *name, int32 workspaceCount, - Desktop *desktop, DrawingEngine *driver) +RootLayer::RootLayer(const char *name, Desktop *desktop, DrawingEngine *driver) : Layer(BRect(0, 0, 0, 0), name, 0, B_FOLLOW_ALL, B_WILL_DRAW, driver), + fDesktop(desktop), + fDragMessage(NULL), + fMouseEventLayer(NULL), + fAllRegionsLock("root layer region lock"), - fDesktop(desktop), - fDragMessage(NULL), - fMouseEventLayer(NULL), - fSavedEventMask(0), - fSavedEventOptions(0), - fAllRegionsLock("root layer region lock"), + fDirtyForRedraw(), - fDirtyForRedraw(), - - fActiveWksIndex(0), - fWsCount(0), - fWorkspace(new Workspace*[kMaxWorkspaceCount]), - fWorkspacesLayer(NULL), - fWMState() + fWorkspace(0), + fWorkspacesLayer(NULL), + + fFocus(NULL), + fFront(NULL), + fBack(NULL) { //NOTE: be careful about this one. fRootLayer = this; @@ -80,6 +75,8 @@ RootLayer::RootLayer(const char *name, int32 workspaceCount, fDebugInfo.SetTo(""); #endif + fDrawState->SetHighColor(RGBColor(255, 255, 255)); + #if DISPLAY_HAIKU_LOGO fLogoBitmap = new UtilityBitmap(BRect(0.0, 0.0, kLogoWidth - 1.0, kLogoHeight - 1.0), @@ -95,19 +92,6 @@ RootLayer::RootLayer(const char *name, int32 workspaceCount, fHidden = false; - memset(fWorkspace, 0, sizeof(Workspace*) * kMaxWorkspaceCount); - SetWorkspaceCount(workspaceCount); - - // TODO: this should eventually be replaced by a method to convert the monitor - // number to an index in the name, i.e. workspace_settings_1 for screen #1 -// ReadWorkspaceData(WORKSPACE_DATA_LIST); - - // init the first, default workspace - fWorkspace[fActiveWksIndex] = new Workspace(fActiveWksIndex, 0xFF00FF00, - kDefaultWorkspaceColor); - fDrawState->SetHighColor(RGBColor(255, 255, 255)); - fDrawState->SetLowColor(fWorkspace[fActiveWksIndex]->BGColor()); - #if ON_SCREEN_DEBUGGING_INFO DebugInfoManager::Default()->SetRootLayer(this); #endif @@ -122,6 +106,8 @@ RootLayer::RootLayer(const char *name, int32 workspaceCount, MarkForRebuild(Bounds()); MarkForRedraw(Bounds()); + _UpdateWorkspace(fDesktop->WorkspaceAt(fDesktop->CurrentWorkspace())); + TriggerRebuild(); TriggerRedraw(); } @@ -131,10 +117,6 @@ RootLayer::~RootLayer() { delete fDragMessage; - for (int32 i = 0; i < fWsCount; i++) - delete fWorkspace[i]; - delete[] fWorkspace; - fFirstChild = NULL; // this prevents the Layer destructor from freeing our children again // (the Desktop destructor already took care of that) @@ -180,402 +162,269 @@ RootLayer::ResizeBy(float x, float y) } -void -RootLayer::AddWindowLayer(WindowLayer* windowLayer) +bool +RootLayer::_SetFocus(WindowLayer* focus, BRegion& update) { - if (!windowLayer->IsHidden()) { - CRITICAL("RootLayer::AddWindowLayer - windowLayer must be hidden\n"); + // TODO: test for FFM and B_LOCK_WINDOW_FOCUS + + if (focus == fFocus) + return true; + + if (fFocus != NULL) { + update.Include(&fFocus->VisibleRegion()); + //fFocus->SetFocus(false); + } + + fFocus = focus; + + if (focus != NULL) { + // TODO: the unlocking is evil, but there is currently no cleaner way to do this, ugh... + // (this is also responsible for an occasional crash on quit) + Unlock(); + fDesktop->EventDispatcher().SetFocus(&focus->Window()->FocusMessenger()); + Lock(); + update.Include(&focus->VisibleRegion()); + } else + fDesktop->EventDispatcher().SetFocus(NULL); + + return true; +} + + +bool +RootLayer::SetFocus(WindowLayer* focus) +{ + BRegion update; + bool success = _SetFocus(focus, update); + if (!success) + return false; + + MarkForRedraw(update); + TriggerRedraw(); + return true; +} + + +void +RootLayer::_SetFront(WindowLayer* windowLayer, BRegion& update) +{ + if (windowLayer == NULL) { + fBack = NULL; + fFront = NULL; return; } - // Subset modals also need to have a main window before appearing in workspace list. - int32 feel = windowLayer->Feel(); - if (feel != B_FLOATING_SUBSET_WINDOW_FEEL && feel != B_MODAL_SUBSET_WINDOW_FEEL) { - uint32 workspaces = windowLayer->Workspaces(); - // add to current workspace - if (workspaces == 0) - fWorkspace[fActiveWksIndex]->AddWindowLayer(windowLayer); - else { - // add to desired workspaces - for (int32 i = 0; i < fWsCount; i++) { - if (fWorkspace[i] && (workspaces & (0x00000001UL << i))) - fWorkspace[i]->AddWindowLayer(windowLayer); - } - } + if (!windowLayer->SupportsFront() && fFront != NULL) + return; + + BRegion previous = windowLayer->FullVisible(); + + _RemoveChildFromList(windowLayer); + _AddChildToList(windowLayer); + + windowLayer->GetOnScreenRegion(update); + update.Exclude(&previous); + + fFront = windowLayer; + + if (windowLayer == fBack || fBack == NULL) + _UpdateBack(); +} + + +/*! search the visible windows for a valid back window + (only normal windows can be back windows) +*/ +void +RootLayer::_UpdateBack() +{ + fBack = NULL; + + for (WindowLayer* window = (WindowLayer*)FirstChild(); + window != NULL; window = (WindowLayer*)window->NextLayer()) { + if (window->IsHidden() || !window->SupportsFront()) + continue; + + fBack = window; + break; } +} - // we _DO_NOT_ need to invalidate here. At this point our WindowLayer is hidden! - // set some internals +/*! search the visible windows for a valid front window + (only normal windows can be front windows) +*/ +void +RootLayer::_UpdateFront() +{ + // TODO: for now, just choose the top window + fFront = NULL; + + for (WindowLayer* window = (WindowLayer*)LastChild(); + window != NULL; window = (WindowLayer*)window->PreviousLayer()) { + if (window->IsHidden() || !window->SupportsFront()) + continue; + + fFront = window; + break; + } +} + + +void +RootLayer::_UpdateFronts() +{ + _UpdateBack(); + _UpdateFront(); +} + + +void +RootLayer::ActivateWindow(WindowLayer* windowLayer) +{ + BAutolock _(fAllRegionsLock); + + BRegion changed; + _SetFront(windowLayer, changed); + + // TODO: if this window has any floating windows, add them here + + MarkForRebuild(changed); + TriggerRebuild(); + + _SetFocus(windowLayer, changed); + _WindowsChanged(changed); + MarkForRedraw(changed); + TriggerRedraw(); +} + + +void +RootLayer::SendBehindWindow(WindowLayer* windowLayer, WindowLayer* behindOf) +{ + BAutolock _(fAllRegionsLock); + + if (windowLayer == Back()) + return; + + bool wasFocus = windowLayer == Focus(); + + BRegion changed = windowLayer->FullVisible(); + + _RemoveChildFromList(windowLayer); + if (behindOf == NULL) + behindOf = Back(); + + _AddChildToList(windowLayer, behindOf); + + // TODO: if this window has any floating windows, remove them here + + MarkForRebuild(changed); + TriggerRebuild(); + + _UpdateFronts(); + _SetFocus(Front(), changed); + + changed.Exclude(&windowLayer->FullVisible()); + if (wasFocus != (Focus() == windowLayer)) + changed.Include(&windowLayer->VisibleRegion()); + + _WindowsChanged(changed); + MarkForRedraw(changed); + TriggerRedraw(); +} + + +void +RootLayer::AddWindowLayer(WindowLayer* windowLayer) +{ + STRACE(("AddWindowLayer(%p \"%s\")\n", windowLayer, windowLayer->Name())); + + if (windowLayer->SupportsFront()) + _AddChildToList(windowLayer); + else + _AddChildToList(windowLayer, Back()); + windowLayer->SetRootLayer(this); - windowLayer->fParent = this; + + if (!windowLayer->IsHidden()) + ActivateWindow(windowLayer); } void RootLayer::RemoveWindowLayer(WindowLayer* windowLayer) { - // Note: removing a subset window is also permited/performed. - if (!windowLayer->IsHidden()) - { - CRITICAL("RootLayer::RemoveWindowLayer - windowLayer must be hidden\n"); - return; - } + HideWindowLayer(windowLayer); - // security measure: in case of windows whose workspace count is 0(current workspace), - // we don't know the exact workspaces to remove it from. And how all modal and floating - // windows have 0 as a workspace index, this action is fully justified. - for (int32 i = 0; i < fWsCount; i++) { - if (fWorkspace[i]) - fWorkspace[i]->RemoveWindowLayer(windowLayer); - } - - // we _DO_NOT_ need to invalidate here. At this point our WindowLayer is hidden! + _RemoveChildFromList(windowLayer); LayerRemoved(windowLayer); - - // set some internals windowLayer->SetRootLayer(NULL); - windowLayer->fParent = NULL; } void -RootLayer::AddSubsetWindowLayer(WindowLayer *windowLayer, WindowLayer *toWindowLayer) +RootLayer::_UpdateWorkspace(Workspace& workspace) { - // SUBSET windows _must_ have their workspaceIndex set to 0x0 - if (windowLayer->Workspaces() != 0UL) - { - CRITICAL("SUBSET windows _must_ have their workspaceIndex set to 0x0\n"); - return; - } + fColor = workspace.Color(); - // there is no point in continuing - this subset window won't be shown, - // from 'toWindowLayer's point of view - if (windowLayer->IsHidden() || toWindowLayer->IsHidden()) - { - return; - } - - bool invalidate = false; - bool invalid; - Workspace::State oldWMState; - ActiveWorkspace()->GetState(&oldWMState); - - // we try to add WindowLayers to all workspaces. If they are not needed, nothing will be done. - // If they are needed, Workspace automaticaly allocates space and inserts them. - for (int32 i = 0; i < fWsCount; i++) { - invalid = false; - - if (fWorkspace[i] && fWorkspace[i]->HasWindowLayer(toWindowLayer)) - invalid = fWorkspace[i]->ShowWindowLayer(windowLayer, false); - - if (fActiveWksIndex == i) - invalidate = invalid; - } - - if (invalidate) - RevealNewWMState(oldWMState); + // TODO: for on-screen debugging stuff only + fDrawState->SetLowColor(fColor); } void -RootLayer::RemoveSubsetWindowLayer(WindowLayer *windowLayer, WindowLayer *fromWindowLayer) +RootLayer::SetWorkspace(int32 index, Workspace& workspace) { - // there is no point in continuing - this subset window is not visible - // at least not visible from 'fromWindowLayer's point of view. - if (windowLayer->IsHidden() || fromWindowLayer->IsHidden()) - return; + BAutolock _(fAllRegionsLock); - bool invalidate = false; - bool invalid; - Workspace::State oldWMState; - ActiveWorkspace()->GetState(&oldWMState); + int32 previousIndex = fWorkspace; - // we try to remove from all workspaces. If windowLayer is not in there, nothing will be done. - for (int32 i = 0; i < fWsCount; i++) { - invalid = false; + // build region of windows that are no longer visible in the new workspace - if (fWorkspace[i] && fWorkspace[i]->HasWindowLayer(fromWindowLayer)) - invalid = fWorkspace[i]->HideWindowLayer(windowLayer); + BRegion changed; + for (Layer* layer = FirstChild(); layer != NULL; layer = layer->NextLayer()) { + _RemoveChildFromList(layer); - if (fActiveWksIndex == i) - invalidate = invalid; - } + // TODO: we should only allow WindowLayer as our children, anyway + WindowLayer* window = dynamic_cast(layer); + if (window == NULL || window->IsHidden()) + continue; - if (invalidate) - RevealNewWMState(oldWMState); -} - -// NOTE: This must be called by RootLayer's thread!!!! -bool RootLayer::SetActiveWorkspace(int32 index) -{ - STRACE(("RootLayer(%s)::SetActiveWorkspace(%ld)\n", Name(), index)); - - // nice try! - if (index >= fWsCount || index == fActiveWksIndex || index < 0) - return false; - - // you cannot switch workspaces on R5 if there is an event mask BView -// if (fNotifyLayer && fNotifyLayer->Owner()) -// return false; - - // if you're dragging something you are allowed to change workspaces only if - // the Layer being dragged is a B_NORMAL_WINDOW_FEEL WindowLayer. - WindowLayer *draggedWindowLayer = dynamic_cast(fMouseEventLayer); - if (fMouseEventLayer != NULL) { - if (draggedWindowLayer) { - if (draggedWindowLayer->Feel() != B_NORMAL_WINDOW_FEEL) - return false; - } else - return false; - } - - // if fWorkspace[index] object does not exist, create and add allowed WindowLayers - if (!fWorkspace[index]) { - // TODO: we NEED datas from a file!!! - fWorkspace[index] = new Workspace(index, 0xFF00FF00, kDefaultWorkspaceColor); - - // we need to lock the window list here so no other window can be created - fDesktop->Lock(); - - const BObjectList& windowList = fDesktop->WindowList(); - int32 windowCount = windowList.CountItems(); - - for (int32 i = 0; i < windowCount; i++) { - WindowLayer* windowLayer = windowList.ItemAt(i); - - // is WindowLayer on this workspace? - if (windowLayer->Workspaces() & (0x00000001UL << index)) { - fWorkspace[index]->AddWindowLayer(windowLayer); - - if (!windowLayer->IsHidden()) - fWorkspace[index]->ShowWindowLayer(windowLayer); - } - } - - fDesktop->Unlock(); - } - // adjust our DrawData to workspace colors - rgb_color bg = fWorkspace[index]->BGColor().GetColor32(); - if ((bg.red + bg.green + bg.blue) / 3 > 128) - fDrawState->SetHighColor(RGBColor(0, 0, 0)); - else - fDrawState->SetHighColor(RGBColor(255, 255, 255)); - fDrawState->SetLowColor(fWorkspace[index]->BGColor()); - - // save some datas - int32 exIndex = ActiveWorkspaceIndex(); - Workspace::State oldWMState; - ActiveWorkspace()->GetState(&oldWMState); - - // send the workspace changed message for the old workspace - { - Layer *layer; - for (int32 i = 0; (layer = static_cast(fWMState.WindowList.ItemAt(i++))); ) { - layer->WorkspaceActivated(fActiveWksIndex, false); + if ((window->Workspaces() & (1UL << index)) == 0) { + // this window will no longer be visible + changed.Include(&window->FullVisible()); } } - fActiveWksIndex = index; + fWorkspace = index; + _UpdateWorkspace(workspace); - if (draggedWindowLayer && !ActiveWorkspace()->HasWindowLayer(draggedWindowLayer)) { - // Workspace class expects a window to be hidden when it's about to be removed. - // As we surely know this windows is visible, we simply set fHidden to true and then - // change it back when adding windowLayer to the current workspace. - draggedWindowLayer->fHidden = true; - fWorkspace[exIndex]->HideWindowLayer(draggedWindowLayer); - fWorkspace[exIndex]->RemoveWindowLayer(draggedWindowLayer); + // add new windows, and include them in the changed region - but only + // those that were not visible before - draggedWindowLayer->fHidden = false; - ActiveWorkspace()->AddWindowLayer(draggedWindowLayer); - ActiveWorkspace()->ShowWindowLayer(draggedWindowLayer); + for (int32 i = 0; i < workspace.CountWindows(); i++) { + WindowLayer* window = workspace.WindowAt(i); - // TODO: can you call SetWindowLayerWorskpaces() instead of this? - uint32 wks = draggedWindowLayer->Workspaces(); - BMessage changedMsg(B_WORKSPACES_CHANGED); - changedMsg.AddInt64("when", real_time_clock_usecs()); - changedMsg.AddInt32("old", wks); - wks &= ~(0x00000001 << exIndex); - wks |= (0x00000001 << fActiveWksIndex); - changedMsg.AddInt32("new", wks); - draggedWindowLayer->QuietlySetWorkspaces(wks); - draggedWindowLayer->Window()->SendMessageToClient(&changedMsg, B_NULL_TOKEN); - } - - RevealNewWMState(oldWMState); - - // send the workspace changed message for the new workspace - { - Layer *layer; - for (int32 i = 0; (layer = static_cast(fWMState.WindowList.ItemAt(i++))); ) { - layer->WorkspaceActivated(fActiveWksIndex, true); + if (!window->IsHidden() + && (window->Workspaces() & (1UL << previousIndex)) == 0) { + // this window was not visible before + BRegion region; + window->GetOnScreenRegion(region); + changed.Include(®ion); } + + _AddChildToList(window); } - // workspace changed - return true; -} + MarkForRebuild(changed); + TriggerRebuild(); - -void -RootLayer::SetWindowLayerWorskpaces(WindowLayer *windowLayer, uint32 oldIndex, uint32 newIndex) -{ - // if the active notify Layer is somehow related to windowLayer, then - // this window/WindowLayer is not allowed to leave this workspace. -// TODO: this looks wrong: I doubt the window is supposed to open in two workspaces then -// if (fNotifyLayer && (fNotifyLayer == windowLayer || fNotifyLayer->Owner() == windowLayer)) -// newIndex |= (0x00000001UL << fActiveWksIndex); - - uint32 localOldIndex = oldIndex; - uint32 localNewIndex = newIndex; - bool invalidate = false; - bool invalid; - - // if we're in the current workspace only, reflect that in the workspace index - if (localOldIndex == 0UL) - localOldIndex |= (0x00000001UL << fActiveWksIndex); - if (localNewIndex == 0UL) - localNewIndex |= (0x00000001UL << fActiveWksIndex); - - // you *cannot* set workspaces index for a window other than a normal one! - // Note: See ServerWindow class. - if (windowLayer->Feel() != B_NORMAL_WINDOW_FEEL || localOldIndex == localNewIndex) - return; - - Workspace::State oldWMState; - ActiveWorkspace()->GetState(&oldWMState); - - for (int32 i = 0; i < 32; i++) { - if (fWorkspace[i]) { - invalid = false; - - if (!(localNewIndex & (0x00000001UL << i)) && fWorkspace[i]->HasWindowLayer(windowLayer)) { - if (!windowLayer->IsHidden()) { - // a little trick to force Workspace to properly pick the next front. - windowLayer->fHidden = true; - invalid = fWorkspace[i]->HideWindowLayer(windowLayer); - windowLayer->fHidden = false; - } - fWorkspace[i]->RemoveWindowLayer(windowLayer); - } - - if ((localNewIndex & (0x00000001UL << i)) && !fWorkspace[i]->HasWindowLayer(windowLayer)) { - fWorkspace[i]->AddWindowLayer(windowLayer); - if (!windowLayer->IsHidden()) - invalid = fWorkspace[i]->ShowWindowLayer(windowLayer); - } - - if (fActiveWksIndex == i) - invalidate = invalid; - } - } - - windowLayer->WorkspacesChanged(oldIndex, newIndex); - - if (invalidate) - RevealNewWMState(oldWMState); -} - - -void -RootLayer::SetWorkspaceCount(int32 wksCount) -{ - if (wksCount < 1) - wksCount = 1; - if (wksCount > kMaxWorkspaceCount) - wksCount = kMaxWorkspaceCount; - - for (int32 i = wksCount; i < fWsCount; i++) { - delete fWorkspace[i]; - fWorkspace[i] = NULL; - } - - fWsCount = wksCount; -} - - -void -RootLayer::ReadWorkspaceData(const char *path) -{ - BMessage msg, settings; - BFile file(path,B_READ_ONLY); - char string[20]; - - if (file.InitCheck() == B_OK && msg.Unflatten(&file) == B_OK) { - int32 count; - - if (msg.FindInt32("workspace_count", &count)!=B_OK) - count = 9; - - SetWorkspaceCount(count); - - for (int32 i = 0; i < count; i++) { - Workspace *ws=(Workspace*)fWorkspace[i]; - if (!ws) - continue; - - sprintf(string,"workspace %ld",i); - - if (msg.FindMessage(string,&settings) == B_OK) { - ws->GetSettings(settings); - settings.MakeEmpty(); - } else - ws->GetDefaultSettings(); - } - } else { - SetWorkspaceCount(9); - - for (int32 i = 0; i < 9; i++) { - Workspace *ws=(Workspace*)fWorkspace[i]; - if (!ws) - continue; - - ws->GetDefaultSettings(); - } - } -} - - -void -RootLayer::SaveWorkspaceData(const char *path) -{ - BMessage msg,dummy; - BFile file(path, B_READ_WRITE | B_CREATE_FILE); - - if (file.InitCheck() != B_OK) { - printf("ERROR: Couldn't save workspace data in RootLayer\n"); - return; - } - - char string[20]; - int32 count = fWsCount; - - if (msg.Unflatten(&file) == B_OK) { - // if we were successful in unflattening the file, it means we're - // going to need to save over the existing data - for(int32 i = 0; i < count; i++) { - sprintf(string,"workspace %ld",i); - if(msg.FindMessage(string,&dummy)==B_OK) - msg.RemoveName(string); - } - } - - for (int32 i = 0; i < count; i++) { - sprintf(string,"workspace %ld",i); - - Workspace *ws = (Workspace*)fWorkspace[i]; - - if (!ws) { - dummy.MakeEmpty(); - ws->PutSettings(&dummy,i); - msg.AddMessage(string,&dummy); - } else { - // We're not supposed to have this happen, but we'll suck it up, anyway. :P - Workspace::PutDefaultSettings(&msg,i); - } - } + _WindowsChanged(changed); + MarkForRedraw(changed); + TriggerRedraw(); } @@ -584,130 +433,74 @@ RootLayer::HideWindowLayer(WindowLayer* windowLayer) { BAutolock _(fAllRegionsLock); - bool invalidate = false; - bool invalid; - Workspace::State oldWMState; - ActiveWorkspace()->GetState(&oldWMState); + BRegion changed = windowLayer->FullVisible(); + windowLayer->Hide(); + _UpdateFronts(); - windowLayer->Hide(false); + // TODO: if this window has any floating windows, remove them here - for (int32 i = 0; i < fWsCount; i++) { - invalid = false; + MarkForRebuild(changed); + TriggerRebuild(); - if (fWorkspace[i] && fWorkspace[i]->HasWindowLayer(windowLayer)) - invalid = fWorkspace[i]->HideWindowLayer(windowLayer); + if (windowLayer == Focus()) + _SetFocus(Front(), changed); + _WindowsChanged(changed); - if (fActiveWksIndex == i) { - invalidate = invalid; - - if (dynamic_cast(windowLayer->FirstChild()) != NULL) - SetWorkspacesLayer(NULL); - } - } - - if (invalidate) - RevealNewWMState(oldWMState); + MarkForRedraw(changed); + TriggerRedraw(); } void -RootLayer::ShowWindowLayer(WindowLayer* windowLayer) +RootLayer::ShowWindowLayer(WindowLayer* windowLayer, bool toFront) { + STRACE(("ShowWindowLayer(%p)\n", windowLayer)); + + if (!windowLayer->IsHidden()) + return; + BAutolock _(fAllRegionsLock); - bool invalidate = false; - bool invalid; - Workspace::State oldWMState; - ActiveWorkspace()->GetState(&oldWMState); + windowLayer->Show(); + BRegion changed = windowLayer->FullVisible(); - windowLayer->Show(false); + if (toFront) + _SetFront(windowLayer, changed); + else + _UpdateFront(); - for (int32 i = 0; i < fWsCount; i++) { - invalid = false; + // TODO: if this window has any floating windows, remove them here - if (fWorkspace[i] - && (fWorkspace[i]->HasWindowLayer(windowLayer) - || windowLayer->Feel() == B_MODAL_SUBSET_WINDOW_FEEL - // subset modals are a bit like floating windows, they are being added - // and removed from workspace when there's at least a normal window - // that uses them. - || windowLayer->Level() == B_FLOATING_APP)) - // floating windows are inserted/removed on-the-fly so this window, - // although needed may not be in workspace's list. - { - invalid = fWorkspace[i]->ShowWindowLayer(windowLayer); - - // ToDo: this won't work with FFM - fWorkspace[i]->AttemptToSetFocus(windowLayer); - } - - if (fActiveWksIndex == i) { - invalidate = invalid; - - if (dynamic_cast(windowLayer->FirstChild()) != NULL) - SetWorkspacesLayer(windowLayer->FirstChild()); - } - } - - if (invalidate) - RevealNewWMState(oldWMState); + // TODO: support FFM and B_AVOID_FOCUS + if (Front() == windowLayer || Focus() == NULL) + _SetFocus(windowLayer, changed); + _WindowsChanged(changed); + MarkForRedraw(changed); + TriggerRedraw(); } void -RootLayer::ChangeWindowLayerFeel(WindowLayer *windowLayer, int32 newFeel) +RootLayer::SetWindowLayerFeel(WindowLayer *windowLayer, int32 newFeel) { BAutolock _(fAllRegionsLock); - bool isVisible = false; - bool isVisibleInActiveWorkspace = false; - - Workspace::State oldWMState; - ActiveWorkspace()->GetState(&oldWMState); - - if (!windowLayer->IsHidden()) { - isVisible = true; - isVisibleInActiveWorkspace = ActiveWorkspace()->HasWindowLayer(windowLayer); - // just hide, don't invalidate - windowLayer->Hide(false); - // all workspaces must be up-to-date with this change of feel. - for (int32 i = 0; i < kMaxWorkspaceCount; i++) { - if (fWorkspace[i]) { - fWorkspace[i]->HideWindowLayer(windowLayer); - fWorkspace[i]->RemoveWindowLayer(windowLayer); - } - } - } - - fDesktop->SetWindowLayerFeel(windowLayer, newFeel); - - if (isVisible) { - // just show, don't invalidate - windowLayer->Show(false); - // all workspaces must be up-to-date with this change of feel. - for (int32 i = 0; i < kMaxWorkspaceCount; i++) { - if (fWorkspace[i]) { - fWorkspace[i]->AddWindowLayer(windowLayer); - fWorkspace[i]->ShowWindowLayer(windowLayer); - } - } - - if (isVisibleInActiveWorkspace) - RevealNewWMState(oldWMState); - } + // TODO } +void +RootLayer::SetWindowLayerLook(WindowLayer *windowLayer, int32 newLook) +{ + BAutolock _(fAllRegionsLock); + + // TODO +} + +#if 0 void RootLayer::RevealNewWMState(Workspace::State &oldWMState) { - // clear fWMState - fWMState.Focus = NULL; - fWMState.Front = NULL; - fWMState.WindowList.MakeEmpty(); - - ActiveWorkspace()->GetState(&fWMState); - // send window activation messages if (oldWMState.Focus != fWMState.Focus) { if (oldWMState.Focus) @@ -718,184 +511,16 @@ RootLayer::RevealNewWMState(Workspace::State &oldWMState) } else fDesktop->EventDispatcher().SetFocus(NULL); } - - // calculate the region that must be invalidated/redrawn - - bool redraw = false; - // first, if the focus window changed, make sure the decorators reflect this state. - BRegion dirtyRegion; - if (oldWMState.Focus != fWMState.Focus) { - if (oldWMState.Focus) { - dirtyRegion.Include(&oldWMState.Focus->VisibleRegion()); - redraw = true; - } - if (fWMState.Focus) { - dirtyRegion.Include(&fWMState.Focus->VisibleRegion()); - redraw = true; - } - if (redraw) { - MarkForRedraw(dirtyRegion); - } - } - - bool invalidate = false; - // check to see if window count changed over states - if (oldWMState.WindowList.CountItems() != fWMState.WindowList.CountItems()) { - invalidate = true; - } else if (memcmp(oldWMState.WindowList.Items(), fWMState.WindowList.Items(), - fWMState.WindowList.CountItems()*sizeof(void*)) != 0) { - invalidate = true; - } - - if (invalidate) { - // clear visible areas for windows not visible anymore. - int32 oldWindowCount = oldWMState.WindowList.CountItems(); - int32 newWindowCount = fWMState.WindowList.CountItems(); - BList oldStrippedList, newStrippedList; - for (int32 i = 0; i < oldWindowCount; ++i) { - Layer *layer = static_cast(oldWMState.WindowList.ItemAtFast(i)); - if (!layer) - continue; - - bool stillPresent = false; - for (int32 j = 0; j < newWindowCount; ++j) { - if (layer == fWMState.WindowList.ItemAtFast(j)) { - stillPresent = true; - break; - } - } - - if (!stillPresent) { - MarkForRebuild(layer->FullVisible()); - MarkForRedraw(layer->FullVisible()); - - layer->_ClearVisibleRegions(); - } else - oldStrippedList.AddItem(layer); - } - - fFirstChild = NULL; - fLastChild = NULL; - - // for new windows, invalidate(rebuild & redraw) the maximum that it can occupy. - for (int32 i = 0; i < newWindowCount; ++i) { - Layer *layer = static_cast(fWMState.WindowList.ItemAtFast(i)); - if (!layer) - continue; - - // insert layer into RootLayer list - if (i == 0) - fFirstChild = layer; - - if (fLastChild != NULL) - fLastChild->fNextSibling = layer; - layer->fPreviousSibling = fLastChild; - layer->fNextSibling = NULL; - - fLastChild = layer; - - bool isNewWindow = true; - for (int32 j = 0; j < oldWindowCount; ++j) { - if (layer == oldWMState.WindowList.ItemAtFast(j)) { - isNewWindow = false; - break; - } - } - - if (isNewWindow) { - BRegion invalid; - - // invalidate the maximum area which this layer/window can occupy. - layer->GetOnScreenRegion(invalid); - - MarkForRebuild(invalid); - MarkForRedraw(invalid); - } else - newStrippedList.AddItem(layer); - } - - // if a window came in front ot others, invalidate its previously hidden area. - oldWindowCount = oldStrippedList.CountItems(); - newWindowCount = newStrippedList.CountItems(); - for (int32 i = 0; i < oldWindowCount; ++i) { - Layer *layer = static_cast(oldStrippedList.ItemAtFast(i)); - if (!layer) - continue; - if (i < newStrippedList.IndexOf(layer)) { - BRegion invalid; - - // start by invalidating the maximum area which this layer/window can occupy. - layer->GetOnScreenRegion(invalid); - - // no reason to invalidate what's currently visible. - invalid.Exclude(&layer->FullVisible()); - - MarkForRebuild(invalid); - MarkForRedraw(invalid); - } - } -/* -// for debugging -GetDrawingEngine()->ConstrainClippingRegion(&fDirtyForRedraw); -RGBColor c(rand()%255,rand()%255,rand()%255); -GetDrawingEngine()->FillRect(BRect(0,0,800,600), c); -snooze(2000000); -GetDrawingEngine()->ConstrainClippingRegion(NULL); -*/ - // redraw of focus change is automaticaly done - redraw = false; - // trigger region rebuilding and redraw - TriggerRebuild(); - TriggerRedraw(); - } else if (redraw) { - MarkForRedraw(dirtyRegion); - TriggerRedraw(); - } } +#endif - -bool -RootLayer::SetActive(WindowLayer* newActive, bool activate) +void +RootLayer::_WindowsChanged(BRegion& region) { - bool returnValue = false; - uint32 workspaceIndex = newActive->Workspaces(); - if (workspaceIndex == 0) - workspaceIndex = 0x00000001UL << fActiveWksIndex; + if (fWorkspacesLayer == NULL) + return; - for (int32 i = 0; i < kMaxWorkspaceCount; i++) { - if (fWorkspace[i] && (workspaceIndex & (0x00000001UL << i))) { - if (i == fActiveWksIndex) { - Workspace::State oldWMState; - ActiveWorkspace()->GetState(&oldWMState); - - if (activate) - returnValue = ActiveWorkspace()->AttemptToActivate(newActive); - else - returnValue = ActiveWorkspace()->AttemptToMoveToBack(newActive); - - RevealNewWMState(oldWMState); - } else { - fWorkspace[i]->AttemptToActivate(newActive); - // NOTE: for multiple monitor support, if a workspaces is mapped to - // a Screen, we must invalidate/redraw to see the change. - } - } - } - - // If this WindowLayer does not appear in current workspace, - // change to the first one who does. - if (activate && !(workspaceIndex & (0x00000001UL << fActiveWksIndex))) { - // find an workspace index in which this Layer appears - for (int32 i = 0; i < kMaxWorkspaceCount; i++) { - if (workspaceIndex & (0x00000001UL << i)) { - SetActiveWorkspace(i); - returnValue = Active() == newActive; - break; - } - } - } - - return returnValue; + region.Include(&fWorkspacesLayer->VisibleRegion()); } @@ -983,19 +608,18 @@ RootLayer::DragMessage(void) const } -// PRIVATE methods - - void -RootLayer::Draw(const BRect &r) +RootLayer::Draw(const BRect& rect) { - fDriver->FillRect(r, fWorkspace[fActiveWksIndex]->BGColor()); + fDriver->FillRect(rect, fColor); + #ifdef APPSERVER_ROOTLAYER_SHOW_WORKSPACE_NUMBER char string[30]; - sprintf(string, "Workspace %ld", fActiveWksIndex + 1); + sprintf(string, "Workspace %ld", fWorkspace + 1); fDriver->DrawString(string, strlen(string), BPoint(5, 15), - fDrawState); + fDrawState); #endif // APPSERVER_ROOTLAYER_SHOW_WORKSPACE_NUMBER + #if ON_SCREEN_DEBUGGING_INFO BPoint location(5, 40); float textHeight = 15.0; // be lazy @@ -1048,18 +672,20 @@ RootLayer::MarkForRedraw(const BRegion &dirty) fDirtyForRedraw.Include(&dirty); } + void RootLayer::TriggerRedraw() { BAutolock locker(fAllRegionsLock); -/* -// for debugging -GetDrawingEngine()->ConstrainClippingRegion(&fDirtyForRedraw); -RGBColor c(rand()%255,rand()%255,rand()%255); -GetDrawingEngine()->FillRect(BRect(0,0,800,600), c); -snooze(2000000); -GetDrawingEngine()->ConstrainClippingRegion(NULL); -*/ + +#if 0 + // for debugging + GetDrawingEngine()->ConstrainClippingRegion(&fDirtyForRedraw); + RGBColor color(rand()%255, rand()%255, rand()%255); + GetDrawingEngine()->FillRect(Bounds(), color); + snooze(200000); + GetDrawingEngine()->ConstrainClippingRegion(NULL); +#endif _AllRedraw(fDirtyForRedraw); fDirtyForRedraw.MakeEmpty(); diff --git a/src/servers/app/RootLayer.h b/src/servers/app/RootLayer.h index 4c613c3b53..b0ccb6ff6c 100644 --- a/src/servers/app/RootLayer.h +++ b/src/servers/app/RootLayer.h @@ -40,116 +40,103 @@ namespace BPrivate { class UtilityBitmap; #endif -/*! - \class RootLayer RootLayer.h - \brief Class used for the top layer of each workspace's Layer tree - - RootLayers are used to head up the top of each Layer tree and reimplement certain - Layer functions to act accordingly. There is only one for each workspace class. - -*/ + class RootLayer : public Layer { -public: - RootLayer(const char *name, int32 workspaceCount, - Desktop *desktop, DrawingEngine *driver); - virtual ~RootLayer(void); + public: + RootLayer(const char *name, Desktop *desktop, + DrawingEngine *driver); + virtual ~RootLayer(); - Desktop* GetDesktop() const { return fDesktop; } + Desktop* GetDesktop() const { return fDesktop; } - virtual void MoveBy(float x, float y); - virtual void ResizeBy(float x, float y); - virtual void ScrollBy(float x, float y) - { /* not allowed */ } + virtual void MoveBy(float x, float y); + virtual void ResizeBy(float x, float y); + virtual void ScrollBy(float x, float y) + { /* not allowed */ } - void HideWindowLayer(WindowLayer* windowLayer); - void ShowWindowLayer(WindowLayer* windowLayer); - void SetWindowLayerWorskpaces(WindowLayer *windowLayer, - uint32 oldIndex, uint32 newIndex); + void HideWindowLayer(WindowLayer* windowLayer); + void ShowWindowLayer(WindowLayer* windowLayer, bool toFront = true); - void RevealNewWMState(Workspace::State &oldWMState); -// TODO: we need to replace Winborder* with Layer* - inline WindowLayer* Focus() const { return fWMState.Focus; } - inline WindowLayer* Front() const { return fWMState.Front; } - inline WindowLayer* Active() const { return fWMState.Focus; } - bool SetActive(WindowLayer* newActive, bool activate = true); +// void RevealNewWMState(Workspace::State &oldWMState); + bool SetFocus(WindowLayer* focus); + WindowLayer* Focus() const { return fFocus; } + WindowLayer* Front() const { return fFront; } + WindowLayer* Back() const { return fBack; } - inline void SetWorkspaceCount(int32 wksCount); - inline int32 WorkspaceCount() const { return fWsCount; } - inline Workspace* WorkspaceAt(int32 index) const { return fWorkspace[index]; } - inline Workspace* ActiveWorkspace() const { return fWorkspace[fActiveWksIndex]; } - inline int32 ActiveWorkspaceIndex() const { return fActiveWksIndex; } - bool SetActiveWorkspace(int32 index); + void SetWorkspace(int32 index, Workspace& workspace); + void SetWorkspacesLayer(Layer* layer) { fWorkspacesLayer = layer; } + Layer* WorkspacesLayer() const { return fWorkspacesLayer; } - void ReadWorkspaceData(const char *path); - void SaveWorkspaceData(const char *path); +#if 0 + void SetBGColor(const RGBColor &col); + RGBColor BGColor(void) const; +#endif - void SetWorkspacesLayer(Layer* layer) { fWorkspacesLayer = layer; } - Layer* WorkspacesLayer() const { return fWorkspacesLayer; } - - void SetBGColor(const RGBColor &col); - RGBColor BGColor(void) const; + void SetDragMessage(BMessage *msg); + BMessage* DragMessage() const; - void SetDragMessage(BMessage *msg); - BMessage* DragMessage(void) const; + void SetMouseEventLayer(Layer* layer); - void SetMouseEventLayer(Layer* layer); + void LayerRemoved(Layer* layer); - void LayerRemoved(Layer* layer); + // Other methods + bool Lock() { return fAllRegionsLock.Lock(); } + void Unlock() { fAllRegionsLock.Unlock(); } + bool IsLocked() { return fAllRegionsLock.IsLocked(); } - // Other methods - bool Lock() { return fAllRegionsLock.Lock(); } - void Unlock() { fAllRegionsLock.Unlock(); } - bool IsLocked() { return fAllRegionsLock.IsLocked(); } + void ActivateWindow(WindowLayer* window); + void SendBehindWindow(WindowLayer* window, WindowLayer* front); - void ChangeWindowLayerFeel(WindowLayer *windowLayer, int32 newFeel); + void SetWindowLayerFeel(WindowLayer *windowLayer, int32 newFeel); + void SetWindowLayerLook(WindowLayer *windowLayer, int32 newLook); - void MarkForRedraw(const BRegion &dirty); - void TriggerRedraw(); + void MarkForRedraw(const BRegion &dirty); + void TriggerRedraw(); - virtual void Draw(const BRect &r); + void Draw(const BRect &r); - thread_id LockingThread() { return fAllRegionsLock.LockingThread(); } + thread_id LockingThread() { return fAllRegionsLock.LockingThread(); } -private: -friend class Desktop; + void AddWindowLayer(WindowLayer* windowLayer); + void RemoveWindowLayer(WindowLayer* windowLayer); - // these are meant for Desktop class only! - void AddWindowLayer(WindowLayer* windowLayer); - void RemoveWindowLayer(WindowLayer* windowLayer); - void AddSubsetWindowLayer(WindowLayer *windowLayer, WindowLayer *toWindowLayer); - void RemoveSubsetWindowLayer(WindowLayer *windowLayer, WindowLayer *fromWindowLayer); + void MouseEventHandler(BMessage *msg); - void MouseEventHandler(BMessage *msg); - Layer* _ChildAt(BPoint where); + private: + bool _SetFocus(WindowLayer* focus, BRegion& update); + void _SetFront(WindowLayer* front, BRegion& update); + void _UpdateBack(); + void _UpdateFront(); + void _UpdateFronts(); - Desktop* fDesktop; - BMessage* fDragMessage; - Layer* fMouseEventLayer; + void _WindowsChanged(BRegion& region); + void _UpdateWorkspace(Workspace& workspace); - uint32 fSavedEventMask; - uint32 fSavedEventOptions; + Layer* _ChildAt(BPoint where); - BLocker fAllRegionsLock; + Desktop* fDesktop; + BMessage* fDragMessage; + Layer* fMouseEventLayer; - BRegion fDirtyForRedraw; + BLocker fAllRegionsLock; - int32 fActiveWksIndex; - int32 fWsCount; - Workspace** fWorkspace; - Layer* fWorkspacesLayer; + BRegion fDirtyForRedraw; -// TODO: fWMState MUST be associated with a surface. This is the case now -// with RootLayer, but after Axel's refractoring this should go in -// WorkspaceLayer, I think. - Workspace::State fWMState; + int32 fWorkspace; + RGBColor fColor; + Layer* fWorkspacesLayer; + + WindowLayer* fFocus; + WindowLayer* fFront; + WindowLayer* fBack; #if ON_SCREEN_DEBUGGING_INFO - friend class DebugInfoManager; - void AddDebugInfo(const char* string); - BString fDebugInfo; + friend class DebugInfoManager; + void AddDebugInfo(const char* string); + BString fDebugInfo; #endif #if DISPLAY_HAIKU_LOGO - UtilityBitmap* fLogoBitmap; + UtilityBitmap* fLogoBitmap; #endif }; diff --git a/src/servers/app/ServerApp.cpp b/src/servers/app/ServerApp.cpp index 288f3489c9..57eb50b4ed 100644 --- a/src/servers/app/ServerApp.cpp +++ b/src/servers/app/ServerApp.cpp @@ -849,18 +849,12 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) { STRACE(("ServerApp %s: get current workspace\n", Signature())); - // TODO: Locking this way is not nice - RootLayer *root = fDesktop->RootLayer(); - root->Lock(); - - fLink.StartMessage(SERVER_TRUE); - fLink.Attach(root->ActiveWorkspaceIndex()); + fLink.StartMessage(B_OK); + fLink.Attach(fDesktop->CurrentWorkspace()); fLink.Flush(); - - root->Unlock(); break; } - + case AS_ACTIVATE_WORKSPACE: { STRACE(("ServerApp %s: activate workspace\n", Signature())); @@ -868,15 +862,11 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) // TODO: See above int32 index; link.Read(&index); - RootLayer *root = fDesktop->RootLayer(); - root->Lock(); - root->SetActiveWorkspace(index); - root->Unlock(); - // no reply - + + fDesktop->SetWorkspace(index); break; } - + case AS_SHOW_CURSOR: { STRACE(("ServerApp %s: Show Cursor\n", Signature())); @@ -2188,31 +2178,22 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) { STRACE(("ServerApp %s: get desktop color\n", Signature())); - uint32 workspaceIndex; - link.Read(&workspaceIndex); + uint32 index; + link.Read(&index); - // ToDo: locking is probably wrong - why the hell is there no (safe) - // way to get to the workspace object directly? - RootLayer *root = fDesktop->RootLayer(); - root->Lock(); - - Workspace *workspace; + fLink.StartMessage(B_OK); + fDesktop->Lock(); // we're nice to our children (and also take the default case // into account which asks for the current workspace) - if (workspaceIndex > (uint32)root->WorkspaceCount()) - workspace = root->ActiveWorkspace(); - else - workspace = root->WorkspaceAt(workspaceIndex); + if (index >= (uint32)kMaxWorkspaces) + index = fDesktop->CurrentWorkspace(); - if (workspace != NULL) { - fLink.StartMessage(B_OK); - fLink.Attach(workspace->BGColor().GetColor32()); - } else - fLink.StartMessage(B_ERROR); + Workspace& workspace = fDesktop->WorkspaceAt(index); + fLink.Attach(workspace.Color().GetColor32()); + fDesktop->Unlock(); fLink.Flush(); - root->Unlock(); break; } diff --git a/src/servers/app/ServerApp.h b/src/servers/app/ServerApp.h index 44a162e29a..b099f668ae 100644 --- a/src/servers/app/ServerApp.h +++ b/src/servers/app/ServerApp.h @@ -14,7 +14,6 @@ #include "MessageLooper.h" -#include "SubWindowList.h" #include "BGet++.h" #include @@ -78,9 +77,6 @@ class ServerApp : public MessageLooper { BPrivate::BTokenSpace& ViewTokens() { return fViewTokens; } - // ToDo: public? - SubWindowList fAppSubWindowList; - private: virtual void _DispatchMessage(int32 code, BPrivate::LinkReceiver &link); virtual void _MessageLooper(); diff --git a/src/servers/app/ServerWindow.cpp b/src/servers/app/ServerWindow.cpp index 90bff06742..e15649d315 100644 --- a/src/servers/app/ServerWindow.cpp +++ b/src/servers/app/ServerWindow.cpp @@ -294,13 +294,11 @@ ServerWindow::Show() return; RootLayer* rootLayer = fWindowLayer->GetRootLayer(); - if (rootLayer && rootLayer->Lock()) { + if (rootLayer) rootLayer->ShowWindowLayer(fWindowLayer); - rootLayer->Unlock(); - } - + if (fDirectWindowData != NULL) - HandleDirectConnection(B_DIRECT_START|B_BUFFER_RESET); + HandleDirectConnection(B_DIRECT_START | B_BUFFER_RESET); } @@ -316,12 +314,10 @@ ServerWindow::Hide() if (fDirectWindowData != NULL) HandleDirectConnection(B_DIRECT_STOP); - + RootLayer* rootLayer = fWindowLayer->GetRootLayer(); - if (rootLayer && rootLayer->Lock()) { + if (rootLayer) rootLayer->HideWindowLayer(fWindowLayer); - rootLayer->Unlock(); - } } @@ -404,23 +400,6 @@ ServerWindow::NotifyZoom() SendMessageToClient(&msg); } -/*! - \brief Notifies window of a change in screen resolution - \param frame Size of the new resolution - \param color_space Color space of the new screen mode -*/ -void -ServerWindow::NotifyScreenModeChanged(const BRect frame, const color_space colorSpace) -{ - STRACE(("ServerWindow %s: ScreenModeChanged\n", fTitle)); - - BMessage msg(B_SCREEN_CHANGED); - msg.AddRect("frame", frame); - msg.AddInt32("mode", (int32)colorSpace); - - SendMessageToClient(&msg); -} - void ServerWindow::GetInfo(window_info& info) @@ -696,7 +675,8 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link) if (rootLayer) { rootLayer->LayerRemoved(fCurrentLayer); - rootLayer->TriggerRedraw(); + if (!fCurrentLayer->IsHidden()) + rootLayer->TriggerRedraw(); } if (fCurrentLayer->EventMask() != 0) { @@ -992,7 +972,7 @@ if (rootLayer) rootLayer->Lock(); fCurrentLayer->SetViewColor(RGBColor(c)); - if (rootLayer) { + if (rootLayer && !fCurrentLayer->IsHidden()) { rootLayer->MarkForRedraw(fCurrentLayer->VisibleRegion()); rootLayer->TriggerRedraw(); } @@ -1177,7 +1157,7 @@ if (rootLayer) link.Read(&invalRect); - if (rootLayer) { + if (rootLayer && !fCurrentLayer->IsHidden()) { BRect converted(invalRect.LeftTop(), invalRect.RightBottom()); fCurrentLayer->ConvertToScreen(&converted); @@ -1206,13 +1186,12 @@ if (rootLayer) invalidReg.Include(rect); } - if (rootLayer) { + if (rootLayer && !fCurrentLayer->IsHidden()) { fCurrentLayer->ConvertToScreen(&invalidReg); rootLayer->MarkForRedraw(invalidReg); rootLayer->TriggerRedraw(); } - break; } case AS_BEGIN_UPDATE: @@ -1239,41 +1218,6 @@ if (rootLayer) STRACE(("ServerWindow %s: Message Delete_Layer_Root unimplemented\n", Title())); break; } - case AS_SHOW_WINDOW: - { - STRACE(("ServerWindow %s: Message AS_SHOW_WINDOW\n", Title())); - Show(); - break; - } - case AS_HIDE_WINDOW: - { - STRACE(("ServerWindow %s: Message AS_HIDE_WINDOW\n", Title())); - Hide(); - break; - } - case AS_SEND_BEHIND: - { - STRACE(("ServerWindow %s: Message Send_Behind unimplemented\n", Title())); - int32 token; - team_id teamID; - status_t status = B_NAME_NOT_FOUND; - - link.Read(&token); - link.Read(&teamID); - - WindowLayer *behindOf; - if ((behindOf = fDesktop->FindWindowLayerByClientToken(token, teamID)) != NULL) { - fWindowLayer->GetRootLayer()->Lock(); - // TODO: move to back ATM. Fix this later! - fWindowLayer->GetRootLayer()->SetActive(fWindowLayer, false); - fWindowLayer->GetRootLayer()->Unlock(); - status = B_OK; - } - - fLink.StartMessage(status); - fLink.Flush(); - break; - } case AS_BEGIN_TRANSACTION: { STRACE(("ServerWindow %s: Message AS_BEGIN_TRANSACTION unimplemented\n", @@ -1333,16 +1277,14 @@ if (rootLayer) link.Read(&mainToken); link.Read(&teamID, sizeof(team_id)); - windowLayer = fDesktop->FindWindowLayerByClientToken(mainToken, teamID); + windowLayer = NULL; //fDesktop->FindWindowLayerByClientToken(mainToken, teamID); if (windowLayer) { - fLink.StartMessage(SERVER_TRUE); + fLink.StartMessage(B_OK); fLink.Flush(); - fWindowLayer->GetRootLayer()->Lock(); - fDesktop->AddWindowLayerToSubset(fWindowLayer, windowLayer); - fWindowLayer->GetRootLayer()->Unlock(); + //fDesktop->AddWindowLayerToSubset(fWindowLayer, windowLayer); } else { - fLink.StartMessage(SERVER_FALSE); + fLink.StartMessage(B_ERROR); fLink.Flush(); } break; @@ -1357,16 +1299,14 @@ if (rootLayer) link.Read(&mainToken); link.Read(&teamID, sizeof(team_id)); - windowLayer = fDesktop->FindWindowLayerByClientToken(mainToken, teamID); + windowLayer = NULL; //fDesktop->FindWindowLayerByClientToken(mainToken, teamID); if (windowLayer) { - fLink.StartMessage(SERVER_TRUE); + fLink.StartMessage(B_OK); fLink.Flush(); - fWindowLayer->GetRootLayer()->Lock(); - fDesktop->RemoveWindowLayerFromSubset(fWindowLayer, windowLayer); - fWindowLayer->GetRootLayer()->Unlock(); + //fDesktop->RemoveWindowLayerFromSubset(fWindowLayer, windowLayer); } else { - fLink.StartMessage(SERVER_FALSE); + fLink.StartMessage(B_ERROR); fLink.Flush(); } break; @@ -1420,10 +1360,7 @@ if (rootLayer) uint32 newWorkspaces; link.Read(&newWorkspaces); - fWindowLayer->GetRootLayer()->Lock(); - fWindowLayer->GetRootLayer()->SetWindowLayerWorskpaces(fWindowLayer, - fWindowLayer->Workspaces(), newWorkspaces); - fWindowLayer->GetRootLayer()->Unlock(); + fDesktop->SetWindowWorkspaces(fWindowLayer, newWorkspaces); break; } case AS_WINDOW_RESIZE: @@ -1485,19 +1422,6 @@ if (rootLayer) fLink.Flush(); break; } - case AS_ACTIVATE_WINDOW: - { - DTRACE(("ServerWindow %s: Message AS_ACTIVATE_WINDOW: Layer: %s\n", Title(), fCurrentLayer->Name())); - bool activate = true; - - link.Read(&activate); - - if (rootLayer && rootLayer->Lock()) { - rootLayer->SetActive(fWindowLayer, activate); - rootLayer->Unlock(); - } - break; - } // Some BView drawing messages, but which don't need clipping case AS_LAYER_SET_HIGH_COLOR: { @@ -2129,6 +2053,52 @@ ServerWindow::_MessageLooper() CRITICAL("ServerWindow: a window must be hidden before it's deleted\n"); break; + // TODO: these are here temporarily, as they don't lock the root layer + case AS_SHOW_WINDOW: + STRACE(("ServerWindow %s: Message AS_SHOW_WINDOW\n", Title())); + Show(); + break; + + case AS_HIDE_WINDOW: + STRACE(("ServerWindow %s: Message AS_HIDE_WINDOW\n", Title())); + Hide(); + break; + + case AS_ACTIVATE_WINDOW: + { + DTRACE(("ServerWindow %s: Message AS_ACTIVATE_WINDOW: Layer: %s\n", Title(), fCurrentLayer->Name())); + bool activate = true; + + receiver.Read(&activate); + + if (activate) + fDesktop->ActivateWindow(fWindowLayer); + else + fDesktop->SendBehindWindow(fWindowLayer, NULL); + break; + } + case AS_SEND_BEHIND: + { + STRACE(("ServerWindow %s: Message Send_Behind unimplemented\n", Title())); + int32 token; + team_id teamID; + status_t status; + + receiver.Read(&token); + receiver.Read(&teamID); + + WindowLayer *behindOf; + if ((behindOf = fDesktop->FindWindowLayerByClientToken(token, teamID)) != NULL) { + fDesktop->SendBehindWindow(fWindowLayer, behindOf); + status = B_OK; + } else + status = B_NAME_NOT_FOUND; + + fLink.StartMessage(status); + fLink.Flush(); + break; + } + case B_QUIT_REQUESTED: STRACE(("ServerWindow %s received quit request\n", Title())); NotifyQuitRequested(); diff --git a/src/servers/app/ServerWindow.h b/src/servers/app/ServerWindow.h index 889e334d32..b8793f4824 100644 --- a/src/servers/app/ServerWindow.h +++ b/src/servers/app/ServerWindow.h @@ -14,7 +14,6 @@ #include "MessageLooper.h" -#include "SubWindowList.h" #include #include @@ -68,8 +67,6 @@ public: void NotifyQuitRequested(); void NotifyMinimize(bool minimize); void NotifyZoom(); - void NotifyScreenModeChanged(const BRect frame, - const color_space cspace); // util methods. const BMessenger& FocusMessenger() const { return fFocusMessenger; } @@ -103,9 +100,6 @@ public: void GetInfo(window_info& info); - // ToDo: public?? - SubWindowList fSubWindowList; - private: // methods for retrieving and creating a tree strcture of Layers. Layer* CreateLayerTree(BPrivate::LinkReceiver &link, Layer **_parent); diff --git a/src/servers/app/SubWindowList.h b/src/servers/app/SubWindowList.h index e02e3ba223..1f79c3206d 100644 --- a/src/servers/app/SubWindowList.h +++ b/src/servers/app/SubWindowList.h @@ -17,8 +17,8 @@ class WindowLayer; class SubWindowList : public BList { public: - SubWindowList(void); - virtual ~SubWindowList(void); + SubWindowList(); + virtual ~SubWindowList(); void AddWindowLayer(WindowLayer *windowLayer); diff --git a/src/servers/app/WindowLayer.cpp b/src/servers/app/WindowLayer.cpp index 727be207c7..908a44dc6d 100644 --- a/src/servers/app/WindowLayer.cpp +++ b/src/servers/app/WindowLayer.cpp @@ -117,6 +117,7 @@ WindowLayer::WindowLayer(const BRect &frame, if (window->App()->GetDesktop()->ScreenAt(0)) { window->App()->GetDesktop()->ScreenAt(0)->GetMode(width, height, colorSpace, frequency); // TODO: MOVE THIS AWAY!!! RemoveBy contains calls to virtual methods! Also, there is not TopLayer()! + fFrame.OffsetTo(B_ORIGIN); WindowLayer::ResizeBy(width - frame.Width(), height - frame.Height()); } } @@ -390,6 +391,8 @@ WindowLayer::GetSizeLimits(float* minWidth, float* maxWidth, void WindowLayer::MouseDown(BMessage *msg, BPoint where) { + Desktop* desktop = Window()->App()->GetDesktop(); + // default action is to drag the WindowLayer Layer *target = LayerAt(where); if (target == this) { @@ -449,19 +452,19 @@ WindowLayer::MouseDown(BMessage *msg, BPoint where) // based on what the Decorator returned, properly place this window. if (action == DEC_MOVETOBACK) { - GetRootLayer()->SetActive(this, false); + desktop->SendBehindWindow(this, NULL); } else { GetRootLayer()->SetMouseEventLayer(this); - GetRootLayer()->SetActive(this); + desktop->ActivateWindow(this); } } else if (target != NULL) { // clicking a simple Layer. - if (GetRootLayer()->ActiveWorkspace()->Focus() != this) { - DesktopSettings desktopSettings(GetRootLayer()->GetDesktop()); + if (GetRootLayer()->Focus() != this) { + DesktopSettings desktopSettings(desktop); // not in FFM mode? if (desktopSettings.MouseMode() == B_NORMAL_MOUSE) - GetRootLayer()->SetActive(this); + desktop->ActivateWindow(this); if ((WindowFlags() & B_WILL_ACCEPT_FIRST_CLICK) == 0) return; @@ -554,17 +557,11 @@ WindowLayer::MouseMoved(BMessage *msg, BPoint where) fLastMousePosition = where; // change focus in FFM mode - DesktopSettings desktopSettings(GetRootLayer()->GetDesktop()); - // TODO: Focus should be a RootLayer option/feature, NOT a Workspace one!!! - WindowLayer* exFocus = GetRootLayer()->Focus(); - if (desktopSettings.MouseMode() != B_NORMAL_MOUSE && exFocus != this) { - GetRootLayer()->ActiveWorkspace()->AttemptToSetFocus(this); - // Workspace::SetFocus() *attempts* to set a new focus WindowLayer, it may not succeed -// if (exFocus != Focus()) { - // TODO: invalidate border area and send message to client for the widgets to light up - // What message? Is there a message on Focus change? -// } - } + Desktop* desktop = Window()->App()->GetDesktop(); + DesktopSettings desktopSettings(desktop); + + if (desktopSettings.MouseMode() != B_NORMAL_MOUSE && GetRootLayer()->Focus() != this) + GetRootLayer()->SetFocus(this); Layer* target = LayerAt(where); if (target != NULL && target != this) { @@ -668,6 +665,16 @@ WindowLayer::UpdateScreen() } +bool +WindowLayer::SupportsFront() +{ + if (fFeel == kDesktopWindowFeel) + return false; + + return true; +} + + void WindowLayer::QuietlySetFeel(int32 feel) { diff --git a/src/servers/app/WindowLayer.h b/src/servers/app/WindowLayer.h index 1c1ad0f2d1..c6e565ee32 100644 --- a/src/servers/app/WindowLayer.h +++ b/src/servers/app/WindowLayer.h @@ -107,6 +107,10 @@ class WindowLayer : public Layer { inline int32 Level() const { return fLevel; } inline uint32 WindowFlags() const { return fWindowFlags; } inline uint32 Workspaces() const { return fWorkspaces; } + void SetWorkspaces(uint32 workspaces) + { fWorkspaces = workspaces; } + + bool SupportsFront(); // 0.0 -> left .... 1.0 -> right void SetTabLocation(float location); diff --git a/src/servers/app/Workspace.cpp b/src/servers/app/Workspace.cpp index 29ef795af8..0692856863 100644 --- a/src/servers/app/Workspace.cpp +++ b/src/servers/app/Workspace.cpp @@ -1,1794 +1,86 @@ -//------------------------------------------------------------------------------ -// Copyright (c) 2001-2005, Haiku, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. -// -// File Name: Workspace.cpp -// Author: Adi Oanca -// Description: Tracks windows inside one workspace -// -// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -// Notes: IMPORTANT WARNING -// This object does not use any locking mechanism. It is designed -// to be used by RootLayer class ONLY. DO NOT USE from elsewhere! -// -// Design Spec: -// The purpose of this class it to have visible windows appear in the -// correct order as defined by GUI guidelines. Those define 3 main type of windows: -// normal windows, modal and floating windows. Aditionally there must be support -// for another 2 types of windows which will be used in special cases. We're talking -// about system front windows which always will be the front-most and have focus, and -// system last windows which will always be behind all other kind of windows. -// -// Normal windows will always be in Workspace's list, be it they are hidden -// or not. They are added by hand (AddWindowLayer()) only. Same goes for system last -// windows, system first, modall all and floating all windows. Those remaining -// are: modal subset, modal app, floating subset and floating app. Those will be -// added and removed on-the-fly as they are needed. -// -// To keep correct track of modal subset/app and floating subset/app windows -// we need to have them in a list. Also, we want every normal window to -// maintain its floating windows order. For that we define a list for every normal -// window in which we'll add floating subset & app windows alongside with subset -// modals. Application modals go in a separate list which is hold for every -// application (ServerApp) object. For normal window's list: when a floating win -// is need (when normal window becomes front) it is always removed and automaticaly -// added to workspace's list. When that normal looses front state, it reinserts -// all floating windows it has used back into its list, thus saving the exact order -// of floating windows. Modal windows are never removed from normal or application's -// list, but they are automaticaly added and removed from workspace's list as needed. -// (ex: a modal app won't appear until a normal window from the same app is visible) -// -// Front status is a bit hard to explain. It's a state which helps keep -// the wanted order. For example, if a modal window is set to have front status, -// an automatic search is made to see if another modal was created after this -// one and thus needs to have front state (read: thus have to be in front this). -// Another use is to have floating windows pop up in front of a normal window when -// no modal exist to steal front state. -//------------------------------------------------------------------------------ +/* + * Copyright 2005, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ + + +#include "RootLayer.h" +#include "Workspace.h" +#include "WindowLayer.h" + #include #include -#include -#include -#include "Workspace.h" -#include "Layer.h" -#include "WindowLayer.h" -#include "ServerWindow.h" -#include "ServerApp.h" -#include "RGBColor.h" -#include "SubWindowList.h" -//#define DEBUG_WORKSPACE +static RGBColor kDefaultColor = RGBColor(51, 102, 152); -#ifdef DEBUG_WORKSPACE -# include -# define STRACE(x) printf x -#else -# define STRACE(x) ; -#endif -#ifdef DEBUG_WORKSPACE -# include -# define STRACESTREAM() PrintToStream() -#else -# define STRACESTREAM() ; -#endif +Workspace::Workspace() + : + fWindows(20) +{ + _SetDefaults(); +} + + +Workspace::~Workspace() +{ +} + void -Workspace::State::PrintToStream() +Workspace::SetWindows(const BObjectList& windows) { - printf("WS::State - Front: %s\n", Front? Front->Name(): "NULL"); - printf("WS::State - Focus: %s\n", Focus? Focus->Name(): "NULL"); - - for (int32 i = 0; i < WindowList.CountItems(); ++i) { - Layer *l = (Layer*)WindowList.ItemAt(i); - if (l) - printf("\t %ld - %s\n", i, l->Name()); - } -} - -//---------------------------------------------------------------------------------- -/*! - \brief Creates a new Workspace object which has its own resolution and background color. -*/ -Workspace::Workspace(const int32 ID, const uint32 colorspace, const RGBColor& BGColor) - : fBGColor(BGColor) -{ -STRACE(("New Workspace(%ld)\n", fID)); - fID = ID; - - fBottomItem = NULL; - fTopItem = NULL; - fFocusItem = NULL; - fFrontItem = NULL; - - memset(&fDisplayMode, 0, sizeof(fDisplayMode)); - fDisplayMode.space = colorspace; -} - -//---------------------------------------------------------------------------------- -/*! - \brief Frees internal data. -*/ -Workspace::~Workspace(void) -{ -STRACE(("~Workspace(%ld) - say bye bye\n", fID)); - fFocusItem = NULL; - fFrontItem = NULL; - - ListData *toast; - while(fBottomItem) - { - toast = fBottomItem; - fBottomItem = fBottomItem->upperItem; - - fPool.ReleaseMemory(toast); - } - fBottomItem = NULL; - fTopItem = NULL; -} - - -/*! - \brief Adds layer ptr to workspace's list of WindowLayers. -*/ -void -Workspace::AddWindowLayer(WindowLayer *winBorder) -{ -STRACE(("W(%ld)::AddWindowLayer(%s)\n", fID, winBorder?winBorder->Name():"NULL")); - if (winBorder->Level() == B_FLOATING_APP) { - // floating windows are automaticaly added when needed - // you cannot add one by hand. - return; - } - - if (HasItem(winBorder)) { - // NOTE: you may remove 'debugger' at Release Candidate time - debugger("WindowLayer ALREADY in Workspace's list\n"); - return; - } - - // allocate a new item - ListData* item = fPool.GetCleanMemory(winBorder); - - // place this winBorder in what seems the most appropriate location. - // Do not change front window - placeInFront(item, false); -} - - -/* - \brief Removes a WindowLayer from workspace's list. -*/ -void -Workspace::RemoveWindowLayer(WindowLayer *winBorder) -{ - STRACE(("W(%ld)::RemoveWindowLayer(%s)\n", fID, winBorder?winBorder->Name():"NULL")); - ListData* item = HasItem(winBorder); - - if (item) { - RemoveItem(item); - fPool.ReleaseMemory(item); - } + fWindows.MakeEmpty(); + fWindows.AddList((BObjectList *)&windows); } bool -Workspace::HasWindowLayer(const WindowLayer* winBorder) const +Workspace::AddWindow(WindowLayer* window) { - return HasItem(winBorder) ? true: false; -} - - -WindowLayer * -Workspace::Focus() const -{ - return fFocusItem ? fFocusItem->layerPtr : NULL; -} - - -WindowLayer * -Workspace::Front() const -{ - return fFrontItem ? fFrontItem->layerPtr: NULL; -} - - -WindowLayer * -Workspace::Active() const -{ - return fFocusItem ? fFocusItem->layerPtr : NULL; -} - - -/*! - \brief Method that returns the state of window manager. - \param state - a pointer to a valid Workspace::State structure - \return void - - Fills the state structure with the most important window manager attibutes: - front window, focus window, active window and the list of windows starting from - the backmost one at position 0 and ending with the most visible window. -*/ -void -Workspace::GetState(Workspace::State *state) const -{ - state->Front = Front(); - state->Focus = Focus(); - - ListData *cursor = fTopItem; - while (cursor) { - if (!cursor->layerPtr->IsHidden()) - state->WindowList.AddItem(cursor->layerPtr); - cursor = cursor->lowerItem; - } -} - - -bool -Workspace::AttemptToSetFront(WindowLayer *newFront) -{ - return MoveToFront(newFront); -} - - -int32 -Workspace::AttemptToSetFocus(WindowLayer *newFocus) -{ - ListData* newFocusItem = HasItem(newFocus); - - return _SetFocus(newFocusItem); -} - -bool -Workspace::AttemptToMoveToBack(WindowLayer *newBack) -{ - return MoveToBack(newBack); -} - -bool -Workspace::AttemptToActivate(WindowLayer *toActivate) -{ - MoveToFront(toActivate); - AttemptToSetFocus(toActivate); - return Active() == toActivate; -} -/* - \brief This method provides you the list of visible windows in this workspace. - \param list The list of visible WindowLayers found in this workspace. - \param itemCount Number of WindowLayer pointers found in the list. -*/ -bool -Workspace::GetWindowLayerList(void **list, int32 *itemCount ) const -{ - int32 count = 0; - ListData* cursor; - - cursor = fBottomItem; - while (cursor) { - if (!cursor->layerPtr->IsHidden()) - count++; - cursor = cursor->upperItem; - } - - if (*itemCount < count) { - // buffer not big enough. buffer must be count high - *itemCount = count; - return false; - } - - if (list) { - *itemCount = count; - - cursor = fBottomItem; - while (cursor) { - if (!cursor->layerPtr->IsHidden()) { - *list = cursor->layerPtr; - list++; - } - cursor = cursor->upperItem; - } - } - - return true; -} - -/*! - \brief Makes the specified WindowLayer the focus one. - \param newFocus WindowLayer which will try to take focus state. - \return 0 - setting focus failed, focus did not change. - 1 - the new focus WindowLayer is \a winBorder - 2 - focus changed but not to \a winBorder because in front of it there - are other modal windows. - - Set a new focus WindowLayer if possible. -*/ - -int32 -Workspace::_SetFocus(ListData *newFocusItem) -{ - if (!newFocusItem || newFocusItem == fFocusItem - || (newFocusItem && !newFocusItem->layerPtr->IsHidden() - && newFocusItem->layerPtr->WindowFlags() & B_AVOID_FOCUS)) - return 0L; - - WindowLayer *newFocus = newFocusItem->layerPtr; - bool rv = 1; - - switch(newFocus->Level()) { - case B_MODAL_APP: - case B_NORMAL: { - ListData *item = newFocusItem->upperItem; - while ( item && - !item->layerPtr->IsHidden() && - ((item->layerPtr->Level() == B_MODAL_APP && - item->layerPtr->App()->ClientTeam() == newFocus->App()->ClientTeam()) || - item->layerPtr->Level() >= B_MODAL_ALL)) - { - if (item->layerPtr->WindowFlags() & B_AVOID_FOCUS) - newFocusItem = NULL; - else - newFocusItem = item; - rv = 2; - } - } - break; - - case B_SYSTEM_FIRST: - case B_MODAL_ALL: { - ListData *item = newFocusItem->upperItem; - while ( item && - !item->layerPtr->IsHidden() && - item->layerPtr->Level() >= newFocus->Level()) - { - if (item->layerPtr->WindowFlags() & B_AVOID_FOCUS) - newFocusItem = NULL; - else - newFocusItem = item; - rv = 2; - } - } - break; - - default: - break; - } - - fFocusItem = newFocusItem; - - return rv; -} - -/*! - \brief Makes the specified WindowLayer the front one. - \param newFront WindowLayer which will try to take front state. - \param doNotDisturb In case user is busy typing something, don't bring \a newFront - in front stealing front&focus, but place imediately after. - \return True if the list of WindowLayers has changed, false otherwise. - - This method tries to make \a newFront the new front WindowLayer. "It tries" because - if this a B_NORMAL window with subset or application modals those will be displayed - in front and get the front state. If no subset or application modals exist, then this - B_NORMAL window will get front (and focus) state and subset and application floating - window will be shown in front. - Note that floating windows cannot get/have front state. -*/ -bool -Workspace::MoveToFront(WindowLayer *newFront, bool doNotDisturb) -{ - STRACE(("\nWks(%ld)::MoveToFront ~%s~ \n", fID, newFront?newFront->Name():"NULL")); - if (!newFront) - return false; - - if (newFront->IsHidden() || newFront->Level() == B_SYSTEM_LAST) - return false; - - if (fFrontItem && newFront == fFrontItem->layerPtr) { - // we didn't change windows order - return false; - } - - return ShowWindowLayer(newFront); -} - - -/*! - \brief Moves the specified WindowLayer in the back as it is possible. - \param newLast WindowLayer which will be placed in the back. - \return True if the list of WindowLayers has changed, false otherwise. - - WindowLayer \a newLast will go in the back as much as possible. Note that this - action is tricky. While normal windows will always go into the back, front modal windows - won't go into the back if the next front window will be a B_NORMAL or B_MODAL_APP part - of the same team which was previously created. If it were possible it would - undermine the role of modal windows in the system. Another example regards B_FLOATING_APP - windows. These will ge in the back as possible, but never farther than the front - B_NORMAL window in front of which they appear. -*/ -bool -Workspace::MoveToBack(WindowLayer *newLast) -{ - STRACE(("Wks(%ld)::MoveToBack(%s) \n", fID, newLast? newLast->Name(): "NULL")); - if (newLast->IsHidden()) - return false; - - ListData *newLastItem; - newLastItem = HasItem(newLast); - if (!newLastItem) - return false; - - ListData *previous = newLastItem->upperItem; - bool returnValue = false; - bool changeFront = false; - int32 level = newLast->Level(); - if (level > B_SYSTEM_FIRST) - level = B_SYSTEM_FIRST; - - if (fFrontItem && fFrontItem == newLastItem) - changeFront = true; - - switch(newLast->Level()) - { - case B_MODAL_ALL: - case B_SYSTEM_FIRST: - case B_SYSTEM_LAST: - { - // these kind of windows do not change position - return false; - } - break; - case B_NORMAL: - { - ListData *cursor = newLastItem->upperItem; - - // we are already the back-most window. - if (!cursor || cursor->layerPtr->Level() == B_SYSTEM_LAST ) - return false; - - if (changeFront) - saveFloatingWindows(fFrontItem); - } - // NOTE: no 'break;' here... - case B_FLOATING_APP: - case B_FLOATING_ALL: - { - returnValue = placeToBack(newLastItem); - } - break; - case B_MODAL_APP: - { - ListData *cursor = newLastItem->upperItem; - - // we are already the back-most window. - if (!cursor || cursor->layerPtr->Level() == B_SYSTEM_LAST ) - return false; - - // this is a modal app - if (newLast->App()->fAppSubWindowList.HasItem(newLast)) { - ListData* before; - - // remove now to properly place later - RemoveItem(newLastItem); - - while (cursor) { - if (!cursor->layerPtr->IsHidden() - && cursor->layerPtr->Level() > B_SYSTEM_LAST - && cursor->layerPtr->App()->ClientTeam() == newLast->App()->ClientTeam()) - break; - - cursor = cursor->upperItem; - } - - if (cursor) - before = cursor->lowerItem; - else - before = fTopItem; - - InsertItem(newLastItem, before); - } else { - // this is a modal subset - // this subset modal is visible, it means its main window must be visible. search for it. - ListData *mainWindowItem, *before; - int32 indexThis = 0, indexCursor; - - // search by going deep - while (cursor) { - if (cursor->layerPtr->Level() == B_NORMAL && !cursor->layerPtr->IsHidden() - && (indexThis = cursor->layerPtr->fSubWindowList.IndexOf(newLast)) >= 0) - break; - cursor = cursor->upperItem; - } - - if (!cursor) - debugger("MoveToBack: SubsetWindow: can't find main Window!\n"); - - RemoveItem(newLastItem); - - // good. found our main window. now go up and properly place. - mainWindowItem = cursor; - before = cursor->lowerItem; - - cursor = cursor->lowerItem; - while (cursor) { - if (cursor->layerPtr->Level() == B_MODAL_APP && !cursor->layerPtr->IsHidden() - && cursor->layerPtr->App()->ClientTeam() == newLast->App()->ClientTeam()) - { - indexCursor = mainWindowItem->layerPtr->fSubWindowList.IndexOf(cursor->layerPtr); - if (indexCursor >= 0) - { - if (indexThis < indexCursor) - { - before = cursor; - break; - } - else - { - before = cursor->lowerItem; - } - } - } - cursor = cursor->lowerItem; - } - - InsertItem(newLastItem, before); - } - returnValue = true; - } - break; - default: - { - debugger("MoveToBack: unknown window feel\n"); - return false; - } - } - - if (previous == newLastItem->upperItem) - returnValue = false; - - // The following applies ONLY to B_NORMAL and B_MODAL_APP windows. - - if (changeFront) - { - ListData *newFront; - newFront = findNextFront(); - if (newFront) - returnValue |= MoveToFront(newFront->layerPtr); - else - debugger("MoveToBack: can't find new front! We should find one!\n"); - } - - return returnValue; -} - - -/*! - \brief Hides a WindowLayer. - \param winBorder WindowLayer to be hidden. - \return True if the list of WindowLayers has changed, false otherwise. - - WindowLayer \a winBorder will be hidden. Some, like floating or subset modals - may also be removed from Workspace's list. - If \a winBorder if the front WindowLayer, another one (or none) will be automaticaly - chosen. Same goes for focus. -*/ -bool -Workspace::HideWindowLayer(WindowLayer *winBorder) -{ - STRACE(("W(%ld)::HideWindowLayer(%s) \n", fID, winBorder? winBorder->Name(): "NULL")); - bool returnValue = false; - int32 level = winBorder->Level(); - bool changeFront = false; - bool changeFocus = false; - ListData* nextFocus = NULL; - - if (fFrontItem && fFrontItem->layerPtr == winBorder) - changeFront = true; - - if (fFocusItem && fFocusItem->layerPtr == winBorder) { - changeFocus = true; - nextFocus = fFocusItem->lowerItem; - } - - if (level > B_SYSTEM_FIRST) - level = B_SYSTEM_FIRST; - - switch (level) { - case B_MODAL_ALL: - case B_SYSTEM_FIRST: - case B_SYSTEM_LAST: - case B_FLOATING_ALL: - // window is just hidden. do nothing. its position is OK as it is now. - returnValue = true; - break; - - case B_FLOATING_APP: - if (fFrontItem && fFrontItem->layerPtr->Level() == B_NORMAL) { - ListData* item = HasItem(winBorder); - if (item) { - fFrontItem->layerPtr->fSubWindowList.AddWindowLayer(winBorder); - - RemoveItem(item); - fPool.ReleaseMemory(item); - - returnValue = true; - } - } - break; - - case B_NORMAL: - { - if (fFrontItem && fFrontItem->layerPtr == winBorder) - saveFloatingWindows(fFrontItem); - - // remove B_MODAL_SUBSET windows present before this window. - ListData* itemThis = HasItem(winBorder); - ListData* toast; - ListData* item = itemThis->lowerItem; - while (item) { - // if this modal subset is in our list ONLY (not in other visible normal window's one), - // then remove from Workspace's list. - if (item->layerPtr->Level() == B_MODAL_APP) { - if (winBorder->fSubWindowList.HasItem(item->layerPtr)) { - if (!searchFirstMainWindow(item->layerPtr)) { - // if this modal subset has front state, make sure another window will get that status. - if (fFrontItem == item) - changeFront = true; - - toast = item; - item = item->lowerItem; - RemoveItem(toast); - fPool.ReleaseMemory(toast); - } - } else if (!searchANormalWindow(item->layerPtr) - && !(item->layerPtr->Workspaces() & (0x00000001 << fID))) { - // if this modal subset has front state, make sure another window will get that status. - if (fFrontItem == item) - changeFront = true; - - toast = item; - item = item->lowerItem; - RemoveItem(toast); - fPool.ReleaseMemory(toast); - } else - item = item->lowerItem; - } else - item = item->lowerItem; - } - - returnValue = true; - break; - } - - case B_MODAL_APP: - { - // if a subset modal, then remove from Workspace's list. - if (winBorder->App()->fAppSubWindowList.HasItem(winBorder)) { - ListData* toast = HasItem(winBorder); - if (toast) { - RemoveItem(toast); - fPool.ReleaseMemory(toast); - - returnValue = true; - } - } - break; - } - - default: - debugger("HideWindowLayer: what kind of window is this?\n"); - } - - // select a new Front if needed - if (changeFront) { - fFrontItem = NULL; - - ListData* newFront = findNextFront(); - if (newFront) - MoveToFront(newFront->layerPtr); - } - - if (!HasItem(fFocusItem)) - fFocusItem = NULL; - - // floating windows can have focus state. what if this removed window is - // the focus window? There will be no focus anymore. - // So, start a search to set the new focus - if (!fFocusItem || changeFocus) { - if (!HasItem(nextFocus)) - nextFocus = NULL; - - if (nextFocus == NULL) { - nextFocus = fBottomItem; - - while (nextFocus) { - if (!nextFocus->layerPtr->IsHidden() - && !(nextFocus->layerPtr->WindowFlags() & B_AVOID_FOCUS)) - break; - else - nextFocus = nextFocus->upperItem; - } - } - - fFocusItem = nextFocus; - } - - return returnValue; -} - -/*! - \brief Shows a WindowLayer. - \param winBorder WindowLayer to be show. - \return True if the list of WindowLayers has changed, false otherwise. - - WindowLayer \a winBorder will be shown. Other windows like floating or modal - ones will be placed in front if needed. Front & Focus state will be given to \a winBorder - unless a modal windows steals both. -*/ -bool -Workspace::ShowWindowLayer(WindowLayer *winBorder, bool userBusy) -{ - STRACE(("W(%ld)::ShowWindowLayer(%s) \n", fID, winBorder? winBorder->Name(): "NULL")); - bool returnValue = false; - int32 level = winBorder->Level(); - if (level > B_SYSTEM_FIRST) - level = B_SYSTEM_FIRST; - - // Before you go understand this method, please note that 'placeInFront' MUST be - // called of EVERY window except B_FLOATING_APP when - // ADDING a new window to Workspace's list!!! - - switch (level) { - // B_MODAL_ALL, B_FLOATNG_ALL, B_SYSTEM_FIRST & B_SYSTEM_LAST - // will be removed ONLY when are deleted! - // ALSO, they will ALWAYS be the first/last windows in hierarchy, no matter - // if they are hidden or not - they keep their order. - - case B_MODAL_ALL: - case B_SYSTEM_FIRST: - case B_SYSTEM_LAST: - { - // nothing special to be done. just compare indexes to see if front state will change. - if (fFrontItem) { - int32 reverseIndexThis, reverseIndexFront; - ListData* itemThis = HasItem(winBorder, &reverseIndexThis); - - HasItem(fFrontItem->layerPtr, &reverseIndexFront); - - if (reverseIndexThis < reverseIndexFront) { - if (fFrontItem->layerPtr->Level() == B_NORMAL) - saveFloatingWindows(fFrontItem); - - fFrontItem = itemThis; - } - } else { - // of course, if there is no front item, then set this one. - fFrontItem = HasItem(winBorder); - } - returnValue = true; - break; - } - - case B_FLOATING_ALL: - { - // simply relocate. A floating window can't have front state. - ListData* itemThis = HasItem(winBorder); - RemoveItem(itemThis); - placeInFront(itemThis, userBusy); - - returnValue = true; - break; - } - - // FLOATING windows are always removed from Workspace's list when changing to a new front window. - - case B_FLOATING_APP: - { - // see if we have a front window which is a B_NORMAL window and who's list of floating - // and modal windows contains our window. - if (fFrontItem && fFrontItem->layerPtr->Level() == B_NORMAL) { - // if this winBorder is the focus it is already the first among floating app windows. - if (fFocusItem && fFocusItem->layerPtr == winBorder) - break; - - ListData* itemThis = NULL; - // remove from B_NORMAL's list. - if (fFrontItem->layerPtr->fSubWindowList.RemoveItem(winBorder)) { - // we need to add this window - itemThis = fPool.GetCleanMemory(winBorder); - } else { - itemThis = HasItem(winBorder); - // window is already in Workspace's list. Find and temporarly remove. - if (itemThis) - RemoveItem(itemThis); - } - - if (itemThis) { - // insert in front of other B_FLOATING_APP windows. - ListData* item = fFrontItem->lowerItem; - while (item && item->layerPtr->Level() == B_FLOATING_APP) - item = item->lowerItem; - - InsertItem(itemThis, item); - - returnValue = true; - } - } - break; - } - - case B_NORMAL: - { - ListData* itemThis = HasItem(winBorder); - - if (!itemThis) { - debugger("ShowWindowLayer: B_NORMAL window - cannot find specified window in workspace's list\n"); - return false; - } - - // front status will change. if a normal window has front state, - // remove and save floating windows order that may be above it. - if (fFrontItem && fFrontItem->layerPtr->Level() == B_NORMAL) - saveFloatingWindows(fFrontItem); - - RemoveItem(itemThis); - - placeInFront(itemThis, userBusy); - - ListData* newFront = itemThis; - - if (windowHasVisibleModals(winBorder)) - newFront = putModalsInFront(itemThis); - - if (fFrontItem) { - if (!userBusy) { - int32 revFrontItemIndex, revNewFrontIndex; - - HasItem(fFrontItem, &revFrontItemIndex); - HasItem(newFront, &revNewFrontIndex); - if (revNewFrontIndex < revFrontItemIndex) - fFrontItem = newFront; - } - } else { - fFrontItem = newFront; - } - - if (fFrontItem->layerPtr->Level() == B_NORMAL) - putFloatingInFront(fFrontItem); - - returnValue = true; - break; - } - - // MODAL windows usualy stay in Workspace's list, but they are scatered, so we must gather them - // when needed. - - case B_MODAL_APP: - { - // build a list of modal windows to know what windows should be placed before this one. - BList tempList; - - // APP modal - if (winBorder->App()->fAppSubWindowList.HasItem(winBorder)) { - // take only application's modals - tempList.AddList(&winBorder->App()->fAppSubWindowList); - if (fFrontItem - && fFrontItem->layerPtr->App()->ClientTeam() == winBorder->App()->ClientTeam()) - userBusy = false; - } else { - // SUBSET modal - WindowLayer *mainWindow = searchFirstMainWindow(winBorder); - if (mainWindow) { - // add both mainWindow's subset modals and application's modals - tempList.AddList(&mainWindow->fSubWindowList); - tempList.AddList(&winBorder->App()->fAppSubWindowList); - if (fFrontItem && fFrontItem->layerPtr == mainWindow) - userBusy = false; - } else { - // none of the unhiden normal windows havs this window as part of its subset. - // as a result this window won't be added to Workspace's list for it to be shown. - return false; - } - } - - // === list ready === - - // front status will change. if a normal window has front state, - // remove and save floating windows order that may be above it. - if (fFrontItem && fFrontItem->layerPtr->Level() == B_NORMAL) - saveFloatingWindows(fFrontItem); - - // find and remove the Workspace's entry for this WindowLayer. - ListData *itemThis; - itemThis = HasItem(winBorder); - if (itemThis) { - RemoveItem(itemThis); - } else { - // not found? no problem. create a new entry. - itemThis = fPool.GetCleanMemory(winBorder); - } - - placeInFront(itemThis, userBusy); - - // now place other modals windows above - int32 revIndexThis, revIndexItem; - ListData *newFront = itemThis; - - // find the index of this window in Workspace's list. It will be used to place higher - // indexed windows above, if it's the case. - HasItem(itemThis, &revIndexThis); - - { - ListData* before = itemThis->lowerItem; - int32 i, count; - WindowLayer** wbList; - ListData* itemX; - int32 indexThisInTempList; - - indexThisInTempList = tempList.IndexOf(winBorder); - if (indexThisInTempList < 0) - debugger("ShowWindowLayer: modal window: design flaw!!!\n"); - - count = tempList.CountItems(); - wbList = (WindowLayer**)tempList.Items(); - for (i = indexThisInTempList; i < count; i++) { - if (!wbList[i]->IsHidden()) { - itemX = HasItem(wbList[i], &revIndexItem); - if (itemX && revIndexItem > revIndexThis) { - removeAndPlaceBefore(itemX, before); - newFront = itemX; - } - } - } - } - - if (fFrontItem) { - if (!userBusy) { - int32 revFrontItemIndex, revNewFrontIndex; - - HasItem(fFrontItem, &revFrontItemIndex); - HasItem(newFront, &revNewFrontIndex); - if (revNewFrontIndex < revFrontItemIndex) - fFrontItem = newFront; - } - - if (fFrontItem->layerPtr->Level() == B_NORMAL) - putFloatingInFront(fFrontItem); - } else { - fFrontItem = newFront; - } - - returnValue = true; - break; - } - - default: - debugger("What kind of window is this???\n"); - } - - if (!HasItem(fFocusItem)) - fFocusItem = NULL; - - // set new Focus if needed - if (Focus() == NULL) { - ListData* cursor = fBottomItem; - - fFocusItem = NULL; - while (cursor != NULL && fFocusItem == NULL) { - if (!cursor->layerPtr->IsHidden() - && !(cursor->layerPtr->WindowFlags() & B_AVOID_FOCUS)) { - if (cursor->layerPtr->Level() == B_FLOATING_APP - || cursor->layerPtr->Level() == B_FLOATING_ALL) { - // set focus to floating windows only if directly targeted - if (cursor->layerPtr == winBorder) { - fFocusItem = cursor; - } else - cursor = cursor->upperItem; - } else - fFocusItem = cursor; - } else - cursor = cursor->upperItem; - } - } - - return returnValue; -} - - -status_t -Workspace::SetDisplayMode(const display_mode &mode) -{ - fDisplayMode = mode; - return B_OK; -} - - -status_t -Workspace::GetDisplayMode(display_mode &mode) const -{ - mode = fDisplayMode; - return B_OK; + return fWindows.AddItem(window); } void -Workspace::SetBGColor(const RGBColor &c) +Workspace::RemoveWindow(WindowLayer* window) { - fBGColor = c; -} - - -RGBColor -Workspace::BGColor(void) const -{ - return fBGColor; -} - - -/*! - \brief Retrieves settings from a container message passed to PutSettings - \param A BMessage containing data from a PutSettings() call - - This function will place default values whenever a particular setting cannot - be found. -*/ -void -Workspace::GetSettings(const BMessage &msg) -{ - BMessage container; - rgb_color *color; - ssize_t size; - - char fieldname[4]; - sprintf(fieldname,"%d",(uint8)fID); - - // First, find the container message corresponding to the workspace's index - if(msg.FindMessage(fieldname,&container)!=B_OK) - { - GetDefaultSettings(); - return; - } - - if(container.FindInt32("timing_pixel_clock",(int32*)&fDisplayMode.timing.pixel_clock) != B_OK) - fDisplayMode.timing.pixel_clock=25175; - if(container.FindInt16("timing_h_display",(int16*)&fDisplayMode.timing.h_display)!=B_OK) - fDisplayMode.timing.h_display=640; - if(container.FindInt16("timing_h_sync_start",(int16*)&fDisplayMode.timing.h_sync_start)!=B_OK) - fDisplayMode.timing.h_sync_start=656; - if(container.FindInt16("timing_h_sync_end",(int16*)&fDisplayMode.timing.h_sync_end)!=B_OK) - fDisplayMode.timing.h_sync_end=752; - if(container.FindInt16("timing_h_total",(int16*)&fDisplayMode.timing.h_total)!=B_OK) - fDisplayMode.timing.h_total=800; - if(container.FindInt16("timing_v_display",(int16*)&fDisplayMode.timing.v_display)!=B_OK) - fDisplayMode.timing.v_display=480; - if(container.FindInt16("timing_v_sync_start",(int16*)&fDisplayMode.timing.v_sync_start)!=B_OK) - fDisplayMode.timing.v_sync_start=490; - if(container.FindInt16("timing_v_sync_end",(int16*)&fDisplayMode.timing.v_sync_end)!=B_OK) - fDisplayMode.timing.v_sync_end=492; - if(container.FindInt16("timing_v_total",(int16*)&fDisplayMode.timing.v_total)!=B_OK) - fDisplayMode.timing.v_total=525; - if(container.FindInt32("timing_flags",(int32*)&fDisplayMode.timing.flags)!=B_OK) - fDisplayMode.timing.flags=0; - - if(container.FindInt32("color_space", (int32*)&fDisplayMode.space) != B_OK) - fDisplayMode.space = B_CMAP8; - - if(container.FindData("bgcolor",B_RGB_COLOR_TYPE,(const void **)&color,&size)==B_OK) - fBGColor.SetColor(*color); - else - fBGColor.SetColor(0,0,0); - - if(container.FindInt16("virtual_width", (int16 *)&fDisplayMode.virtual_width) != B_OK) - fDisplayMode.virtual_width = 640; - if(container.FindInt16("virtual_height", (int16 *)&fDisplayMode.virtual_height) != B_OK) - fDisplayMode.virtual_height = 480; -} - -//---------------------------------------------------------------------------------- -//! Sets workspace settings to defaults -void Workspace::GetDefaultSettings(void) -{ - fBGColor.SetColor(0,0,0); - - fDisplayMode.timing.pixel_clock = 25175; - fDisplayMode.timing.h_display = 640; - fDisplayMode.timing.h_sync_start = 656; - fDisplayMode.timing.h_sync_end = 752; - fDisplayMode.timing.h_total = 800; - fDisplayMode.timing.v_display = 480; - fDisplayMode.timing.v_sync_start = 490; - fDisplayMode.timing.v_sync_end = 492; - fDisplayMode.timing.v_total = 525; - fDisplayMode.timing.flags = 0; - fDisplayMode.space = B_CMAP8; - - fDisplayMode.virtual_width = 640; - fDisplayMode.virtual_height = 480; -} - -//---------------------------------------------------------------------------------- -/*! - \brief Places the screen settings for the workspace in the passed BMessage - \param msg BMessage pointer to receive the settings - \param index The index number of the workspace in the desktop - - This function will fail if passed a NULL pointer. The settings for the workspace are - saved in a BMessage in a BMessage. - - The message itself is placed in a field string based on its index - "1", "2", etc. - - The format is as follows: - display_timing "timing_XXX" -> fDisplayTiming members (see Accelerant.h) - uint32 "color_space" -> color space of the workspace - rgb_color "bgcolor" -> background color of the workspace - int16 "virtual_width" -> virtual width of the workspace - int16 "virtual_height" -> virtual height of the workspace -*/ -void Workspace::PutSettings(BMessage *msg, const uint8 &index) const -{ - if(!msg) - return; - - BMessage container; - rgb_color color=fBGColor.GetColor32(); - - // a little longer than we need in case someone tries to pass index=255 or something - char fieldname[4]; - - container.AddInt32("timing_pixel_clock",fDisplayMode.timing.pixel_clock); - container.AddInt16("timing_h_display",fDisplayMode.timing.h_display); - container.AddInt16("timing_h_sync_start",fDisplayMode.timing.h_sync_start); - container.AddInt16("timing_h_sync_end",fDisplayMode.timing.h_sync_end); - container.AddInt16("timing_h_total",fDisplayMode.timing.h_total); - container.AddInt16("timing_v_display",fDisplayMode.timing.v_display); - container.AddInt16("timing_v_sync_start",fDisplayMode.timing.v_sync_start); - container.AddInt16("timing_v_sync_end",fDisplayMode.timing.v_sync_end); - container.AddInt16("timing_v_total",fDisplayMode.timing.v_total); - container.AddInt32("timing_flags",fDisplayMode.timing.flags); - - container.AddInt32("color_space", fDisplayMode.space); - container.AddData("bgcolor", B_RGB_COLOR_TYPE, &color, sizeof(rgb_color)); - - container.AddInt16("virtual_width", fDisplayMode.virtual_width); - container.AddInt16("virtual_height", fDisplayMode.virtual_height); - - sprintf(fieldname,"%d",index); - - // Just in case... - msg->RemoveName(fieldname); - - msg->AddMessage(fieldname,&container); -} - -//---------------------------------------------------------------------------------- -/*! - \brief Places default settings for the workspace in the passed BMessage - \param msg BMessage pointer to receive the settings - \param index The index number of the workspace in the desktop -*/ -void Workspace::PutDefaultSettings(BMessage *msg, const uint8 &index) -{ - if(!msg) - return; - - BMessage container; - rgb_color color={ 0,0,0,255 }; - - // a little longer than we need in case someone tries to pass index=255 or something - char fieldname[4]; - - // These default settings the same ones as found in ~/config/settings/ - // app_server_settings on R5 - - container.AddInt32("timing_pixel_clock",25175); - container.AddInt16("timing_h_display",640); - container.AddInt16("timing_h_sync_start",656); - container.AddInt16("timing_h_sync_end",752); - container.AddInt16("timing_h_total",800); - container.AddInt16("timing_v_display",480); - container.AddInt16("timing_v_sync_start",490); - container.AddInt16("timing_v_sync_end",492); - container.AddInt16("timing_v_total",525); - container.AddInt32("timing_flags",0); - - container.AddInt32("color_space",B_CMAP8); - container.AddData("bgcolor",B_RGB_COLOR_TYPE,&color,sizeof(rgb_color)); - - container.AddInt16("virtual_width",640); - container.AddInt16("virtual_height",480); - - sprintf(fieldname,"%d",index); - - // Just in case... - msg->RemoveName(fieldname); - - msg->AddMessage(fieldname, &container); -} - -//---------------------------------------------------------------------------------- -// Debug method - -void -Workspace::PrintToStream() const -{ - printf("Workspace %ld hierarchy shown from back to front:\n", fID); - for (ListData *item = fTopItem; item != NULL; item = item->lowerItem) - { - WindowLayer *wb = (WindowLayer*)item->layerPtr; - printf("\tName: %s\t%s", wb->Name(), wb->IsHidden()?"Hidden\t": "Visible\t"); - if(wb->Feel() == B_FLOATING_SUBSET_WINDOW_FEEL) - printf("\t%s\n", "B_FLOATING_SUBSET_WINDOW_FEEL"); - if(wb->Feel() == B_FLOATING_APP_WINDOW_FEEL) - printf("\t%s\n", "B_FLOATING_APP_WINDOW_FEEL"); - if(wb->Feel() == B_FLOATING_ALL_WINDOW_FEEL) - printf("\t%s\n", "B_FLOATING_ALL_WINDOW_FEEL"); - if(wb->Feel() == B_MODAL_SUBSET_WINDOW_FEEL) - printf("\t%s\n", "B_MODAL_SUBSET_WINDOW_FEEL"); - if(wb->Feel() == B_MODAL_APP_WINDOW_FEEL) - printf("\t%s\n", "B_MODAL_APP_WINDOW_FEEL"); - if(wb->Feel() == B_MODAL_ALL_WINDOW_FEEL) - printf("\t%s\n", "B_MODAL_ALL_WINDOW_FEEL"); - if(wb->Feel() == B_NORMAL_WINDOW_FEEL) - printf("\t%s\n", "B_NORMAL_WINDOW_FEEL"); - if(wb->Feel() == B_SYSTEM_LAST) - printf("\t%s\n", "B_SYSTEM_LAST"); - if(wb->Feel() >= B_SYSTEM_FIRST) - printf("\t%s\n", "B_SYSTEM_FIRST"); - - } - printf("Focus Layer:\t%s\n", fFocusItem? fFocusItem->layerPtr->Name(): "NULL"); - printf("Front Layer:\t%s\n\n", fFrontItem? fFrontItem->layerPtr->Name(): "NULL"); + fWindows.RemoveItem(window); } void -Workspace::PrintItem(ListData *item) const +Workspace::SetDisplaysFromDesktop(Desktop* desktop) { - printf("ListData members:\n"); - if(item) - { - printf("WindowLayer:\t%s\n", item->layerPtr? item->layerPtr->Name(): "NULL"); - printf("UpperItem:\t%s\n", item->upperItem? item->upperItem->layerPtr->Name(): "NULL"); - printf("LowerItem:\t%s\n", item->lowerItem? item->lowerItem->layerPtr->Name(): "NULL"); - } - else - { - printf("NULL item\n"); - } -} - -//---------------------------------------------------------------------------------- -// PRIVATE -//---------------------------------------------------------------------------------- -/* - Insert item in the top-bottom direction. -*/ -void -Workspace::InsertItem(ListData *item, ListData *before) -{ - // insert before one other item; - if (before) { - if (before->upperItem) - before->upperItem->lowerItem = item; - - item->upperItem = before->upperItem; - item->lowerItem = before; - before->upperItem = item; - - if (fTopItem == before) - fTopItem = item; - } else { - // insert item at the end. - item->upperItem = fBottomItem; - if (fBottomItem) - fBottomItem->lowerItem = item; - - fBottomItem = item; - - if (!fTopItem) - fTopItem = item; - } } void -Workspace::RemoveItem(ListData *item) +Workspace::SetColor(const RGBColor& color) { - if (!item) - return; - - if (fBottomItem == item) - fBottomItem = item->upperItem; - else - item->lowerItem->upperItem = item->upperItem; - - if (fTopItem == item) - fTopItem = item->lowerItem; - else - item->upperItem->lowerItem = item->lowerItem; - - // set all these to NULL to avoid confusion later. - - item->upperItem = NULL; - item->lowerItem = NULL; - - if (fFocusItem == item) - fFocusItem = NULL; - - if (fFrontItem == item) - fFrontItem = NULL; -} - - -ListData* -Workspace::HasItem(const ListData *item, int32 *index) const -{ - int32 idx = 0; - ListData* itemX; - - for (itemX = fBottomItem; itemX != NULL; itemX = itemX->upperItem) { - if (item == itemX) - break; - - idx++; - } - - if (index && itemX) - *index = idx; - - return itemX; -} - - -ListData* -Workspace::HasItem(const WindowLayer *layer, int32 *index) const -{ - int32 idx = 0; - ListData* itemX; - - for (itemX = fBottomItem; itemX != NULL; itemX = itemX->upperItem) { - if (layer == itemX->layerPtr) - break; - - idx++; - } - - if (index && itemX) - *index = idx; - - return itemX; -} - - -/*! - \brief Returns the index of the specified item starting from the back-most window. -*/ -int32 -Workspace::IndexOf(const ListData *item) const -{ - if (!item) - return -1; - - int32 index = 0; - for (ListData *itemX = fTopItem; itemX != NULL; itemX = itemX->lowerItem) { - if (itemX->layerPtr == item->layerPtr) - return index; - index++; - } - return -1; -} - - -inline bool -Workspace::placeToBack(ListData *newLast) -{ - int32 level = newLast->layerPtr->Level(); - ListData* cursor = newLast->upperItem; - - switch (level) { - case B_FLOATING_ALL: - case B_FLOATING_APP: - { - int32 count = 0; - while (cursor && cursor->layerPtr->Level() == level) { - if (!cursor->layerPtr->IsHidden()) - count++; - cursor = cursor->upperItem; - } - - // we're already the last floating window - if (count == 0) - return false; - else { - bool changeFocus = false; - - if (fFocusItem == newLast) - changeFocus = true; - - if (changeFocus) { - ListData* cursor = newLast->upperItem; - while (cursor - && (cursor->layerPtr->IsHidden() - || cursor->layerPtr->WindowFlags() & B_AVOID_FOCUS) - && cursor->layerPtr->Level() == level) { - cursor = cursor->upperItem; - } - - // give focus only if a unhidden floating window could be selected - // otherwise this('newLast') window keeps focus - if (cursor->layerPtr->Level() == level) - fFocusItem = cursor; - } - - RemoveItem(newLast); - InsertItem(newLast, cursor ? cursor->lowerItem : fTopItem); - - return true; - } - break; - } - - case B_NORMAL: - { - int32 count = 0; - int32 cursorLevel; - while (cursor) { - cursorLevel = cursor->layerPtr->Level(); - if (cursorLevel == B_MODAL_APP) - cursorLevel = B_NORMAL; - - if (cursorLevel < level) { - break; - } else { - count++; - cursor = cursor->upperItem; - } - } - - // we're already the last normal window - if (count == 0) - return false; - else { - RemoveItem(newLast); - InsertItem(newLast, cursor ? cursor->lowerItem : fTopItem); - return true; - } - break; - } - } - - return false; -} - -//---------------------------------------------------------------------------------- -/*! - \brief Based on it's WindowLayer type, places this item in front as it is possible. -*/ -void -Workspace::placeInFront(ListData *item, const bool userBusy) -{ - if (!item) - return; - - int32 level = item->layerPtr->Level(); - ListData* cursor = fBottomItem; - int32 cursorLevel; - - // make MODAL windows act just like normal ones. - if (level == B_MODAL_APP) - level = B_NORMAL; - - // B_SYSTEM_LAST - always place (the most) last - if (level == B_SYSTEM_LAST) { - InsertItem(item, fTopItem); - return; - } - - // search for the exact place... - while (cursor) { - cursorLevel = cursor->layerPtr->Level(); - - // make MODAL windows act just like normal ones. - if (cursorLevel == B_MODAL_APP) - cursorLevel = B_NORMAL; - - if (level < cursorLevel) { - cursor = cursor->upperItem; - continue; - } else { - // that's it, we've found the proper place. - break; - } - } - - if (cursor) { - // if user is busy typing something, or has an opened menu... - if (userBusy && cursor == fFrontItem) - InsertItem(item, cursor); - else - InsertItem(item, cursor->lowerItem); - } else - InsertItem(item, fTopItem); -} - - -inline bool -Workspace::removeAndPlaceBefore(ListData *item, ListData *beforeItem) -{ - if (item && item != beforeItem) { - RemoveItem(item); - // insert into proper place. - InsertItem(item, beforeItem); - return true; - } - return false; -} - -/*! - \brief Insert the specified WindowLayer before given item. First search the - specified WindowLayer in Workspace's list an remove it. - \resolution: private -*/ -inline bool -Workspace::removeAndPlaceBefore(const WindowLayer *wb, ListData *beforeItem) -{ - return removeAndPlaceBefore(HasItem(wb), beforeItem); -} - - -inline WindowLayer* -Workspace::searchANormalWindow(WindowLayer *wb) const -{ - ListData* listItem = fBottomItem; - while (listItem) { - if (listItem->layerPtr->Level() == B_NORMAL && !listItem->layerPtr->IsHidden() - && listItem->layerPtr->App()->ClientTeam() == wb->App()->ClientTeam()) - return listItem->layerPtr; - - listItem = listItem->upperItem; - } - return NULL; -} - - -inline WindowLayer* -Workspace::searchFirstMainWindow(WindowLayer *wb) const -{ - ListData* listItem = fBottomItem; - while (listItem) { - if (listItem->layerPtr->Level() == B_NORMAL && !listItem->layerPtr->IsHidden() - && listItem->layerPtr->App()->ClientTeam() == wb->App()->ClientTeam() - && listItem->layerPtr->fSubWindowList.HasItem(wb)) - return listItem->layerPtr; - - listItem = listItem->upperItem; - } - return NULL; -} - -//---------------------------------------------------------------------------------- - -inline -bool Workspace::windowHasVisibleModals(const WindowLayer *winBorder) const -{ - int32 i, count; - WindowLayer **wbList; - - // check window's list - count = winBorder->fSubWindowList.CountItems(); - wbList = (WindowLayer**)winBorder->fSubWindowList.Items(); - for(i = 0; i < count; i++) - { - if (wbList[i]->Level() == B_MODAL_APP && !wbList[i]->IsHidden()) - return true; - } - - // application's list only has modal windows. - count = winBorder->App()->fAppSubWindowList.CountItems(); - wbList = (WindowLayer**)winBorder->App()->fAppSubWindowList.Items(); - for(i = 0; i < count; i++) - { - if (!wbList[i]->IsHidden()) - return true; - } - - return false; -} - -//---------------------------------------------------------------------------------- - -inline -ListData* Workspace::putModalsInFront(ListData *item) -{ - int32 i, count, revIndex, revIndexItem; - WindowLayer **wbList; - ListData *itemX; - ListData *lastPlaced = NULL; - ListData *before = item->lowerItem; - - HasItem(item, &revIndex); - - // check window's list - count = item->layerPtr->fSubWindowList.CountItems(); - wbList = (WindowLayer**)item->layerPtr->fSubWindowList.Items(); - for(i = 0; i < count; i++) - { - if (wbList[i]->Level() == B_MODAL_APP && !wbList[i]->IsHidden()) - { - itemX = HasItem(wbList[i], &revIndexItem); - if (!itemX) - { - itemX = fPool.GetCleanMemory(wbList[i]); - - InsertItem(itemX, before); - lastPlaced = itemX; - } - else if (revIndexItem > revIndex) - { - removeAndPlaceBefore(itemX, before); - lastPlaced = itemX; - } - } - } - - // application's list only has modal windows. - count = item->layerPtr->App()->fAppSubWindowList.CountItems(); - wbList = (WindowLayer**)item->layerPtr->App()->fAppSubWindowList.Items(); - for(i = 0; i < count; i++) - { - if (!wbList[i]->IsHidden()) - { - itemX = HasItem(wbList[i], &revIndexItem); - if (!itemX) - { - itemX = fPool.GetCleanMemory(wbList[i]); - - InsertItem(itemX, before); - lastPlaced = itemX; - } - else if (revIndexItem > revIndex) - { - removeAndPlaceBefore(itemX, before); - lastPlaced = itemX; - } - } - } - - return lastPlaced; + fColor = color; } void -Workspace::putFloatingInFront(ListData *item) -{ - int32 i; - ListData *newItem; - ListData *before = item->lowerItem; - WindowLayer *wb; - - i = 0; - while ((wb = (WindowLayer*)item->layerPtr->fSubWindowList.ItemAt(i))) - { - if (wb->Level() == B_MODAL_APP) - { - break; - } - else if (!wb->IsHidden()) - { - newItem = fPool.GetCleanMemory(wb); - - InsertItem(newItem, before); - - item->layerPtr->fSubWindowList.RemoveItem(i); - } - else - i++; - } -} - -//---------------------------------------------------------------------------------- - -inline -void Workspace::saveFloatingWindows(ListData *itemNormal) -{ - ListData *item = itemNormal->lowerItem; - ListData *toast; - while(item) - { - if (item->layerPtr->Level() == B_FLOATING_APP) - { - itemNormal->layerPtr->fSubWindowList.AddWindowLayer(item->layerPtr); - - toast = item; - item = item->lowerItem; - RemoveItem(toast); - fPool.ReleaseMemory(toast); - } - else - break; - } -} - -//---------------------------------------------------------------------------------- - -inline -ListData* Workspace::findNextFront() const -{ - ListData *item = fBottomItem; - - while(item) - { - if (!item->layerPtr->IsHidden() - && item->layerPtr->Level() != B_FLOATING_ALL - && item->layerPtr->Level() != B_FLOATING_APP - && !(item->layerPtr->WindowFlags() & B_AVOID_FRONT)) - { - return item; - } - item = item->upperItem; - } - - // we cannot ignore anymore B_AVOID_FRONT windows. - - item = fBottomItem; - while(item) - { - if (!item->layerPtr->IsHidden() - && item->layerPtr->Level() != B_FLOATING_ALL - && item->layerPtr->Level() != B_FLOATING_APP) - { - return item; - } - item = item->upperItem; - } - - return NULL; -} - - - - -// TODO: BAD, bad memory manager!!! replace!!! -Workspace::MemoryPool::MemoryPool() +Workspace::SetSettings(BMessage& settings) { } -Workspace::MemoryPool::~MemoryPool() + +void +Workspace::GetSettings(BMessage& settings) { } -inline -ListData* Workspace::MemoryPool::GetCleanMemory(WindowLayer *winBorder) + +void +Workspace::_SetDefaults() { - ListData *item = (ListData*)malloc(sizeof(ListData)); - item->layerPtr = winBorder; - item->upperItem = NULL; - item->lowerItem = NULL; - return item; + fColor.SetColor(kDefaultColor); } -inline -void Workspace::MemoryPool::ReleaseMemory(ListData *mem) -{ - free(mem); -} - -void Workspace::MemoryPool::expandBuffer(int32 start) -{ -} diff --git a/src/servers/app/Workspace.h b/src/servers/app/Workspace.h index ad8e9e16f1..a290cbf67b 100644 --- a/src/servers/app/Workspace.h +++ b/src/servers/app/Workspace.h @@ -1,166 +1,67 @@ -//------------------------------------------------------------------------------ -// Copyright (c) 2001-2005, Haiku, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a -// copy of this software and associated documentation files (the "Software"), -// to deal in the Software without restriction, including without limitation -// the rights to use, copy, modify, merge, publish, distribute, sublicense, -// and/or sell copies of the Software, and to permit persons to whom the -// Software is furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -// DEALINGS IN THE SOFTWARE. -// -// File Name: Workspace.h -// Author: Adi Oanca -// Description: Tracks workspaces -// -// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -// Notes: IMPORTANT WARNING -// This object does not use any locking mechanism. It is designed -// to be used only by RootLayer class. DO NOT USE from another class! -//------------------------------------------------------------------------------ -#ifndef _WORKSPACE_H_ -#define _WORKSPACE_H_ +/* + * Copyright 2005, Haiku. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ +#ifndef WORKSPACE_H +#define WORKSPACE_H -#include -#include -#include #include "RGBColor.h" +#include +#include + + +class RootLayer; class WindowLayer; -struct ListData -{ - bool isFree; - WindowLayer *layerPtr; - ListData *upperItem; - ListData *lowerItem; + +struct display_info { + BString identifier; + BPoint origin; + display_mode mode; }; class Workspace { public: - class State { - public: - State() : Front(NULL), Focus(NULL), WindowList(50) { } + Workspace(); + ~Workspace(); - void PrintToStream(); + void SetWindows(const BObjectList& windows); + bool AddWindow(WindowLayer* window); + void RemoveWindow(WindowLayer* window); - WindowLayer* Front; - WindowLayer* Focus; - BList WindowList; - }; - Workspace( const int32 ID, - const uint32 colorspace, - const RGBColor& BGColor); - ~Workspace(); + int32 CountWindows() const { return fWindows.CountItems(); } + WindowLayer* WindowAt(int32 index) const { return fWindows.ItemAt(index); } - int32 ID() const { return fID; } + // displays - void AddWindowLayer(WindowLayer *winBorder); - void RemoveWindowLayer(WindowLayer *winBorder); - bool HasWindowLayer(const WindowLayer *winBorder) const; + void SetDisplaysFromDesktop(Desktop* desktop); - WindowLayer* Focus() const; - WindowLayer* Front() const; - WindowLayer* Active() const; - void GetState(Workspace::State *state) const; - bool AttemptToSetFront(WindowLayer *newFront); - int32 AttemptToSetFocus(WindowLayer *newFocus); - bool AttemptToMoveToBack(WindowLayer *newBack); - bool AttemptToActivate(WindowLayer *toActivate); + int32 CountDisplays() const { return fDisplays.CountItems(); } + const display_info* DisplayAt(int32 index) const { return fDisplays.ItemAt(index); } - bool GetWindowLayerList(void **list, int32 *itemCount ) const; + // configuration - bool MoveToBack(WindowLayer *newLast); - bool MoveToFront(WindowLayer *newFront, bool doNotDisturb = false); + const RGBColor& Color() const { return fColor; } + void SetColor(const RGBColor& color); - bool HideWindowLayer(WindowLayer *winBorder); - bool ShowWindowLayer(WindowLayer *winBorder, bool userBusy = false); + void SetSettings(BMessage& settings); + void GetSettings(BMessage& settings); - // resolution related methods. - status_t SetDisplayMode(const display_mode &mode); - status_t GetDisplayMode(display_mode &mode) const; - - void SetBGColor(const RGBColor &c); - RGBColor BGColor(void) const; - - // settings related methods - void GetSettings(const BMessage &msg); - void GetDefaultSettings(void); - void PutSettings(BMessage *msg, const uint8 &index) const; - static void PutDefaultSettings(BMessage *msg, const uint8 &index); - - // debug methods - void PrintToStream(void) const; - void PrintItem(ListData *item) const; - -private: - void InsertItem(ListData *item, ListData *before); - void RemoveItem(ListData *item); - ListData* HasItem(const ListData *item, int32 *index = NULL) const; - ListData* HasItem(const WindowLayer *layer, int32 *index = NULL) const; - int32 IndexOf(const ListData *item) const; - - bool placeToBack(ListData *newLast); - void placeInFront(ListData *item, const bool userBusy); - - int32 _SetFocus(ListData *newFocusItem); - - bool removeAndPlaceBefore(const WindowLayer *wb, ListData *beforeItem); - bool removeAndPlaceBefore(ListData *item, ListData *beforeItem); - - WindowLayer* searchFirstMainWindow(WindowLayer *wb) const; - WindowLayer* searchANormalWindow(WindowLayer *wb) const; - - bool windowHasVisibleModals(const WindowLayer *winBorder) const; - ListData* putModalsInFront(ListData *item); - void putFloatingInFront(ListData *item); - void saveFloatingWindows(ListData *itemNormal); - - ListData* findNextFront() const; - - class MemoryPool - { - public: - MemoryPool(); - ~MemoryPool(); - ListData* GetCleanMemory(WindowLayer* winborder); - void ReleaseMemory(ListData* mem); private: - void expandBuffer(int32 start); - ListData *buffer; - int32 count; - }; + void _SetDefaults(); - int32 fID; - RGBColor fBGColor; + BObjectList fWindows; + WindowLayer* fFront; + WindowLayer* fFocus; - // first visible onscreen - ListData *fBottomItem; + BObjectList fDisplays; - // the last visible(or covered by other Layers) - ListData *fTopItem; - - // the focus WindowLayer - for keyboard events - ListData *fFocusItem; - - // pointer for which "big" actions are intended - ListData *fFrontItem; - - // settings for each workspace - display_mode fDisplayMode; - - MemoryPool fPool; + RGBColor fColor; }; -#endif +#endif /* WORKSPACE_H */ diff --git a/src/servers/app/WorkspacesLayer.cpp b/src/servers/app/WorkspacesLayer.cpp index 524019686b..5ed18d5e61 100644 --- a/src/servers/app/WorkspacesLayer.cpp +++ b/src/servers/app/WorkspacesLayer.cpp @@ -34,7 +34,7 @@ WorkspacesLayer::~WorkspacesLayer() void WorkspacesLayer::_GetGrid(int32& columns, int32& rows) { - int32 count = GetRootLayer()->WorkspaceCount(); + int32 count = 4; //GetRootLayer()->WorkspaceCount(); rows = 1; for (int32 i = 2; i < count; i++) { @@ -140,8 +140,8 @@ WorkspacesLayer::_DrawWorkspace(int32 index) { BRect rect = _WorkspaceAt(index); - Workspace* workspace = GetRootLayer()->WorkspaceAt(index); - bool active = workspace == GetRootLayer()->ActiveWorkspace(); + Workspace* workspace = NULL; + bool active = index == 0; if (active) { // draw active frame RGBColor black(0, 0, 0); @@ -155,7 +155,7 @@ WorkspacesLayer::_DrawWorkspace(int32 index) // ToDo: fix me - workspaces must always exist, not only on first visit! if (workspace != NULL) - color = workspace->BGColor(); + color = workspace->Color(); else color.SetColor(51, 102, 152); @@ -171,9 +171,9 @@ WorkspacesLayer::_DrawWorkspace(int32 index) if (workspace != NULL) { WindowLayer* windows[256]; - int32 count = 256; - if (!workspace->GetWindowLayerList((void **)&windows, &count)) - return; + int32 count = 0; +// if (!workspace->GetWindowLayerList((void **)&windows, &count)) +// return; uint16 width, height; uint32 colorSpace; @@ -244,7 +244,7 @@ WorkspacesLayer::Draw(const BRect& updateRect) // draw workspaces - int32 count = GetRootLayer()->WorkspaceCount(); + int32 count = 4; //GetRootLayer()->WorkspaceCount(); for (int32 i = 0; i < count; i++) { _DrawWorkspace(i);