xref: /haiku/src/servers/app/Workspace.cpp (revision 2ae568931fcac7deb9f1e6ff4e47213fbfe4029b)
1 //------------------------------------------------------------------------------
2 //	Copyright (c) 2001-2005, Haiku, Inc.
3 //
4 //	Permission is hereby granted, free of charge, to any person obtaining a
5 //	copy of this software and associated documentation files (the "Software"),
6 //	to deal in the Software without restriction, including without limitation
7 //	the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 //	and/or sell copies of the Software, and to permit persons to whom the
9 //	Software is furnished to do so, subject to the following conditions:
10 //
11 //	The above copyright notice and this permission notice shall be included in
12 //	all copies or substantial portions of the Software.
13 //
14 //	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 //	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 //	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 //	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 //	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 //	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 //	DEALINGS IN THE SOFTWARE.
21 //
22 //	File Name:		Workspace.cpp
23 //	Author:			Adi Oanca <adioanca@cotty.iren.ro>
24 //	Description:	Tracks windows inside one workspace
25 //
26 //  !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
27 //  Notes:			IMPORTANT WARNING
28 //					This object does not use any locking mechanism. It is designed
29 //					to be used by RootLayer class ONLY. DO NOT USE from elsewhere!
30 //
31 //	Design Spec:
32 //			The purpose of this class it to have visible windows appear in the
33 // correct order as defined by GUI guidelines. Those define 3 main type of windows:
34 // normal windows, modal and floating windows. Aditionally there must be support
35 // for another 2 types of windows which will be used in special cases. We're talking
36 // about system front windows which always will be the front-most and have focus, and
37 // system last windows which will always be behind all other kind of windows.
38 //
39 //			Normal windows will always be in Workspace's list, be it they are hidden
40 // or not. They are added by hand (AddWindowLayer()) only. Same goes for system last
41 // windows, system first, modall all and floating all windows. Those remaining
42 // are: modal subset, modal app, floating subset and floating app. Those will be
43 // added and removed on-the-fly as they are needed.
44 //
45 //			To keep correct track of modal subset/app and floating subset/app windows
46 // we need to have them in a list. Also, we want every normal window to
47 // maintain its floating windows order. For that we define a list for every normal
48 // window in which we'll add floating subset & app windows alongside with subset
49 // modals. Application modals go in a separate list which is hold for every
50 // application (ServerApp) object. For normal window's list: when a floating win
51 // is need (when normal window becomes front) it is always removed and automaticaly
52 // added to workspace's list. When that normal looses front state, it reinserts
53 // all floating windows it has used back into its list, thus saving the exact order
54 // of floating windows. Modal windows are never removed from normal or application's
55 // list, but they are automaticaly added and removed from workspace's list as needed.
56 // (ex: a modal app won't appear until a normal window from the same app is visible)
57 //
58 //			Front status is a bit hard to explain. It's a state which helps keep
59 // the wanted order. For example, if a modal window is set to have front status,
60 // an automatic search is made to see if another modal was created after this
61 // one and thus needs to have front state (read: thus have to be in front this).
62 // Another use is to have floating windows pop up in front of a normal window when
63 // no modal exist to steal front state.
64 //------------------------------------------------------------------------------
65 #include <stdio.h>
66 #include <stdlib.h>
67 #include <Window.h>
68 #include <TypeConstants.h>
69 
70 #include "Workspace.h"
71 #include "Layer.h"
72 #include "WindowLayer.h"
73 #include "ServerWindow.h"
74 #include "ServerApp.h"
75 #include "RGBColor.h"
76 #include "SubWindowList.h"
77 
78 //#define DEBUG_WORKSPACE
79 
80 #ifdef DEBUG_WORKSPACE
81 #	include <stdio.h>
82 #	define STRACE(x) printf x
83 #else
84 #	define STRACE(x) ;
85 #endif
86 
87 #ifdef DEBUG_WORKSPACE
88 #	include <stdio.h>
89 #	define STRACESTREAM() PrintToStream()
90 #else
91 #	define STRACESTREAM() ;
92 #endif
93 
94 void
95 Workspace::State::PrintToStream()
96 {
97 	printf("WS::State - Front: %s\n", Front? Front->Name(): "NULL");
98 	printf("WS::State - Focus: %s\n", Focus? Focus->Name(): "NULL");
99 
100 	for (int32 i = 0; i < WindowList.CountItems(); ++i) {
101 		Layer *l = (Layer*)WindowList.ItemAt(i);
102 		if (l)
103 			printf("\t %ld - %s\n", i, l->Name());
104 	}
105 }
106 
107 //----------------------------------------------------------------------------------
108 /*!
109 	\brief	Creates a new Workspace object which has its own resolution and background color.
110 */
111 Workspace::Workspace(const int32 ID, const uint32 colorspace, const RGBColor& BGColor)
112 	: fBGColor(BGColor)
113 {
114 STRACE(("New Workspace(%ld)\n", fID));
115 	fID			= ID;
116 
117 	fBottomItem	= NULL;
118 	fTopItem	= NULL;
119 	fFocusItem	= NULL;
120 	fFrontItem	= NULL;
121 
122 	memset(&fDisplayMode, 0, sizeof(fDisplayMode));
123 	fDisplayMode.space = colorspace;
124 }
125 
126 //----------------------------------------------------------------------------------
127 /*!
128 	\brief	Frees internal data.
129 */
130 Workspace::~Workspace(void)
131 {
132 STRACE(("~Workspace(%ld) - say bye bye\n", fID));
133 	fFocusItem		= NULL;
134 	fFrontItem		= NULL;
135 
136 	ListData		*toast;
137 	while(fBottomItem)
138 	{
139 		toast		= fBottomItem;
140 		fBottomItem	= fBottomItem->upperItem;
141 
142 		fPool.ReleaseMemory(toast);
143 	}
144 	fBottomItem		= NULL;
145 	fTopItem		= NULL;
146 }
147 
148 
149 /*!
150 	\brief	Adds layer ptr to workspace's list of WindowLayers.
151 */
152 void
153 Workspace::AddWindowLayer(WindowLayer *winBorder)
154 {
155 STRACE(("W(%ld)::AddWindowLayer(%s)\n", fID, winBorder?winBorder->Name():"NULL"));
156 	if (winBorder->Level() == B_FLOATING_APP) {
157 		// floating windows are automaticaly added when needed
158 		// you cannot add one by hand.
159 		return;
160 	}
161 
162 	if (HasItem(winBorder)) {
163 		// NOTE: you may remove 'debugger' at Release Candidate time
164 		debugger("WindowLayer ALREADY in Workspace's list\n");
165 		return;
166 	}
167 
168 	// allocate a new item
169 	ListData* item = fPool.GetCleanMemory(winBorder);
170 
171 	// place this winBorder in what seems the most appropriate location.
172 	// Do not change front window
173 	placeInFront(item, false);
174 }
175 
176 
177 /*
178 	\brief	Removes a WindowLayer from workspace's list.
179 */
180 void
181 Workspace::RemoveWindowLayer(WindowLayer *winBorder)
182 {
183 	STRACE(("W(%ld)::RemoveWindowLayer(%s)\n", fID, winBorder?winBorder->Name():"NULL"));
184 	ListData* item = HasItem(winBorder);
185 
186 	if (item) {
187 		RemoveItem(item);
188 		fPool.ReleaseMemory(item);
189 	}
190 }
191 
192 
193 bool
194 Workspace::HasWindowLayer(const WindowLayer* winBorder) const
195 {
196 	return HasItem(winBorder) ? true: false;
197 }
198 
199 
200 WindowLayer *
201 Workspace::Focus() const
202 {
203 	return fFocusItem ? fFocusItem->layerPtr : NULL;
204 }
205 
206 
207 WindowLayer *
208 Workspace::Front() const
209 {
210 	return fFrontItem ? fFrontItem->layerPtr: NULL;
211 }
212 
213 
214 WindowLayer *
215 Workspace::Active() const
216 {
217 	return fFocusItem ? fFocusItem->layerPtr : NULL;
218 }
219 
220 
221 /*!
222 	\brief Method that returns the state of window manager.
223 	\param state - a pointer to a valid Workspace::State structure
224 	\return void
225 
226 	Fills the state structure with the most important window manager attibutes:
227 	front window, focus window, active window and the list of windows starting from
228 	the backmost one at position 0 and ending with the most visible window.
229 */
230 void
231 Workspace::GetState(Workspace::State *state) const
232 {
233 	state->Front = Front();
234 	state->Focus = Focus();
235 
236 	ListData *cursor = fTopItem;
237 	while (cursor) {
238 		if (!cursor->layerPtr->IsHidden())
239 			state->WindowList.AddItem(cursor->layerPtr);
240 		cursor = cursor->lowerItem;
241 	}
242 }
243 
244 
245 bool
246 Workspace::AttemptToSetFront(WindowLayer *newFront)
247 {
248 	return MoveToFront(newFront);
249 }
250 
251 
252 int32
253 Workspace::AttemptToSetFocus(WindowLayer *newFocus)
254 {
255 	ListData* newFocusItem = HasItem(newFocus);
256 
257 	return _SetFocus(newFocusItem);
258 }
259 
260 bool
261 Workspace::AttemptToMoveToBack(WindowLayer *newBack)
262 {
263 	return MoveToBack(newBack);
264 }
265 
266 bool
267 Workspace::AttemptToActivate(WindowLayer *toActivate)
268 {
269 	MoveToFront(toActivate);
270 	AttemptToSetFocus(toActivate);
271 	return Active() == toActivate;
272 }
273 /*
274 	\brief	This method provides you the list of visible windows in this workspace.
275 	\param	list The list of visible WindowLayers found in this workspace.
276 	\param	itemCount Number of WindowLayer pointers found in the list.
277 */
278 bool
279 Workspace::GetWindowLayerList(void **list, int32 *itemCount ) const
280 {
281 	int32 count = 0;
282 	ListData* cursor;
283 
284 	cursor = fBottomItem;
285 	while (cursor) {
286 		if (!cursor->layerPtr->IsHidden())
287 			count++;
288 		cursor = cursor->upperItem;
289 	}
290 
291 	if (*itemCount < count) {
292 		// buffer not big enough. buffer must be count high
293 		*itemCount = count;
294 		return false;
295 	}
296 
297 	if (list) {
298 		*itemCount = count;
299 
300 		cursor = fBottomItem;
301 		while (cursor) {
302 			if (!cursor->layerPtr->IsHidden()) {
303 				*list = cursor->layerPtr;
304 				list++;
305 			}
306 			cursor = cursor->upperItem;
307 		}
308 	}
309 
310 	return true;
311 }
312 
313 /*!
314 	\brief	Makes the specified WindowLayer the focus one.
315 	\param	newFocus WindowLayer which will try to take focus state.
316 	\return	0 - setting focus failed, focus did not change.
317 			1 - the new focus WindowLayer is \a winBorder
318 			2 - focus changed but not to \a winBorder because in front of it there
319 				are other modal windows.
320 
321 	Set a new focus WindowLayer if possible.
322 */
323 
324 int32
325 Workspace::_SetFocus(ListData *newFocusItem)
326 {
327 	if (!newFocusItem || newFocusItem == fFocusItem
328 			|| (newFocusItem && !newFocusItem->layerPtr->IsHidden()
329 				&& newFocusItem->layerPtr->WindowFlags() & B_AVOID_FOCUS))
330 		return 0L;
331 
332 	WindowLayer *newFocus = newFocusItem->layerPtr;
333 	bool rv = 1;
334 
335 	switch(newFocus->Level()) {
336 		case B_MODAL_APP:
337 		case B_NORMAL: {
338 			ListData *item = newFocusItem->upperItem;
339 			while (	item &&
340 					!item->layerPtr->IsHidden() &&
341 					((item->layerPtr->Level() == B_MODAL_APP &&
342 						item->layerPtr->App()->ClientTeam() == newFocus->App()->ClientTeam()) ||
343 					 item->layerPtr->Level() >= B_MODAL_ALL))
344 			{
345 				if (item->layerPtr->WindowFlags() & B_AVOID_FOCUS)
346 					newFocusItem = NULL;
347 				else
348 					newFocusItem = item;
349 				rv = 2;
350 			}
351 		}
352 		break;
353 
354 		case B_SYSTEM_FIRST:
355 		case B_MODAL_ALL: {
356 			ListData *item = newFocusItem->upperItem;
357 			while (	item &&
358 					!item->layerPtr->IsHidden() &&
359 					item->layerPtr->Level() >= newFocus->Level())
360 			{
361 				if (item->layerPtr->WindowFlags() & B_AVOID_FOCUS)
362 					newFocusItem = NULL;
363 				else
364 					newFocusItem = item;
365 				rv = 2;
366 			}
367 		}
368 		break;
369 
370 		default:
371 		break;
372 	}
373 
374 	fFocusItem = newFocusItem;
375 
376 	return rv;
377 }
378 
379 /*!
380 	\brief	Makes the specified WindowLayer the front one.
381 	\param	newFront WindowLayer which will try to take front state.
382 	\param	doNotDisturb In case user is busy typing something, don't bring \a newFront
383 			in front stealing front&focus, but place imediately after.
384 	\return	True if the list of WindowLayers has changed, false otherwise.
385 
386 	This method tries to make \a newFront the new front WindowLayer. "It tries" because
387 	if this a B_NORMAL window with subset or application modals those will be displayed
388 	in front and get the front state. If no subset or application modals exist, then this
389 	B_NORMAL window will get front (and focus) state and subset and application floating
390 	window will be shown in front.
391 	Note that floating windows cannot get/have front state.
392 */
393 bool
394 Workspace::MoveToFront(WindowLayer *newFront, bool doNotDisturb)
395 {
396 	STRACE(("\nWks(%ld)::MoveToFront ~%s~ \n", fID, newFront?newFront->Name():"NULL"));
397 	if (!newFront)
398 		return false;
399 
400 	if (newFront->IsHidden() || newFront->Level() == B_SYSTEM_LAST)
401 		return false;
402 
403 	if (fFrontItem && newFront == fFrontItem->layerPtr) {
404 		// we didn't change windows order
405 		return false;
406 	}
407 
408 	return ShowWindowLayer(newFront);
409 }
410 
411 
412 /*!
413 	\brief	Moves the specified WindowLayer in the back as it is possible.
414 	\param	newLast WindowLayer which will be placed in the back.
415 	\return	True if the list of WindowLayers has changed, false otherwise.
416 
417 		WindowLayer \a newLast will go in the back as much as possible. Note that this
418 	action is tricky. While normal windows will always go into the back, front modal windows
419 	won't go into the back if the next front window will be a B_NORMAL or B_MODAL_APP part
420 	of the same team which was previously created. If it were possible it would
421 	undermine the role of modal windows in the system. Another example regards B_FLOATING_APP
422 	windows. These will ge in the back as possible, but never farther than the front
423 	B_NORMAL window in front of which they appear.
424 */
425 bool
426 Workspace::MoveToBack(WindowLayer *newLast)
427 {
428 	STRACE(("Wks(%ld)::MoveToBack(%s) \n", fID, newLast? newLast->Name(): "NULL"));
429 	if (newLast->IsHidden())
430 		return false;
431 
432 	ListData		*newLastItem;
433 	newLastItem		= HasItem(newLast);
434 	if (!newLastItem)
435 		return false;
436 
437 	ListData	*previous = newLastItem->upperItem;
438 	bool		returnValue	= false;
439 	bool		changeFront	= false;
440 	int32		level		= newLast->Level();
441 	if (level > B_SYSTEM_FIRST)
442 		level = B_SYSTEM_FIRST;
443 
444 	if (fFrontItem && fFrontItem == newLastItem)
445 		changeFront = true;
446 
447 	switch(newLast->Level())
448 	{
449 		case B_MODAL_ALL:
450 		case B_SYSTEM_FIRST:
451 		case B_SYSTEM_LAST:
452 		{
453 			// these kind of windows do not change position
454 			return false;
455 		}
456 		break;
457 		case B_NORMAL:
458 		{
459 			ListData	*cursor = newLastItem->upperItem;
460 
461 			// we are already the back-most window.
462 			if (!cursor || cursor->layerPtr->Level() == B_SYSTEM_LAST )
463 				return false;
464 
465 			if (changeFront)
466 				saveFloatingWindows(fFrontItem);
467 		}
468 		// NOTE: no 'break;' here...
469 		case B_FLOATING_APP:
470 		case B_FLOATING_ALL:
471 		{
472 			returnValue = placeToBack(newLastItem);
473 		}
474 		break;
475 		case B_MODAL_APP:
476 		{
477 			ListData	*cursor = newLastItem->upperItem;
478 
479 			// we are already the back-most window.
480 			if (!cursor || cursor->layerPtr->Level() == B_SYSTEM_LAST )
481 				return false;
482 
483 			// this is a modal app
484 			if (newLast->App()->fAppSubWindowList.HasItem(newLast)) {
485 				ListData* before;
486 
487 				// remove now to properly place later
488 				RemoveItem(newLastItem);
489 
490 				while (cursor) {
491 					if (!cursor->layerPtr->IsHidden()
492 						&& cursor->layerPtr->Level() > B_SYSTEM_LAST
493 						&& cursor->layerPtr->App()->ClientTeam() == newLast->App()->ClientTeam())
494 						break;
495 
496 					cursor	= cursor->upperItem;
497 				}
498 
499 				if (cursor)
500 					before	= cursor->lowerItem;
501 				else
502 					before	= fTopItem;
503 
504 				InsertItem(newLastItem, before);
505 			} else {
506 				// this is a modal subset
507 				// this subset modal is visible, it means its main window must be visible. search for it.
508 				ListData	*mainWindowItem, *before;
509 				int32		indexThis = 0, indexCursor;
510 
511 				// search by going deep
512 				while (cursor) {
513 					if (cursor->layerPtr->Level() == B_NORMAL && !cursor->layerPtr->IsHidden()
514 						&& (indexThis = cursor->layerPtr->fSubWindowList.IndexOf(newLast)) >= 0)
515 						break;
516 					cursor	= cursor->upperItem;
517 				}
518 
519 				if (!cursor)
520 					debugger("MoveToBack: SubsetWindow: can't find main Window!\n");
521 
522 				RemoveItem(newLastItem);
523 
524 				// good. found our main window. now go up and properly place.
525 				mainWindowItem = cursor;
526 				before = cursor->lowerItem;
527 
528 				cursor = cursor->lowerItem;
529 				while (cursor) {
530 					if (cursor->layerPtr->Level() == B_MODAL_APP && !cursor->layerPtr->IsHidden()
531 						&& cursor->layerPtr->App()->ClientTeam() == newLast->App()->ClientTeam())
532 					{
533 						indexCursor	= mainWindowItem->layerPtr->fSubWindowList.IndexOf(cursor->layerPtr);
534 						if (indexCursor >= 0)
535 						{
536 							if (indexThis < indexCursor)
537 							{
538 								before = cursor;
539 								break;
540 							}
541 							else
542 							{
543 								before = cursor->lowerItem;
544 							}
545 						}
546 					}
547 					cursor	= cursor->lowerItem;
548 				}
549 
550 				InsertItem(newLastItem, before);
551 			}
552 			returnValue = true;
553 		}
554 		break;
555 		default:
556 		{
557 			debugger("MoveToBack: unknown window feel\n");
558 			return false;
559 		}
560 	}
561 
562 	if (previous == newLastItem->upperItem)
563 		returnValue = false;
564 
565 	// The following applies ONLY to B_NORMAL and B_MODAL_APP windows.
566 
567 	if (changeFront)
568 	{
569 		ListData	*newFront;
570 		newFront	= findNextFront();
571 		if (newFront)
572 			returnValue |= MoveToFront(newFront->layerPtr);
573 		else
574 			debugger("MoveToBack: can't find new front! We should find one!\n");
575 	}
576 
577 	return returnValue;
578 }
579 
580 
581 /*!
582 	\brief	Hides a WindowLayer.
583 	\param	winBorder WindowLayer to be hidden.
584 	\return	True if the list of WindowLayers has changed, false otherwise.
585 
586 	WindowLayer \a winBorder will be hidden. Some, like floating or subset modals
587 	may also be removed from Workspace's list.
588 	If \a winBorder if the front WindowLayer, another one (or none) will be automaticaly
589 	chosen. Same goes for focus.
590 */
591 bool
592 Workspace::HideWindowLayer(WindowLayer *winBorder)
593 {
594 	STRACE(("W(%ld)::HideWindowLayer(%s) \n", fID, winBorder? winBorder->Name(): "NULL"));
595 	bool returnValue = false;
596 	int32 level = winBorder->Level();
597 	bool changeFront = false;
598 	bool changeFocus = false;
599 	ListData* nextFocus = NULL;
600 
601 	if (fFrontItem && fFrontItem->layerPtr == winBorder)
602 		changeFront = true;
603 
604 	if (fFocusItem && fFocusItem->layerPtr == winBorder) {
605 		changeFocus = true;
606 		nextFocus = fFocusItem->lowerItem;
607 	}
608 
609 	if (level > B_SYSTEM_FIRST)
610 		level = B_SYSTEM_FIRST;
611 
612 	switch (level) {
613 		case B_MODAL_ALL:
614 		case B_SYSTEM_FIRST:
615 		case B_SYSTEM_LAST:
616 		case B_FLOATING_ALL:
617 			// window is just hidden. do nothing. its position is OK as it is now.
618 			returnValue = true;
619 			break;
620 
621 		case B_FLOATING_APP:
622 			if (fFrontItem && fFrontItem->layerPtr->Level() == B_NORMAL) {
623 				ListData* item = HasItem(winBorder);
624 				if (item) {
625 					fFrontItem->layerPtr->fSubWindowList.AddWindowLayer(winBorder);
626 
627 					RemoveItem(item);
628 					fPool.ReleaseMemory(item);
629 
630 					returnValue = true;
631 				}
632 			}
633 			break;
634 
635 		case B_NORMAL:
636 		{
637 			if (fFrontItem && fFrontItem->layerPtr == winBorder)
638 				saveFloatingWindows(fFrontItem);
639 
640 			// remove B_MODAL_SUBSET windows present before this window.
641 			ListData* itemThis = HasItem(winBorder);
642 			ListData* toast;
643 			ListData* item = itemThis->lowerItem;
644 			while (item) {
645 				// if this modal subset is in our list ONLY (not in other visible normal window's one),
646 				// then remove from Workspace's list.
647 				if (item->layerPtr->Level() == B_MODAL_APP) {
648 					if (winBorder->fSubWindowList.HasItem(item->layerPtr)) {
649 						if (!searchFirstMainWindow(item->layerPtr)) {
650 							// if this modal subset has front state, make sure another window will get that status.
651 							if (fFrontItem == item)
652 								changeFront = true;
653 
654 							toast = item;
655 							item = item->lowerItem;
656 							RemoveItem(toast);
657 							fPool.ReleaseMemory(toast);
658 						}
659 					} else if (!searchANormalWindow(item->layerPtr)
660 						&& !(item->layerPtr->Workspaces() & (0x00000001 << fID))) {
661 						// if this modal subset has front state, make sure another window will get that status.
662 						if (fFrontItem == item)
663 							changeFront = true;
664 
665 						toast = item;
666 						item = item->lowerItem;
667 						RemoveItem(toast);
668 						fPool.ReleaseMemory(toast);
669 					} else
670 						item = item->lowerItem;
671 				} else
672 					item = item->lowerItem;
673 			}
674 
675 			returnValue = true;
676 			break;
677 		}
678 
679 		case B_MODAL_APP:
680 		{
681 			// if a subset modal, then remove from Workspace's list.
682 			if (winBorder->App()->fAppSubWindowList.HasItem(winBorder)) {
683 				ListData* toast = HasItem(winBorder);
684 				if (toast) {
685 					RemoveItem(toast);
686 					fPool.ReleaseMemory(toast);
687 
688 					returnValue = true;
689 				}
690 			}
691 			break;
692 		}
693 
694 		default:
695 			debugger("HideWindowLayer: what kind of window is this?\n");
696 	}
697 
698 	// select a new Front if needed
699 	if (changeFront) {
700 		fFrontItem = NULL;
701 
702 		ListData* newFront = findNextFront();
703 		if (newFront)
704 			MoveToFront(newFront->layerPtr);
705 	}
706 
707 	if (!HasItem(fFocusItem))
708 		fFocusItem = NULL;
709 
710 	// floating windows can have focus state. what if this removed window is
711 	// the focus window? There will be no focus anymore.
712 	// So, start a search to set the new focus
713 	if (!fFocusItem || changeFocus) {
714 		if (!HasItem(nextFocus))
715 			nextFocus = NULL;
716 
717 		if (nextFocus == NULL) {
718 			nextFocus = fBottomItem;
719 
720 			while (nextFocus) {
721 				if (!nextFocus->layerPtr->IsHidden()
722 					&& !(nextFocus->layerPtr->WindowFlags() & B_AVOID_FOCUS))
723 					break;
724 				else
725 					nextFocus = nextFocus->upperItem;
726 			}
727 		}
728 
729 		fFocusItem = nextFocus;
730 	}
731 
732 	return returnValue;
733 }
734 
735 /*!
736 	\brief	Shows a WindowLayer.
737 	\param	winBorder WindowLayer to be show.
738 	\return	True if the list of WindowLayers has changed, false otherwise.
739 
740 	WindowLayer \a winBorder will be shown. Other windows like floating or modal
741 	ones will be placed in front if needed. Front & Focus state will be given to \a winBorder
742 	unless a modal windows steals both.
743 */
744 bool
745 Workspace::ShowWindowLayer(WindowLayer *winBorder, bool userBusy)
746 {
747 	STRACE(("W(%ld)::ShowWindowLayer(%s) \n", fID, winBorder? winBorder->Name(): "NULL"));
748 	bool returnValue = false;
749 	int32 level = winBorder->Level();
750 	if (level > B_SYSTEM_FIRST)
751 		level = B_SYSTEM_FIRST;
752 
753 	// Before you go understand this method, please note that 'placeInFront' MUST be
754 	// called of EVERY window except B_FLOATING_APP when
755 	// ADDING a new window to Workspace's list!!!
756 
757 	switch (level) {
758 		// B_MODAL_ALL, B_FLOATNG_ALL, B_SYSTEM_FIRST & B_SYSTEM_LAST
759 		// will be removed ONLY when are deleted!
760 		// ALSO, they will ALWAYS be the first/last windows in hierarchy, no matter
761 		// if they are hidden or not - they keep their order.
762 
763 		case B_MODAL_ALL:
764 		case B_SYSTEM_FIRST:
765 		case B_SYSTEM_LAST:
766 		{
767 			// nothing special to be done. just compare indexes to see if front state will change.
768 			if (fFrontItem) {
769 				int32 reverseIndexThis, reverseIndexFront;
770 				ListData* itemThis = HasItem(winBorder, &reverseIndexThis);
771 
772 				HasItem(fFrontItem->layerPtr, &reverseIndexFront);
773 
774 				if (reverseIndexThis < reverseIndexFront) {
775 					if (fFrontItem->layerPtr->Level() == B_NORMAL)
776 						saveFloatingWindows(fFrontItem);
777 
778 					fFrontItem = itemThis;
779 				}
780 			} else {
781 				// of course, if there is no front item, then set this one.
782 				fFrontItem	= HasItem(winBorder);
783 			}
784 			returnValue = true;
785 			break;
786 		}
787 
788 		case B_FLOATING_ALL:
789 		{
790 			// simply relocate. A floating window can't have front state.
791 			ListData* itemThis = HasItem(winBorder);
792 			RemoveItem(itemThis);
793 			placeInFront(itemThis, userBusy);
794 
795 			returnValue = true;
796 			break;
797 		}
798 
799 		// FLOATING windows are always removed from Workspace's list when changing to a new front window.
800 
801 		case B_FLOATING_APP:
802 		{
803 			// see if we have a front window which is a B_NORMAL window and who's list of floating
804 			// and modal windows contains our window.
805 			if (fFrontItem && fFrontItem->layerPtr->Level() == B_NORMAL) {
806 				// if this winBorder is the focus it is already the first among floating app windows.
807 				if (fFocusItem && fFocusItem->layerPtr == winBorder)
808 					break;
809 
810 				ListData* itemThis = NULL;
811 				// remove from B_NORMAL's list.
812 				if (fFrontItem->layerPtr->fSubWindowList.RemoveItem(winBorder)) {
813 					// we need to add this window
814 					itemThis = fPool.GetCleanMemory(winBorder);
815 				} else {
816 					itemThis = HasItem(winBorder);
817 					// window is already in Workspace's list. Find and temporarly remove.
818 					if (itemThis)
819 						RemoveItem(itemThis);
820 				}
821 
822 				if (itemThis) {
823 					// insert in front of other B_FLOATING_APP windows.
824 					ListData* item = fFrontItem->lowerItem;
825 					while (item && item->layerPtr->Level() == B_FLOATING_APP)
826 						item = item->lowerItem;
827 
828 					InsertItem(itemThis, item);
829 
830 					returnValue = true;
831 				}
832 			}
833 			break;
834 		}
835 
836 		case B_NORMAL:
837 		{
838 			ListData* itemThis = HasItem(winBorder);
839 
840 			if (!itemThis) {
841 				debugger("ShowWindowLayer: B_NORMAL window - cannot find specified window in workspace's list\n");
842 				return false;
843 			}
844 
845 			// front status will change. if a normal window has front state,
846 			// remove and save floating windows order that may be above it.
847 			if (fFrontItem && fFrontItem->layerPtr->Level() == B_NORMAL)
848 				saveFloatingWindows(fFrontItem);
849 
850 			RemoveItem(itemThis);
851 
852 			placeInFront(itemThis, userBusy);
853 
854 			ListData* newFront = itemThis;
855 
856 			if (windowHasVisibleModals(winBorder))
857 				newFront = putModalsInFront(itemThis);
858 
859 			if (fFrontItem) {
860 				if (!userBusy) {
861 					int32 revFrontItemIndex, revNewFrontIndex;
862 
863 					HasItem(fFrontItem, &revFrontItemIndex);
864 					HasItem(newFront, &revNewFrontIndex);
865 					if (revNewFrontIndex < revFrontItemIndex)
866 						fFrontItem	= newFront;
867 				}
868 			} else {
869 				fFrontItem	= newFront;
870 			}
871 
872 			if (fFrontItem->layerPtr->Level() == B_NORMAL)
873 				putFloatingInFront(fFrontItem);
874 
875 			returnValue = true;
876 			break;
877 		}
878 
879 		// MODAL windows usualy stay in Workspace's list, but they are scatered, so we must gather them
880 		// when needed.
881 
882 		case B_MODAL_APP:
883 		{
884 			// build a list of modal windows to know what windows should be placed before this one.
885 			BList tempList;
886 
887 			// APP modal
888 			if (winBorder->App()->fAppSubWindowList.HasItem(winBorder)) {
889 				// take only application's modals
890 				tempList.AddList(&winBorder->App()->fAppSubWindowList);
891 				if (fFrontItem
892 					&& fFrontItem->layerPtr->App()->ClientTeam() == winBorder->App()->ClientTeam())
893 					userBusy = false;
894 			} else {
895 				// SUBSET modal
896 				WindowLayer	*mainWindow = searchFirstMainWindow(winBorder);
897 				if (mainWindow) {
898 					// add both mainWindow's subset modals and application's modals
899 					tempList.AddList(&mainWindow->fSubWindowList);
900 					tempList.AddList(&winBorder->App()->fAppSubWindowList);
901 					if (fFrontItem && fFrontItem->layerPtr == mainWindow)
902 						userBusy = false;
903 				} else {
904 					// none of the unhiden normal windows havs this window as part of its subset.
905 					// as a result this window won't be added to Workspace's list for it to be shown.
906 					return false;
907 				}
908 			}
909 
910 			// === list ready ===
911 
912 			// front status will change. if a normal window has front state,
913 			// remove and save floating windows order that may be above it.
914 			if (fFrontItem && fFrontItem->layerPtr->Level() == B_NORMAL)
915 				saveFloatingWindows(fFrontItem);
916 
917 			// find and remove the Workspace's entry for this WindowLayer.
918 			ListData	*itemThis;
919 			itemThis	= HasItem(winBorder);
920 			if (itemThis) {
921 				RemoveItem(itemThis);
922 			} else {
923 				// not found? no problem. create a new entry.
924 				itemThis = fPool.GetCleanMemory(winBorder);
925 			}
926 
927 			placeInFront(itemThis, userBusy);
928 
929 			// now place other modals windows above
930 			int32		revIndexThis, revIndexItem;
931 			ListData	*newFront	= itemThis;
932 
933 			// find the index of this window in Workspace's list. It will be used to place higher
934 			// indexed windows above, if it's the case.
935 			HasItem(itemThis, &revIndexThis);
936 
937 			{
938 				ListData* before = itemThis->lowerItem;
939 				int32 i, count;
940 				WindowLayer** wbList;
941 				ListData* itemX;
942 				int32 indexThisInTempList;
943 
944 				indexThisInTempList	= tempList.IndexOf(winBorder);
945 				if (indexThisInTempList < 0)
946 					debugger("ShowWindowLayer: modal window: design flaw!!!\n");
947 
948 				count = tempList.CountItems();
949 				wbList = (WindowLayer**)tempList.Items();
950 				for (i = indexThisInTempList; i < count; i++) {
951 					if (!wbList[i]->IsHidden()) {
952 						itemX = HasItem(wbList[i], &revIndexItem);
953 						if (itemX && revIndexItem > revIndexThis) {
954 							removeAndPlaceBefore(itemX, before);
955 							newFront = itemX;
956 						}
957 					}
958 				}
959 			}
960 
961 			if (fFrontItem) {
962 				if (!userBusy) {
963 					int32 revFrontItemIndex, revNewFrontIndex;
964 
965 					HasItem(fFrontItem, &revFrontItemIndex);
966 					HasItem(newFront, &revNewFrontIndex);
967 					if (revNewFrontIndex < revFrontItemIndex)
968 						fFrontItem	= newFront;
969 				}
970 
971 				if (fFrontItem->layerPtr->Level() == B_NORMAL)
972 					putFloatingInFront(fFrontItem);
973 			} else {
974 				fFrontItem	= newFront;
975 			}
976 
977 			returnValue = true;
978 			break;
979 		}
980 
981 		default:
982 			debugger("What kind of window is this???\n");
983 	}
984 
985 	if (!HasItem(fFocusItem))
986 		fFocusItem = NULL;
987 
988 	// set new Focus if needed
989 	if (Focus() == NULL) {
990 		ListData* cursor = fBottomItem;
991 
992 		fFocusItem = NULL;
993 		while (cursor != NULL && fFocusItem == NULL) {
994 			if (!cursor->layerPtr->IsHidden()
995 				&& !(cursor->layerPtr->WindowFlags() & B_AVOID_FOCUS)) {
996 				if (cursor->layerPtr->Level() == B_FLOATING_APP
997 					|| cursor->layerPtr->Level() == B_FLOATING_ALL) {
998 					// set focus to floating windows only if directly targeted
999 					if (cursor->layerPtr == winBorder) {
1000 						fFocusItem = cursor;
1001 					} else
1002 						cursor = cursor->upperItem;
1003 				} else
1004 					fFocusItem = cursor;
1005 			} else
1006 				cursor = cursor->upperItem;
1007 		}
1008 	}
1009 
1010 	return returnValue;
1011 }
1012 
1013 
1014 status_t
1015 Workspace::SetDisplayMode(const display_mode &mode)
1016 {
1017 	fDisplayMode = mode;
1018 	return B_OK;
1019 }
1020 
1021 
1022 status_t
1023 Workspace::GetDisplayMode(display_mode &mode) const
1024 {
1025 	mode = fDisplayMode;
1026 	return B_OK;
1027 }
1028 
1029 
1030 void
1031 Workspace::SetBGColor(const RGBColor &c)
1032 {
1033 	fBGColor = c;
1034 }
1035 
1036 
1037 RGBColor
1038 Workspace::BGColor(void) const
1039 {
1040 	return fBGColor;
1041 }
1042 
1043 
1044 /*!
1045 	\brief Retrieves settings from a container message passed to PutSettings
1046 	\param A BMessage containing data from a PutSettings() call
1047 
1048 	This function will place default values whenever a particular setting cannot
1049 	be found.
1050 */
1051 void
1052 Workspace::GetSettings(const BMessage &msg)
1053 {
1054 	BMessage container;
1055 	rgb_color *color;
1056 	ssize_t size;
1057 
1058 	char fieldname[4];
1059 	sprintf(fieldname,"%d",(uint8)fID);
1060 
1061 	// First, find the container message corresponding to the workspace's index
1062 	if(msg.FindMessage(fieldname,&container)!=B_OK)
1063 	{
1064 		GetDefaultSettings();
1065 		return;
1066 	}
1067 
1068 	if(container.FindInt32("timing_pixel_clock",(int32*)&fDisplayMode.timing.pixel_clock) != B_OK)
1069 		fDisplayMode.timing.pixel_clock=25175;
1070 	if(container.FindInt16("timing_h_display",(int16*)&fDisplayMode.timing.h_display)!=B_OK)
1071 		fDisplayMode.timing.h_display=640;
1072 	if(container.FindInt16("timing_h_sync_start",(int16*)&fDisplayMode.timing.h_sync_start)!=B_OK)
1073 		fDisplayMode.timing.h_sync_start=656;
1074 	if(container.FindInt16("timing_h_sync_end",(int16*)&fDisplayMode.timing.h_sync_end)!=B_OK)
1075 		fDisplayMode.timing.h_sync_end=752;
1076 	if(container.FindInt16("timing_h_total",(int16*)&fDisplayMode.timing.h_total)!=B_OK)
1077 		fDisplayMode.timing.h_total=800;
1078 	if(container.FindInt16("timing_v_display",(int16*)&fDisplayMode.timing.v_display)!=B_OK)
1079 		fDisplayMode.timing.v_display=480;
1080 	if(container.FindInt16("timing_v_sync_start",(int16*)&fDisplayMode.timing.v_sync_start)!=B_OK)
1081 		fDisplayMode.timing.v_sync_start=490;
1082 	if(container.FindInt16("timing_v_sync_end",(int16*)&fDisplayMode.timing.v_sync_end)!=B_OK)
1083 		fDisplayMode.timing.v_sync_end=492;
1084 	if(container.FindInt16("timing_v_total",(int16*)&fDisplayMode.timing.v_total)!=B_OK)
1085 		fDisplayMode.timing.v_total=525;
1086 	if(container.FindInt32("timing_flags",(int32*)&fDisplayMode.timing.flags)!=B_OK)
1087 		fDisplayMode.timing.flags=0;
1088 
1089 	if(container.FindInt32("color_space", (int32*)&fDisplayMode.space) != B_OK)
1090 		fDisplayMode.space = B_CMAP8;
1091 
1092 	if(container.FindData("bgcolor",B_RGB_COLOR_TYPE,(const void **)&color,&size)==B_OK)
1093 		fBGColor.SetColor(*color);
1094 	else
1095 		fBGColor.SetColor(0,0,0);
1096 
1097 	if(container.FindInt16("virtual_width", (int16 *)&fDisplayMode.virtual_width) != B_OK)
1098 		fDisplayMode.virtual_width = 640;
1099 	if(container.FindInt16("virtual_height", (int16 *)&fDisplayMode.virtual_height) != B_OK)
1100 		fDisplayMode.virtual_height = 480;
1101 }
1102 
1103 //----------------------------------------------------------------------------------
1104 //! Sets workspace settings to defaults
1105 void Workspace::GetDefaultSettings(void)
1106 {
1107 	fBGColor.SetColor(0,0,0);
1108 
1109 	fDisplayMode.timing.pixel_clock = 25175;
1110 	fDisplayMode.timing.h_display = 640;
1111 	fDisplayMode.timing.h_sync_start = 656;
1112 	fDisplayMode.timing.h_sync_end = 752;
1113 	fDisplayMode.timing.h_total = 800;
1114 	fDisplayMode.timing.v_display = 480;
1115 	fDisplayMode.timing.v_sync_start = 490;
1116 	fDisplayMode.timing.v_sync_end = 492;
1117 	fDisplayMode.timing.v_total = 525;
1118 	fDisplayMode.timing.flags = 0;
1119 	fDisplayMode.space = B_CMAP8;
1120 
1121 	fDisplayMode.virtual_width = 640;
1122 	fDisplayMode.virtual_height = 480;
1123 }
1124 
1125 //----------------------------------------------------------------------------------
1126 /*!
1127 	\brief Places the screen settings for the workspace in the passed BMessage
1128 	\param msg BMessage pointer to receive the settings
1129 	\param index The index number of the workspace in the desktop
1130 
1131 	This function will fail if passed a NULL pointer. The settings for the workspace are
1132 	saved in a BMessage in a BMessage.
1133 
1134 	The message itself is placed in a field string based on its index - "1", "2", etc.
1135 
1136 	The format is as follows:
1137 	display_timing "timing_XXX" -> fDisplayTiming members (see Accelerant.h)
1138 	uint32 "color_space" -> color space of the workspace
1139 	rgb_color "bgcolor" -> background color of the workspace
1140 	int16 "virtual_width" -> virtual width of the workspace
1141 	int16 "virtual_height" -> virtual height of the workspace
1142 */
1143 void Workspace::PutSettings(BMessage *msg, const uint8 &index) const
1144 {
1145 	if(!msg)
1146 		return;
1147 
1148 	BMessage container;
1149 	rgb_color color=fBGColor.GetColor32();
1150 
1151 	// a little longer than we need in case someone tries to pass index=255 or something
1152 	char fieldname[4];
1153 
1154 	container.AddInt32("timing_pixel_clock",fDisplayMode.timing.pixel_clock);
1155 	container.AddInt16("timing_h_display",fDisplayMode.timing.h_display);
1156 	container.AddInt16("timing_h_sync_start",fDisplayMode.timing.h_sync_start);
1157 	container.AddInt16("timing_h_sync_end",fDisplayMode.timing.h_sync_end);
1158 	container.AddInt16("timing_h_total",fDisplayMode.timing.h_total);
1159 	container.AddInt16("timing_v_display",fDisplayMode.timing.v_display);
1160 	container.AddInt16("timing_v_sync_start",fDisplayMode.timing.v_sync_start);
1161 	container.AddInt16("timing_v_sync_end",fDisplayMode.timing.v_sync_end);
1162 	container.AddInt16("timing_v_total",fDisplayMode.timing.v_total);
1163 	container.AddInt32("timing_flags",fDisplayMode.timing.flags);
1164 
1165 	container.AddInt32("color_space", fDisplayMode.space);
1166 	container.AddData("bgcolor", B_RGB_COLOR_TYPE, &color, sizeof(rgb_color));
1167 
1168 	container.AddInt16("virtual_width", fDisplayMode.virtual_width);
1169 	container.AddInt16("virtual_height", fDisplayMode.virtual_height);
1170 
1171 	sprintf(fieldname,"%d",index);
1172 
1173 	// Just in case...
1174 	msg->RemoveName(fieldname);
1175 
1176 	msg->AddMessage(fieldname,&container);
1177 }
1178 
1179 //----------------------------------------------------------------------------------
1180 /*!
1181 	\brief Places default settings for the workspace in the passed BMessage
1182 	\param msg BMessage pointer to receive the settings
1183 	\param index The index number of the workspace in the desktop
1184 */
1185 void Workspace::PutDefaultSettings(BMessage *msg, const uint8 &index)
1186 {
1187 	if(!msg)
1188 		return;
1189 
1190 	BMessage container;
1191 	rgb_color color={ 0,0,0,255 };
1192 
1193 	// a little longer than we need in case someone tries to pass index=255 or something
1194 	char fieldname[4];
1195 
1196 	// These default settings the same ones as found in ~/config/settings/
1197 	// app_server_settings on R5
1198 
1199 	container.AddInt32("timing_pixel_clock",25175);
1200 	container.AddInt16("timing_h_display",640);
1201 	container.AddInt16("timing_h_sync_start",656);
1202 	container.AddInt16("timing_h_sync_end",752);
1203 	container.AddInt16("timing_h_total",800);
1204 	container.AddInt16("timing_v_display",480);
1205 	container.AddInt16("timing_v_sync_start",490);
1206 	container.AddInt16("timing_v_sync_end",492);
1207 	container.AddInt16("timing_v_total",525);
1208 	container.AddInt32("timing_flags",0);
1209 
1210 	container.AddInt32("color_space",B_CMAP8);
1211 	container.AddData("bgcolor",B_RGB_COLOR_TYPE,&color,sizeof(rgb_color));
1212 
1213 	container.AddInt16("virtual_width",640);
1214 	container.AddInt16("virtual_height",480);
1215 
1216 	sprintf(fieldname,"%d",index);
1217 
1218 	// Just in case...
1219 	msg->RemoveName(fieldname);
1220 
1221 	msg->AddMessage(fieldname, &container);
1222 }
1223 
1224 //----------------------------------------------------------------------------------
1225 // Debug method
1226 
1227 void
1228 Workspace::PrintToStream() const
1229 {
1230 	printf("Workspace %ld hierarchy shown from back to front:\n", fID);
1231 	for (ListData *item = fTopItem; item != NULL; item = item->lowerItem)
1232 	{
1233 		WindowLayer		*wb = (WindowLayer*)item->layerPtr;
1234 		printf("\tName: %s\t%s", wb->Name(), wb->IsHidden()?"Hidden\t": "Visible\t");
1235 		if(wb->Feel() == B_FLOATING_SUBSET_WINDOW_FEEL)
1236 			printf("\t%s\n", "B_FLOATING_SUBSET_WINDOW_FEEL");
1237 		if(wb->Feel() == B_FLOATING_APP_WINDOW_FEEL)
1238 			printf("\t%s\n", "B_FLOATING_APP_WINDOW_FEEL");
1239 		if(wb->Feel() == B_FLOATING_ALL_WINDOW_FEEL)
1240 			printf("\t%s\n", "B_FLOATING_ALL_WINDOW_FEEL");
1241 		if(wb->Feel() == B_MODAL_SUBSET_WINDOW_FEEL)
1242 			printf("\t%s\n", "B_MODAL_SUBSET_WINDOW_FEEL");
1243 		if(wb->Feel() == B_MODAL_APP_WINDOW_FEEL)
1244 			printf("\t%s\n", "B_MODAL_APP_WINDOW_FEEL");
1245 		if(wb->Feel() == B_MODAL_ALL_WINDOW_FEEL)
1246 			printf("\t%s\n", "B_MODAL_ALL_WINDOW_FEEL");
1247 		if(wb->Feel() == B_NORMAL_WINDOW_FEEL)
1248 			printf("\t%s\n", "B_NORMAL_WINDOW_FEEL");
1249 		if(wb->Feel() == B_SYSTEM_LAST)
1250 			printf("\t%s\n", "B_SYSTEM_LAST");
1251 		if(wb->Feel() >= B_SYSTEM_FIRST)
1252 			printf("\t%s\n", "B_SYSTEM_FIRST");
1253 
1254 	}
1255 	printf("Focus Layer:\t%s\n", fFocusItem? fFocusItem->layerPtr->Name(): "NULL");
1256 	printf("Front Layer:\t%s\n\n", fFrontItem? fFrontItem->layerPtr->Name(): "NULL");
1257 }
1258 
1259 
1260 void
1261 Workspace::PrintItem(ListData *item) const
1262 {
1263 	printf("ListData members:\n");
1264 	if(item)
1265 	{
1266 		printf("WindowLayer:\t%s\n", item->layerPtr? item->layerPtr->Name(): "NULL");
1267 		printf("UpperItem:\t%s\n", item->upperItem? item->upperItem->layerPtr->Name(): "NULL");
1268 		printf("LowerItem:\t%s\n", item->lowerItem? item->lowerItem->layerPtr->Name(): "NULL");
1269 	}
1270 	else
1271 	{
1272 		printf("NULL item\n");
1273 	}
1274 }
1275 
1276 //----------------------------------------------------------------------------------
1277 // PRIVATE
1278 //----------------------------------------------------------------------------------
1279 /*
1280 	Insert item in the top-bottom direction.
1281 */
1282 void
1283 Workspace::InsertItem(ListData *item, ListData *before)
1284 {
1285 	// insert before one other item;
1286 	if (before) {
1287 		if (before->upperItem)
1288 			before->upperItem->lowerItem = item;
1289 
1290 		item->upperItem = before->upperItem;
1291 		item->lowerItem = before;
1292 		before->upperItem = item;
1293 
1294 		if (fTopItem == before)
1295 			fTopItem = item;
1296 	} else {
1297 		// insert item at the end.
1298 		item->upperItem = fBottomItem;
1299 		if (fBottomItem)
1300 			fBottomItem->lowerItem = item;
1301 
1302 		fBottomItem = item;
1303 
1304 		if (!fTopItem)
1305 			fTopItem = item;
1306 	}
1307 }
1308 
1309 
1310 void
1311 Workspace::RemoveItem(ListData *item)
1312 {
1313 	if (!item)
1314 		return;
1315 
1316 	if (fBottomItem == item)
1317 		fBottomItem = item->upperItem;
1318 	else
1319 		item->lowerItem->upperItem	= item->upperItem;
1320 
1321 	if (fTopItem == item)
1322 		fTopItem = item->lowerItem;
1323 	else
1324 		item->upperItem->lowerItem	= item->lowerItem;
1325 
1326 	// set all these to NULL to avoid confusion later.
1327 
1328 	item->upperItem	= NULL;
1329 	item->lowerItem	= NULL;
1330 
1331 	if (fFocusItem == item)
1332 		fFocusItem = NULL;
1333 
1334 	if (fFrontItem == item)
1335 		fFrontItem = NULL;
1336 }
1337 
1338 
1339 ListData*
1340 Workspace::HasItem(const ListData *item, int32 *index) const
1341 {
1342 	int32 idx = 0;
1343 	ListData* itemX;
1344 
1345 	for (itemX = fBottomItem; itemX != NULL; itemX = itemX->upperItem) {
1346 		if (item == itemX)
1347 			break;
1348 
1349 		idx++;
1350 	}
1351 
1352 	if (index && itemX)
1353 		*index = idx;
1354 
1355 	return itemX;
1356 }
1357 
1358 
1359 ListData*
1360 Workspace::HasItem(const WindowLayer *layer, int32 *index) const
1361 {
1362 	int32 idx = 0;
1363 	ListData* itemX;
1364 
1365 	for (itemX = fBottomItem; itemX != NULL; itemX = itemX->upperItem) {
1366 		if (layer == itemX->layerPtr)
1367 			break;
1368 
1369 		idx++;
1370 	}
1371 
1372 	if (index && itemX)
1373 		*index = idx;
1374 
1375 	return itemX;
1376 }
1377 
1378 
1379 /*!
1380 	\brief Returns the index of the specified item starting from the back-most window.
1381 */
1382 int32
1383 Workspace::IndexOf(const ListData *item) const
1384 {
1385 	if (!item)
1386 		return -1;
1387 
1388 	int32 index = 0;
1389 	for (ListData *itemX = fTopItem; itemX != NULL; itemX = itemX->lowerItem) {
1390 		if (itemX->layerPtr == item->layerPtr)
1391 			return index;
1392 		index++;
1393 	}
1394 	return -1;
1395 }
1396 
1397 
1398 inline bool
1399 Workspace::placeToBack(ListData *newLast)
1400 {
1401 	int32 level = newLast->layerPtr->Level();
1402 	ListData* cursor = newLast->upperItem;
1403 
1404 	switch (level) {
1405 		case B_FLOATING_ALL:
1406 		case B_FLOATING_APP:
1407 		{
1408 			int32 count = 0;
1409 			while (cursor && cursor->layerPtr->Level() == level) {
1410 				if (!cursor->layerPtr->IsHidden())
1411 					count++;
1412 				cursor = cursor->upperItem;
1413 			}
1414 
1415 			// we're already the last floating window
1416 			if (count == 0)
1417 				return false;
1418 			else {
1419 				bool changeFocus = false;
1420 
1421 				if (fFocusItem == newLast)
1422 					changeFocus = true;
1423 
1424 				if (changeFocus) {
1425 					ListData* cursor = newLast->upperItem;
1426 					while (cursor
1427 						&& (cursor->layerPtr->IsHidden()
1428 							|| cursor->layerPtr->WindowFlags() & B_AVOID_FOCUS)
1429 						&& cursor->layerPtr->Level() == level) {
1430 						cursor	= cursor->upperItem;
1431 					}
1432 
1433 					// give focus only if a unhidden floating window could be selected
1434 					// otherwise this('newLast') window keeps focus
1435 					if (cursor->layerPtr->Level() == level)
1436 						fFocusItem	= cursor;
1437 				}
1438 
1439 				RemoveItem(newLast);
1440 				InsertItem(newLast, cursor ? cursor->lowerItem : fTopItem);
1441 
1442 				return true;
1443 			}
1444 			break;
1445 		}
1446 
1447 		case B_NORMAL:
1448 		{
1449 			int32 count = 0;
1450 			int32 cursorLevel;
1451 			while (cursor) {
1452 				cursorLevel	= cursor->layerPtr->Level();
1453 				if (cursorLevel == B_MODAL_APP)
1454 				 	cursorLevel = B_NORMAL;
1455 
1456 				if (cursorLevel < level) {
1457 					break;
1458 				} else {
1459 					count++;
1460 					cursor	= cursor->upperItem;
1461 				}
1462 			}
1463 
1464 			// we're already the last normal window
1465 			if (count == 0)
1466 				return false;
1467 			else {
1468 				RemoveItem(newLast);
1469 				InsertItem(newLast, cursor ? cursor->lowerItem : fTopItem);
1470 				return true;
1471 			}
1472 			break;
1473 		}
1474 	}
1475 
1476 	return false;
1477 }
1478 
1479 //----------------------------------------------------------------------------------
1480 /*!
1481 	\brief Based on it's WindowLayer type, places this item in front as it is possible.
1482 */
1483 void
1484 Workspace::placeInFront(ListData *item, const bool userBusy)
1485 {
1486 	if (!item)
1487 		return;
1488 
1489 	int32 level = item->layerPtr->Level();
1490 	ListData* cursor = fBottomItem;
1491 	int32 cursorLevel;
1492 
1493 	// make MODAL windows act just like normal ones.
1494 	if (level == B_MODAL_APP)
1495 		level = B_NORMAL;
1496 
1497 	// B_SYSTEM_LAST - always place (the most) last
1498 	if (level == B_SYSTEM_LAST) {
1499 		InsertItem(item, fTopItem);
1500 		return;
1501 	}
1502 
1503 	// search for the exact place...
1504 	while (cursor) {
1505 		cursorLevel = cursor->layerPtr->Level();
1506 
1507 		// make MODAL windows act just like normal ones.
1508 		if (cursorLevel == B_MODAL_APP)
1509 			cursorLevel = B_NORMAL;
1510 
1511 		if (level < cursorLevel) {
1512 			cursor = cursor->upperItem;
1513 			continue;
1514 		} else {
1515 			// that's it, we've found the proper place.
1516 			break;
1517 		}
1518 	}
1519 
1520 	if (cursor) {
1521 		// if user is busy typing something, or has an opened menu...
1522 		if (userBusy && cursor == fFrontItem)
1523 			InsertItem(item, cursor);
1524 		else
1525 			InsertItem(item, cursor->lowerItem);
1526 	} else
1527 		InsertItem(item, fTopItem);
1528 }
1529 
1530 
1531 inline bool
1532 Workspace::removeAndPlaceBefore(ListData *item, ListData *beforeItem)
1533 {
1534 	if (item && item != beforeItem) {
1535 		RemoveItem(item);
1536 		// insert into proper place.
1537 		InsertItem(item, beforeItem);
1538 		return true;
1539 	}
1540 	return false;
1541 }
1542 
1543 /*!
1544 	\brief Insert the specified WindowLayer before given item. First search the
1545 			specified WindowLayer in Workspace's list an remove it.
1546 	\resolution: private
1547 */
1548 inline bool
1549 Workspace::removeAndPlaceBefore(const WindowLayer *wb, ListData *beforeItem)
1550 {
1551 	return removeAndPlaceBefore(HasItem(wb), beforeItem);
1552 }
1553 
1554 
1555 inline WindowLayer*
1556 Workspace::searchANormalWindow(WindowLayer *wb) const
1557 {
1558 	ListData* listItem = fBottomItem;
1559 	while (listItem) {
1560 		if (listItem->layerPtr->Level() == B_NORMAL && !listItem->layerPtr->IsHidden()
1561 			&& listItem->layerPtr->App()->ClientTeam() == wb->App()->ClientTeam())
1562 			return listItem->layerPtr;
1563 
1564 		listItem = listItem->upperItem;
1565 	}
1566 	return NULL;
1567 }
1568 
1569 
1570 inline WindowLayer*
1571 Workspace::searchFirstMainWindow(WindowLayer *wb) const
1572 {
1573 	ListData* listItem = fBottomItem;
1574 	while (listItem) {
1575 		if (listItem->layerPtr->Level() == B_NORMAL && !listItem->layerPtr->IsHidden()
1576 			&& listItem->layerPtr->App()->ClientTeam() == wb->App()->ClientTeam()
1577 			&& listItem->layerPtr->fSubWindowList.HasItem(wb))
1578 			return listItem->layerPtr;
1579 
1580 		listItem = listItem->upperItem;
1581 	}
1582 	return NULL;
1583 }
1584 
1585 //----------------------------------------------------------------------------------
1586 
1587 inline
1588 bool Workspace::windowHasVisibleModals(const WindowLayer *winBorder) const
1589 {
1590 	int32		i, count;
1591 	WindowLayer	**wbList;
1592 
1593 	// check window's list
1594 	count		= winBorder->fSubWindowList.CountItems();
1595 	wbList		= (WindowLayer**)winBorder->fSubWindowList.Items();
1596 	for(i = 0; i < count; i++)
1597 	{
1598 		if (wbList[i]->Level() == B_MODAL_APP && !wbList[i]->IsHidden())
1599 			return true;
1600 	}
1601 
1602 	// application's list only has modal windows.
1603 	count		= winBorder->App()->fAppSubWindowList.CountItems();
1604 	wbList		= (WindowLayer**)winBorder->App()->fAppSubWindowList.Items();
1605 	for(i = 0; i < count; i++)
1606 	{
1607 		if (!wbList[i]->IsHidden())
1608 			return true;
1609 	}
1610 
1611 	return false;
1612 }
1613 
1614 //----------------------------------------------------------------------------------
1615 
1616 inline
1617 ListData* Workspace::putModalsInFront(ListData *item)
1618 {
1619 	int32		i, count, revIndex, revIndexItem;
1620 	WindowLayer	**wbList;
1621 	ListData	*itemX;
1622 	ListData	*lastPlaced = NULL;
1623 	ListData	*before = item->lowerItem;
1624 
1625 	HasItem(item, &revIndex);
1626 
1627 	// check window's list
1628 	count		= item->layerPtr->fSubWindowList.CountItems();
1629 	wbList		= (WindowLayer**)item->layerPtr->fSubWindowList.Items();
1630 	for(i = 0; i < count; i++)
1631 	{
1632 		if (wbList[i]->Level() == B_MODAL_APP && !wbList[i]->IsHidden())
1633 		{
1634 			itemX	= HasItem(wbList[i], &revIndexItem);
1635 			if (!itemX)
1636 			{
1637 				itemX		= fPool.GetCleanMemory(wbList[i]);
1638 
1639 				InsertItem(itemX, before);
1640 				lastPlaced	= itemX;
1641 			}
1642 			else if (revIndexItem > revIndex)
1643 			{
1644 				removeAndPlaceBefore(itemX, before);
1645 				lastPlaced	= itemX;
1646 			}
1647 		}
1648 	}
1649 
1650 	// application's list only has modal windows.
1651 	count		= item->layerPtr->App()->fAppSubWindowList.CountItems();
1652 	wbList		= (WindowLayer**)item->layerPtr->App()->fAppSubWindowList.Items();
1653 	for(i = 0; i < count; i++)
1654 	{
1655 		if (!wbList[i]->IsHidden())
1656 		{
1657 			itemX	= HasItem(wbList[i], &revIndexItem);
1658 			if (!itemX)
1659 			{
1660 				itemX		= fPool.GetCleanMemory(wbList[i]);
1661 
1662 				InsertItem(itemX, before);
1663 				lastPlaced	= itemX;
1664 			}
1665 			else if (revIndexItem > revIndex)
1666 			{
1667 				removeAndPlaceBefore(itemX, before);
1668 				lastPlaced	= itemX;
1669 			}
1670 		}
1671 	}
1672 
1673 	return lastPlaced;
1674 }
1675 
1676 
1677 void
1678 Workspace::putFloatingInFront(ListData *item)
1679 {
1680 	int32		i;
1681 	ListData	*newItem;
1682 	ListData	*before = item->lowerItem;
1683 	WindowLayer	*wb;
1684 
1685 	i = 0;
1686 	while ((wb = (WindowLayer*)item->layerPtr->fSubWindowList.ItemAt(i)))
1687 	{
1688 		if (wb->Level() == B_MODAL_APP)
1689 		{
1690 			break;
1691 		}
1692 		else if (!wb->IsHidden())
1693 		{
1694 			newItem				= fPool.GetCleanMemory(wb);
1695 
1696 			InsertItem(newItem, before);
1697 
1698 			item->layerPtr->fSubWindowList.RemoveItem(i);
1699 		}
1700 		else
1701 			i++;
1702 	}
1703 }
1704 
1705 //----------------------------------------------------------------------------------
1706 
1707 inline
1708 void Workspace::saveFloatingWindows(ListData *itemNormal)
1709 {
1710 	ListData		*item = itemNormal->lowerItem;
1711 	ListData		*toast;
1712 	while(item)
1713 	{
1714 		if (item->layerPtr->Level() == B_FLOATING_APP)
1715 		{
1716 			itemNormal->layerPtr->fSubWindowList.AddWindowLayer(item->layerPtr);
1717 
1718 			toast	= item;
1719 			item	= item->lowerItem;
1720 			RemoveItem(toast);
1721 			fPool.ReleaseMemory(toast);
1722 		}
1723 		else
1724 			break;
1725 	}
1726 }
1727 
1728 //----------------------------------------------------------------------------------
1729 
1730 inline
1731 ListData* Workspace::findNextFront() const
1732 {
1733 	ListData	*item = fBottomItem;
1734 
1735 	while(item)
1736 	{
1737 		if (!item->layerPtr->IsHidden()
1738 			&& item->layerPtr->Level() != B_FLOATING_ALL
1739 			&& item->layerPtr->Level() != B_FLOATING_APP
1740 			&& !(item->layerPtr->WindowFlags() & B_AVOID_FRONT))
1741 		{
1742 			return item;
1743 		}
1744 		item = item->upperItem;
1745 	}
1746 
1747 	// we cannot ignore anymore B_AVOID_FRONT windows.
1748 
1749 	item	= fBottomItem;
1750 	while(item)
1751 	{
1752 		if (!item->layerPtr->IsHidden()
1753 			&& item->layerPtr->Level() != B_FLOATING_ALL
1754 			&& item->layerPtr->Level() != B_FLOATING_APP)
1755 		{
1756 			return item;
1757 		}
1758 		item = item->upperItem;
1759 	}
1760 
1761 	return NULL;
1762 }
1763 
1764 
1765 
1766 
1767 // TODO: BAD, bad memory manager!!! replace!!!
1768 Workspace::MemoryPool::MemoryPool()
1769 {
1770 }
1771 
1772 Workspace::MemoryPool::~MemoryPool()
1773 {
1774 }
1775 
1776 inline
1777 ListData* Workspace::MemoryPool::GetCleanMemory(WindowLayer *winBorder)
1778 {
1779 	ListData	*item = (ListData*)malloc(sizeof(ListData));
1780 	item->layerPtr = winBorder;
1781 	item->upperItem = NULL;
1782 	item->lowerItem = NULL;
1783 	return item;
1784 }
1785 
1786 inline
1787 void Workspace::MemoryPool::ReleaseMemory(ListData *mem)
1788 {
1789 	free(mem);
1790 }
1791 
1792 void Workspace::MemoryPool::expandBuffer(int32 start)
1793 {
1794 }
1795