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