haiku/src/servers/app/server/Workspace.cpp

1017 lines
35 KiB
C++
Raw Normal View History

#include <stdio.h>
#include <Window.h>
#include "ServerApp.h"
#include "Workspace.h"
#include "Layer.h"
#include "WinBorder.h"
#include "ServerWindow.h"
#include "RGBColor.h"
#include "Globals.h"
#include "FMWList.h"
#include "RootLayer.h"
#include "Desktop.h"
//#define DEBUG_WORKSPACE
#ifdef DEBUG_WORKSPACE
# include <stdio.h>
# define STRACE(x) printf x
#else
# define STRACE(x) ;
#endif
#ifdef DEBUG_WORKSPACE
# include <stdio.h>
# define STRACESTREAM() PrintToStream()
#else
# define STRACESTREAM() ;
#endif
Workspace::Workspace(const uint32 colorspace, int32 ID, const RGBColor& BGColor){
fID = ID;
fSpace = colorspace;
fBGColor = BGColor;
fBottomItem = NULL;
fTopItem = NULL;
fCurrentItem= NULL;
fFocusItem = NULL;
fFrontItem = NULL;
}
//---------------------------------------------------------------------------
Workspace::~Workspace(){
//printf("~Workspace( %ld )\n", fID);
ListData *toast;
while(fBottomItem){
toast = fBottomItem;
fBottomItem = fBottomItem->upperItem;
delete 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 SearchAndSerNewFocus witch 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.
*/
bool Workspace::AddLayerPtr(WinBorder* layer){
// allocate a new item
ListData *item;
item = new ListData;
item->layerPtr = layer;
item->upperItem = NULL;
item->lowerItem = NULL;
// 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()));
// do a *smart* search and set the new 'front'
SearchAndSetNewFront(layer);
// do a *smart* search and set the new 'focus'
SearchAndSetNewFocus(layer);
STRACESTREAM();
return true;
}
/* 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.
*/
//---------------------------------------------------------------------------
bool Workspace::RemoveLayerPtr(WinBorder* layer){
if (!layer)
return false;
STRACE(("\n#RemoveLayerPtr(%s)\n", layer->GetName()));
// search to see if this workspace has WinBorder's pointer in its list
ListData *item = NULL;
if ((item = HasItem(layer))){
ListData *nextItem = NULL;
bool wasFront, wasFocus;
// prepare to set new front/focus if this layer was front/focus
nextItem = item->upperItem;
wasFront = fFrontItem->layerPtr == layer;
wasFocus = fFrontItem->layerPtr == layer;
// remove any floating window our window may have
ListData *listItem = item->lowerItem;
while(listItem && (listItem->layerPtr->GetServerFeel() == B_FLOATING_SUBSET_FEEL
|| listItem->layerPtr->GetServerFeel() == B_FLOATING_APP_FEEL))
{ // *carefully* remove the item from the list
ListData *itemX = listItem;
listItem = listItem->lowerItem;
RemoveItem(itemX);
}
// remove from workspace's list
RemoveItem(item);
// reset some internal variables
layer->SetMainWinBorder(NULL);
// its RootLayer is set to NULL by Layer::RemoveChild(layer);
STRACESTREAM();
if (wasFront)
SearchAndSetNewFront(nextItem? nextItem->layerPtr: NULL);
if (wasFocus)
SearchAndSetNewFocus(nextItem? nextItem->layerPtr: NULL);
// delete item struct, we no longer need that
delete item;
return true;
}
else
return false;
}
//---------------------------------------------------------------------------
bool Workspace::SetFocusLayer(WinBorder* layer){
SearchAndSetNewFocus(layer);
return true;
}
//---------------------------------------------------------------------------
WinBorder* Workspace::FocusLayer() const{
return fFocusItem ? fFocusItem->layerPtr : NULL;
}
//---------------------------------------------------------------------------
bool Workspace::SetFrontLayer(WinBorder* layer){
STRACE(("\n@SetFrontLayer( %s )\n", layer? layer->GetName(): "NULL"));
SearchAndSetNewFront(layer);
STRACESTREAM();
return true;
}
//---------------------------------------------------------------------------
WinBorder* Workspace::FrontLayer() const{
return fFrontItem? fFrontItem->layerPtr: NULL;
}
//---------------------------------------------------------------------------
WinBorder* Workspace::GoToBottomItem(){
fCurrentItem = fBottomItem;
return fCurrentItem ? fCurrentItem->layerPtr : NULL;
}
//---------------------------------------------------------------------------
WinBorder* Workspace::GoToUpperItem(){
if (fCurrentItem){
fCurrentItem = fCurrentItem->upperItem;
return fCurrentItem ? fCurrentItem->layerPtr : NULL;
}
else
return NULL;
}
//---------------------------------------------------------------------------
WinBorder* Workspace::GoToTopItem(){
fCurrentItem = fTopItem;
return fCurrentItem ? fCurrentItem->layerPtr : NULL;
}
//---------------------------------------------------------------------------
WinBorder* Workspace::GoToLowerItem(){
if (fCurrentItem){
fCurrentItem = fCurrentItem->lowerItem;
return fCurrentItem ? fCurrentItem->layerPtr : NULL;
}
else
return NULL;
}
//---------------------------------------------------------------------------
bool Workspace::GoToItem(WinBorder* layer){
if (!layer)
return false;
if (fCurrentItem && fCurrentItem->layerPtr == layer){
return true;
}
for( ListData *item = fBottomItem; item != NULL; item = item->upperItem){
if (item->layerPtr == layer){
fCurrentItem = item;
return true;
}
}
return false;
}
//---------------------------------------------------------------------------
void Workspace::InsertItem(ListData* item, ListData* before){
// insert before one other item;
if (before){
if (before->upperItem)
before->upperItem->lowerItem = item;
item->upperItem = before->upperItem;
before->upperItem = item;
item->lowerItem = before;
// if we're inserting at top of the stack, change it accordingly.
if(fTopItem == before)
fTopItem = item;
}
// insert item at bottom.
else{
item->upperItem = fBottomItem;
if (fBottomItem)
fBottomItem->lowerItem = item;
fBottomItem = item;
if (!fTopItem)
fTopItem = item;
}
}
//---------------------------------------------------------------------------
void Workspace::RemoveItem(ListData* item){
if (!item)
return;
if (fBottomItem == item){
fBottomItem = item->upperItem;
}
else{
item->lowerItem->upperItem = item->upperItem;
}
if (fTopItem == item){
fTopItem = item->lowerItem;
}
else{
item->upperItem->lowerItem = item->lowerItem;
}
// set all these to NULL to avoid confusion later.
item->upperItem = NULL;
item->lowerItem = NULL;
if (fFocusItem == item)
fFocusItem = NULL;
if (fFrontItem == item)
fFrontItem = NULL;
if (fCurrentItem == item)
fCurrentItem = NULL;
}
//---------------------------------------------------------------------------
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, is *place* 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 window *ONLY*!
* 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 = fBottomItem;
ListData *item = NULL;
// search a window that is not hidden and does *not* have B_AVOID_FRONT flag.
item = pref;
while(pref && item->lowerItem != pref){
if ( !(item->layerPtr->Window()->GetFlags() & B_AVOID_FRONT) && !(item->layerPtr->IsHidden()) )
break;
if (item == fTopItem)
item = fBottomItem;
else
item = item->upperItem;
}
// if true, it means we have windows with B_AVOID_FRONT flag *only*, so pick one.
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;
// temporally 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()->GetFeel();
switch(feel){
case B_NORMAL_WINDOW_FEEL:{
while(cursor && cursor->layerPtr->GetServerFeel() > B_MODAL_APP_FEEL){
cursor = cursor->upperItem;
}
InsertItem(pref, cursor? cursor->lowerItem: NULL);
break;
}
case B_SYSTEM_LAST:{
while(cursor && cursor->layerPtr->GetServerFeel() > pref->layerPtr->GetServerFeel()){
cursor = cursor->upperItem;
}
InsertItem(pref, cursor? cursor->lowerItem: fTopItem);
break;
}
case B_SYSTEM_FIRST:
case B_FLOATING_ALL_WINDOW_FEEL:
case B_MODAL_ALL_WINDOW_FEEL:
case B_MODAL_APP_WINDOW_FEEL:{
while(cursor && cursor->layerPtr->GetServerFeel() > pref->layerPtr->GetServerFeel()){
cursor = cursor->upperItem;
}
InsertItem(pref, cursor? cursor->lowerItem: NULL);
break;
}
// 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.
case B_FLOATING_SUBSET_WINDOW_FEEL:{
for(cursor = fBottomItem; cursor; cursor = cursor->upperItem){
if (cursor->layerPtr->GetServerFeel() <= pref->layerPtr->GetServerFeel()
&& (cursor->layerPtr == pref->layerPtr->MainWinBorder()
|| cursor->layerPtr->MainWinBorder() == pref->layerPtr->MainWinBorder())
)
{ break; }
else if(pref->layerPtr->GetServerFeel() == B_FLOATING_SUBSET_FEEL
&& cursor->layerPtr->GetServerFeel() == B_FLOATING_APP_FEEL)
{ break; }
}
if (cursor)
InsertItem(pref, cursor? cursor->lowerItem: NULL);
break;
}
// 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
case B_MODAL_SUBSET_WINDOW_FEEL:{
for(cursor = fBottomItem; cursor; cursor = cursor->upperItem){
if (cursor->layerPtr->GetServerFeel() <= pref->layerPtr->GetServerFeel())
break;
else if(pref->layerPtr->GetServerFeel() == B_MODAL_SUBSET_FEEL
&& cursor->layerPtr->GetServerFeel() == B_MODAL_APP_FEEL
&& pref->layerPtr->Window()->GetClientTeamID()
!= cursor->layerPtr->Window()->GetClientTeamID())
break;
}
if (cursor)
InsertItem(pref, cursor? cursor->lowerItem: NULL);
break;
}
// place in front of: its main window, other floating windows
// NOTE that this happens only if its main window is the front most one.
case B_FLOATING_APP_WINDOW_FEEL:{
for(cursor = fBottomItem; cursor; cursor = cursor->upperItem){
if (cursor->layerPtr->GetServerFeel() <= pref->layerPtr->GetServerFeel()
&& pref->layerPtr->Window()->GetClientTeamID() ==
cursor->layerPtr->Window()->GetClientTeamID())
{ 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 clerverly selects the new FINAL front window.
*/
//---------------------------------------------------------------------------
void Workspace::SearchAndSetNewFront(WinBorder* preferred){
// the new front must not be the same as the previous one.
if (fFrontItem && fFrontItem->layerPtr == preferred)
return;
// properly place this 'preferred' WinBorder.
ListData *lastInserted;
lastInserted = FindPlace(HasItem(preferred));
preferred = lastInserted? lastInserted->layerPtr: NULL;
// if the new front layer is the same... there is no point continuing
if(fFrontItem == lastInserted)
return;
if (lastInserted && !(lastInserted->layerPtr->IsHidden())){
int32 prefFeel = preferred->Window()->GetFeel();
if (prefFeel == B_NORMAL_WINDOW_FEEL){
STRACE((" NORMAL Window '%s' -", preferred->GetName()));
if (fFrontItem){
// if they are in the same team...
if (preferred->Window()->GetClientTeamID() == fFrontItem->layerPtr->Window()->GetClientTeamID()){
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){
int32 feel = listItem->layerPtr->Window()->GetFeel();
if (feel == B_FLOATING_SUBSET_WINDOW_FEEL || feel == B_MODAL_SUBSET_WINDOW_FEEL){
if(preferred->Window()->GetFMWList()->HasItem(listItem->layerPtr)){
commonFMW.AddItem(listItem->layerPtr);
// *carefully* remove the item from the list
ListData *item = listItem;
listItem = listItem->lowerItem;
RemoveItem(item);
}
// also remove floating windows. Those, SURELY belong to
// 'fFrontItem' - this being the *old* front window.
else if (feel == B_FLOATING_SUBSET_WINDOW_FEEL){
// *carefully* remove the item from the list
ListData *item = listItem;
listItem = listItem->lowerItem;
RemoveItem(item);
}
else
listItem = listItem->lowerItem;
}
// ALSO collect application's floating and modal windows,
// for reinsertion, later.
else if (feel == B_FLOATING_APP_WINDOW_FEEL || feel == B_MODAL_APP_WINDOW_FEEL){
if(listItem->layerPtr->Window()->GetClientTeamID() ==
preferred->Window()->GetClientTeamID())
{
appFMW.AddItem(listItem->layerPtr);
// *carefully* remove the item from the list
ListData *item = listItem;
listItem = listItem->lowerItem;
RemoveItem(item);
}
}
else
listItem = listItem->lowerItem;
}
// put in the final list, items that are not found in the common list
count = preferred->Window()->GetFMWList()->CountItems();
for (i=0; i<count; i++){
void *item = preferred->Window()->GetFMWList()->ItemAt(i);
if (commonFMW.HasItem(item)){ }
else
finalFMWList.AddItem(item);
}
// colapse 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()->GetFeel() == B_MODAL_SUBSET_WINDOW_FEEL
|| wb->Window()->GetFeel() == B_MODAL_APP_WINDOW_FEEL))
|| (fBottomItem &&
(fBottomItem->layerPtr->Window()->GetFeel() == B_MODAL_ALL_WINDOW_FEEL
|| fBottomItem->layerPtr->Window()->GetFeel() == 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; i<count; i++){
WinBorder *wb = (WinBorder*)finalFMWList.ItemAt(i);
if(wb->Window()->GetFeel() == B_FLOATING_SUBSET_WINDOW_FEEL
|| wb->Window()->GetFeel() == B_FLOATING_APP_WINDOW_FEEL)
{
// set its new MainWinBorder
if(wb->Window()->GetFeel() == 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()->GetFeel() == 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->GetServerFeel() == B_FLOATING_SUBSET_FEEL
|| listItem->layerPtr->GetServerFeel() == 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;
} // else - if diferrent ClientTeamID()s.
} // 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()->GetFeel();
if ((feel == B_MODAL_SUBSET_WINDOW_FEEL
&& preferred->Window()->GetFMWList()->HasItem(listItem->layerPtr))
|| (feel == B_MODAL_APP_WINDOW_FEEL
&& preferred->Window()->GetClientTeamID() ==
listItem->layerPtr->Window()->GetClientTeamID()
))
{
// *carefully* remove the item from the list
ListData *item = listItem;
listItem = listItem->lowerItem;
RemoveItem(item);
}
else
listItem = listItem->lowerItem;
}
// add to the final list window's subset windows. (..._SUBSET_...)
finalFMWList.AddFMWList( preferred->Window()->GetFMWList() );
// also add application's ones. (..._APP_...)
finalFMWList.AddFMWList(preferred->Window()->GetApp()->GetFMWList());
// 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()->GetFeel() == B_MODAL_SUBSET_WINDOW_FEEL
|| wb->Window()->GetFeel() == B_MODAL_APP_WINDOW_FEEL))
|| (fBottomItem &&
(fBottomItem->layerPtr->Window()->GetFeel() == B_MODAL_ALL_WINDOW_FEEL
|| fBottomItem->layerPtr->Window()->GetFeel() == 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; i<count; i++){
WinBorder *wb = (WinBorder*)finalFMWList.ItemAt(i);
// do not insert floating windows if the last is a modal one.
if(wb->Window()->GetFeel() == B_FLOATING_SUBSET_WINDOW_FEEL
|| wb->Window()->GetFeel() == B_FLOATING_APP_WINDOW_FEEL)
{
// set its new MainWinBorder
if(wb->Window()->GetFeel() == 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()->GetFeel() == 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->GetName()));
// 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->GetName()));
FMWList finalMWList;
int32 count, i;
int32 prefIndex;
if (fFrontItem && fFrontItem->layerPtr->GetServerFeel() == B_NORMAL_FEEL)
{
// remove front window's floating(_SUBSET_/_APP_) windows, if any.
ListData *listItem = fFrontItem->lowerItem;
while(listItem && (listItem->layerPtr->GetServerFeel() == B_FLOATING_SUBSET_FEEL
|| listItem->layerPtr->GetServerFeel() == B_FLOATING_APP_FEEL))
{ // *carefully* remove the item from the list
ListData *item = listItem;
listItem = listItem->lowerItem;
RemoveItem(item);
}
}
// 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()->GetFMWList()->IndexOf(preferred);
count = preferred->MainWinBorder()->Window()->GetFMWList()->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()->GetFMWList();
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()->GetApp()->GetFMWList()->CountItems();
listPtr = preferred->Window()->GetApp()->GetFMWList();
for(i = 0; i < count; i++){
wb = (WinBorder*)listPtr->ItemAt(i);
if (wb->Window()->GetFeel() == 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()->GetApp()->GetFMWList()->IndexOf(preferred);
count = preferred->Window()->GetApp()->GetFMWList()->CountItems();
if (prefIndex >= 0){
WinBorder *wb = NULL;
// add modal windows from application's subset - windows that are
// positioned after 'preferred'.
FMWList *listPtr = preferred->Window()->GetApp()->GetFMWList();
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; i<count; i++){
WinBorder *wb = (WinBorder*)finalMWList.ItemAt(i);
// wb is surely a modal so... ATM make it the front one.
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(prefFeel == B_MODAL_ALL_WINDOW_FEEL
|| prefFeel == B_SYSTEM_FIRST)
{
STRACE((" MODAL ALL/SYSTEM FIRST Window '%s'\n", preferred->GetName()));
// remove all application's floating windows.
if (fFrontItem && fFrontItem->layerPtr->GetServerFeel() == B_NORMAL_FEEL)
{
ListData *listItem = fFrontItem->lowerItem;
while(listItem &&
(listItem->layerPtr->GetServerFeel() == B_FLOATING_SUBSET_FEEL
|| listItem->layerPtr->GetServerFeel() == 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!
printf("SERVER: PANIC: \"%s\": What kind of window is this???\n", preferred->GetName());
}
}
if(preferred){
int32 feel = fBottomItem->layerPtr->Window()->GetFeel();
// if preferred is one of these *don't* give front state to it!
if(preferred->GetServerFeel() == B_FLOATING_SUBSET_FEEL
|| preferred->GetServerFeel() == B_FLOATING_APP_FEEL
|| preferred->GetServerFeel() == B_FLOATING_ALL_FEEL)
{ }
// if the last in workspace's list is one of these, GIVE focus to it!
else if(feel == B_SYSTEM_FIRST || feel == B_MODAL_ALL_WINDOW_FEEL){
fFrontItem = fBottomItem;
}
// the SYSTEM_LAST will get the front status, only if it's the only
// WinBorder in this workspace.
else if (preferred->GetServerFeel() == B_SYSTEM_LAST){
if(fBottomItem->layerPtr == preferred)
fFrontItem = HasItem(preferred);
}
// this is in case of MODAL[APP/SUBSET] and NORMAL windows
else{
fFrontItem = HasItem(preferred);
}
}
else{ fFrontItem = NULL; }
}
/* 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){
return;
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()->GetFlags() & B_AVOID_FOCUS)
continue;
// this means there is no modal window before our preferred one.
if (item->layerPtr == preferred)
break;
// we now chose a modal window to give focus to
if (item->layerPtr->GetServerFeel() == B_SYSTEM_FIRST
|| item->layerPtr->GetServerFeel() == B_MODAL_ALL_FEEL
|| item->layerPtr->GetServerFeel() == B_MODAL_APP_FEEL
|| item->layerPtr->GetServerFeel() == B_MODAL_SUBSET_FEEL)
{
break;
}
}
if (item != fFocusItem){
// TODO: item->ColorTabInGrey & send message to client
// TODO: item->ColorTabInYellow & send message to client
// TODO: Rebuild & Redraw.
fFocusItem = item;
}
}
/* The method moves a window to the back of its subset.
*/
//---------------------------------------------------------------------------
void Workspace::MoveToBack(WinBorder* newLast){
STRACE(("\n!MoveToBack(%s) -", newLast? newLast->GetName(): "NULL"));
// does the list have this element?
ListData *item = HasItem(newLast);
if(item){
ListData *listItem = NULL;
switch(item->layerPtr->GetServerFeel()){
case B_FLOATING_ALL_FEEL:{
STRACE((" B_FLOATING_ALL_FEEL window\n"));
// search the place where we should insert it later
listItem = item->upperItem;
while(listItem && (listItem->layerPtr->GetServerFeel() == item->layerPtr->GetServerFeel()))
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->GetServerFeel() == B_FLOATING_SUBSET_FEEL
|| listItem->layerPtr->GetServerFeel() == B_FLOATING_APP_FEEL))
listItem = listItem->upperItem;
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->GetServerFeel() == B_MODAL_SUBSET_FEEL
|| listItem->layerPtr->GetServerFeel() == B_MODAL_APP_FEEL
|| listItem->layerPtr->GetServerFeel() == B_NORMAL_FEEL))
listItem = listItem->upperItem;
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->GetServerFeel() >= item->layerPtr->GetServerFeel())){
listItem = listItem->upperItem;
}
break;
}
}
if ((listItem && item->lowerItem == listItem->lowerItem)
|| (listItem == NULL && item == fTopItem))
{
// 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->GetServerFeel() == B_NORMAL_FEEL && fFrontItem->layerPtr == newLast){
ListData *iter = item->lowerItem;
while(iter &&
(iter->layerPtr->GetServerFeel() == B_FLOATING_SUBSET_FEEL
|| iter->layerPtr->GetServerFeel() == B_FLOATING_APP_FEEL))
{
// *carefully* remove the item from the list
ListData *itemX = iter;
iter = iter->lowerItem;
RemoveItem(itemX);
}
}
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);
if (wasFront)
SearchAndSetNewFront(nextPreferred);
if (wasFocus)
SearchAndSetNewFocus(nextPreferred);
}
STRACESTREAM();
}
else
STRACE((" this operation was not needed\n"));
}
//---------------------------------------------------------------------------
void Workspace::SetLocalSpace(const uint32 colorspace){
fSpace = colorspace;
}
//---------------------------------------------------------------------------
uint32 Workspace::LocalSpace() const{
return fSpace;
}
//---------------------------------------------------------------------------
void Workspace::SetBGColor(const RGBColor &c){
fBGColor = c;
}
//---------------------------------------------------------------------------
RGBColor Workspace::BGColor(void) const{
return fBGColor;
}
//---------------------------------------------------------------------------
// Debug methods!!!
//---------------------------------------------------------------------------
void Workspace::PrintToStream() const{
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");
if (wb->Window()->GetFeel() == B_FLOATING_SUBSET_WINDOW_FEEL)
printf("\t%s\n", "B_FLOATING_SUBSET_WINDOW_FEEL");
if (wb->Window()->GetFeel() == B_FLOATING_APP_WINDOW_FEEL)
printf("\t%s\n", "B_FLOATING_APP_WINDOW_FEEL");
if (wb->Window()->GetFeel() == B_FLOATING_ALL_WINDOW_FEEL)
printf("\t%s\n", "B_FLOATING_ALL_WINDOW_FEEL");
if (wb->Window()->GetFeel() == B_MODAL_SUBSET_WINDOW_FEEL)
printf("\t%s\n", "B_MODAL_SUBSET_WINDOW_FEEL");
if (wb->Window()->GetFeel() == B_MODAL_APP_WINDOW_FEEL)
printf("\t%s\n", "B_MODAL_APP_WINDOW_FEEL");
if (wb->Window()->GetFeel() == B_MODAL_ALL_WINDOW_FEEL)
printf("\t%s\n", "B_MODAL_ALL_WINDOW_FEEL");
if (wb->Window()->GetFeel() == B_NORMAL_WINDOW_FEEL)
printf("\t%s\n", "B_NORMAL_WINDOW_FEEL");
if (wb->Window()->GetFeel() == B_SYSTEM_LAST)
printf("\t%s\n", "B_SYSTEM_LAST");
if (wb->Window()->GetFeel() == 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");
}