diff --git a/src/servers/app/server/Desktop.cpp b/src/servers/app/server/Desktop.cpp index 4980b5a714..797917d55e 100644 --- a/src/servers/app/server/Desktop.cpp +++ b/src/servers/app/server/Desktop.cpp @@ -37,6 +37,7 @@ #include "RootLayer.h" #include "ServerConfig.h" #include "ServerScreen.h" +#include "ServerApp.h" #include "ServerWindow.h" #include "ViewDriver.h" #include "DirectDriver.h" @@ -158,23 +159,25 @@ void Desktop::InitMode(void) //--------------------------------------------------------------------------- +inline Screen* Desktop::ScreenAt(int32 index) const { - Screen *sc= static_cast(fScreenList.ItemAt(index)); - - return sc; + return static_cast(fScreenList.ItemAt(index)); } +inline int32 Desktop::ScreenCount(void) const { return fScreenList.CountItems(); } +inline Screen* Desktop::ActiveScreen(void) const { return fActiveScreen; } +inline void Desktop::SetActiveRootLayerByIndex(int32 listIndex) { RootLayer *rl=RootLayerAt(listIndex); @@ -183,6 +186,7 @@ void Desktop::SetActiveRootLayerByIndex(int32 listIndex) SetActiveRootLayer(rl); } +inline void Desktop::SetActiveRootLayer(RootLayer* rl) { if (fActiveRootLayer == rl) @@ -196,6 +200,7 @@ RootLayer* Desktop::ActiveRootLayer(void) const return fActiveRootLayer; } +inline int32 Desktop::ActiveRootLayerIndex(void) const { int32 rootLayerCount = CountRootLayers(); @@ -207,18 +212,19 @@ int32 Desktop::ActiveRootLayerIndex(void) const return -1; } +inline RootLayer* Desktop::RootLayerAt(int32 index) { - RootLayer *rl=static_cast(fRootLayerList.ItemAt(index)); - - return rl; + return static_cast(fRootLayerList.ItemAt(index)); } +inline int32 Desktop::CountRootLayers() const { return fRootLayerList.CountItems(); } +inline DisplayDriver* Desktop::GetDisplayDriver() const { return ScreenAt(0)->DDriver(); @@ -228,55 +234,215 @@ DisplayDriver* Desktop::GetDisplayDriver() const // Methods for layer(WinBorder) manipulation. //--------------------------------------------------------------------------- - -void Desktop::AddWinBorder(WinBorder* winBorder) +void Desktop::AddWinBorder(WinBorder *winBorder) { - desktop->fGeneralLock.Lock(); - - if(fWinBorderList.HasItem(winBorder)) + if (!winBorder) return; - // special case for Tracker background window. - if (winBorder->Level() == B_SYSTEM_LAST) - { - // it's added in all RottLayers - for(int32 i=0; iAddWinBorder(winBorder); - } - else - // other windows are added to the current RootLayer only. - ActiveRootLayer()->AddWinBorder(winBorder); + int32 feel = winBorder->Window()->Feel(); - // add that pointer to user winboder list so that we can keep track of them. - fLayerLock.Lock(); + // we're playing with window list. lock first. + Lock(); + + if (fWinBorderList.HasItem(winBorder)) + { + Unlock(); + debugger("AddWinBorder: WinBorder already in Desktop list\n"); + return; + } + + // we have a new window. store a record of it. fWinBorderList.AddItem(winBorder); - fLayerLock.Unlock(); - desktop->fGeneralLock.Unlock(); + // 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) + { + WinBorder *wb = NULL; + int32 count = fWinBorderList.CountItems(); + + for(int32 i = 0; i < count; i++) + { + wb = (WinBorder*)fWinBorderList.ItemAt(i); + if (wb->App()->ClientTeamID() == winBorder->App()->ClientTeamID() + && wb->Window()->Feel() == B_NORMAL_WINDOW_FEEL) + // R2: RootLayer comparison is needed. + { + wb->fFMWList.AddWinBorder(winBorder); + } + } + } + + // add application's list of modal windows. + if (feel == B_MODAL_APP_WINDOW_FEEL) + { + winBorder->App()->fAppFMWList.AddWinBorder(winBorder); + } + + // hey, unlock! + Unlock(); + + // R2: how to determine the RootLayer to which this window should be added??? + // for now, use ActiveRootLayer() because we only have one instance. + + // these are added to windows's FMWList and Workspaces when + // BWindow::AddToSubset() is called. not now. + if (feel != B_FLOATING_SUBSET_WINDOW_FEEL && feel != B_MODAL_SUBSET_WINDOW_FEEL) + { + // send WinBorder to be added to workspaces + ActiveRootLayer()->AddWinBorder(winBorder); + } } -void Desktop::RemoveWinBorder(WinBorder* winBorder) +void Desktop::RemoveWinBorder(WinBorder *winBorder) { - desktop->fGeneralLock.Lock(); + if (!winBorder) + return; - if(winBorder->Level() == B_SYSTEM_LAST) + // we're playing with window list. lock first. + Lock(); + + // remove from main WinBorder list. + if (fWinBorderList.RemoveItem(winBorder)) { - for(int32 i=0; iRemoveWinBorder(winBorder); + int32 feel = winBorder->Window()->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) + { + WinBorder *wb = NULL; + int32 count = fWinBorderList.CountItems(); + + for (int32 i = 0; i < count; i++) + { + wb = (WinBorder*)fWinBorderList.ItemAt(i); + + if (wb->Window()->Feel() == B_NORMAL_WINDOW_FEEL + && wb->App()->ClientTeamID() == winBorder->App()->ClientTeamID()) + // R2: RootLayer comparison is needed. We'll see. + { + wb->fFMWList.RemoveItem(winBorder); + } + } + } + + // remove from application's list + if (feel == B_MODAL_APP_WINDOW_FEEL) + { + winBorder->App()->fAppFMWList.RemoveItem(winBorder); + } } else - winBorder->GetRootLayer()->RemoveWinBorder(winBorder); + { + Unlock(); + debugger("RemoveWinBorder: WinBorder not found in Desktop list\n"); + return; + } - fLayerLock.Lock(); - fWinBorderList.RemoveItem(winBorder); - fLayerLock.Unlock(); + // unlock! + Unlock(); + + // Tell to winBorder's RootLayer about this. + ActiveRootLayer()->RemoveWinBorder(winBorder); - desktop->fGeneralLock.Unlock(); } -bool Desktop::HasWinBorder(WinBorder* winBorder) +void Desktop::AddWinBorderToSubset(WinBorder *winBorder, WinBorder *toWinBorder) { - return fWinBorderList.HasItem(winBorder); + // we're playing with window list. lock first. + Lock(); + + if (!winBorder || !toWinBorder + || !fWinBorderList.HasItem(winBorder) || !fWinBorderList.HasItem(toWinBorder)) + { + Unlock(); + debugger("AddWinBorderToSubset: NULL WinBorder or not found in Desktop list\n"); + return; + } + + if ( (winBorder->Window()->Feel() == B_FLOATING_SUBSET_WINDOW_FEEL + || winBorder->Window()->Feel() == B_MODAL_SUBSET_WINDOW_FEEL) + && toWinBorder->Window()->Feel() == B_NORMAL_WINDOW_FEEL + && toWinBorder->App()->ClientTeamID() == winBorder->App()->ClientTeamID() + && !toWinBorder->fFMWList.HasItem(winBorder)) + { + // add to normal_window's list + toWinBorder->fFMWList.AddWinBorder(winBorder); + } + else + { + Unlock(); + debugger("AddWinBorderToSubset: you must add a subset_window to a normal_window's subset with the same team_id\n"); + return; + } + + // hey, unlock! + Unlock(); + + // send WinBorder to be added to workspaces, if not already in there. + ActiveRootLayer()->AddSubsetWinBorder(winBorder, toWinBorder); +} + +void Desktop::RemoveWinBorderFromSubset(WinBorder *winBorder, WinBorder *fromWinBorder) +{ + // we're playing with window list. lock first. + Lock(); + + if (!winBorder || !fromWinBorder + || !fWinBorderList.HasItem(winBorder) || !fWinBorderList.HasItem(fromWinBorder)) + { + Unlock(); + debugger("RemoveWinBorderFromSubset: NULL WinBorder or not found in Desktop list\n"); + return; + } + + if (fromWinBorder->Window()->Feel() == B_NORMAL_WINDOW_FEEL) + { + //remove from this normal_window's subset. + fromWinBorder->fFMWList.RemoveItem(winBorder); + } + else + { + Unlock(); + debugger("RemoveWinBorderFromSubset: you must remove a subset_window from a normal_window's subset\n"); + return; + } + + // hey, unlock! + Unlock(); + + // remove WinBorder from workspace, if needed - some other windows may still have it in their subset + ActiveRootLayer()->RemoveSubsetWinBorder(winBorder, fromWinBorder); +} + +inline +bool Desktop::HasWinBorder(WinBorder *winBorder) +{ + bool isIn = false; + Lock(); + isIn = fWinBorderList.HasItem(winBorder); + Unlock(); + return isIn; +} + +WinBorder* Desktop::FindWinBorderByServerWindowTokenAndTeamID(int32 token, team_id teamID) +{ + WinBorder* wb; + + Lock(); + for (int32 i = 0; (wb = (WinBorder*)fWinBorderList.ItemAt(i)); i++) + { + if (wb->Window()->ClientToken() == token + && wb->Window()->ClientTeamID() == teamID) + break; + } + Unlock(); + + return wb; } //--------------------------------------------------------------------------- @@ -322,33 +488,6 @@ mode_mouse Desktop::FFMouseMode(void) const return fMouseMode; } -void Desktop::RemoveSubsetWindow(WinBorder* wb) -{ - WinBorder *winBorder = NULL; - - fLayerLock.Lock(); - int32 count = fWinBorderList.CountItems(); - for(int32 i=0; i < count; i++) - { - winBorder = static_cast(fWinBorderList.ItemAt(i)); - if (winBorder->Level() == B_NORMAL_FEEL) - winBorder->Window()->fWinFMWList.RemoveItem(wb); - } - fLayerLock.Unlock(); - - RootLayer *rl = winBorder->GetRootLayer(); - - if (!fGeneralLock.IsLocked()) - debugger("Desktop::RemoveWinBorder() - fGeneralLock must be locked!\n"); - if (!(rl->fMainLock.IsLocked())) - debugger("Desktop::RemoveWinBorder() - fMainLock must be locked!\n"); - - int32 countWKs = rl->WorkspaceCount(); - for (int32 i=0; i < countWKs; i++) - rl->WorkspaceAt(i+1)->RemoveWinBorder(wb); - -} - void Desktop::PrintToStream(void) { printf("RootLayer List:\n=======\n"); @@ -366,33 +505,6 @@ void Desktop::PrintToStream(void) printf("\t%ld\n", ((Screen*)fScreenList.ItemAt(i))->ScreenNumber()); } -WinBorder* Desktop::FindWinBorderByServerWindowTokenAndTeamID(int32 token, team_id teamID) -{ - WinBorder* wb; - fLayerLock.Lock(); - for (int32 i = 0; (wb = (WinBorder*)fWinBorderList.ItemAt(i)); i++) - { - if (wb->Window()->ClientToken() == token - && wb->Window()->ClientTeamID() == teamID) - break; - } - fLayerLock.Unlock(); - - return wb; -} - void Desktop::PrintVisibleInRootLayerNo(int32 no) { - if (no<0 || no>=fRootLayerList.CountItems()) - return; - - printf("Visible windows in RootLayer %ld, Workspace %ld\n", - ActiveRootLayerIndex(), ActiveRootLayer()->ActiveWorkspaceIndex()); - WinBorder *wb = NULL; - Workspace *ws = ActiveRootLayer()->ActiveWorkspace(); - for(wb = (WinBorder*)ws->GoToTopItem(); wb != NULL; wb = (WinBorder*)ws->GoToLowerItem()) - { - if (!wb->IsHidden()) - wb->PrintToStream(); - } } diff --git a/src/servers/app/server/Desktop.h b/src/servers/app/server/Desktop.h index 4622a8173a..2dad7c58d7 100644 --- a/src/servers/app/server/Desktop.h +++ b/src/servers/app/server/Desktop.h @@ -45,7 +45,7 @@ class Desktop public: // startup methods Desktop(void); - ~Desktop(void); + virtual ~Desktop(void); void Init(void); // 1-BigScreen or n-SmallScreens @@ -67,8 +67,24 @@ public: // Methods for layer(WinBorder) manipulation. void AddWinBorder(WinBorder *winBorder); void RemoveWinBorder(WinBorder *winBorder); + void AddWinBorderToSubset(WinBorder *winBorder, WinBorder *toWinBorder); + void RemoveWinBorderFromSubset(WinBorder *winBorder, WinBorder *fromWinBorder); bool HasWinBorder(WinBorder *winBorder); + WinBorder* FindWinBorderByServerWindowTokenAndTeamID(int32 token, team_id teamID); + // get list of registed windows + const BList& WindowList() const + { + if (!IsLocked()) + debugger("You must lock before getting registered windows list\n"); + return fWinBorderList; + } + + // locking with regards to registered windows list + bool Lock() { return fWinLock.Lock(); } + void Unlock() { return fWinLock.Unlock(); } + bool IsLocked() const { return fWinLock.IsLocked(); } + // Methods for various desktop stuff handled by the server void SetScrollBarInfo(const scroll_bar_info &info); scroll_bar_info ScrollBarInfo(void) const; @@ -85,27 +101,22 @@ public: void PrintToStream(void); void PrintVisibleInRootLayerNo(int32 no); - // "Private" to app_server :-) - means they should not be used very much - void RemoveSubsetWindow(WinBorder *wb); - WinBorder *FindWinBorderByServerWindowTokenAndTeamID(int32 token, team_id teamID); - - BLocker fGeneralLock; - BLocker fLayerLock; - BList fWinBorderList; - private: - void AddDriver(DisplayDriver *driver); - - BList fRootLayerList; - RootLayer *fActiveRootLayer; + void AddDriver(DisplayDriver *driver); - BList fScreenList; - Screen *fActiveScreen; + BList fWinBorderList; + BLocker fWinLock; + + BList fRootLayerList; + RootLayer *fActiveRootLayer; + + BList fScreenList; + Screen *fActiveScreen; scroll_bar_info fScrollBarInfo; - menu_info fMenuInfo; - mode_mouse fMouseMode; - bool fFFMouseMode; + menu_info fMenuInfo; + mode_mouse fMouseMode; + bool fFFMouseMode; }; extern Desktop *desktop; diff --git a/src/servers/app/server/Globals.h b/src/servers/app/server/Globals.h index 4bc1dde699..e3345b89d1 100644 --- a/src/servers/app/server/Globals.h +++ b/src/servers/app/server/Globals.h @@ -1,14 +1,4 @@ #ifndef _GLOBALS_H_ #define _GLOBALS_H_ -#define B_SYSTEM_LAST 10 -#define B_NORMAL_FEEL 11 -#define B_FLOATING_SUBSET_FEEL 12 -#define B_FLOATING_APP_FEEL 13 -#define B_MODAL_SUBSET_FEEL 14 -#define B_MODAL_APP_FEEL 15 -#define B_FLOATING_ALL_FEEL 16 -#define B_MODAL_ALL_FEEL 17 -#define B_SYSTEM_FIRST 18 - #endif diff --git a/src/servers/app/server/Layer.cpp b/src/servers/app/server/Layer.cpp index ae56ca167d..ebed73d120 100644 --- a/src/servers/app/server/Layer.cpp +++ b/src/servers/app/server/Layer.cpp @@ -102,7 +102,7 @@ Layer::Layer(BRect frame, const char *name, int32 token, uint32 resize, fInUpdate = false; fIsTopLayer = false; - fLevel = 0; + fLevel = -100; fViewToken = token; fServerWin = NULL; @@ -201,7 +201,7 @@ void Layer::AddChild(Layer *layer, ServerWindow *serverWin) c->SetRootLayer(c->fParent->fRootLayer); // 2.2) this Layer must know if it has a ServerWindow object attached. - fServerWin=serverWin; + c->fServerWin=serverWin; // 2.3) we are attached to the main tree so build our full region. c->RebuildFullRegion(); @@ -298,7 +298,7 @@ void Layer::RemoveChild(Layer *layer) // 2.1) set the RootLayer for this object. c->SetRootLayer(NULL); // 2.2) this Layer must know if it has a ServerWindow object attached. - fServerWin=NULL; + c->fServerWin=NULL; // 2.3) we were removed from the main tree so clear our full region. c->fFull.MakeEmpty(); // 2.4) clear fullVisible region. @@ -645,7 +645,10 @@ void Layer::Draw(const BRect &r) r.PrintToStream(); #endif - fDriver->FillRect(r, fLayerData->viewcolor); +// fDriver->FillRect(r, fLayerData->viewcolor); + srand(123); + RGBColor c(rand()%255,rand()%255,rand()%255); + fDriver->FillRect(r, c); // empty HOOK function. } @@ -730,14 +733,14 @@ void Layer::RebuildFullRegion(void) STRACE(("Layer(%s)::RebuildFullRegion()\n", GetName())); if (fParent) - fFull.Set( fParent->ConvertToTop( fFrame ) ); + fFull.Set(fParent->ConvertToTop(fFrame )); else - fFull.Set( fFrame ); + fFull.Set(fFrame); // TODO: restrict to screen coordinates // TODO: Convert to screen coordinates - + LayerData *ld; ld = fLayerData; do @@ -1086,9 +1089,9 @@ void Layer::StartRebuildRegions( const BRegion& reg, Layer *target, uint32 actio BRegion oldVisible = fVisible; fVisible = fFullVisible; - + // Rebuild regions for children... - for(Layer *lay = VirtualBottomChild(); lay != NULL; lay = VirtualUpperSibling()) + for(Layer *lay = VirtualBottomChild(); lay; lay = VirtualUpperSibling()) { if (lay == target) lay->RebuildRegions(reg, action, pt, BPoint(0.0f, 0.0f)); @@ -1404,7 +1407,7 @@ BRegion Layer::ConvertToTop(BRegion *reg) //! Converts the passed rectangle to screen coordinates BRect Layer::ConvertToTop(BRect rect) { - if (fParent!=NULL) + if (fParent) return(fParent->ConvertToTop(rect.OffsetByCopy(fFrame.LeftTop())) ); else return(rect); @@ -1412,7 +1415,7 @@ BRect Layer::ConvertToTop(BRect rect) BPoint Layer::ConvertFromTop(BPoint pt) { - if (fParent!=NULL) + if (fParent) { return(fParent->ConvertFromTop(pt-fFrame.LeftTop())); } diff --git a/src/servers/app/server/Layer.h b/src/servers/app/server/Layer.h index 7ebdb6d561..dd0fa30c1f 100644 --- a/src/servers/app/server/Layer.h +++ b/src/servers/app/server/Layer.h @@ -36,6 +36,7 @@ #include #include #include +#include "ServerWindow.h" #include "RGBColor.h" enum @@ -60,7 +61,7 @@ enum AS_ROOTLAYER_CLASS = 3, }; -class ServerWindow; +class ServerApp; class RootLayer; class DisplayDriver; class LayerData; @@ -101,9 +102,9 @@ public: virtual void Draw(const BRect &r); - virtual void Show(bool invalidate=true); - virtual void Hide(bool invalidate=true); - virtual bool IsHidden(void) const; + void Show(bool invalidate=true); + void Hide(bool invalidate=true); + bool IsHidden(void) const; BRect Bounds(void) const; BRect Frame(void) const; @@ -126,6 +127,7 @@ public: DisplayDriver *GetDisplayDriver(void) const { return fDriver; } ServerWindow *Window(void) const { return fServerWin; } + ServerApp *App(void) const { return fServerWin? fServerWin->App(): NULL; } virtual bool HasClient(void) { return true; } bool IsServerLayer() const; int32 Level() const { return fLevel; } diff --git a/src/servers/app/server/RootLayer.cpp b/src/servers/app/server/RootLayer.cpp index 8442be3208..33b9c4e3d6 100644 --- a/src/servers/app/server/RootLayer.cpp +++ b/src/servers/app/server/RootLayer.cpp @@ -22,7 +22,7 @@ // File Name: RootLayer.cpp // Author: Gabe Yoder // DarkWyrm -// Adi Oanca +// Adi Oanca // Description: Class used for the top layer of each workspace's Layer tree // //------------------------------------------------------------------------------ @@ -65,6 +65,15 @@ RootLayer::RootLayer(const char *name, int32 workspaceCount, { fDesktop = desktop; + fWinBorderList = NULL; + fWinBorderCount = 0; + fWinBorderIndex = 0; + fWsCount = 0; + fActiveWksIndex = 0; + memset(&fWorkspace[0], 0, sizeof(Workspace*)*32); + SetWorkspaceCount(workspaceCount); + SetActiveWorkspace(0L); + fMouseTarget = NULL; fDragMessage = NULL; fScreenShotIndex = 1; @@ -73,7 +82,6 @@ RootLayer::RootLayer(const char *name, int32 workspaceCount, //NOTE: be careful about this one. fRootLayer = this; - fActiveWorkspace = NULL; fRows = 0; fColumns = 0; @@ -112,6 +120,15 @@ RootLayer::~RootLayer() if (fDragMessage) delete fDragMessage; + for (int32 i = 0; i < fWsCount; i++) + { + if (fWorkspace[i]) + { + delete fWorkspace[i]; + fWorkspace[i] = NULL; + } + } + // RootLayer object just uses Screen objects, it is not allowed to delete them. } @@ -257,6 +274,7 @@ void RootLayer::GoInvalidate(const Layer *layer, const BRegion ®ion) void RootLayer::invalidate_layer(Layer *layer, const BRegion ®ion) { // NOTE: our thread (WorkingThread) is locked here. + STRACE(("RootLayer::invalidate_layer(%s)\n", layer->GetName())); if (layer->fParent) layer = layer->fParent; @@ -300,22 +318,344 @@ void RootLayer::ResizeBy(float x, float y) Layer* RootLayer::VirtualTopChild() const { - return fActiveWorkspace->GoToTopItem(); + if (fWinBorderList) + { + free(fWinBorderList); + fWinBorderList = NULL; + } + + void **list; + ActiveWorkspace()->GetWinBorderList(list, &fWinBorderCount); + fWinBorderList = (WinBorder**)list; + fWinBorderIndex = fWinBorderCount-1; + + if (fWinBorderIndex < fWinBorderCount && fWinBorderIndex >= 0) + return fWinBorderList[fWinBorderIndex--]; + + return NULL; } Layer* RootLayer::VirtualLowerSibling() const { - return fActiveWorkspace->GoToLowerItem(); + if (fWinBorderIndex < fWinBorderCount && fWinBorderIndex > 0) + return fWinBorderList[fWinBorderIndex--]; + + return NULL; } Layer* RootLayer::VirtualUpperSibling() const { - return fActiveWorkspace->GoToUpperItem(); + if (fWinBorderIndex < fWinBorderCount && fWinBorderIndex > 0) + return fWinBorderList[fWinBorderIndex++]; + + return NULL; } Layer* RootLayer::VirtualBottomChild() const { - return fActiveWorkspace->GoToBottomItem(); + if (fWinBorderList) + { + free(fWinBorderList); + fWinBorderList = NULL; + } + + void **list; + ActiveWorkspace()->GetWinBorderList(list, &fWinBorderCount); + fWinBorderList = (WinBorder**)list; + fWinBorderIndex = 0; + + if (fWinBorderIndex < fWinBorderCount && fWinBorderIndex >= 0) + return fWinBorderList[fWinBorderIndex++]; + + return NULL; +} + + +void RootLayer::AddWinBorder(WinBorder* winBorder) +{ + if (!winBorder->IsHidden()) + { + debugger("RootLayer::RemoveWinBorder - winBorder must be hidden\n"); + return; + } + + uint32 wks = winBorder->Window()->Workspaces(); + + // add to current workspace + if (wks == 0) + { + fWorkspace[fActiveWksIndex]->AddWinBorder(winBorder); + } + // add to desired workspaces + else + { + for (int32 i = 0; i < fWsCount; i++) + { + if (fWorkspace[i] && (wks & (0x00000001UL << i))) + fWorkspace[i]->AddWinBorder(winBorder); + } + } + + // we _DO_NOT_ need to invalidate here. At this point our WinBorder is hidden! + + // set some internals + winBorder->SetRootLayer(this); + winBorder->fParent = this; +} + +void RootLayer::RemoveWinBorder(WinBorder* winBorder) +{ + // Note: removing a subset window is also permited/performed. + + if (!winBorder->IsHidden()) + { + debugger("RootLayer::RemoveWinBorder - winBorder must be hidden\n"); + return; + } + + // 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]->RemoveWinBorder(winBorder); + + // we _DO_NOT_ need to invalidate here. At this point our WinBorder is hidden! + + // set some internals + winBorder->SetRootLayer(NULL); + winBorder->fParent = NULL; +} + +void RootLayer::AddSubsetWinBorder(WinBorder *winBorder, WinBorder *toWinBorder) +{ + // SUBSET windows _must_ have their workspaceIndex set to 0x0 + if (winBorder->Window()->Workspaces() != 0UL) + { + debugger("SUBSET windows _must_ have their workspaceIndex set to 0x0\n"); + return; + } + + // there is no point in continuing - this subset window won't be shown, + // from 'toWinBorder's point of view + if (winBorder->IsHidden() || toWinBorder->IsHidden()) + { + return; + } + + bool invalidate = false; + bool invalid; + + // we try to add WinBorders 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]->HasWinBorder(toWinBorder)) + invalid = fWorkspace[i]->ShowWinBorder(winBorder, false); + + if (fActiveWksIndex == i) + invalidate = invalid; + } + + if (invalidate) + { + // RootLayer::Invalidate(&winborder's full) + } +} + +void RootLayer::RemoveSubsetWinBorder(WinBorder *winBorder, WinBorder *fromWinBorder) +{ + // there is no point in continuing - this subset window is not visible + // at least not visible from 'fromWinBorder's point of view. + if (winBorder->IsHidden() || fromWinBorder->IsHidden()) + { + return; + } + + bool invalidate = false; + bool invalid; + + // we try to remove from all workspaces. If winBorder is not in there, nothing will be done. + for (int32 i = 0; i < fWsCount; i++) + { + invalid = false; + + if (fWorkspace[i] && fWorkspace[i]->HasWinBorder(fromWinBorder)) + invalid = fWorkspace[i]->HideWinBorder(winBorder); + + if (fActiveWksIndex == i) + invalidate = invalid; + } + + if (invalidate) + { + // RootLayer::Invalidate(&winBorder's visible); + } +} + + +// NOTE: This must be called by RootLayer's thread!!!! +void RootLayer::SetActiveWorkspace(int32 index) +{ + STRACE(("RootLayer(%s)::SetActiveWorkspace(%ld)\n", GetName(), index)); + desktop->Lock(); + + // if fWorkspace[index] object does not exist, create and add allowed WinBorders + if (!fWorkspace[index]) + { + // TODO: we NEED datas from a file!!! + fWorkspace[index] = new Workspace(index, 0xFF00FF00, RGBColor()); + + const BList& windowList = desktop->WindowList(); + + int32 ptrCount = windowList.CountItems(); + WinBorder **ptrWin = (WinBorder**)windowList.Items(); + + for (int32 i = 0; i < ptrCount; i++) + { + if (ptrWin[i]->Window()->Workspaces() & (0x00000001UL << index)) + { + fWorkspace[index]->AddWinBorder(ptrWin[i]); + if (!ptrWin[i]->IsHidden()) + fWorkspace[index]->ShowWinBorder(ptrWin[i]); + } + } + } + + if (ActiveWorkspace()->Focus()) + { + BMessage activateMsg(B_WINDOW_ACTIVATED); + activateMsg.AddBool("active", false); +// ActiveWorkspace()->Focus()->layerPtr->Window()->SendMsgToClient(&msg); + } + + { + int32 ptrCount; + WinBorder **ptrWin = NULL; + BMessage activatedMsg(B_WORKSPACE_ACTIVATED); + activatedMsg.AddInt32("workspace", fActiveWksIndex); + activatedMsg.AddBool("active", false); + + ActiveWorkspace()->GetWinBorderList((void**&)ptrWin, &ptrCount); + if (ptrWin) + { + for (int32 i = 0; i < ptrCount; i++) + { + //ptrWin[i]->Window()->SendMsgToClient(&activatedMsg); + } + + delete ptrWin; + } + } + + fActiveWksIndex = index; + + { + int32 ptrCount; + WinBorder **ptrWin = NULL; + BMessage activatedMsg(B_WORKSPACE_ACTIVATED); + activatedMsg.AddInt32("workspace", fActiveWksIndex); + activatedMsg.AddBool("active", true); + + ActiveWorkspace()->GetWinBorderList((void**&)ptrWin, &ptrCount); + if (ptrWin) + { + for (int32 i = 0; i < ptrCount; i++) + { + //ptrWin[i]->Window()->SendMsgToClient(&activatedMsg); + } + + delete ptrWin; + } + } + + if (ActiveWorkspace()->Focus()) + { + BMessage activateMsg(B_WINDOW_ACTIVATED); + activateMsg.AddBool("active", true); +// ActiveWorkspace()->Focus()->layerPtr->Window()->SendMsgToClient(&msg); + } + +// TODO: if the user is holding/moving a window, *IF* the window *is not* +// in future active workspace, remove from curent one and place in +// future active workspace. + + // RootLayer::Invalidate(&RootLayer's fFullVisible) + + desktop->Unlock(); +} + +void RootLayer::SetWinBorderWorskpaces(WinBorder *winBorder, uint32 newWksIndex) +{ + // you *cannot* set workspaces index for a window other than a normal one! + // Note: See ServerWindow class. + if (winBorder->Window()->Feel() != B_NORMAL_WINDOW_FEEL) + return; + + bool invalidate = false; + bool invalid; + uint32 oldWksIndex = winBorder->Window()->Workspaces(); + + for (int32 i = 0; i < 32; i++) + { + if (fWorkspace[i]) + { + invalid = false; + + if (oldWksIndex & (0x00000001UL << i) && + !(newWksIndex & (0x00000001UL << i))) + { + if (!winBorder->IsHidden()) + { + // a little trick to force Workspace to properly pick the next front. + winBorder->Hide(); + invalid = fWorkspace[i]->HideWinBorder(winBorder); + winBorder->Show(); + } + fWorkspace[i]->RemoveWinBorder(winBorder); + } + else + if (newWksIndex & (0x00000001UL << i) && + !(oldWksIndex & (0x00000001UL << i))) + { + fWorkspace[i]->AddWinBorder(winBorder); + if (!winBorder->IsHidden()) + invalid = fWorkspace[i]->ShowWinBorder(winBorder); + } + else + { + // do nothing. winBorder was, and it's still is a member of this workspace + // OR, winBorder wasn't and it not be in this workspace + } + + if (fActiveWksIndex == i) + invalidate = invalid; + } + } + + if (invalidate) + ; // RootLayer::Invalidate(winBorder's full visible) +} + +void RootLayer::SetWorkspaceCount(int32 wksCount) +{ + if (wksCount < 1) + wksCount = 1; + if (wksCount > 32) + wksCount = 32; + + for (int32 i = wksCount; i < fWsCount; i++) + { + if (fWorkspace[i]) + { + delete fWorkspace[i]; + fWorkspace[i] = NULL; + } + } + + fWsCount = wksCount; } void RootLayer::ReadWorkspaceData(const char *path) @@ -335,7 +675,7 @@ void RootLayer::ReadWorkspaceData(const char *path) for(int32 i=0; iAddWinBorder(winBorder); - } -} - -void RootLayer::AddWinBorder(WinBorder* winBorder) -{ - // The main job of this function, besides adding winBorder as a child, is to determine - // in which workspaces to add this window. - - STRACE(("*RootLayer::AddWinBorder(%s)\n", winBorder->GetName())); - desktop->fGeneralLock.Lock(); - - STRACE(("*RootLayer::AddWinBorder(%s) - General lock acquired\n", winBorder->GetName())); - fMainLock.Lock(); - - STRACE(("*RootLayer::AddWinBorder(%s) - Main lock acquired\n", winBorder->GetName())); - - // in case we want to be added to the current workspace - if (winBorder->Window()->Workspaces() == B_CURRENT_WORKSPACE) - winBorder->Window()->QuietlySetWorkspaces(0x00000001 << (ActiveWorkspaceIndex()-1)); - - // add winBorder to the known list of WinBorders so we can keep track of it. - AddChild(winBorder, winBorder->Window()); - - // add winBorder to the desired workspaces - switch(winBorder->Window()->Feel()) - { - case B_MODAL_SUBSET_WINDOW_FEEL: - case B_FLOATING_SUBSET_WINDOW_FEEL: - { - // this kind of window isn't added anywhere. It will be added - // to main window's subset when winBorder::AddToSubsetOf(main) - // will be called. - break; - } - case B_MODAL_APP_WINDOW_FEEL: - case B_FLOATING_APP_WINDOW_FEEL: - { - // add to app's list of Floating/Modal windows (as opposed to the system's) - winBorder->Window()->App()->fAppFMWList.AddItem(winBorder); - - // determine in which workspaces to add this winBorder object. - uint32 wks = 0; - for (int32 i=0; iGoToBottomItem(); wb!=NULL; wb = ws->GoToUpperItem()) - { - if ( winBorder->Window()->ClientTeamID() == wb->Window()->ClientTeamID()) - { - wks = wks | winBorder->Window()->Workspaces(); - break; - } - } - } - - AddWinBorderToWorkspaces(winBorder, wks); - break; - } - - case B_MODAL_ALL_WINDOW_FEEL: - case B_FLOATING_ALL_WINDOW_FEEL: - { - // add to system's list of Floating/Modal Windows - fMainFMWList.AddItem(winBorder); - - // add this winBorder to all workspaces - AddWinBorderToWorkspaces(winBorder, 0xffffffffUL); - break; - } - - case B_NORMAL_WINDOW_FEEL: - { - // add this winBorder to the specified workspaces - AddWinBorderToWorkspaces(winBorder, winBorder->Window()->Workspaces()); - break; - } - - case B_SYSTEM_LAST: - case B_SYSTEM_FIRST: - { - // add this winBorder to all workspaces - AddWinBorderToWorkspaces(winBorder, 0xffffffffUL); - break; - } - default:{ - debugger("RootLayer::AddWinBorder() - what kind of window is this?"); - break; - } - } // end switch(winborder->Feel()) - - fMainLock.Unlock(); - STRACE(("*RootLayer::AddWinBorder(%s) - Main lock released\n", winBorder->GetName())); - - desktop->fGeneralLock.Unlock(); - STRACE(("*RootLayer::AddWinBorder(%s) - General lock released\n", winBorder->GetName())); - - STRACE(("#RootLayer::AddWinBorder(%s)\n", winBorder->GetName())); -} - -void RootLayer::RemoveWinBorder(WinBorder* winBorder) -{ - // This method does 3 things: - // 1) Removes MODAL/SUBSET windows from system/app/window subset list. - // 2) Removes this window from any workspace it appears in. - // 3) Removes this window from RootLayer's list of children. - - desktop->fGeneralLock.Lock(); - fMainLock.Lock(); - - int32 feel = winBorder->Window()->Feel(); - if(feel == B_MODAL_SUBSET_WINDOW_FEEL || feel == B_FLOATING_SUBSET_WINDOW_FEEL) - { - desktop->RemoveSubsetWindow(winBorder); - } - else - if (feel == B_MODAL_APP_WINDOW_FEEL || feel == B_FLOATING_APP_WINDOW_FEEL) - { - RemoveAppWindow(winBorder); - } - else - if(feel == B_MODAL_ALL_WINDOW_FEEL || feel == B_FLOATING_ALL_WINDOW_FEEL - || feel == B_SYSTEM_FIRST || feel == B_SYSTEM_LAST) - { - if(feel == B_MODAL_ALL_WINDOW_FEEL || feel == B_FLOATING_ALL_WINDOW_FEEL) - fMainFMWList.RemoveItem(winBorder); - - int32 count = WorkspaceCount(); - for(int32 i=0; i < count; i++) - WorkspaceAt(i+1)->RemoveWinBorder(winBorder); - } - else - { // for B_NORMAL_WINDOW_FEEL - uint32 workspaces = winBorder->Window()->Workspaces(); - int32 count = WorkspaceCount(); - for( int32 i=0; i < 32 && i < count; i++) - { - if( workspaces & (0x00000001UL << i)) - WorkspaceAt(i+1)->RemoveWinBorder(winBorder); - } - } - - RemoveChild(winBorder); - - fMainLock.Unlock(); - desktop->fGeneralLock.Unlock(); -} void RootLayer::HideWinBorder(WinBorder* winBorder) { @@ -584,101 +768,18 @@ void RootLayer::ShowWinBorder(WinBorder* winBorder) msg.Flush(); } -WinBorder* RootLayer::WinBorderAt(const BPoint& pt){ - WinBorder *target = NULL; - WinBorder *wb = NULL; - - for( wb = fActiveWorkspace->GoToBottomItem(); wb; wb = fActiveWorkspace->GoToUpperItem()) +WinBorder* RootLayer::WinBorderAt(const BPoint& pt) const{ + for (int32 i = 0; i < fWinBorderCount; i++) { - if(!wb->IsHidden() && wb->HasPoint(pt)) - { - target = wb; - break; - } + if (fWinBorderList[i]->fFullVisible.Contains(pt)) + return fWinBorderList[i]; } - return target; + return NULL; } -void RootLayer::ChangeWorkspacesFor(WinBorder* winBorder, uint32 newWorkspaces) +WinBorder* RootLayer::FocusWinBorder() const { - // only normal windows are affected by this change - if(!winBorder->fLevel != B_NORMAL_FEEL) - return; - - uint32 oldWorkspaces = winBorder->Window()->Workspaces(); - for(int32 i=0; i < WorkspaceCount(); i++) - { - if ((oldWorkspaces & (0x00000001 << i)) && (newWorkspaces & (0x00000001 << i))) - { - // do nothing. - } - else - if(oldWorkspaces & (0x00000001 << i)) - { - WorkspaceAt(i+1)->RemoveWinBorder(winBorder); - } - else - if (newWorkspaces & (0x00000001 << i)) - { - WorkspaceAt(i+1)->AddWinBorder(winBorder); - } - } -} - -bool RootLayer::SetFrontWinBorder(WinBorder* winBorder) -{ - if(!winBorder) - return false; - - STRACE(("*RootLayer::SetFrontWinBorder(%s)\n", winBorder? winBorder->GetName():"NULL")); - - fMainLock.Lock(); - STRACE(("*RootLayer::SetFrontWinBorder(%s) - main lock acquired\n", winBorder? winBorder->GetName():"NULL")); - - if (!winBorder) - { - ActiveWorkspace()->SearchAndSetNewFront(NULL); - return true; - } - - uint32 workspaces = winBorder->Window()->Workspaces(); - int32 count = WorkspaceCount(); - int32 newWorkspace= 0; - - if (workspaces & (0x00000001UL << (ActiveWorkspaceIndex()-1)) ) - { - newWorkspace = ActiveWorkspaceIndex(); - } - else - { - int32 i; - for( i = 0; i < 32 && i < count; i++) - { - if( workspaces & (0x00000001UL << i)) - { - newWorkspace = i+1; - break; - } - } - - if (i == count || i == 32) - newWorkspace = ActiveWorkspaceIndex(); - } - - if(newWorkspace != ActiveWorkspaceIndex()) - { - WorkspaceAt(newWorkspace)->SearchAndSetNewFront(winBorder); - SetActiveWorkspaceByIndex(newWorkspace); - } - else - { - ActiveWorkspace()->SearchAndSetNewFront(winBorder); - } - - fMainLock.Unlock(); - STRACE(("*RootLayer::SetFrontWinBorder(%s) - main lock released\n", winBorder? winBorder->GetName():"NULL")); - STRACE(("#RootLayer::SetFrontWinBorder(%s)\n", winBorder? winBorder->GetName():"NULL")); - return true; + return ActiveWorkspace()->Focus(); } void RootLayer::SetScreens(Screen *screen[], int32 rows, int32 columns) @@ -749,154 +850,9 @@ bool RootLayer::SetScreenResolution(int32 width, int32 height, uint32 colorspace return false; } - -void RootLayer::SetWorkspaceCount(const int32 count) -{ - STRACE(("*RootLayer::SetWorkspaceCount(%ld)\n", count)); - - if ((count < 1 && count > 32) || count == WorkspaceCount()) - return; - - int32 exActiveWorkspaceIndex = ActiveWorkspaceIndex(); - - BList newWSPtrList; - void *workspacePtr; - - fMainLock.Lock(); - STRACE(("*RootLayer::SetWorkspaceCount(%ld) - main lock acquired\n", count)); - - for(int i=0; i < count; i++) - { - workspacePtr = fWorkspaceList.ItemAt(i); - if (workspacePtr) - newWSPtrList.AddItem(workspacePtr); - else - { - Workspace *ws; - ws = new Workspace(fColorSpace, i+1, BGColor()); - newWSPtrList.AddItem(ws); - } - } - - // delete other Workspace objects if the count is smaller than current one. - for (int j=count; j < fWorkspaceList.CountItems(); j++) - { - Workspace *ws = NULL; - ws = static_cast(fWorkspaceList.ItemAt(j)); - if (ws) - delete ws; - else - { - STRACE(("\nSERVER: PANIC: in RootLayer::SetWorkspaceCount()\n\n")); - return; - } - } - - fWorkspaceList = newWSPtrList; - - fMainLock.Unlock(); - STRACE(("*RootLayer::SetWorkspaceCount(%ld) - main lock released\n", count)); - - if (exActiveWorkspaceIndex > count) - SetActiveWorkspaceByIndex(count); - - // if true, this is the first time this method is called. - if (exActiveWorkspaceIndex == -1) - SetActiveWorkspaceByIndex(1); - - STRACE(("#RootLayer::SetWorkspaceCount(%ld)\n", count)); -} - -int32 RootLayer::WorkspaceCount() const -{ - return fWorkspaceList.CountItems(); -} - -Workspace* RootLayer::WorkspaceAt(const int32 index) const -{ - Workspace *ws = NULL; - ws = static_cast(fWorkspaceList.ItemAt(index-1)); - - return ws; -} - -void RootLayer::SetActiveWorkspaceByIndex(const int32 index) -{ - Workspace *ws = NULL; - ws = static_cast(fWorkspaceList.ItemAt(index-1)); - if (ws) - SetActiveWorkspace(ws); -} - -void RootLayer::SetActiveWorkspace(Workspace *ws) -{ - if (fActiveWorkspace == ws || !ws) - return; - - int32 index; - WinBorder *winborder; - - // Notify windows in current workspace of change - if(fActiveWorkspace) - { - index=fWorkspaceList.IndexOf(fActiveWorkspace); - winborder=fActiveWorkspace->GoToTopItem(); - while(winborder) - { - winborder->Window()->WorkspaceActivated(index,false); - winborder=(WinBorder*)winborder->fLowerSibling; - } - } - - fActiveWorkspace = ws; - - // Notify windows in new workspace of change - index=fWorkspaceList.IndexOf(fActiveWorkspace); - winborder=fActiveWorkspace->GoToTopItem(); - while(winborder) - { - winborder->Window()->WorkspaceActivated(index,true); - winborder=(WinBorder*)winborder->fLowerSibling; - } -} - -int32 RootLayer::ActiveWorkspaceIndex() const{ - if (fActiveWorkspace) - return fActiveWorkspace->ID(); - else - return -1; -} - -Workspace* RootLayer::ActiveWorkspace() const -{ - return fActiveWorkspace; -} - -void RootLayer::SetBGColor(const RGBColor &col) -{ - ActiveWorkspace()->SetBGColor(col); - - fLayerData->viewcolor = col; -} - -int32 RootLayer::Buttons(void) -{ - return fButtons; -} - -RGBColor RootLayer::BGColor(void) const -{ - return fLayerData->viewcolor; -} - -void RootLayer::RemoveAppWindow(WinBorder *wb) -{ - wb->Window()->App()->fAppFMWList.RemoveItem(wb); - - int32 count = WorkspaceCount(); - for(int32 i=0; i < count; i++) - WorkspaceAt(i+1)->RemoveWinBorder(wb); -} +//--------------------------------------------------------------------------- +// Workspace related methods +//--------------------------------------------------------------------------- //--------------------------------------------------------------------------- // Input related methods @@ -930,79 +886,13 @@ void RootLayer::MouseEventHandler(int32 code, BPortLink& msg) fButtons=evt.buttons; // printf("MOUSE DOWN: at (%f, %f)\n", evt.where.x, evt.where.y); - - WinBorder *target=NULL; - Workspace *ws=NULL; - ws = ActiveWorkspace(); - target = WinBorderAt(evt.where); + WinBorder *target = WinBorderAt(evt.where); if (target) { - desktop->fGeneralLock.Lock(); - fMainLock.Lock(); - - STRACE(("Target: %s\n", target->GetName())); - STRACE(("Front: %s\n", ws->FrontLayer()->GetName())); - STRACE(("Focus: %s\n", ws->FocusLayer()->GetName())); - - WinBorder *previousFocus=NULL; - WinBorder *activeFocus=NULL; - BRegion invalidRegion; - - // TODO: Figure out the be:view_where field in B_MOUSE_DOWN for RootLayer - // A little sniffing around R5's B_MOUSE_DOWN messages has revealed an - // undocumented field: a BPoint entry called "be:view_where" which probably - // helps the window determine the target view. Testing so far has revealed - // that it has the same value as the "where" field - - if (target!=ws->FrontLayer()) - { - ws->BringToFrontANormalWindow(target); - ws->SearchAndSetNewFront(target); - previousFocus = ws->FocusLayer(); - ws->SearchAndSetNewFocus(target); - activeFocus = ws->FocusLayer(); - - activeFocus->Window()->Lock(); - previousFocus->Window()->Lock(); - - if (target == activeFocus && target->Window()->Flags() & B_WILL_ACCEPT_FIRST_CLICK) - target->MouseDown(evt, true); - else - target->MouseDown(evt, false); - - // may or may not be empty. - - // TODO: B_MOUSE_DOWN: what if modal of floating windows are in front of us? - invalidRegion.Include(&(activeFocus->fFull)); - invalidRegion.Include(&(activeFocus->fTopLayer->fFull)); - // allow previous window's decorator to lowlight - redraw_layer(previousFocus, previousFocus->fVisible); - // highlight the visible part of the new focus window - redraw_layer(activeFocus, activeFocus->fVisible); - // rebuild regions and redraw the hidden parts of activeFocus - invalidate_layer(activeFocus, invalidRegion); - - fMouseTarget = target; - - STRACE(("2Target: %s\n", target->GetName())); - STRACE(("2Front: %s\n", ws->FrontLayer()->GetName())); - STRACE(("2Focus: %s\n", ws->FocusLayer()->GetName())); - - previousFocus->Window()->Unlock(); - activeFocus->Window()->Unlock(); - } - else // target == ws->FrontLayer() - { - target->Window()->Lock(); - target->MouseDown(evt, true); - target->Window()->Unlock(); - } - - fMainLock.Unlock(); - desktop->fGeneralLock.Unlock(); - } - else // target == NULL - { + target->Window()->Lock(); + target->MouseDown(evt, true); + target->Window()->Unlock(); + fMouseTarget = target; } break; } @@ -1021,20 +911,14 @@ void RootLayer::MouseEventHandler(int32 code, BPortLink& msg) msg.Read(&evt.where.y); msg.Read(&evt.modifiers); - if (!fMouseTarget) + fMouseTarget = NULL; + WinBorder *target = WinBorderAt(evt.where); + if (target) { - WinBorder *target = WinBorderAt(BPoint(evt.where.x, evt.where.y)); - if(!target) - break; - fMouseTarget=target; + target->Window()->Lock(); + target->MouseUp(evt); + target->Window()->Unlock(); } - - fMouseTarget->Window()->Lock(); - fMouseTarget->MouseUp(evt); - fMouseTarget->Window()->Unlock(); - - fMouseTarget=NULL; - STRACE(("MOUSE UP: at (%f, %f)\n", evt.where.x, evt.where.y)); break; @@ -1055,18 +939,14 @@ void RootLayer::MouseEventHandler(int32 code, BPortLink& msg) msg.Read(&evt.buttons); GetDisplayDriver()->MoveCursorTo(evt.where.x, evt.where.y); - - if (!fMouseTarget) + + WinBorder *target = WinBorderAt(evt.where); + if (target) { - WinBorder *target = WinBorderAt(BPoint(evt.where.x, evt.where.y)); - if(!target) - break; - fMouseTarget=target; + target->Window()->Lock(); + target->MouseMoved(evt); + target->Window()->Unlock(); } - - fMouseTarget->Window()->Lock(); - fMouseTarget->MouseMoved(evt); - fMouseTarget->Window()->Unlock(); break; } @@ -1082,11 +962,13 @@ void RootLayer::MouseEventHandler(int32 code, BPortLink& msg) msg.Read(&evt.wheel_delta_x); msg.Read(&evt.wheel_delta_y); - WinBorder *target; - BPoint cursorPos = GetDisplayDriver()->GetCursorPosition(); - if ((target = WinBorderAt(cursorPos))) - target->MouseWheel(evt, cursorPos); - + if (FocusWinBorder()) + { + BPoint cursorPos = GetDisplayDriver()->GetCursorPosition(); + FocusWinBorder()->Window()->Lock(); + FocusWinBorder()->MouseWheel(evt, cursorPos); + FocusWinBorder()->Window()->Unlock(); + } break; } default: @@ -1274,10 +1156,9 @@ void RootLayer::KeyboardEventHandler(int32 code, BPortLink& msg) Workspace *ws=ActiveWorkspace(); - desktop->fGeneralLock.Lock(); - fMainLock.Lock(); + Lock(); - WinBorder *target=ws->FocusLayer(); + WinBorder *target=ws->Focus(); if(target) { ServerWindow *win=target->Window(); @@ -1302,8 +1183,8 @@ void RootLayer::KeyboardEventHandler(int32 code, BPortLink& msg) } } - fMainLock.Unlock(); - desktop->fGeneralLock.Unlock(); + Unlock(); + if (string) free(string); break; @@ -1371,10 +1252,9 @@ void RootLayer::KeyboardEventHandler(int32 code, BPortLink& msg) Workspace *ws=ActiveWorkspace(); - desktop->fGeneralLock.Lock(); - fMainLock.Lock(); + Lock(); - WinBorder *target=ws->FocusLayer(); + WinBorder *target=ws->Focus(); if(target) { ServerWindow *win=target->Window(); @@ -1397,8 +1277,8 @@ void RootLayer::KeyboardEventHandler(int32 code, BPortLink& msg) } } - fMainLock.Unlock(); - desktop->fGeneralLock.Unlock(); + Unlock(); + if (string) free(string); break; @@ -1424,10 +1304,9 @@ void RootLayer::KeyboardEventHandler(int32 code, BPortLink& msg) Workspace *ws=ActiveWorkspace(); - desktop->fGeneralLock.Lock(); - fMainLock.Lock(); + Lock(); - WinBorder *target=ws->FocusLayer(); + WinBorder *target=ws->Focus(); if(target) { ServerWindow *win=target->Window(); @@ -1443,8 +1322,7 @@ void RootLayer::KeyboardEventHandler(int32 code, BPortLink& msg) } } - fMainLock.Unlock(); - desktop->fGeneralLock.Unlock(); + Unlock(); break; } case B_UNMAPPED_KEY_UP: @@ -1468,10 +1346,9 @@ void RootLayer::KeyboardEventHandler(int32 code, BPortLink& msg) Workspace *ws=ActiveWorkspace(); - desktop->fGeneralLock.Lock(); - fMainLock.Lock(); + Lock(); - WinBorder *target=ws->FocusLayer(); + WinBorder *target=ws->Focus(); if(target) { ServerWindow *win=target->Window(); @@ -1487,8 +1364,7 @@ void RootLayer::KeyboardEventHandler(int32 code, BPortLink& msg) } } - fMainLock.Unlock(); - desktop->fGeneralLock.Unlock(); + Unlock(); break; } case B_MODIFIERS_CHANGED: @@ -1510,10 +1386,9 @@ void RootLayer::KeyboardEventHandler(int32 code, BPortLink& msg) Workspace *ws=ActiveWorkspace(); - desktop->fGeneralLock.Lock(); - fMainLock.Lock(); + Lock(); - WinBorder *target=ws->FocusLayer(); + WinBorder *target=ws->Focus(); if(target) { ServerWindow *win=target->Window(); @@ -1528,8 +1403,7 @@ void RootLayer::KeyboardEventHandler(int32 code, BPortLink& msg) win->SendMessageToClient(&keymsg); } } - fMainLock.Unlock(); - desktop->fGeneralLock.Unlock(); + Unlock(); break; } default: @@ -1566,103 +1440,64 @@ void RootLayer::PrintToStream() printf("Screen rows: %ld\nScreen columns: %ld\n", fRows, fColumns); printf("Resolution for all Screens: %ldx%ldx%ld\n", fScreenXResolution, fScreenYResolution, fColorSpace); printf("Workspace list:\n"); - for(int32 i=0; iID()); - ((Workspace*)fWorkspaceList.ItemAt(i))->PrintToStream(); + printf("\t~~~Workspace: %ld\n", ((Workspace*)fWorkspace[i])->ID()); + ((Workspace*)fWorkspace[i])->PrintToStream(); printf("~~~~~~~~\n"); } - printf("Active Workspace: %ld\n", fActiveWorkspace? fActiveWorkspace->ID(): -1); } +// PRIVATE methods void RootLayer::show_winBorder(WinBorder *winBorder) { - desktop->fGeneralLock.Lock(); - fMainLock.Lock(); + bool invalidate = false; + bool invalid; - int32 wksCount; - uint32 feel = winBorder->Window()->Feel(); - // make WinBorder unhidden, but *do not* rebuild and redraw! We'll do that - // after we bring it (its modal and floating windows also) in front. winBorder->Show(false); - if ( (feel == B_FLOATING_SUBSET_WINDOW_FEEL || feel == B_MODAL_SUBSET_WINDOW_FEEL) - && winBorder->MainWinBorder() == NULL) + for (int32 i = 0; i < fWsCount; i++) { - // This window hasn't been added to a normal window subset, - // so don't call placement or redrawing methods - } - else - { - wksCount = WorkspaceCount(); - for(int32 i = 0; i < wksCount; i++) - { - if (winBorder->Window()->Workspaces() & (0x00000001UL << i)) - { - WinBorder *previousFocus; - BRegion invalidRegion; - Workspace *ws; - - // TODO: can you unify this method with Desktop::MouseEventHandler::B_MOUSE_DOWN - - ws = WorkspaceAt(i+1); - ws->BringToFrontANormalWindow(winBorder); - ws->SearchAndSetNewFront(winBorder); - previousFocus = ws->FocusLayer(); - ws->SearchAndSetNewFocus(winBorder); - - // TODO: only do this in for the active workspace! - - // first redraw previous window's decorator. It has lost focus state. - if (previousFocus) - redraw_layer(winBorder, previousFocus->fVisible); + invalid = false; - // we must build the rebuild region. we have nowhere to take it from. - // include decorator's(if any) and fTopLayer's full regions. - winBorder->fTopLayer->RebuildFullRegion(); - winBorder->RebuildFullRegion(); - invalidRegion.Include(&(winBorder->fTopLayer->fFull)); - if (winBorder->fDecorator) - invalidRegion.Include(&(winBorder->fFull)); + if (fWorkspace[i] && fWorkspace[i]->HasWinBorder(winBorder)) + invalid = fWorkspace[i]->ShowWinBorder(winBorder); - invalidate_layer(winBorder, invalidRegion); - } - } + if (fActiveWksIndex == i) + invalidate = invalid; } - fMainLock.Unlock(); - desktop->fGeneralLock.Unlock(); + if (invalidate) + { + BRegion reg(winBorder->fFull); + reg.Include(&winBorder->fTopLayer->fFull); + invalidate_layer(this, reg); +// invalidate_layer(this, winBorder->fFull); + } } void RootLayer::hide_winBorder(WinBorder *winBorder) { - Workspace *ws = NULL; - - desktop->fGeneralLock.Lock(); - fMainLock.Lock(); - - winBorder->Hide(); - - int32 wksCount= WorkspaceCount(); - for(int32 i = 0; i < wksCount; i++) - { - ws = WorkspaceAt(i+1); + bool invalidate = false; + bool invalid; - if (ws->FrontLayer() == winBorder) - { - ws->HideSubsetWindows(winBorder); - ws->SearchAndSetNewFocus(ws->FrontLayer()); - } - else - { - if (ws->FocusLayer() == winBorder) - ws->SearchAndSetNewFocus(winBorder); - else{ - // TODO: RootLayer or Desktop class should take care of invalidating - } - } + winBorder->Show(false); + + for (int32 i = 0; i < fWsCount; i++) + { + invalid = false; + + if (fWorkspace[i] && fWorkspace[i]->HasWinBorder(winBorder)) + invalid = fWorkspace[i]->HideWinBorder(winBorder); + + if (fActiveWksIndex == i) + invalidate = invalid; } - fMainLock.Unlock(); - desktop->fGeneralLock.Unlock(); -} \ No newline at end of file + + if (invalidate) + { + invalidate_layer(this, winBorder->fFullVisible); + } +} + diff --git a/src/servers/app/server/RootLayer.h b/src/servers/app/server/RootLayer.h index 01d636677e..afe3d55f40 100644 --- a/src/servers/app/server/RootLayer.h +++ b/src/servers/app/server/RootLayer.h @@ -68,35 +68,32 @@ public: virtual Layer *VirtualUpperSibling(void) const; virtual Layer *VirtualBottomChild(void) const; - void ReadWorkspaceData(const char *path); - void SaveWorkspaceData(const char *path); - - void AddWinBorder(WinBorder *winBorder); - void RemoveWinBorder(WinBorder *winBorder); void HideWinBorder(WinBorder* winBorder); void ShowWinBorder(WinBorder* winBorder); - WinBorder* WinBorderAt(const BPoint& pt); - void ChangeWorkspacesFor(WinBorder *winBorder, uint32 newWorkspaces); - bool SetFrontWinBorder(WinBorder *winBorder); + void SetWinBorderWorskpaces(WinBorder *winBorder, uint32 newWksIndex); + WinBorder* WinBorderAt(const BPoint& pt) const; + WinBorder* FocusWinBorder() const; + + void SetWorkspaceCount(int32 wksCount); + int32 WorkspaceCount() const { return fWsCount; } + Workspace* WorkspaceAt(int32 index) const { return fWorkspace[index]; } + Workspace* ActiveWorkspace() const { return fWorkspace[fActiveWksIndex]; } + int32 ActiveWorkspaceIndex() const { return fActiveWksIndex; } + void SetActiveWorkspace(int32 index); + + void ReadWorkspaceData(const char *path); + void SaveWorkspaceData(const char *path); void SetScreens(Screen *screen[], int32 rows, int32 columns); Screen **Screens(void); bool SetScreenResolution(int32 width, int32 height, uint32 colorspace); int32 ScreenRows(void) const { return fRows; } int32 ScreenColumns(void) const { return fColumns; } - - void SetWorkspaceCount(const int32 count); - int32 WorkspaceCount(void) const; - Workspace *WorkspaceAt(const int32 index) const; - void SetActiveWorkspaceByIndex(const int32 index); - void SetActiveWorkspace(Workspace *ws); - int32 ActiveWorkspaceIndex(void) const; - Workspace *ActiveWorkspace(void) const; - + void SetBGColor(const RGBColor &col); RGBColor BGColor(void) const; - int32 Buttons(void); + int32 Buttons(void) { return fButtons; } virtual bool HasClient(void) { return false; } void AddWinBorderToWorkspaces(WinBorder *winBorder, uint32 wks); @@ -124,18 +121,17 @@ public: // Debug methods void PrintToStream(void); - // "Private" to app_server :-) - they should not be used - void RemoveAppWindow(WinBorder *wb); - - FMWList fMainFMWList; BRegion fRedrawReg; BList fCopyRegList; BList fCopyList; -// TODO: remove! Quick! - BLocker fMainLock; - private: +friend class Desktop; + // these are meant for Desktop class only! + void AddWinBorder(WinBorder* winBorder); + void RemoveWinBorder(WinBorder* winBorder); + void AddSubsetWinBorder(WinBorder *winBorder, WinBorder *toWinBorder); + void RemoveSubsetWinBorder(WinBorder *winBorder, WinBorder *fromWinBorder); void show_winBorder(WinBorder* winBorder); void hide_winBorder(WinBorder* winBorder); @@ -160,8 +156,12 @@ private: uint32 fColorSpace; int32 fButtons; - BList fWorkspaceList; - Workspace *fActiveWorkspace; + int32 fActiveWksIndex; + int32 fWsCount; + Workspace* fWorkspace[32]; + mutable WinBorder** fWinBorderList; + mutable int32 fWinBorderCount; + mutable int32 fWinBorderIndex; int32 fScreenShotIndex; bool fQuiting; diff --git a/src/servers/app/server/ServerApp.cpp b/src/servers/app/server/ServerApp.cpp index ae5f55190d..dac66521bb 100644 --- a/src/servers/app/server/ServerApp.cpp +++ b/src/servers/app/server/ServerApp.cpp @@ -66,7 +66,7 @@ # define STRACE(x) ; #endif -#define DEBUG_SERVERAPP_FONT +//#define DEBUG_SERVERAPP_FONT #ifdef DEBUG_SERVERAPP_FONT # include @@ -317,6 +317,57 @@ int32 ServerApp::MonitorApp(void *data) switch(code) { + case AS_CREATE_WINDOW: + { + // Create the ServerWindow to node monitor a new OBWindow + + // Attached data: + // 2) BRect window frame + // 3) uint32 window look + // 4) uint32 window feel + // 5) uint32 window flags + // 6) uint32 workspace index + // 7) int32 BHandler token of the window + // 8) port_id window's message port + // 9) const char * title + + BRect frame; + uint32 look; + uint32 feel; + uint32 flags; + uint32 wkspaces; + int32 token = B_NULL_TOKEN; + port_id sendPort = -1; + port_id looperPort = -1; + char *title = NULL; + port_id replyport = -1; + + msgqueue.Read(&frame); + msgqueue.Read((int32*)&look); + msgqueue.Read((int32*)&feel); + msgqueue.Read((int32*)&flags); + msgqueue.Read((int32*)&wkspaces); + msgqueue.Read(&token); + msgqueue.Read(&sendPort); + msgqueue.Read(&looperPort); + msgqueue.ReadString(&title); + + STRACE(("ServerApp %s: Got 'New Window' message, trying to do smething...\n",app->fSignature.String())); + + // ServerWindow constructor will reply with port_id of a newly created port + ServerWindow *sw = NULL; + sw = new ServerWindow(frame, title, look, feel, flags, app, + sendPort, looperPort, replyport, wkspaces, token); + sw->Init(); + + STRACE(("\nServerApp %s: New Window %s (%.1f,%.1f,%.1f,%.1f)\n", + app->fSignature.String(),title,frame.left,frame.top,frame.right,frame.bottom)); + + if (title) + free(title); + + break; + } case AS_QUIT_APP: { // This message is received only when the app_server is asked to shut down in @@ -548,57 +599,6 @@ void ServerApp::DispatchMessage(int32 code, LinkMsgReader &msg) } break; } - case AS_CREATE_WINDOW: - { - // Create the ServerWindow to node monitor a new OBWindow - - // Attached data: - // 2) BRect window frame - // 3) uint32 window look - // 4) uint32 window feel - // 5) uint32 window flags - // 6) uint32 workspace index - // 7) int32 BHandler token of the window - // 8) port_id window's message port - // 9) const char * title - - BRect frame; - uint32 look; - uint32 feel; - uint32 flags; - uint32 wkspaces; - int32 token = B_NULL_TOKEN; - port_id sendPort = -1; - port_id looperPort = -1; - char *title = NULL; - port_id replyport = -1; - - msg.Read(&frame); - msg.Read((int32*)&look); - msg.Read((int32*)&feel); - msg.Read((int32*)&flags); - msg.Read((int32*)&wkspaces); - msg.Read(&token); - msg.Read(&sendPort); - msg.Read(&looperPort); - msg.ReadString(&title); - - STRACE(("ServerApp %s: Got 'New Window' message, trying to do smething...\n",fSignature.String())); - - // ServerWindow constructor will reply with port_id of a newly created port - ServerWindow *sw = NULL; - sw = new ServerWindow(frame, title, look, feel, flags, this, - sendPort, looperPort, replyport, wkspaces, token); - sw->Init(); - - STRACE(("\nServerApp %s: New Window %s (%.1f,%.1f,%.1f,%.1f)\n", - fSignature.String(),title,frame.left,frame.top,frame.right,frame.bottom)); - - if (title) - free(title); - - break; - } case AS_CREATE_BITMAP: { STRACE(("ServerApp %s: Received BBitmap creation request\n",fSignature.String())); @@ -747,7 +747,7 @@ void ServerApp::DispatchMessage(int32 code, LinkMsgReader &msg) } case AS_ACTIVATE_WORKSPACE: { - STRACE(("ServerApp %s: Activate Workspace\n",fSignature.String())); + STRACE(("ServerApp %s: Activate Workspace UNIMPLEMETED\n",fSignature.String())); // Attached data // 1) int32 workspace index @@ -756,9 +756,6 @@ void ServerApp::DispatchMessage(int32 code, LinkMsgReader &msg) int32 workspace; msg.Read(&workspace); - RootLayer *root=desktop->ActiveRootLayer(); - if(root) - root->SetActiveWorkspaceByIndex(workspace); break; } @@ -1128,15 +1125,15 @@ void ServerApp::DispatchMessage(int32 code, LinkMsgReader &msg) // Returns: // 1) font_family The name of the font family // 2) font_style - name of the style - int32 famid, styid; + uint16 famid, styid; port_id replyport; font_family fam; font_style sty; - msg.Read(&famid); - msg.Read(&styid); + msg.Read(&famid); + msg.Read(&styid); msg.Read(&replyport); - + replylink.SetSendPort(replyport); fontserver->Lock(); @@ -1157,6 +1154,7 @@ void ServerApp::DispatchMessage(int32 code, LinkMsgReader &msg) } fontserver->Unlock(); + break; } case AS_GET_FONT_DIRECTION: diff --git a/src/servers/app/server/ServerApp.h b/src/servers/app/server/ServerApp.h index 2148176715..aaff1d08d7 100644 --- a/src/servers/app/server/ServerApp.h +++ b/src/servers/app/server/ServerApp.h @@ -78,7 +78,7 @@ public: team_id ClientTeamID(); FMWList fAppFMWList; - +const char * Title() const { return fSignature.String(); } protected: friend class AppServer; friend class ServerWindow; diff --git a/src/servers/app/server/ServerWindow.cpp b/src/servers/app/server/ServerWindow.cpp index fc05aa3d32..dd0b0d6e05 100644 --- a/src/servers/app/server/ServerWindow.cpp +++ b/src/servers/app/server/ServerWindow.cpp @@ -45,7 +45,6 @@ #include "ServerApp.h" #include "ServerProtocol.h" #include "WinBorder.h" -#include "Desktop.h" #include "TokenHandler.h" #include "Utils.h" #include "DisplayDriver.h" @@ -53,10 +52,10 @@ #include "Workspace.h" #include "MessagePrivate.h" -#define DEBUG_SERVERWINDOW +//#define DEBUG_SERVERWINDOW //#define DEBUG_SERVERWINDOW_MOUSE //#define DEBUG_SERVERWINDOW_KEYBOARD -#define DEBUG_SERVERWINDOW_GRAPHICS +//#define DEBUG_SERVERWINDOW_GRAPHICS #ifdef DEBUG_SERVERWINDOW @@ -150,7 +149,30 @@ ServerWindow::ServerWindow(BRect rect, const char *string, uint32 wlook, fClientLooperPort = looperPort; fClientTeamID = winapp->ClientTeamID(); fWorkspaces = index; - + + // floating and modal windows must appear in every workspace where + // their main window is present. Thus their wksIndex will be set to + // '0x0' and they will be made visible when needed. + switch (fFeel) + { + case B_MODAL_APP_WINDOW_FEEL: + case B_MODAL_SUBSET_WINDOW_FEEL: + case B_FLOATING_APP_WINDOW_FEEL: + case B_FLOATING_SUBSET_WINDOW_FEEL: + fWorkspaces = 0x0UL; + break; + case B_MODAL_ALL_WINDOW_FEEL: + case B_FLOATING_ALL_WINDOW_FEEL: + case B_SYSTEM_LAST: + case B_SYSTEM_FIRST: + fWorkspaces = 0xffffffffUL; + break; + case B_NORMAL_WINDOW_FEEL: + if (fWorkspaces == 0x0UL) + ;; +// TODO: get RootLayer's ActiveWorkspaceIndex + } + fWinBorder = NULL; cl = NULL; //current layer @@ -178,7 +200,6 @@ void ServerWindow::Init(void) { fWinBorder = new WinBorder( fFrame, fTitle.String(), fLook, fFeel, 0UL, this, desktop->GetDisplayDriver()); - fWinBorder->RebuildFullRegion(); // Spawn our message-monitoring thread fMonitorThreadID = spawn_thread(MonitorWin, fTitle.String(), B_NORMAL_PRIORITY, this); @@ -192,9 +213,14 @@ ServerWindow::~ServerWindow(void) { STRACE(("*ServerWindow (%s):~ServerWindow()\n",fTitle.String())); - desktop->RemoveWinBorder(fWinBorder); - STRACE(("ServerWindow(%s) Successfully removed from the desktop\n", fTitle.String())); - + if (fWinBorder) + { + delete fWinBorder; + fWinBorder = NULL; + } + + cl = NULL; + if(fMsgSender) { delete fMsgSender; @@ -206,14 +232,6 @@ ServerWindow::~ServerWindow(void) delete fMsgReader; fMsgReader=NULL; } - - if (fWinBorder) - { - delete fWinBorder; - fWinBorder = NULL; - } - - cl = NULL; STRACE(("#ServerWindow(%s) will exit NOW\n", fTitle.String())); } @@ -245,7 +263,7 @@ void ServerWindow::Quit(void) //! Shows the window's WinBorder void ServerWindow::Show(void) { - + STRACE(("ServerWindow %s: Show\n",fTitle.String())); if (!IsLocked()) debugger("you must lock a ServerWindow object before calling ::Show()\n"); @@ -258,6 +276,7 @@ void ServerWindow::Show(void) //! Hides the window's WinBorder void ServerWindow::Hide(void) { + STRACE(("ServerWindow %s: Hide\n",fTitle.String())); if (!IsLocked()) debugger("you must lock a ServerWindow object before calling ::Hide()\n"); @@ -565,7 +584,7 @@ Layer * ServerWindow::CreateLayerTree(Layer *localRoot, LinkMsgReader &link) link.Read(&childCount); STRACE(("ServerWindow(%s)::CreateLayerTree()-> layer %s, token %ld\n", fTitle.String(),name,token)); - + Layer *newLayer; newLayer = new Layer(frame, name, token, resizeMask, flags, desktop->GetDisplayDriver()); @@ -719,7 +738,7 @@ void ServerWindow::DispatchMessage(int32 code, LinkMsgReader &link) case AS_LAYER_CREATE_ROOT: { STRACE(("ServerWindow %s: Message AS_LAYER_CREATE_ROOT\n", fTitle.String())); - + // Start receiving top_view data -- pass NULL as the parent view. // This should be the *only* place where this happens. if (cl != NULL) @@ -732,8 +751,6 @@ void ServerWindow::DispatchMessage(int32 code, LinkMsgReader &link) // connect decorator and top layer. fWinBorder->AddChild(fWinBorder->fTopLayer, NULL); - desktop->AddWinBorder(fWinBorder); - break; } @@ -1439,7 +1456,9 @@ void ServerWindow::DispatchMessage(int32 code, LinkMsgReader &link) WinBorder *wb; int32 mainToken; team_id teamID; - + +printf("ServerWindow %s: Message AS_ADD_TO_SUBSET UNIMPLEMENTED\n",fTitle.String()); + link.Read(&mainToken); link.Read(&teamID, sizeof(team_id)); @@ -1449,7 +1468,7 @@ void ServerWindow::DispatchMessage(int32 code, LinkMsgReader &link) fMsgSender->StartMessage(SERVER_TRUE); fMsgSender->Flush(); - fWinBorder->AddToSubsetOf(wb); +// fWinBorder->AddToSubsetOf(wb); } else { @@ -1464,6 +1483,8 @@ void ServerWindow::DispatchMessage(int32 code, LinkMsgReader &link) WinBorder *wb; int32 mainToken; team_id teamID; + +printf("ServerWindow %s: Message AS_REM_FROM_SUBSET UNIMPLEMENTED\n",fTitle.String()); link.Read(&mainToken); link.Read(&teamID, sizeof(team_id)); @@ -1474,7 +1495,7 @@ void ServerWindow::DispatchMessage(int32 code, LinkMsgReader &link) fMsgSender->StartMessage(SERVER_TRUE); fMsgSender->Flush(); - fWinBorder->RemoveFromSubsetOf(wb); +// fWinBorder->RemoveFromSubsetOf(wb); } else { diff --git a/src/servers/app/server/WinBorder.cpp b/src/servers/app/server/WinBorder.cpp index 85763b94e8..8450aadb8b 100644 --- a/src/servers/app/server/WinBorder.cpp +++ b/src/servers/app/server/WinBorder.cpp @@ -88,8 +88,6 @@ WinBorder::WinBorder(const BRect &r, const char *name, const int32 look, const i fMouseButtons = 0; fKeyModifiers = 0; - fServerHidden = false; - fMainWinBorder = NULL; fDecorator = NULL; fTopLayer = NULL; fAdFlags = fAdFlags | B_LAYER_CHILDREN_DEPENDANT; @@ -107,6 +105,10 @@ WinBorder::WinBorder(const BRect &r, const char *name, const int32 look, const i if (feel!= B_NO_BORDER_WINDOW_LOOK) fDecorator = new_decorator(r, name, look, feel, flags, fDriver); + RebuildFullRegion(); + + desktop->AddWinBorder(this); + STRACE(("WinBorder %s:\n",GetName())); STRACE(("\tFrame: (%.1f,%.1f,%.1f,%.1f)\n",r.left,r.top,r.right,r.bottom)); STRACE(("\tWindow %s\n",win?win->Title():"NULL")); @@ -115,6 +117,9 @@ WinBorder::WinBorder(const BRect &r, const char *name, const int32 look, const i WinBorder::~WinBorder(void) { STRACE(("WinBorder(%s)::~WinBorder()\n",GetName())); + + desktop->RemoveWinBorder(this); + if (fTopLayer){ delete fTopLayer; fTopLayer = NULL; @@ -402,7 +407,14 @@ void WinBorder::Draw(const BRect &r) // if we have a visible region, it is decorator's one. if(fDecorator) + { + WinBorder *wb = GetRootLayer()->FocusWinBorder(); + if (wb && wb == this) + fDecorator->SetFocus(true); + else + fDecorator->SetFocus(false); fDecorator->Draw(fUpdateReg.Frame()); + } } //! Moves the winborder with redraw @@ -427,25 +439,6 @@ void WinBorder::ResizeBy(float x, float y) resize_layer(x,y); } -//! Returns true if hidden -bool WinBorder::IsHidden() const -{ - if (fServerHidden) - return true; - - return Layer::IsHidden(); -} - -void WinBorder::ServerHide() -{ - fServerHidden = true; -} - -void WinBorder::ServerUnhide() -{ - fServerHidden = false; -} - //! Sets the minimum and maximum sizes of the window void WinBorder::SetSizeLimits(float minwidth, float maxwidth, float minheight, float maxheight) { @@ -473,186 +466,6 @@ bool WinBorder::HasPoint(const BPoint& pt) const return fFullVisible.Contains(pt); } -void WinBorder::SetMainWinBorder(WinBorder *newMain) -{ - fMainWinBorder = newMain; -} - -WinBorder* WinBorder::MainWinBorder() const -{ - return fMainWinBorder; -} - -void WinBorder::SetLevel(void) -{ - switch(fServerWin->Feel()) - { - case B_NORMAL_WINDOW_FEEL: - fLevel = B_NORMAL_FEEL; - break; - case B_FLOATING_SUBSET_WINDOW_FEEL: - fLevel = B_FLOATING_SUBSET_FEEL; - break; - case B_FLOATING_APP_WINDOW_FEEL: - fLevel = B_FLOATING_APP_FEEL; - break; - case B_FLOATING_ALL_WINDOW_FEEL: - fLevel = B_FLOATING_ALL_FEEL; - break; - case B_MODAL_SUBSET_WINDOW_FEEL: - fLevel = B_MODAL_SUBSET_FEEL; - break; - case B_MODAL_APP_WINDOW_FEEL: - fLevel = B_MODAL_APP_FEEL; - break; - case B_MODAL_ALL_WINDOW_FEEL: - fLevel = B_MODAL_ALL_FEEL; - break; - case B_SYSTEM_LAST: - case B_SYSTEM_FIRST: - - // TODO: uncomment later when this code makes its way into the real server! -// if(_win->ServerTeamID() != _win->ClientTeamID()) -// _win->QuietlySetFeel(B_NORMAL_WINDOW_FEEL); -// else - fLevel = fServerWin->Feel(); - break; - default: - fServerWin->QuietlySetFeel(B_NORMAL_WINDOW_FEEL); - fLevel = B_NORMAL_FEEL; - break; - } -} - -// Makes the calling WinBorder a subset window of another -void WinBorder::AddToSubsetOf(WinBorder* main) -{ - STRACE(("WinBorder(%s)::AddToSubsetOf()\n", GetName())); - if (!main || (main && !(main->GetRootLayer()))) - return; - - if (main->Window()->fWinFMWList.HasItem(this) || !(desktop->HasWinBorder(this))) - return; - - if (main->Window()->Feel() == B_NORMAL_WINDOW_FEEL && - (Window()->Feel()==B_FLOATING_SUBSET_WINDOW_FEEL || Window()->Feel()==B_MODAL_SUBSET_WINDOW_FEEL) ) - { - // if the main window is hidden also hide this one. - if(main->IsHidden()) - Hide();//fHidden = true; - - // add to main window's subset - main->Window()->fWinFMWList.AddItem(this); - - // set this member accordingly - fMainWinBorder = main; - - // because this window is in a subset it should appear in the - // workspaces its main window appears in. - Window()->QuietlySetWorkspaces(main->Window()->Workspaces()); - - // this is a modal window, so add it to main window's workspaces. - if (Window()->Feel() == B_MODAL_SUBSET_WINDOW_FEEL) - { - RootLayer *rl = main->GetRootLayer(); - rl->fMainLock.Lock(); - rl->AddWinBorderToWorkspaces(this, main->Window()->Workspaces()); - rl->fMainLock.Unlock(); - } - - // this a *floating* window so if the main window is 'front', and add it to workspace. - if ( !(main->IsHidden()) && Window()->Feel() == B_FLOATING_SUBSET_WINDOW_FEEL) - { - RootLayer *rl = main->GetRootLayer(); - - desktop->fGeneralLock.Lock(); - STRACE(("WinBorder(%s)::AddToSubsetOf(%s) - General lock acquired\n", GetName(), main->GetName())); - - rl->fMainLock.Lock(); - STRACE(("WinBorder(%s)::AddToSubsetOf(%s) - Main lock acquired\n", GetName(), main->GetName())); - - for(int32 i = 0; i < rl->WorkspaceCount(); i++) - { - Workspace *ws = rl->WorkspaceAt(i+1); - if(ws->FrontLayer() == main) - ws->AddWinBorder(this); - } - - rl->fMainLock.Unlock(); - STRACE(("WinBorder(%s)::AddToSubsetOf(%s) - Main lock released\n", GetName(), main->GetName())); - - desktop->fGeneralLock.Unlock(); - STRACE(("WinBorder(%s)::AddToSubsetOf(%s) - General lock released\n", GetName(), main->GetName())); - } - } -} - -// Removes the calling WinBorder from the subset window of another -void WinBorder::RemoveFromSubsetOf(WinBorder* main) -{ - STRACE(("WinBorder(%s)::RemoveFromSubsetOf()\n", GetName())); - RootLayer *rl = main->GetRootLayer(); - - desktop->fGeneralLock.Lock(); - STRACE(("WinBorder(%s)::RemoveFromSubsetOf(%s) - General lock acquired\n", GetName(), main->GetName())); - - rl->fMainLock.Lock(); - STRACE(("WinBorder(%s)::RemoveFromSubsetOf(%s) - Main lock acquired\n", GetName(), main->GetName())); - - // remove from main window's subset list. - if(main->Window()->fWinFMWList.RemoveItem(this)) - { - int32 count = main->GetRootLayer()->WorkspaceCount(); - for(int32 i=0; i < count; i++) - { - if(main->Window()->Workspaces() & (0x00000001 << i)) - { - Workspace *ws = main->GetRootLayer()->WorkspaceAt(i+1); - - // if its main window is in 'i' workspaces, remove it from - // workspace 'i' if it's in there... - ws->RemoveWinBorder(this); - } - } - } - fMainWinBorder = NULL; - - rl->fMainLock.Unlock(); - STRACE(("WinBorder(%s)::RemoveFromSubsetOf(%s) - Main lock released\n", GetName(), main->GetName())); - - desktop->fGeneralLock.Unlock(); - STRACE(("WinBorder(%s)::RemoveFromSubsetOf(%s) - General lock released\n", GetName(), main->GetName())); -} - -//! Prints information about the WinBorder's current state -void WinBorder::PrintToStream() -{ - printf("\t%s", GetName()); - - if (fLevel == B_FLOATING_SUBSET_FEEL) - printf("\t%s", "B_FLOATING_SUBSET_WINDOW_FEEL"); - - if (fLevel == B_FLOATING_APP_FEEL) - printf("\t%s", "B_FLOATING_APP_WINDOW_FEEL"); - - if (fLevel == B_FLOATING_ALL_FEEL) - printf("\t%s", "B_FLOATING_ALL_WINDOW_FEEL"); - - if (fLevel == B_MODAL_SUBSET_FEEL) - printf("\t%s", "B_MODAL_SUBSET_WINDOW_FEEL"); - - if (fLevel == B_MODAL_APP_FEEL) - printf("\t%s", "B_MODAL_APP_WINDOW_FEEL"); - - if (fLevel == B_MODAL_ALL_FEEL) - printf("\t%s", "B_MODAL_ALL_WINDOW_FEEL"); - - if (fLevel == B_NORMAL_FEEL) - printf("\t%s", "B_NORMAL_WINDOW_FEEL"); - - printf("\t%s\n", IsHidden() ? "hidden" : "not hidden"); -} - // Unimplemented. Hook function for handling when system GUI colors change void WinBorder::UpdateColors(void) { @@ -676,3 +489,43 @@ void WinBorder::UpdateScreen(void) { STRACE(("WinBorder %s: UpdateScreen unimplemented\n",GetName())); } + +//--------------------- P R I V A T E ------------------- +void WinBorder::SetLevel() +{ + switch(fServerWin->Feel()) + { + case B_FLOATING_SUBSET_WINDOW_FEEL: + case B_FLOATING_APP_WINDOW_FEEL: + fLevel = B_FLOATING_APP; + break; + + case B_MODAL_SUBSET_WINDOW_FEEL: + case B_MODAL_APP_WINDOW_FEEL: + fLevel = B_MODAL_APP; + break; + + case B_NORMAL_WINDOW_FEEL: + fLevel = B_NORMAL; + break; + + case B_FLOATING_ALL_WINDOW_FEEL: + fLevel = B_FLOATING_ALL; + break; + + case B_MODAL_ALL_WINDOW_FEEL: + fLevel = B_MODAL_ALL; + break; + + case B_SYSTEM_LAST: + fLevel = B_SYSTEM_LAST; + break; + + case B_SYSTEM_FIRST: + fLevel = B_SYSTEM_FIRST; + break; + + default: + fLevel = B_NORMAL; + } +} \ No newline at end of file diff --git a/src/servers/app/server/WinBorder.h b/src/servers/app/server/WinBorder.h index f9aea1a92c..24234afdf2 100644 --- a/src/servers/app/server/WinBorder.h +++ b/src/servers/app/server/WinBorder.h @@ -31,6 +31,18 @@ #include #include #include "Layer.h" +#include "FMWList.h" + +// these are used by window manager to properly place window. +enum { + B_SYSTEM_LAST = -10L, + B_FLOATING_APP = 0L, + B_MODAL_APP = 1L, + B_NORMAL = 2L, + B_FLOATING_ALL = 3L, + B_MODAL_ALL = 4L, + B_SYSTEM_FIRST = 10L, +}; class ServerWindow; class Decorator; @@ -66,10 +78,6 @@ public: virtual void RebuildFullRegion(void); - virtual bool IsHidden() const; - void ServerHide(); - void ServerUnhide(); - void SetSizeLimits(float minwidth, float maxwidth, float minheight, float maxheight); void MouseDown(PointerEvent& evt, bool sendMessage); @@ -84,21 +92,16 @@ public: virtual bool HasClient(void) { return false; } Decorator *GetDecorator(void) const { return fDecorator; } - WinBorder *MainWinBorder() const; - void SetLevel(); void HighlightDecorator(const bool &active); bool HasPoint(const BPoint &pt) const; - void AddToSubsetOf(WinBorder* main); - void RemoveFromSubsetOf(WinBorder* main); - - void PrintToStream(); - - // Server "private" :-) - should not be used - void SetMainWinBorder(WinBorder *newMain); - + FMWList fFMWList; + +private: + void SetLevel(); + protected: friend class Layer; friend class ServerWindow; @@ -111,8 +114,6 @@ protected: int32 fKeyModifiers; BPoint fLastMousePosition; - bool fServerHidden; - WinBorder *fMainWinBorder; bool fIsMoving; bool fIsResizing; bool fIsClosing; diff --git a/src/servers/app/server/Workspace.cpp b/src/servers/app/server/Workspace.cpp index 5c6055bee5..64ab589789 100644 --- a/src/servers/app/server/Workspace.cpp +++ b/src/servers/app/server/Workspace.cpp @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// Copyright (c) 2001-2002, Haiku, Inc. +// 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"), @@ -20,17 +20,50 @@ // DEALINGS IN THE SOFTWARE. // // File Name: Workspace.cpp -// Author: Adi Oanca +// 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! +// 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. Aditionaly 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 (AddWinBorder()) 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. //------------------------------------------------------------------------------ -#include -#include #include +#include #include #include "Workspace.h" @@ -39,7 +72,6 @@ #include "ServerWindow.h" #include "ServerApp.h" #include "RGBColor.h" -#include "Globals.h" #include "FMWList.h" //#define DEBUG_WORKSPACE @@ -59,23 +91,25 @@ #endif //---------------------------------------------------------------------------------- - -Workspace::Workspace(const uint32 colorspace, int32 ID, const RGBColor& BGColor) +/*! + \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; fSpace = colorspace; - fBGColor = BGColor; fBottomItem = NULL; fTopItem = NULL; - fCurrentItem= NULL; fFocusItem = NULL; fFrontItem = NULL; fVirtualWidth=-1; fVirtualHeight=-1; - - // TODO: find out more about good default values for display timing and init the structure to them + + // TODO: find out more about good default values and init the structure to them fDisplayTiming.pixel_clock=0; fDisplayTiming.h_display=0; fDisplayTiming.h_sync_start=0; @@ -89,1262 +123,815 @@ Workspace::Workspace(const uint32 colorspace, int32 ID, const RGBColor& BGColor) } //---------------------------------------------------------------------------------- - +/*! + \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; - delete toast; + fPool.ReleaseMemory(toast); } fBottomItem = NULL; fTopItem = NULL; - fCurrentItem = NULL; - fFocusItem = NULL; - fFrontItem = NULL; } //---------------------------------------------------------------------------------- -/* - Adds layer ptr to workspace's list of WinBorders. After the item is added a - *smart* search is performed to set the new front WinBorder. Of course, - the first candidate is 'layer', but if it is hidden or it has the - B_AVOID_FRONT flag, surely it won't get that status. - This method also calls SearchAndSetNewFocus which searches for a WinBorder, - to give focus to, having as preferred 'layer'. - Remember, some windows having B_AVOID_FOCUS can't have the focus state. +/*! + \brief Adds layer ptr to workspace's list of WinBorders. */ -bool Workspace::AddWinBorder(WinBorder *layer) +void Workspace::AddWinBorder(WinBorder *winBorder) { - if (layer == NULL) - debugger("NULL pointer in Workspace::AddLayerPtr\n"); +STRACE(("W(%ld)::AddWinBorder(%s)\n", fID, winBorder?winBorder->GetName():"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("WinBorder ALREADY in Workspace's list\n"); + return; + } // allocate a new item - ListData *item; - item = new ListData; - - item->layerPtr = layer; - item->upperItem = NULL; - item->lowerItem = NULL; + ListData *item = fPool.GetCleanMemory(winBorder); - // insert 'item' at the end. It doesn't matter where we add it, - // it will be placed correctly by SearchAndSetNewFront(item->layerPtr); - InsertItem(item, NULL); - - STRACE(("\n*AddLayerPtr(%s) -", layer->GetName())); - - BringToFrontANormalWindow(layer); - - // do a *smart* search and set the new 'front' - SearchAndSetNewFront(layer); - - // do a *smart* search and set the new 'focus' - SearchAndSetNewFocus(layer); - - return true; + // place this winBorder in what seems the most appropriate location. + // Do not change front window + placeInFront(item, false); } //---------------------------------------------------------------------------------- /* - Removes a WinBorder from workspace's list. It DOES NOT delete it! - If this window was the front/focus one it calls SearchAndSetNew(Front/Focus) - to give the respective state to the window below her. + \brief Removes a WinBorder from workspace's list. */ -bool Workspace::RemoveWinBorder(WinBorder *layer) +void Workspace::RemoveWinBorder(WinBorder *winBorder) { - if (layer == NULL) - return false; - - STRACE(("\n*Workspace(%ld)::RemoveLayerPtr(%s)\n", ID(), layer->GetName())); - STRACE(("BEFORE ANY opperation:\n")); - STRACESTREAM(); - - // search to see if this workspace has WinBorder's pointer in its list - ListData *item = NULL; - - if((item = HasItem(layer))) +STRACE(("W(%ld)::RemoveWinBorder(%s)\n", fID, winBorder?winBorder->GetName():"NULL")); + ListData *item = HasItem(winBorder); + if (item) { - ListData *nextItem = NULL; - bool wasFront = false; - bool wasFocus = false; - - wasFront = FrontLayer() == layer; - wasFocus = FocusLayer() == layer; - - // prepare to set new front/focus if this layer was front/focus - nextItem = item->upperItem; - - if(wasFront) - SearchAndSetNewFront(nextItem? nextItem->layerPtr: NULL); - - // remove some windows. - if(item && item->layerPtr->fLevel == B_NORMAL_FEEL) - { - ListData *listItem = item->lowerItem; - while(listItem && (listItem->layerPtr->fLevel == B_FLOATING_SUBSET_FEEL - || listItem->layerPtr->fLevel == B_FLOATING_APP_FEEL - || listItem->layerPtr->fLevel == B_MODAL_SUBSET_FEEL)) - { - // *carefuly* remove the item from the list - ListData *itemX = listItem; - listItem = listItem->lowerItem; - RemoveItem(itemX); - delete itemX; - } - } - RemoveItem(item); - delete item; - STRACESTREAM(); - - // reset some internal variables - layer->SetMainWinBorder(NULL); - - STRACE(("Layer %s found and removed from Workspace No %ld\n", layer->GetName(), ID())); - - SearchAndSetNewFocus(nextItem? nextItem->layerPtr: NULL); - - return true; - } - else - { - STRACE(("Layer %s NOT found in Workspace No %ld\n", layer->GetName(), ID())); - return false; + fPool.ReleaseMemory(item); } } //---------------------------------------------------------------------------------- -bool Workspace::HideSubsetWindows(WinBorder *layer) +bool Workspace::HasWinBorder(const WinBorder* winBorder) const { - if(!layer) - return false; - - // search to see if this workspace has WinBorder's pointer in its list - ListData *item = NULL; - - if((item = HasItem(layer))) - { - ListData *nextItem = NULL; - - // prepare to set new front/focus if this layer was front/focus - nextItem = item->upperItem; - - SearchAndSetNewFront(nextItem? nextItem->layerPtr: NULL); - - // we don't care about focus in this method - //SearchAndSetNewFocus(nextItem? nextItem->layerPtr: NULL); - - // remove some windows. - if(item && item->layerPtr->fLevel == B_NORMAL_FEEL) - { - ListData *listItem = item->lowerItem; - while(listItem && (listItem->layerPtr->fLevel == B_FLOATING_SUBSET_FEEL - || listItem->layerPtr->fLevel == B_FLOATING_APP_FEEL - || listItem->layerPtr->fLevel == B_MODAL_SUBSET_FEEL)) - { - // carefully remove the item from the list - ListData *itemX = listItem; - listItem = listItem->lowerItem; - RemoveItem(itemX); - delete itemX; - } - } - - return true; - } - else - { - return false; - } + return HasItem(winBorder)? true: false; } //---------------------------------------------------------------------------------- -WinBorder *Workspace::FocusLayer() const +WinBorder *Workspace::Focus() const { return fFocusItem ? fFocusItem->layerPtr : NULL; } //---------------------------------------------------------------------------------- -WinBorder *Workspace::FrontLayer() const +WinBorder *Workspace::Front() const { return fFrontItem? fFrontItem->layerPtr: NULL; } //---------------------------------------------------------------------------------- - -WinBorder *Workspace::GoToBottomItem(void) +/* + \brief This method provides you the list of visible windows in this workspace. + \param list The list of visible WinBorders found in this workspace. + \param itemCount Number of WinBorder pointers found in the list. +*/ +void Workspace::GetWinBorderList(void **&list, int32 *itemCount ) const { - fCurrentItem = fBottomItem; - return fCurrentItem ? fCurrentItem->layerPtr : NULL; -} + int32 count = 0; + ListData *cursor; -//---------------------------------------------------------------------------------- - -WinBorder *Workspace::GoToUpperItem(void) -{ - if(fCurrentItem) + cursor = fBottomItem; + while(cursor) { - fCurrentItem = fCurrentItem->upperItem; - return fCurrentItem ? fCurrentItem->layerPtr : NULL; + if (!cursor->layerPtr->IsHidden()) + count++; + cursor = cursor->upperItem; + } + + if (count == 0) + { + *itemCount = 0; + list = NULL; + return; + } + + void **mylist; + mylist = (void**)malloc(sizeof(void*) * count); + if (mylist) + { + list = mylist; + *itemCount = count; + + cursor = fBottomItem; + while(cursor) + { + if (!cursor->layerPtr->IsHidden()) + { + *mylist = cursor->layerPtr; + mylist++; + } + cursor = cursor->upperItem; + } } else - return NULL; -} - -//---------------------------------------------------------------------------------- - -WinBorder *Workspace::GoToTopItem(void) -{ - fCurrentItem = fTopItem; - return fCurrentItem ? fCurrentItem->layerPtr : NULL; -} - -//---------------------------------------------------------------------------------- - -WinBorder *Workspace::GoToLowerItem(void) -{ - if(fCurrentItem) { - fCurrentItem = fCurrentItem->lowerItem; - return fCurrentItem ? fCurrentItem->layerPtr : NULL; + list = NULL; + itemCount = 0; } - else - return NULL; } - + //---------------------------------------------------------------------------------- +/*! + \brief Makes the specified WinBorder the front one. + \param newFront WinBorder 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 WinBorders has changed, false otherwise. -bool Workspace::GoToItem(WinBorder *layer) + This method tries to make \a newFront the new front WinBorder. "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(WinBorder *newFront, bool doNotDisturb) { - if(!layer) +STRACE(("\nWks(%ld)::MoveToFront ~%s~ \n", fID, newFront?newFront->GetName():"NULL")); + if (!newFront) return false; - if(fCurrentItem && fCurrentItem->layerPtr == layer) - return true; - - for( ListData *item = fBottomItem; item != NULL; item = item->upperItem) + if (newFront->IsHidden()) + return false; + + if (fFrontItem && newFront == fFrontItem->layerPtr) { - if(item->layerPtr == layer) + // in case this normal window is the front window, + // BUT it does not have focus. + ListData *newFocusItem = HasItem(newFront); + if (newFocusItem && fFocusItem != newFocusItem + && !(newFront->Window()->Flags() & B_AVOID_FOCUS)) { - fCurrentItem = item; - return true; + fFocusItem = newFocusItem; } + + // we didn't change windows order + return false; } - return false; -} - -//---------------------------------------------------------------------------------- - -ListData *Workspace::HasItem(ListData *item) -{ - for (ListData *itemX = fBottomItem; itemX != NULL; itemX = itemX->upperItem) - { - if(item == itemX) - return itemX; - } - return NULL; -} - -//---------------------------------------------------------------------------------- - -ListData *Workspace::HasItem(WinBorder *layer) -{ - for (ListData *item = fBottomItem; item != NULL; item = item->upperItem) - { - if(item->layerPtr == layer) - return item; - } - return NULL; -} - -//---------------------------------------------------------------------------------- -/* - This, also is a "smart" method. Firstly this funtionality was in - SearchAndSetNewFront, but I've split it for reasons of clarity. Anyway, - what is to be noticed is that those 2 methods work hand-in-hand. - What FindPlace() litelaly does, isplace* the 'pref' item into its - >right< place! If 'pref->layerPtr'(the WinBorder in ListData structure) - does not meet some conditions a search for another, valid, WinBorder is - being made. - - NOTE: Do NOT be confussed! This method places the preferred windowONLY*! - Other windows that need to be placed before it, *WILL* be placed by almost - all code found in SearchAndSetNewFront -*/ -ListData *Workspace::FindPlace(ListData *pref) -{ - // if we received a NULL value, we stil have to give 'front' state to some window... - if(!pref) - pref = HasItem(fBottomItem); else - pref = HasItem(pref); + return ShowWinBorder(newFront); +} - ListData *item = NULL; +//---------------------------------------------------------------------------------- +/*! + \brief Moves the specified WinBorder in the back as it is possible. + \param newLast WinBorder which will be placed in the back. + \return True if the list of WinBorders has changed, false otherwise. - // search a window that is not hidden and does *not* have B_AVOID_FRONT flag. - item = pref; - while(pref && item->lowerItem != pref && (pref->upperItem || pref->lowerItem)) + WinBorder \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(WinBorder *newLast) +{ +STRACE(("Wks(%ld)::MoveToBack(%s) \n", fID, newLast? newLast->GetName(): "NULL")); + if (newLast->IsHidden()) + return false; + + ListData *newLastItem; + newLastItem = HasItem(newLast); + if (!newLastItem) + return false; + + 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()) { - if( !(item->layerPtr->Window()->Flags() & B_AVOID_FRONT) && !(item->layerPtr->IsHidden()) ) - break; - - STRACE(("item: %s - pref: %s\n", item->layerPtr->GetName(), pref->layerPtr->GetName())); - - if(item == fTopItem) - item = fBottomItem; - else - item = item->upperItem; - } - - // if true, it means we have windows with B_AVOID_FRONT flag *only*, - // or they are all hidden. Pick one, if you can. - if(pref && item->lowerItem == pref) - { - for (item = fBottomItem; item; item = item->upperItem) - { - if( !(item->layerPtr->IsHidden()) ) - break; - } - } - - // if the search took place or not... - pref = item; - - // we have exhausted all possibilities to make pref a vaid pointer... so... exit now. - if(!pref) - return NULL; - - // temporarily remove 'pref' to reinsert it later in the right place - RemoveItem(pref); - - // we start searching its place - ListData *cursor = fBottomItem; - int32 feel = pref->layerPtr->Window()->Feel(); - - switch(feel) - { - case B_NORMAL_WINDOW_FEEL: - { - while(cursor && cursor->layerPtr->fLevel > B_MODAL_APP_FEEL) - cursor = cursor->upperItem; - - InsertItem(pref, cursor? cursor->lowerItem: NULL); - break; - } - + case B_MODAL_ALL: + case B_SYSTEM_FIRST: case B_SYSTEM_LAST: { - while(cursor && cursor->layerPtr->fLevel > pref->layerPtr->fLevel) - cursor = cursor->upperItem; - - InsertItem(pref, cursor? cursor->lowerItem: fTopItem); - break; + // these kind of windows do not change position + return false; } - - case B_SYSTEM_FIRST: - case B_FLOATING_ALL_WINDOW_FEEL: - case B_MODAL_ALL_WINDOW_FEEL: - case B_MODAL_APP_WINDOW_FEEL: + break; + case B_NORMAL: { - while(cursor && cursor->layerPtr->fLevel > pref->layerPtr->fLevel) - cursor = cursor->upperItem; - - InsertItem(pref, cursor? cursor->lowerItem: NULL); - break; - } + ListData *cursor = newLastItem->upperItem; - case B_FLOATING_SUBSET_WINDOW_FEEL: + // 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: { - // place in front of: its main window, other subset windows and in front - // of other application's floating windows. - // NOTE that this happens only if its main window is the front most one. - for(cursor = fBottomItem; cursor; cursor = cursor->upperItem) + 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()->fAppFMWList.HasItem(newLast)) { - if(cursor->layerPtr->fLevel <= pref->layerPtr->fLevel - && (cursor->layerPtr == pref->layerPtr->MainWinBorder() - || cursor->layerPtr->MainWinBorder() == pref->layerPtr->MainWinBorder()) ) + ListData *before; + + // remove now to properly place later + RemoveItem(newLastItem); + + while (cursor) { - break; - } - else - if(pref->layerPtr->fLevel == B_FLOATING_SUBSET_FEEL && - cursor->layerPtr->fLevel == B_FLOATING_APP_FEEL) - { - break; - } - } - if(cursor) - InsertItem(pref, cursor? cursor->lowerItem: NULL); - break; - } - - case B_MODAL_SUBSET_WINDOW_FEEL: - { - // place this SUBSET_MODAL behind APP_MODAL ones if they belong - // to the same application OR, in front of all MODAL/NORMAL if - // it belongs to another application - - for(cursor = fBottomItem; cursor; cursor = cursor->upperItem) - { - if(cursor->layerPtr->fLevel <= pref->layerPtr->fLevel) - break; - else - if(pref->layerPtr->fLevel == B_MODAL_SUBSET_FEEL && - cursor->layerPtr->fLevel == B_MODAL_APP_FEEL && - pref->layerPtr->Window()->ClientTeamID() != cursor->layerPtr->Window()->ClientTeamID()) - { - break; - } - } - - if(cursor) - InsertItem(pref, cursor? cursor->lowerItem: NULL); - - break; - } - - case B_FLOATING_APP_WINDOW_FEEL: - { - // place in front of: its main window, other floating windows - // NOTE that this happens only if its main window is the front most one. - for(cursor = fBottomItem; cursor; cursor = cursor->upperItem) - { - if(cursor->layerPtr->fLevel <= pref->layerPtr->fLevel && - pref->layerPtr->Window()->ClientTeamID() == cursor->layerPtr->Window()->ClientTeamID()) - { - break; - } - } - - if(cursor) - InsertItem(pref, cursor? cursor->lowerItem: NULL); - - break; - } - } - - return pref; -} - -//---------------------------------------------------------------------------------- -/* - This method is the key to correct window arangement - With the help of FindPlace it correctly aranges windows. FindPlace, only - inserted the window in the correct place, this method also brings all - other windows that are supposed to be in front of her - I'm talking here - about floating and modal windows. - It also cleverly selects the new FINAL front window. - */ -void Workspace::SearchAndSetNewFront(WinBorder *preferred) -{ - STRACE(("*WS(%ld)::SASNF(%s)\n", ID(), preferred? preferred->GetName(): "NULL")); - - // the new front must not be the same as the previous one. - if(fFrontItem && fFrontItem->layerPtr == preferred && !(preferred->IsHidden())) - { - STRACE(("-WS(%ld)::SASNF(%s) - opperation not needed! Workspace data:", - ID(), preferred? preferred->GetName(): "NULL")); - STRACESTREAM(); - STRACE(("#WS(%ld)::SASNF(%s) ENDED 1\n", ID(), preferred? preferred->GetName(): "NULL")); - - return; - } - - // properly place this 'preferred' WinBorder. - ListData *lastInserted; - lastInserted = FindPlace(HasItem(preferred)); - preferred = lastInserted? lastInserted->layerPtr: NULL; - - STRACE(("-WS(%ld)::SASNF(%s) - after FindPlace...", ID(), preferred? preferred->GetName(): "NULL")); - STRACESTREAM(); - - // if the new front layer is the same... there is no point continuing - if(fFrontItem == lastInserted) - { - STRACE(("-WS(%ld)::SASNF(%s) - new front layer is the same as the old one. Stop!", ID(), preferred? preferred->GetName(): "NULL")); - STRACESTREAM(); - STRACE(("#WS(%ld)::SASNF(%s) ENDED 2\n", ID(), preferred? preferred->GetName(): "NULL")); - - return; - } - - if(!lastInserted) - { - STRACE(("PAAAAANIC: Workspace::SASNF(): 'lastInserted' IS NULL\n")); - } - else - { - STRACE(("\n&&&&Processing for: %s\n", lastInserted->layerPtr->GetName())); - } - - if(lastInserted && !(lastInserted->layerPtr->IsHidden())) - { - int32 prefFeel = preferred->Window()->Feel(); - - if(prefFeel == B_NORMAL_WINDOW_FEEL) - { - STRACE((" NORMAL Window '%s' -", preferred? preferred->GetName(): "NULL")); - - if(fFrontItem) - { - // if they are in the same team... - if(preferred->Window()->ClientTeamID() == fFrontItem->layerPtr->Window()->ClientTeamID()) - { - STRACE((" SAME TeamID\n")); - - // collect subset windows that are common to application's windows... - // NOTE: A subset window *can* be added to more than just one window. - FMWList commonFMW; - FMWList appFMW; - FMWList finalFMWList; - int32 count, i; - - // collect floating and modal windows spread across the workspace only if - // they are in our window's subset - // * also remove them, for repositioning, later. - ListData *listItem = fTopItem; - while(listItem) + if (!cursor->layerPtr->IsHidden() + && cursor->layerPtr->Level() > B_SYSTEM_LAST + && cursor->layerPtr->App()->ClientTeamID() == newLast->App()->ClientTeamID()) { - int32 feel = listItem->layerPtr->Window()->Feel(); - if(feel == B_FLOATING_SUBSET_WINDOW_FEEL || feel == B_MODAL_SUBSET_WINDOW_FEEL) + break; + } + cursor = cursor->upperItem; + } + + if (cursor) + before = cursor->lowerItem; + else + before = fTopItem; + + InsertItem(newLastItem, before); + } + // this is a modal subset + else + { + // 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->fFMWList.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()->ClientTeamID() == newLast->App()->ClientTeamID()) + { + indexCursor = mainWindowItem->layerPtr->fFMWList.IndexOf(cursor->layerPtr); + if (indexCursor >= 0) { - if(preferred->Window()->fWinFMWList.HasItem(listItem->layerPtr)) + if (indexThis < indexCursor) { - commonFMW.AddItem(listItem->layerPtr); - - // *carefully* remove the item from the list - ListData *item = listItem; - listItem = listItem->lowerItem; - RemoveItem(item); - } - else - if(feel == B_FLOATING_SUBSET_WINDOW_FEEL) - { - // also remove floating windows. Those, SURELY belong to - // 'fFrontItem' - this being the *old* front window. - - // *carefully* remove the item from the list - ListData *item = listItem; - listItem = listItem->lowerItem; - RemoveItem(item); + before = cursor; + break; } else { - listItem = listItem->lowerItem; + before = cursor->lowerItem; } } - else if(feel == B_FLOATING_APP_WINDOW_FEEL || feel == B_MODAL_APP_WINDOW_FEEL) - { - // ALSO collect application's floating and modal windows, - // for reinsertion, later. - - if(listItem->layerPtr->Window()->ClientTeamID() == - preferred->Window()->ClientTeamID()) - { - appFMW.AddItem(listItem->layerPtr); - - // *carefully* remove the item from the list - ListData *item = listItem; - listItem = listItem->lowerItem; - RemoveItem(item); - } - else - listItem = listItem->lowerItem; - } - else - listItem = listItem->lowerItem; } - - // put in the final list, items that are not found in the common list - count = preferred->Window()->fWinFMWList.CountItems(); - for (i=0; iWindow()->fWinFMWList.ItemAt(i); - - if(!commonFMW.HasItem(item)) - finalFMWList.AddItem(item); - } - - // collapse the 2 lists - finalFMWList.AddFMWList(&commonFMW); - finalFMWList.AddFMWList(&appFMW); - - // insert windows found in 'finalFMWList' in Workspace's list. - // IF *one* modal is found, do not add floating ones! - - // see if the last WinBorder in the list is a modal window. - // OR if the last one in Workspace's list is a modal window... - WinBorder *wb = (WinBorder*)finalFMWList.LastItem(); - bool lastIsModal = false; - if( (wb && - (wb->Window()->Feel() == B_MODAL_SUBSET_WINDOW_FEEL - || wb->Window()->Feel() == B_MODAL_APP_WINDOW_FEEL)) - || (fBottomItem && - (fBottomItem->layerPtr->Window()->Feel() == B_MODAL_ALL_WINDOW_FEEL - || fBottomItem->layerPtr->Window()->Feel() == B_SYSTEM_FIRST)) - ) - { lastIsModal = true; } - - // this variable will help us in deciding the new front WinBorder. - WinBorder *finalPreferred = preferred; - // now insert items found in finalFMWList into Workspace - count = finalFMWList.CountItems(); - for(i=0; iWindow()->Feel() == B_FLOATING_SUBSET_WINDOW_FEEL - || wb->Window()->Feel() == B_FLOATING_APP_WINDOW_FEEL) - { - // set its new MainWinBorder - if(wb->Window()->Feel() == B_FLOATING_SUBSET_WINDOW_FEEL) - wb->SetMainWinBorder(preferred); - // don't add if the last WinBorder is a modal one. - if(lastIsModal) - continue; - } - else - { - if(wb->Window()->Feel() == B_MODAL_SUBSET_WINDOW_FEEL) - wb->SetMainWinBorder(preferred); - // if this modal window is not hidden, give it the front status. - if(!(wb->IsHidden())) - finalPreferred = wb; - } - - // insert item just after the last inserted one. - ListData *newItem = new ListData(); - newItem->layerPtr = wb; - newItem->lowerItem = lastInserted->lowerItem; - newItem->upperItem = lastInserted; - if(lastInserted->lowerItem) - lastInserted->lowerItem->upperItem = newItem; - lastInserted->lowerItem = newItem; - - if(lastInserted == fBottomItem) - fBottomItem = newItem; - - lastInserted = newItem; - } - preferred = finalPreferred; - } - else - { - STRACE((" DIFERRENT TeamID\n")); - - // remove front window's floating(_SUBSET_/_APP_) windows, if any. - ListData *listItem = fFrontItem->lowerItem; - - while(listItem && (listItem->layerPtr->fLevel == B_FLOATING_SUBSET_FEEL - || listItem->layerPtr->fLevel == B_FLOATING_APP_FEEL)) - { - // *carefully* remove the item from the list - ListData *item = listItem; - listItem = listItem->lowerItem; - RemoveItem(item); - } - - // now, jump to et1: to make a 'clean' selecting of - // windows to be inserted - fFrontItem = NULL; - goto et1; - } // END: else - if different ClientTeamIDs. - - } // if(fFrontItem) && NORMAL_WINDOW - else - { - STRACE((" NO previous FRONT Item\n")); - et1: - FMWList finalFMWList; - int32 count, i; - ListData *listItem = fTopItem; - // remove window's subset and application's *modal* windows spread - // across Workspace's list, to be insert later, in the corect order. - while(listItem) - { - int32 feel = listItem->layerPtr->Window()->Feel(); - if((feel == B_MODAL_SUBSET_WINDOW_FEEL - && preferred->Window()->fWinFMWList.HasItem(listItem->layerPtr)) - || (feel == B_MODAL_APP_WINDOW_FEEL - && preferred->Window()->ClientTeamID() == - listItem->layerPtr->Window()->ClientTeamID() - )) - { - // *carefully* remove the item from the list - ListData *item = listItem; - listItem = listItem->lowerItem; - RemoveItem(item); - } - else - listItem = listItem->lowerItem; + cursor = cursor->lowerItem; } - // add to the final list window's subset windows. (..._SUBSET_...) - finalFMWList.AddFMWList(&(preferred->Window()->fWinFMWList)); - - // also add application's ones. (..._APP_...) - finalFMWList.AddFMWList(&(preferred->Window()->App()->fAppFMWList)); - - // insert windows found in 'finalFMWList' in Workspace's list. - // IF *one* modal is found, do not add floating ones! - - // see if the last WinBorder in the list is a modal window. - WinBorder *wb = (WinBorder*)finalFMWList.LastItem(); - bool lastIsModal = false; - - if( (wb && (wb->Window()->Feel() == B_MODAL_SUBSET_WINDOW_FEEL || - wb->Window()->Feel() == B_MODAL_APP_WINDOW_FEEL)) || - (fBottomItem && (fBottomItem->layerPtr->Window()->Feel() == B_MODAL_ALL_WINDOW_FEEL || - fBottomItem->layerPtr->Window()->Feel() == B_SYSTEM_FIRST)) - ) - { - lastIsModal = true; - } - - // this variable will help us in deciding the new front WinBorder. - WinBorder *finalPreferred = preferred; - - // now insert items found in finalFMWList into Workspace - count = finalFMWList.CountItems(); - for(i=0; iWindow()->Feel() == B_FLOATING_SUBSET_WINDOW_FEEL || - wb->Window()->Feel() == B_FLOATING_APP_WINDOW_FEEL) - { - // set its new MainWinBorder - if(wb->Window()->Feel() == B_FLOATING_SUBSET_WINDOW_FEEL) - wb->SetMainWinBorder(preferred); - - // don't add if the last WinBorder is a modal one. - if(lastIsModal) - continue; - } - else - { - if(wb->Window()->Feel() == B_MODAL_SUBSET_WINDOW_FEEL) - wb->SetMainWinBorder(preferred); - - // if this modal window is not hidden, give it the front status. - if(!(wb->IsHidden())) - finalPreferred = wb; - } - - // insert item just after the last inserted one. - ListData *newItem = new ListData(); - newItem->layerPtr = wb; - newItem->lowerItem = lastInserted->lowerItem; - newItem->upperItem = lastInserted; - if(lastInserted->lowerItem) - lastInserted->lowerItem->upperItem = newItem; - lastInserted->lowerItem = newItem; - - if(lastInserted == fBottomItem) - fBottomItem = newItem; - - lastInserted = newItem; - } - preferred = finalPreferred; - } // else - if(fFrontItem); - - } // END: if _NORMAL_ window. - else - if( prefFeel == B_FLOATING_SUBSET_WINDOW_FEEL || - prefFeel == B_FLOATING_APP_WINDOW_FEEL || - prefFeel == B_FLOATING_ALL_WINDOW_FEEL) - { - STRACE((" FLOATING Window '%s'\n", preferred? preferred->GetName(): "NULL")); - // Do nothing! FindPlace() was called and it has corectly placed our window - // We don't have to do noting here. - } - else - if( prefFeel == B_MODAL_SUBSET_WINDOW_FEEL || - prefFeel == B_MODAL_APP_WINDOW_FEEL) - { - STRACE((" MODAL_APP/SUBSET Window '%s'\n", preferred? preferred->GetName(): "NULL")); - - FMWList finalMWList; - int32 count = 0, i; - int32 prefIndex = -1; - - if(fFrontItem && fFrontItem->layerPtr->fLevel == B_NORMAL_FEEL) - { - // remove front window's floating(_SUBSET_/_APP_) windows, if any. - ListData *listItem = fFrontItem->lowerItem; - while(listItem && (listItem->layerPtr->fLevel == B_FLOATING_SUBSET_FEEL || - listItem->layerPtr->fLevel == B_FLOATING_APP_FEEL)) - { - // *carefully* remove the item from the list - ListData *item = listItem; - listItem = listItem->lowerItem; - RemoveItem(item); - } + InsertItem(newLastItem, before); } - - // If this is a MODAL_SUBSET window, search it's place in its MainWinBorder - // window subset, and then take all modals after it; then continue talking - // modal windoes *only*, from application's set. - // If it is a MODAL_APP only search an take windows in/from application's set - if(prefFeel == B_MODAL_SUBSET_WINDOW_FEEL) - { - prefIndex = preferred->MainWinBorder()->Window()->fWinFMWList.IndexOf(preferred); - count = preferred->MainWinBorder()->Window()->fWinFMWList.CountItems(); - - if(prefIndex >= 0) - { - WinBorder *wb = NULL; - - // add modal windows from its main window subset - windows that are - // positioned after 'preferred'. - FMWList *listPtr = &(preferred->MainWinBorder()->Window()->fWinFMWList); - for(i = prefIndex+1; i < count; i++) - { - // they *all* are modal windows. - wb = (WinBorder*)listPtr->ItemAt(i); - wb->SetMainWinBorder(preferred); - finalMWList.AddItem(wb); - - // remove those windows(if in there), for correct re-insertion later. - ListData *ld = NULL; - if((ld = HasItem(wb))) - RemoveItem(ld); - } - - // add modal windows that are found in application's subset - count = preferred->Window()->App()->fAppFMWList.CountItems(); - listPtr = &(preferred->Window()->App()->fAppFMWList); - for(i = 0; i < count; i++) - { - wb = (WinBorder*)listPtr->ItemAt(i); - if(wb->Window()->Feel() == B_MODAL_APP_WINDOW_FEEL) - { - finalMWList.AddItem(wb); - - // remove those windows(if in there), for correct re-insertion later. - ListData *ld = NULL; - if((ld = HasItem(wb))) - RemoveItem(ld); - } - } - } - } - else - if(prefFeel == B_MODAL_APP_WINDOW_FEEL) - { - prefIndex = preferred->Window()->App()->fAppFMWList.IndexOf(preferred); - count = preferred->Window()->App()->fAppFMWList.CountItems(); - if(prefIndex >= 0) - { - WinBorder *wb = NULL; - - // add modal windows from application's subset - windows that are - // positioned after 'preferred'. - FMWList *listPtr = &(preferred->Window()->App()->fAppFMWList); - for(i = prefIndex+1; i < count; i++) - { - wb = (WinBorder*)listPtr->ItemAt(i); - - // they *all* are modal windows. - finalMWList.AddItem(wb); - - // remove those windows(if in there), for correct re-insertion later. - ListData *ld = NULL; - if((ld = HasItem(wb))) - RemoveItem(ld); - } - } - } - - // insert windows found in 'finalMWList' in Workspace's list, after "preferred" - count = finalMWList.CountItems(); - - // this varable will help us designate the future front. - WinBorder *finalPreferred = preferred; - for(i=0; iIsHidden())) - finalPreferred = wb; - - // insert item just after the last inserted one. - ListData *newItem = new ListData(); - newItem->layerPtr = wb; - newItem->lowerItem = lastInserted->lowerItem; - newItem->upperItem = lastInserted; - if(lastInserted->lowerItem) - lastInserted->lowerItem->upperItem = newItem; - lastInserted->lowerItem = newItem; - - if(lastInserted == fBottomItem) - fBottomItem = newItem; - - lastInserted = newItem; - } - preferred = finalPreferred; - } - else - if(prefFeel == B_MODAL_ALL_WINDOW_FEEL || - prefFeel == B_SYSTEM_FIRST) - { - STRACE((" MODAL ALL/SYSTEM FIRST Window '%s'\n", preferred? preferred->GetName(): "NULL")); - - // remove all application's floating windows. - if(fFrontItem && fFrontItem->layerPtr->fLevel == B_NORMAL_FEEL) - { - ListData *listItem = fFrontItem->lowerItem; - while(listItem && (listItem->layerPtr->fLevel == B_FLOATING_SUBSET_FEEL || - listItem->layerPtr->fLevel == B_FLOATING_APP_FEEL)) - { - // *carefully* remove the item from the list - ListData *item = listItem; - listItem = listItem->lowerItem; - RemoveItem(item); - } - } - } - else if(prefFeel == B_SYSTEM_LAST) - { - ; // Do Nothing. - } - else - { - // We ***should NOT*** reach this point! - STRACE(("SERVER: PANIC: \"%s\": What kind of window is this???\n", preferred? preferred->GetName(): "NULL")); - } - } - else - STRACE((" The window IS Hidden\n")); - - ListData *exFrontItem = fFrontItem; - ListData *newFrontItem = NULL; - if(preferred && fBottomItem) - { - int32 feel = fBottomItem->layerPtr->Window()->Feel(); - - // if preferred is one of these *don't* give front state to it! - if(preferred->fLevel == B_FLOATING_SUBSET_FEEL - || preferred->fLevel == B_FLOATING_APP_FEEL - || preferred->fLevel == B_FLOATING_ALL_FEEL) - { - newFrontItem = exFrontItem; - } - else - if((feel == B_SYSTEM_FIRST || feel == B_MODAL_ALL_WINDOW_FEEL) - && !(fBottomItem->layerPtr->IsHidden()) ) - { - // if the last in workspace's list is one of these, GIVE focus to it! - - newFrontItem = fBottomItem; - } - else - if(preferred->fLevel == B_SYSTEM_LAST && !(preferred->IsHidden()) ) - { - // the SYSTEM_LAST will get the front status, only if it's the only - // WinBorder in this workspace. - - if(fBottomItem->layerPtr == preferred) - newFrontItem = HasItem(preferred); - } - else - if( !(preferred->IsHidden()) ) - { - // this is in case of MODAL[APP/SUBSET] and NORMAL windows - newFrontItem = HasItem(preferred); - } - else - { - newFrontItem = NULL; - } - } - else - { - newFrontItem = NULL; - } - - if(fFrontItem != newFrontItem) - { - fFrontItem = newFrontItem; - - // TODO: call a method something like WinBorder::MakeFront(true); - } - - STRACE(("#WS(%ld)::SASNF(%s) ENDED! Workspace data...", ID(), preferred? preferred->GetName(): "NULL")); - STRACESTREAM(); -} - -//---------------------------------------------------------------------------------- -/* - This method performs a simple opperation. It searched the new focus window - by walking from front to back, cheking for some things, until all variables - correspond. -*/ -void Workspace::SearchAndSetNewFocus(WinBorder *preferred) -{ - STRACE(("*WS(%ld)::SASNFocus(%s)\n", ID(), preferred? preferred->GetName(): "NULL")); - - if(!preferred) - preferred = fBottomItem? fBottomItem->layerPtr : NULL; - - bool selectOthers = false; - ListData *item=NULL; - - for(item = fBottomItem; item != NULL; item = item->upperItem) - { - // if this WinBorder doesn't want to have focus... get to the next one - if(item->layerPtr->Window()->Flags() & B_AVOID_FOCUS) - continue; - - if(preferred && item->layerPtr == preferred) - { - // our preffered one is hidden so... select another one - if(preferred && preferred->IsHidden()) - { - selectOthers = true; - continue; - } - else - { - break; - } - } - - if(item->layerPtr->fLevel == B_SYSTEM_FIRST || item->layerPtr->fLevel == B_MODAL_ALL_FEEL) - { - break; - } - - if(item->layerPtr->fLevel == B_MODAL_APP_FEEL - && (preferred && preferred->Window()->ClientTeamID() == item->layerPtr->Window()->ClientTeamID())) - { - break; - } - - if(item->layerPtr->fLevel == B_MODAL_SUBSET_FEEL - && (preferred && item->layerPtr->MainWinBorder() == preferred)) - { - break; - } - - // select one window, other than a system_last one! - if(selectOthers && item->layerPtr->fLevel != B_SYSTEM_LAST) - { - break; - } - } - - // there are no windows below us to select. take the one from above us. - if(selectOthers && !item) - { - // there HAS to be valid - item = HasItem(preferred); - if(item) - item= item->lowerItem; - } - - // there are NO windows in front of us, and no regular window below us - // maybe there is a system_last window... - if(!item) - item = fTopItem; - - if(item != fFocusItem) - { - if(fFocusItem) - { - ListData *oldItem=fFocusItem; - - oldItem->layerPtr->HighlightDecorator(false); - - BMessage inactive(B_WINDOW_ACTIVATED); - inactive.AddInt64("when",system_time()); - inactive.AddBool("active",false); - oldItem->layerPtr->Window()->SendMessageToClient(&inactive); - } - - fFocusItem=item; - - if(fFocusItem) - { - fFocusItem->layerPtr->HighlightDecorator(true); - - BMessage active(B_WINDOW_ACTIVATED); - active.AddInt64("when",system_time()); - active.AddBool("active",true); - - fFocusItem->layerPtr->Window()->SendMessageToClient(&active); - } - } -} - -//---------------------------------------------------------------------------------- - -void Workspace::BringToFrontANormalWindow(WinBorder *layer) -{ - switch (layer->Window()->Feel()) - { - case B_FLOATING_SUBSET_WINDOW_FEEL: - case B_MODAL_SUBSET_WINDOW_FEEL: - { - SearchAndSetNewFront(layer->MainWinBorder()); - break; - } - case B_FLOATING_APP_WINDOW_FEEL: - case B_MODAL_APP_WINDOW_FEEL: - { - ListData *item = fBottomItem; - team_id tid = layer->Window()->ClientTeamID(); - while(item) - { - if(item->layerPtr->Window()->ClientTeamID() == tid - && item->layerPtr->Window()->Feel() == B_NORMAL_WINDOW_FEEL) - { - break; - } - item = item->upperItem; - } - - if(item) - SearchAndSetNewFront(item->layerPtr); - - break; + returnValue = true; } + break; default: { - // in case of MODAL/FLOATING_ALL or _NORMAL_ or SYSTEM_FIRST/LAST do nothing! + debugger("MoveToBack: unknown window feel\n"); + return false; } } + + // The following applies ONLY to B_NORMAL and B_MODAL_APP windows. + + if (changeFront) + { + ListData *newFront; + newFront = findNextFront(); + if (newFront) + MoveToFront(newFront->layerPtr); + else + debugger("MoveToBack: can't find new front! We should find one!\n"); + } + + return returnValue; } //---------------------------------------------------------------------------------- +/*! + \brief Hides a WinBorder. + \param winBorder WinBorder to be hidden. + \return True if the list of WinBorders has changed, false otherwise. -// This method moves a window to the back of its subset. -void Workspace::MoveToBack(WinBorder *newLast) + WinBorder \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 WinBorder, another one (or none) will be automaticaly +chosen. Same goes for focus. +*/ +bool Workspace::HideWinBorder(WinBorder *winBorder) { - STRACE(("\n!MoveToBack(%s) -", newLast? newLast->GetName(): "NULL")); - - // does the list have this element? - ListData *item = HasItem(newLast); - if(item) +STRACE(("W(%ld)::HideWinBorder(%s) \n", fID, winBorder? winBorder->GetName(): "NULL")); + bool returnValue = false; + int32 level = winBorder->Level(); + bool changeFront = false; + bool changeFocus = false; + + if (fFrontItem && fFrontItem->layerPtr == winBorder) + changeFront = true; + + if (fFocusItem && fFocusItem->layerPtr == winBorder) + changeFocus = true; + + if (level > B_SYSTEM_FIRST) + level = B_SYSTEM_FIRST; + + switch(level) { - ListData *listItem = NULL; - - switch(item->layerPtr->fLevel) + case B_MODAL_ALL: + case B_SYSTEM_FIRST: + case B_SYSTEM_LAST: + case B_FLOATING_ALL: { - case B_FLOATING_ALL_FEEL: + // 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) { - STRACE((" B_FLOATING_ALL_FEEL window\n")); - - // search the place where we should insert it later - listItem = item->upperItem; - while(listItem && (listItem->layerPtr->fLevel == item->layerPtr->fLevel)) - listItem = listItem->upperItem; - - break; - } - - // those 2 flags form a 'virtual' set, so even if FLOATING_APP - // has a greater priority than FLOATING_SUBSET, it is still moved - // behind FLOATING_SUBSET. - case B_FLOATING_SUBSET_FEEL: - case B_FLOATING_APP_FEEL: - { - STRACE((" B_FLOATING_SUBSET_FEEL/B_FLOATING_APP_FEEL window\n")); - - // search the place where we should insert it later - listItem = item->upperItem; - - while(listItem && (listItem->layerPtr->fLevel == B_FLOATING_SUBSET_FEEL || - listItem->layerPtr->fLevel == B_FLOATING_APP_FEEL)) + ListData *item = HasItem(winBorder); + if (item) { - listItem = listItem->upperItem; - } + fFrontItem->layerPtr->fFMWList.AddWinBorder(winBorder); - break; - } - - // the same like with floating window. Those 2 and NORMAL form a'virtual' set. - case B_MODAL_SUBSET_FEEL: - case B_MODAL_APP_FEEL: - { - STRACE((" B_MODAL_SUBSET_FEEL/B_MODAL_APP_FEEL window\n")); - - // search the place where we should insert it later - listItem = item->upperItem; - - while(listItem && (listItem->layerPtr->fLevel == B_MODAL_SUBSET_FEEL || - listItem->layerPtr->fLevel == B_MODAL_APP_FEEL || - listItem->layerPtr->fLevel == B_NORMAL_FEEL)) - { - listItem = listItem->upperItem; - } + RemoveItem(item); + fPool.ReleaseMemory(item); - break; - } - - // here is the simplest, we use the priority levels. - case B_NORMAL_FEEL: - { - STRACE((" B_NORMAL_FEEL window\n")); - listItem = item->upperItem; - while(listItem && (listItem->layerPtr->fLevel >= item->layerPtr->fLevel)) - listItem = listItem->upperItem; - - break; + returnValue = true; + } } } - - if((listItem && item->lowerItem == listItem->lowerItem) - || (listItem == NULL && item == fTopItem)) + break; + case B_NORMAL: { - // do nothing! The window will be in the same position it is now. - } - else - { - // if it's a normal window, first remove any floating windows, - // it or its application has - if(newLast->fLevel == B_NORMAL_FEEL && fFrontItem->layerPtr == newLast) + if (fFrontItem && fFrontItem->layerPtr == winBorder) { - ListData *iter = item->lowerItem; - while(iter && (iter->layerPtr->fLevel == B_FLOATING_SUBSET_FEEL || - iter->layerPtr->fLevel == B_FLOATING_APP_FEEL)) - { - // *carefully* remove the item from the list - ListData *itemX = iter; - iter = iter->lowerItem; - RemoveItem(itemX); - } - + saveFloatingWindows(fFrontItem); } - WinBorder *nextPreferred = item->upperItem? item->upperItem->layerPtr: NULL; - bool wasFront = fFrontItem->layerPtr == newLast; - bool wasFocus = fFocusItem->layerPtr == newLast; - - // remove item - RemoveItem(item); - - // insert in the new, right' position. - InsertItem(item, listItem? listItem->lowerItem: fTopItem); + // 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 + && winBorder->fFMWList.HasItem(item->layerPtr) + && !searchFirstMainWindow(item->layerPtr)) + { + // if this modal subset has front state, make sure another window will get that status. + if (fFrontItem == item) + changeFront = true; - if(wasFront) - SearchAndSetNewFront(nextPreferred); - if(wasFocus) - SearchAndSetNewFocus(nextPreferred); + toast = item; + item = item->lowerItem; + RemoveItem(toast); + fPool.ReleaseMemory(toast); + } + else + break; + } + + returnValue = true; + } + break; + case B_MODAL_APP: + { + // if a subset modal, then remove from Workspace's list. + if (!winBorder->App()->fAppFMWList.HasItem(winBorder)) + { + ListData *toast = HasItem(winBorder); + if (toast) + { + RemoveItem(toast); + fPool.ReleaseMemory(toast); + + returnValue = true; + } + } + } + break; + default: + { + debugger("HideWinBorder: what kind of window is this?\n"); } - STRACESTREAM(); } - else - STRACE((" this operation was not needed\n")); + + // select a new Front if needed + if (changeFront) + { + ListData *newFront; + + fFrontItem = NULL; + fFocusItem = NULL; + newFront = findNextFront(); + if (newFront) + MoveToFront(newFront->layerPtr); + } + + // 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) + { + ListData *cursor = fBottomItem; + + while(cursor) + { + if (!cursor->layerPtr->IsHidden() && !(cursor->layerPtr->Window()->Flags() & B_AVOID_FOCUS)) + break; + else + cursor = cursor->upperItem; + } + + fFocusItem = cursor; + } + + return returnValue; } +//---------------------------------------------------------------------------------- +/*! + \brief Shows a WinBorder. + \param winBorder WinBorder to be show. + \return True if the list of WinBorders has changed, false otherwise. + + WinBorder \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::ShowWinBorder(WinBorder *winBorder, bool userBusy) +{ +STRACE(("W(%ld)::ShowWinBorder(%s) \n", fID, winBorder? winBorder->GetName(): "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; + + itemThis = HasItem(winBorder, &reverseIndexThis); + HasItem(fFrontItem->layerPtr, &reverseIndexFront); + + if (reverseIndexThis < reverseIndexFront) + { + if (fFrontItem->layerPtr->Level() == B_NORMAL) + saveFloatingWindows(fFrontItem); + + fFrontItem = itemThis; + } + } + // of course, if no front item, then set this one. + else + { + 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) + { + ListData *itemThis = NULL; + // remove from B_NORMAL's list. + if (fFrontItem->layerPtr->fFMWList.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("ShowWinBorder: 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()->fAppFMWList.HasItem(winBorder)) + { + // take only application's modals + tempList.AddList(&winBorder->App()->fAppFMWList); + if (fFrontItem + && fFrontItem->layerPtr->App()->ClientTeamID() == winBorder->App()->ClientTeamID()) + userBusy = false; + } + // SUBSET modal + else + { + WinBorder *mainWindow = searchFirstMainWindow(winBorder); + if (mainWindow) + { + // add both mainWindow's subset modals and application's modals + tempList.AddList(&mainWindow->fFMWList); + tempList.AddList(&winBorder->App()->fAppFMWList); + if (fFrontItem && fFrontItem->layerPtr == mainWindow) + userBusy = false; + } + else + { + // none of the unhiden normal windows have this window as part of their 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 WinBorder. + 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; + WinBorder **wbList; + ListData *itemX; + int32 indexThisInTempList; + + indexThisInTempList = tempList.IndexOf(winBorder); + if (indexThisInTempList < 0) + debugger("ShowWinBorder: modal window: design flaw!!!\n"); + + count = tempList.CountItems(); + wbList = (WinBorder**)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"); + } + + // set new Focus if needed + if (returnValue) + { + ListData *cursor = fBottomItem; + + fFocusItem = NULL; + while(cursor) + { + if (!cursor->layerPtr->IsHidden() && !(cursor->layerPtr->Window()->Flags() & 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; + break; + } + else + cursor = cursor->upperItem; + } + else + { + fFocusItem = cursor; + break; + } + } + else + cursor = cursor->upperItem; + } + } + + return returnValue; +} + + //---------------------------------------------------------------------------------- void Workspace::SetLocalSpace(const uint32 colorspace) @@ -1383,14 +970,14 @@ RGBColor Workspace::BGColor(void) const */ void Workspace::GetSettings(const BMessage &msg) { - // TODO: Implement GetSettings + // TODO: Implement } //---------------------------------------------------------------------------------- //! Sets workspace settings to defaults void Workspace::GetDefaultSettings(void) { - // TODO: Implement GetDefaultSettings + // TODO: Implement } //---------------------------------------------------------------------------------- @@ -1413,7 +1000,7 @@ void Workspace::GetDefaultSettings(void) */ void Workspace::PutSettings(BMessage *msg, const int32 &index) const { - // TODO: Implement PutSettings + // TODO: Implement } //---------------------------------------------------------------------------------- @@ -1424,18 +1011,18 @@ void Workspace::PutSettings(BMessage *msg, const int32 &index) const */ void Workspace::PutDefaultSettings(BMessage *msg, const int32 &index) { - // TODO: Implement PutDefaultSettings + // TODO: Implement } //---------------------------------------------------------------------------------- // Debug method void Workspace::PrintToStream() const { - printf("\nWorkspace %ld hierarchy shown from back to front:\n", fID); + printf("Workspace %ld hierarchy shown from back to front:\n", fID); for (ListData *item = fTopItem; item != NULL; item = item->lowerItem) { WinBorder *wb = (WinBorder*)item->layerPtr; - printf("\tName: %s\t%s", wb->GetName(), wb->IsHidden()?"Hidden\t": "NOT Hidden"); + printf("\tName: %s\t%s", wb->GetName(), wb->IsHidden()?"Hidden\t": "Visible\t"); if(wb->Window()->Feel() == B_FLOATING_SUBSET_WINDOW_FEEL) printf("\t%s\n", "B_FLOATING_SUBSET_WINDOW_FEEL"); if(wb->Window()->Feel() == B_FLOATING_APP_WINDOW_FEEL) @@ -1452,14 +1039,12 @@ void Workspace::PrintToStream() const printf("\t%s\n", "B_NORMAL_WINDOW_FEEL"); if(wb->Window()->Feel() == B_SYSTEM_LAST) printf("\t%s\n", "B_SYSTEM_LAST"); - if(wb->Window()->Feel() == B_SYSTEM_FIRST) + if(wb->Window()->Feel() >= B_SYSTEM_FIRST) printf("\t%s\n", "B_SYSTEM_FIRST"); + } printf("Focus Layer:\t%s\n", fFocusItem? fFocusItem->layerPtr->GetName(): "NULL"); - printf("Front Layer:\t%s\n", fFrontItem? fFrontItem->layerPtr->GetName(): "NULL"); -// printf("Current Layer:\t%s\n", fCurrentItem? fCurrentItem->layerPtr->GetName(): "NULL"); -// printf("Top Layer:\t%s\n", fTopItem? fTopItem->layerPtr->GetName(): "NULL"); -// printf("Bottom Layer:\t%s\n", fBottomItem? fBottomItem->layerPtr->GetName(): "NULL"); + printf("Front Layer:\t%s\n\n", fFrontItem? fFrontItem->layerPtr->GetName(): "NULL"); } //---------------------------------------------------------------------------------- @@ -1482,7 +1067,9 @@ void Workspace::PrintItem(ListData *item) const //---------------------------------------------------------------------------------- // PRIVATE //---------------------------------------------------------------------------------- - +/* + Insert item in the top-bottom direction. +*/ void Workspace::InsertItem(ListData *item, ListData *before) { // insert before one other item; @@ -1491,24 +1078,23 @@ void Workspace::InsertItem(ListData *item, ListData *before) if(before->upperItem) before->upperItem->lowerItem = item; item->upperItem = before->upperItem; - before->upperItem = item; item->lowerItem = before; + before->upperItem = item; - // if we're inserting at top of the stack, change it accordingly. if(fTopItem == before) fTopItem = item; } else { - // insert item at bottom. - item->upperItem = fBottomItem; + // insert item at the end. + item->upperItem = fBottomItem; if(fBottomItem) - fBottomItem->lowerItem = item; + fBottomItem->lowerItem = item; - fBottomItem = item; + fBottomItem = item; if(!fTopItem) - fTopItem = item; + fTopItem = item; } } @@ -1535,16 +1121,469 @@ void Workspace::RemoveItem(ListData *item) item->lowerItem = NULL; if(fFocusItem == item) - { - fFocusItem->layerPtr->HighlightDecorator(false); fFocusItem = NULL; - } if(fFrontItem == item) fFrontItem = NULL; - - if(fCurrentItem == item) - fCurrentItem = 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 WinBorder *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->Window()->Flags() & 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 WinBorder 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 WinBorder before given item. First search the + specified WinBorder in Workspace's list an remove it. + \resolution: private +*/ +inline +bool Workspace::removeAndPlaceBefore(const WinBorder *wb, ListData *beforeItem) +{ + return removeAndPlaceBefore(HasItem(wb), beforeItem); +} + +inline +WinBorder* Workspace::searchFirstMainWindow(WinBorder *wb) const +{ + ListData *listItem = fBottomItem; + while (listItem) + { + if (listItem->layerPtr->Level() == B_NORMAL && !listItem->layerPtr->IsHidden() + && listItem->layerPtr->App()->ClientTeamID() == wb->App()->ClientTeamID() + && listItem->layerPtr->fFMWList.HasItem(wb)) + return listItem->layerPtr; + + listItem = listItem->upperItem; + } + return NULL; +} + +//---------------------------------------------------------------------------------- + +inline +bool Workspace::windowHasVisibleModals(const WinBorder *winBorder) const +{ + int32 i, count; + WinBorder **wbList; + + // check window's list + count = winBorder->fFMWList.CountItems(); + wbList = (WinBorder**)winBorder->fFMWList.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()->fAppFMWList.CountItems(); + wbList = (WinBorder**)winBorder->App()->fAppFMWList.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; + WinBorder **wbList; + ListData *itemX; + ListData *lastPlaced = NULL; + ListData *before = item->lowerItem; + + HasItem(item, &revIndex); + + // check window's list + count = item->layerPtr->fFMWList.CountItems(); + wbList = (WinBorder**)item->layerPtr->fFMWList.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()->fAppFMWList.CountItems(); + wbList = (WinBorder**)item->layerPtr->App()->fAppFMWList.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; +} + +//---------------------------------------------------------------------------------- + +inline +void Workspace::putFloatingInFront(ListData *item) +{ + int32 i; + ListData *newItem; + ListData *before = item->lowerItem; + WinBorder *wb; + + i = 0; + while ((wb = (WinBorder*)item->layerPtr->fFMWList.ItemAt(i))) + { + if (wb->Level() == B_MODAL_APP) + { + break; + } + else if (!wb->IsHidden()) + { + newItem = fPool.GetCleanMemory(wb); + + InsertItem(newItem, before); + + item->layerPtr->fFMWList.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->fFMWList.AddWinBorder(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->Window()->Flags() & 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::MemoryPool::~MemoryPool() +{ +} + +inline +ListData* Workspace::MemoryPool::GetCleanMemory(WinBorder *winBorder) +{ + ListData *item = (ListData*)malloc(sizeof(ListData)); + item->layerPtr = winBorder; + item->upperItem = NULL; + item->lowerItem = NULL; + return item; +} + +inline +void Workspace::MemoryPool::ReleaseMemory(ListData *mem) +{ + free(mem); +} + +void Workspace::MemoryPool::expandBuffer(int32 start) +{ +} \ No newline at end of file diff --git a/src/servers/app/server/Workspace.h b/src/servers/app/server/Workspace.h index 967a29a31c..365ef46acc 100644 --- a/src/servers/app/server/Workspace.h +++ b/src/servers/app/server/Workspace.h @@ -1,5 +1,5 @@ //------------------------------------------------------------------------------ -// Copyright (c) 2001-2002, Haiku, Inc. +// 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"), @@ -20,7 +20,7 @@ // DEALINGS IN THE SOFTWARE. // // File Name: Workspace.h -// Author: Adi Oanca +// Author: Adi Oanca // Description: Tracks workspaces // // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -41,6 +41,7 @@ class WinBorder; struct ListData { + bool isFree; WinBorder *layerPtr; ListData *upperItem; ListData *lowerItem; @@ -49,84 +50,101 @@ struct ListData class Workspace { public: - Workspace(const uint32 colorspace, int32 ID, const RGBColor& BGColor); - ~Workspace(void); - - bool AddWinBorder(WinBorder *layer); - bool RemoveWinBorder(WinBorder *layer); - bool HideSubsetWindows(WinBorder *layer); - WinBorder *FocusLayer(void) const; - WinBorder *FrontLayer(void) const; - - void MoveToBack(WinBorder *newLast); - - // The bottom item is the one which is visible - WinBorder *GoToBottomItem(void); - WinBorder *GoToUpperItem(void); - WinBorder *GoToTopItem(void); - WinBorder *GoToLowerItem(void); - bool GoToItem(WinBorder *layer); + Workspace( const int32 ID, + const uint32 colorspace, + const RGBColor& BGColor); + ~Workspace(void); - void SetLocalSpace(const uint32 colorspace); - uint32 LocalSpace(void) const; + int32 ID(void) const { return fID; } - void SetBGColor(const RGBColor &c); - RGBColor BGColor(void) const; + void AddWinBorder(WinBorder *winBorder); + void RemoveWinBorder(WinBorder *winBorder); + bool HasWinBorder(const WinBorder *winBorder) const; + + WinBorder* Focus(void) const; + WinBorder* Front(void) const; + void GetWinBorderList(void **&list, int32 *itemCount ) const; - int32 ID(void) const { return fID; } + bool MoveToBack(WinBorder *newLast); + bool MoveToFront(WinBorder *newFront, bool doNotDisturb = false); + + bool HideWinBorder(WinBorder *winBorder); + bool ShowWinBorder(WinBorder *winBorder, bool userBusy = false); + + // resolution related methods. + void SetLocalSpace(const uint32 colorspace); + uint32 LocalSpace(void) const; - void GetSettings(const BMessage &msg); - void GetDefaultSettings(void); - void PutSettings(BMessage *msg, const int32 &index) const; - static void PutDefaultSettings(BMessage *msg, const int32 &index); - - // debug methods - void PrintToStream(void) const; - void PrintItem(ListData *item) const; - - // TODO: Bad Style. There should be a more elegant way of doing this - // .... private :-) - do not use! - void SearchAndSetNewFront(WinBorder *preferred); - void SearchAndSetNewFocus(WinBorder *preferred); - void BringToFrontANormalWindow(WinBorder *layer); + 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 int32 &index) const; + static void PutDefaultSettings(BMessage *msg, const int32 &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 WinBorder *layer, int32 *index = NULL) const; + int32 IndexOf(const ListData *item) const; + + bool placeToBack(ListData *newLast); + void placeInFront(ListData *item, const bool userBusy); + + bool removeAndPlaceBefore(const WinBorder *wb, ListData *beforeItem); + bool removeAndPlaceBefore(ListData *item, ListData *beforeItem); + + WinBorder* searchFirstMainWindow(WinBorder *wb) const; + + bool windowHasVisibleModals(const WinBorder *winBorder) const; + ListData* putModalsInFront(ListData *item); + void putFloatingInFront(ListData *item); + void saveFloatingWindows(ListData *itemNormal); + + ListData* findNextFront() const; + + class MemoryPool + { + public: + MemoryPool(); + ~MemoryPool(); + ListData* GetCleanMemory(WinBorder* winborder); + void ReleaseMemory(ListData* mem); + private: + void expandBuffer(int32 start); + ListData *buffer; + int32 count; + }; + + int32 fID; + uint32 fSpace; + RGBColor fBGColor; + + // first visible onscreen + ListData *fBottomItem; - void InsertItem(ListData *item, ListData *before); - void RemoveItem(ListData *item); - ListData *HasItem(ListData *item); - ListData *HasItem(WinBorder *layer); + // the last visible(or covered by other Layers) + ListData *fTopItem; - ListData *FindPlace(ListData *pref); + // the focus WinBorder - for keyboard events + ListData *fFocusItem; - int32 fID; - uint32 fSpace; - RGBColor fBGColor; + // pointer for which "big" actions are intended + ListData *fFrontItem; - // first visible onscreen - ListData *fBottomItem; + // settings for each workspace -- example taken from R5's app_server_settings file + display_timing fDisplayTiming; + int16 fVirtualWidth; + int16 fVirtualHeight; - // the last visible(or covered by other Layers) - ListData *fTopItem; - - // pointer to the current element in the list - ListData *fCurrentItem; - - // the focus WinBorder - for keyboard events - ListData *fFocusItem; - - // the item that is the target of mouse operations - ListData *fFrontItem; - - // settings for each workspace -- example taken from R5's app_server_settings file - display_timing fDisplayTiming; - int16 fVirtualWidth; - int16 fVirtualHeight; - - // TODO: find out what specific values need to be contained in fFlags as per R5's server - // not to be confused with display_timing.flags - uint32 fFlags; + MemoryPool fPool; }; #endif