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