xref: /haiku/src/servers/app/Desktop.cpp (revision 820dca4df6c7bf955c46e8f6521b9408f50b2900)
1 /*
2  * Copyright 2001-2011, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Adrian Oanca <adioanca@cotty.iren.ro>
7  *		Stephan Aßmus <superstippi@gmx.de>
8  *		Axel Dörfler <axeld@pinc-software.de>
9  *		Andrej Spielmann <andrej.spielmann@seh.ox.ac.uk>
10  *		Brecht Machiels <brecht@mos6581.org>
11  *		Clemens Zeidler <haiku@clemens-zeidler.de>
12  *		Ingo Weinhold <ingo_weinhold@gmx.de>
13  */
14 
15 
16 /*!	Class used to encapsulate desktop management */
17 
18 
19 #include "Desktop.h"
20 #include <stdio.h>
21 #include <string.h>
22 #include <syslog.h>
23 
24 #include <Debug.h>
25 #include <debugger.h>
26 #include <DirectWindow.h>
27 #include <Entry.h>
28 #include <FindDirectory.h>
29 #include <Message.h>
30 #include <MessageFilter.h>
31 #include <Path.h>
32 #include <Region.h>
33 #include <Roster.h>
34 
35 #include <PrivateScreen.h>
36 #include <ServerProtocol.h>
37 #include <ViewPrivate.h>
38 #include <WindowInfo.h>
39 
40 #include "AppServer.h"
41 #include "ClickTarget.h"
42 #include "DecorManager.h"
43 #include "DesktopSettingsPrivate.h"
44 #include "DrawingEngine.h"
45 #include "FontManager.h"
46 #include "HWInterface.h"
47 #include "InputManager.h"
48 #include "Screen.h"
49 #include "ServerApp.h"
50 #include "ServerConfig.h"
51 #include "ServerCursor.h"
52 #include "ServerWindow.h"
53 #include "SystemPalette.h"
54 #include "WindowPrivate.h"
55 #include "Window.h"
56 #include "Workspace.h"
57 #include "WorkspacesView.h"
58 
59 #if TEST_MODE
60 #	include "EventStream.h"
61 #endif
62 
63 
64 //#define DEBUG_DESKTOP
65 #ifdef DEBUG_DESKTOP
66 #	define STRACE(a) printf a
67 #else
68 #	define STRACE(a) ;
69 #endif
70 
71 
72 static inline float
73 square_vector_length(float x, float y)
74 {
75 	return x * x + y * y;
76 }
77 
78 
79 static inline float
80 square_distance(const BPoint& a, const BPoint& b)
81 {
82 	return square_vector_length(a.x - b.x, a.y - b.y);
83 }
84 
85 
86 class KeyboardFilter : public EventFilter {
87 	public:
88 		KeyboardFilter(Desktop* desktop);
89 
90 		virtual filter_result Filter(BMessage* message, EventTarget** _target,
91 			int32* _viewToken, BMessage* latestMouseMoved);
92 		virtual void RemoveTarget(EventTarget* target);
93 
94 	private:
95 		void _UpdateFocus(int32 key, uint32 modifiers, EventTarget** _target);
96 
97 		Desktop*		fDesktop;
98 		EventTarget*	fLastFocus;
99 		bigtime_t		fTimestamp;
100 };
101 
102 
103 class MouseFilter : public EventFilter {
104 public:
105 	MouseFilter(Desktop* desktop);
106 
107 	virtual filter_result Filter(BMessage* message, EventTarget** _target,
108 		int32* _viewToken, BMessage* latestMouseMoved);
109 
110 private:
111 	Desktop*	fDesktop;
112 	int32		fLastClickButtons;
113 	int32		fLastClickModifiers;
114 	int32		fResetClickCount;
115 	BPoint		fLastClickPoint;
116 	ClickTarget	fLastClickTarget;
117 };
118 
119 
120 //	#pragma mark -
121 
122 
123 KeyboardFilter::KeyboardFilter(Desktop* desktop)
124 	:
125 	fDesktop(desktop),
126 	fLastFocus(NULL),
127 	fTimestamp(0)
128 {
129 }
130 
131 
132 void
133 KeyboardFilter::_UpdateFocus(int32 key, uint32 modifiers, EventTarget** _target)
134 {
135 	if (!fDesktop->LockSingleWindow())
136 		return;
137 
138 	EventTarget* focus = fDesktop->KeyboardEventTarget();
139 
140 #if 0
141 	bigtime_t now = system_time();
142 
143 	// TODO: this is a try to not steal focus from the current window
144 	//	in case you enter some text and a window pops up you haven't
145 	//	triggered yourself (like a pop-up window in your browser while
146 	//	you're typing a password in another window) - maybe this should
147 	//	be done differently, though (using something like B_LOCK_WINDOW_FOCUS)
148 	//	(at least B_WINDOW_ACTIVATED must be postponed)
149 
150 	if (fLastFocus == NULL
151 		|| (focus != fLastFocus && now - fTimestamp > 100000)) {
152 		// if the time span between the key presses is very short
153 		// we keep our previous focus alive - this is safe even
154 		// if the target doesn't exist anymore, as we don't reset
155 		// it, and the event focus passed in is always valid (or NULL)
156 		*_target = focus;
157 		fLastFocus = focus;
158 	}
159 #endif
160 	*_target = focus;
161 	fLastFocus = focus;
162 
163 	fDesktop->UnlockSingleWindow();
164 
165 #if 0
166 	// we always allow to switch focus after the enter key has pressed
167 	if (key == B_ENTER || modifiers == B_COMMAND_KEY
168 		|| modifiers == B_CONTROL_KEY || modifiers == B_OPTION_KEY)
169 		fTimestamp = 0;
170 	else
171 		fTimestamp = now;
172 #endif
173 }
174 
175 
176 filter_result
177 KeyboardFilter::Filter(BMessage* message, EventTarget** _target,
178 	int32* /*_viewToken*/, BMessage* /*latestMouseMoved*/)
179 {
180 	int32 key = 0;
181 	int32 modifiers = 0;
182 
183 	message->FindInt32("key", &key);
184 	message->FindInt32("modifiers", &modifiers);
185 
186 	if ((message->what == B_KEY_DOWN || message->what == B_UNMAPPED_KEY_DOWN)) {
187 		// Check for safe video mode (cmd + ctrl + escape)
188 		if (key == 0x01 && (modifiers & B_COMMAND_KEY) != 0
189 			&& (modifiers & B_CONTROL_KEY) != 0) {
190 			system("screenmode --fall-back &");
191 			return B_SKIP_MESSAGE;
192 		}
193 
194 		bool takeWindow = (modifiers & B_SHIFT_KEY) != 0
195 			|| fDesktop->MouseEventWindow() != NULL;
196 		if (key >= B_F1_KEY && key <= B_F12_KEY) {
197 			// workspace change
198 
199 #if !TEST_MODE
200 			if ((modifiers & (B_COMMAND_KEY | B_CONTROL_KEY | B_OPTION_KEY))
201 					== B_COMMAND_KEY)
202 #else
203 			if ((modifiers & B_CONTROL_KEY) != 0)
204 #endif
205 			{
206 				STRACE(("Set Workspace %" B_PRId32 "\n", key - 1));
207 
208 				fDesktop->SetWorkspaceAsync(key - B_F1_KEY, takeWindow);
209 				return B_SKIP_MESSAGE;
210 			}
211 		} if (key == 0x11
212 			&& (modifiers & (B_COMMAND_KEY | B_CONTROL_KEY | B_OPTION_KEY))
213 					== B_COMMAND_KEY) {
214 			// switch to previous workspace (command + `)
215 			fDesktop->SetWorkspaceAsync(-1, takeWindow);
216 			return B_SKIP_MESSAGE;
217 		}
218 	}
219 
220 	if (message->what == B_KEY_DOWN
221 		|| message->what == B_MODIFIERS_CHANGED
222 		|| message->what == B_UNMAPPED_KEY_DOWN
223 		|| message->what == B_INPUT_METHOD_EVENT)
224 		_UpdateFocus(key, modifiers, _target);
225 
226 	return fDesktop->KeyEvent(message->what, key, modifiers);
227 }
228 
229 
230 void
231 KeyboardFilter::RemoveTarget(EventTarget* target)
232 {
233 	if (target == fLastFocus)
234 		fLastFocus = NULL;
235 }
236 
237 
238 //	#pragma mark -
239 
240 
241 MouseFilter::MouseFilter(Desktop* desktop)
242 	:
243 	fDesktop(desktop),
244 	fLastClickButtons(0),
245 	fLastClickModifiers(0),
246 	fResetClickCount(0),
247 	fLastClickPoint(),
248 	fLastClickTarget()
249 {
250 }
251 
252 
253 filter_result
254 MouseFilter::Filter(BMessage* message, EventTarget** _target, int32* _viewToken,
255 	BMessage* latestMouseMoved)
256 {
257 	BPoint where;
258 	if (message->FindPoint("where", &where) != B_OK)
259 		return B_DISPATCH_MESSAGE;
260 
261 	int32 buttons;
262 	if (message->FindInt32("buttons", &buttons) != B_OK)
263 		buttons = 0;
264 
265 	if (!fDesktop->LockAllWindows())
266 		return B_DISPATCH_MESSAGE;
267 
268 	int32 viewToken = B_NULL_TOKEN;
269 
270 	Window* window = fDesktop->MouseEventWindow();
271 	if (window == NULL)
272 		window = fDesktop->WindowAt(where);
273 
274 	if (window != NULL) {
275 		// dispatch event to the window
276 		switch (message->what) {
277 			case B_MOUSE_DOWN:
278 			{
279 				int32 windowToken = window->ServerWindow()->ServerToken();
280 
281 				// First approximation of click count validation. We reset the
282 				// click count when modifiers or pressed buttons have changed
283 				// or when we've got a different click target, or when the
284 				// previous click location is too far from the new one. We can
285 				// only check the window of the click target here; we'll recheck
286 				// after asking the window.
287 				int32 modifiers = message->FindInt32("modifiers");
288 
289 				int32 originalClickCount = message->FindInt32("clicks");
290 				if (originalClickCount <= 0)
291 					originalClickCount = 1;
292 
293 				int32 clickCount = originalClickCount;
294 				if (clickCount > 1) {
295 					if (modifiers != fLastClickModifiers
296 						|| buttons != fLastClickButtons
297 						|| !fLastClickTarget.IsValid()
298 						|| fLastClickTarget.WindowToken() != windowToken
299 						|| square_distance(where, fLastClickPoint) >= 16
300 						|| clickCount - fResetClickCount < 1) {
301 						clickCount = 1;
302 					} else
303 						clickCount -= fResetClickCount;
304 				}
305 
306 				// notify the window
307 				ClickTarget clickTarget;
308 				window->MouseDown(message, where, fLastClickTarget, clickCount,
309 					clickTarget);
310 
311 				// If the click target changed, always reset the click count.
312 				if (clickCount != 1 && clickTarget != fLastClickTarget)
313 					clickCount = 1;
314 
315 				// update our click count management attributes
316 				fResetClickCount = originalClickCount - clickCount;
317 				fLastClickTarget = clickTarget;
318 				fLastClickButtons = buttons;
319 				fLastClickModifiers = modifiers;
320 				fLastClickPoint = where;
321 
322 				// get the view token from the click target
323 				if (clickTarget.GetType() == ClickTarget::TYPE_WINDOW_CONTENTS)
324 					viewToken = clickTarget.WindowElement();
325 
326 				// update the message's "clicks" field, if necessary
327 				if (clickCount != originalClickCount) {
328 					if (message->HasInt32("clicks"))
329 						message->ReplaceInt32("clicks", clickCount);
330 					else
331 						message->AddInt32("clicks", clickCount);
332 				}
333 
334 				// notify desktop listeners
335 				fDesktop->NotifyMouseDown(window, message, where);
336 				break;
337 			}
338 
339 			case B_MOUSE_UP:
340 				window->MouseUp(message, where, &viewToken);
341 				if (buttons == 0)
342 					fDesktop->SetMouseEventWindow(NULL);
343 				fDesktop->NotifyMouseUp(window, message, where);
344 				break;
345 
346 			case B_MOUSE_MOVED:
347 				window->MouseMoved(message, where, &viewToken,
348 					latestMouseMoved == NULL || latestMouseMoved == message,
349 					false);
350 				fDesktop->NotifyMouseMoved(window, message, where);
351 				break;
352 		}
353 
354 		if (viewToken != B_NULL_TOKEN) {
355 			fDesktop->SetViewUnderMouse(window, viewToken);
356 
357 			*_viewToken = viewToken;
358 			*_target = &window->EventTarget();
359 		}
360 	} else if (message->what == B_MOUSE_DOWN) {
361 		// the mouse-down didn't hit a window -- reset the click target
362 		fResetClickCount = 0;
363 		fLastClickTarget = ClickTarget();
364 		fLastClickButtons = message->FindInt32("buttons");
365 		fLastClickModifiers = message->FindInt32("modifiers");
366 		fLastClickPoint = where;
367 	}
368 
369 	if (window == NULL || viewToken == B_NULL_TOKEN) {
370 		// mouse is not over a window or over a decorator
371 		fDesktop->SetViewUnderMouse(window, B_NULL_TOKEN);
372 		fDesktop->SetCursor(NULL);
373 
374 		*_target = NULL;
375 	}
376 
377 	fDesktop->SetLastMouseState(where, buttons, window);
378 
379 	fDesktop->NotifyMouseEvent(message);
380 
381 	fDesktop->UnlockAllWindows();
382 
383 	return B_DISPATCH_MESSAGE;
384 }
385 
386 
387 //	#pragma mark -
388 
389 
390 static inline uint32
391 workspace_to_workspaces(int32 index)
392 {
393 	return 1UL << index;
394 }
395 
396 
397 static inline bool
398 workspace_in_workspaces(int32 index, uint32 workspaces)
399 {
400 	return (workspaces & (1UL << index)) != 0;
401 }
402 
403 
404 //	#pragma mark -
405 
406 
407 Desktop::Desktop(uid_t userID, const char* targetScreen)
408 	:
409 	MessageLooper("desktop"),
410 
411 	fUserID(userID),
412 	fTargetScreen(strdup(targetScreen)),
413 	fSettings(NULL),
414 	fSharedReadOnlyArea(-1),
415 	fApplicationsLock("application list"),
416 	fShutdownSemaphore(-1),
417 	fShutdownCount(0),
418 	fScreenLock("screen lock"),
419 	fDirectScreenLock("direct screen lock"),
420 	fDirectScreenTeam(-1),
421 	fCurrentWorkspace(0),
422 	fPreviousWorkspace(0),
423 	fAllWindows(kAllWindowList),
424 	fSubsetWindows(kSubsetList),
425 	fFocusList(kFocusList),
426 	fWorkspacesViews(false),
427 
428 	fWorkspacesLock("workspaces list"),
429 	fWindowLock("window lock"),
430 
431 	fMouseEventWindow(NULL),
432 	fWindowUnderMouse(NULL),
433 	fLockedFocusWindow(NULL),
434 	fViewUnderMouse(B_NULL_TOKEN),
435 	fLastMousePosition(B_ORIGIN),
436 	fLastMouseButtons(0),
437 
438 	fFocus(NULL),
439 	fFront(NULL),
440 	fBack(NULL)
441 {
442 	memset(fLastWorkspaceFocus, 0, sizeof(fLastWorkspaceFocus));
443 
444 	char name[B_OS_NAME_LENGTH];
445 	Desktop::_GetLooperName(name, sizeof(name));
446 
447 	fMessagePort = create_port(DEFAULT_MONITOR_PORT_SIZE, name);
448 	if (fMessagePort < B_OK)
449 		return;
450 
451 	fLink.SetReceiverPort(fMessagePort);
452 
453 	// register listeners
454 	RegisterListener(&fStackAndTile);
455 
456 	const DesktopListenerList& newListeners
457 		= gDecorManager.GetDesktopListeners();
458 	for (int i = 0; i < newListeners.CountItems(); i++)
459  		RegisterListener(newListeners.ItemAt(i));
460 }
461 
462 
463 Desktop::~Desktop()
464 {
465 	delete fSettings;
466 
467 	delete_area(fSharedReadOnlyArea);
468 	delete_port(fMessagePort);
469 	gFontManager->DetachUser(fUserID);
470 
471 	free(fTargetScreen);
472 }
473 
474 
475 void
476 Desktop::RegisterListener(DesktopListener* listener)
477 {
478 	DesktopObservable::RegisterListener(listener, this);
479 }
480 
481 
482 status_t
483 Desktop::Init()
484 {
485 	if (fMessagePort < B_OK)
486 		return fMessagePort;
487 
488 	// the system palette needs to be initialized before the
489 	// desktop settings, since it is used there already
490 	InitializeColorMap();
491 
492 	const size_t areaSize = B_PAGE_SIZE;
493 	char name[B_OS_NAME_LENGTH];
494 	snprintf(name, sizeof(name), "d:%d:shared read only", fUserID);
495 	fSharedReadOnlyArea = create_area(name, (void **)&fServerReadOnlyMemory,
496 		B_ANY_ADDRESS, areaSize, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
497 	if (fSharedReadOnlyArea < B_OK)
498 		return fSharedReadOnlyArea;
499 
500 	gFontManager->AttachUser(fUserID);
501 
502 	fSettings = new DesktopSettingsPrivate(fServerReadOnlyMemory);
503 
504 	for (int32 i = 0; i < kMaxWorkspaces; i++) {
505 		_Windows(i).SetIndex(i);
506 		fWorkspaces[i].RestoreConfiguration(*fSettings->WorkspacesMessage(i));
507 	}
508 
509 	fVirtualScreen.SetConfiguration(*this,
510 		fWorkspaces[0].CurrentScreenConfiguration());
511 
512 	if (fVirtualScreen.HWInterface() == NULL) {
513 		debug_printf("Could not initialize graphics output. Exiting.\n");
514 		return B_ERROR;
515 	}
516 
517 	fVirtualScreen.HWInterface()->MoveCursorTo(
518 		fVirtualScreen.Frame().Width() / 2,
519 		fVirtualScreen.Frame().Height() / 2);
520 
521 #if TEST_MODE
522 	gInputManager->AddStream(new InputServerStream);
523 #endif
524 
525 	EventStream* stream = fVirtualScreen.HWInterface()->CreateEventStream();
526 	if (stream == NULL)
527 		stream = gInputManager->GetStream();
528 
529 	fEventDispatcher.SetDesktop(this);
530 	fEventDispatcher.SetTo(stream);
531 	if (fEventDispatcher.InitCheck() != B_OK)
532 		_LaunchInputServer();
533 
534 	fEventDispatcher.SetHWInterface(fVirtualScreen.HWInterface());
535 
536 	fEventDispatcher.SetMouseFilter(new MouseFilter(this));
537 	fEventDispatcher.SetKeyboardFilter(new KeyboardFilter(this));
538 
539 	// draw the background
540 
541 	fScreenRegion = fVirtualScreen.Frame();
542 
543 	BRegion stillAvailableOnScreen;
544 	_RebuildClippingForAllWindows(stillAvailableOnScreen);
545 	_SetBackground(stillAvailableOnScreen);
546 
547 	SetCursor(NULL);
548 		// this will set the default cursor
549 
550 	fVirtualScreen.HWInterface()->SetCursorVisible(true);
551 
552 	return B_OK;
553 }
554 
555 
556 /*!	\brief Send a quick (no attachments) message to all applications.
557 
558 	Quite useful for notification for things like server shutdown, system
559 	color changes, etc.
560 */
561 void
562 Desktop::BroadcastToAllApps(int32 code)
563 {
564 	BAutolock locker(fApplicationsLock);
565 
566 	for (int32 i = fApplications.CountItems(); i-- > 0;) {
567 		fApplications.ItemAt(i)->PostMessage(code);
568 	}
569 }
570 
571 
572 /*!	\brief Send a quick (no attachments) message to all windows.
573 */
574 void
575 Desktop::BroadcastToAllWindows(int32 code)
576 {
577 	AutoWriteLocker _(fWindowLock);
578 
579 	for (Window* window = fAllWindows.FirstWindow(); window != NULL;
580 			window = window->NextWindow(kAllWindowList)) {
581 		window->ServerWindow()->PostMessage(code);
582 	}
583 }
584 
585 
586 filter_result
587 Desktop::KeyEvent(uint32 what, int32 key, int32 modifiers)
588 {
589 	filter_result result = B_DISPATCH_MESSAGE;
590 	if (LockAllWindows()) {
591 		Window* window = MouseEventWindow();
592 		if (window == NULL)
593 			window = WindowAt(fLastMousePosition);
594 
595 		if (window != NULL) {
596 			if (what == B_MODIFIERS_CHANGED)
597 				window->ModifiersChanged(modifiers);
598 		}
599 
600 		if (NotifyKeyPressed(what, key, modifiers))
601 			result = B_SKIP_MESSAGE;
602 
603 		UnlockAllWindows();
604 	}
605 
606 	return result;
607 }
608 
609 
610 // #pragma mark - Mouse and cursor methods
611 
612 
613 void
614 Desktop::SetCursor(ServerCursor* newCursor)
615 {
616 	if (newCursor == NULL)
617 		newCursor = fCursorManager.GetCursor(B_CURSOR_ID_SYSTEM_DEFAULT);
618 
619 	if (newCursor == fCursor)
620 		return;
621 
622 	fCursor = newCursor;
623 
624 	if (fManagementCursor.Get() == NULL)
625 		HWInterface()->SetCursor(newCursor);
626 }
627 
628 
629 ServerCursorReference
630 Desktop::Cursor() const
631 {
632 	return fCursor;
633 }
634 
635 
636 void
637 Desktop::SetManagementCursor(ServerCursor* newCursor)
638 {
639 	if (newCursor == fManagementCursor)
640 		return;
641 
642 	fManagementCursor = newCursor;
643 
644 	HWInterface()->SetCursor(newCursor != NULL ? newCursor : fCursor.Get());
645 }
646 
647 
648 void
649 Desktop::SetLastMouseState(const BPoint& position, int32 buttons,
650 	Window* windowUnderMouse)
651 {
652 	// The all-window-lock is write-locked.
653 	fLastMousePosition = position;
654 	fLastMouseButtons = buttons;
655 
656 	if (fLastMouseButtons == 0 && fLockedFocusWindow) {
657 		fLockedFocusWindow = NULL;
658 		if (fSettings->FocusFollowsMouse())
659 			SetFocusWindow(windowUnderMouse);
660 	}
661 }
662 
663 
664 void
665 Desktop::GetLastMouseState(BPoint* position, int32* buttons) const
666 {
667 	*position = fLastMousePosition;
668 	*buttons = fLastMouseButtons;
669 }
670 
671 
672 //	#pragma mark - Screen methods
673 
674 
675 status_t
676 Desktop::SetScreenMode(int32 workspace, int32 id, const display_mode& mode,
677 	bool makeDefault)
678 {
679 	AutoWriteLocker _(fWindowLock);
680 
681 	if (workspace == B_CURRENT_WORKSPACE_INDEX)
682 		workspace = fCurrentWorkspace;
683 
684 	if (workspace < 0 || workspace >= kMaxWorkspaces)
685 		return B_BAD_VALUE;
686 
687 	Screen* screen = fVirtualScreen.ScreenByID(id);
688 	if (screen == NULL)
689 		return B_NAME_NOT_FOUND;
690 
691 	// Check if the mode has actually changed
692 
693 	if (workspace == fCurrentWorkspace) {
694 		// retrieve from current screen
695 		display_mode oldMode;
696 		screen->GetMode(oldMode);
697 
698 		if (!memcmp(&oldMode, &mode, sizeof(display_mode)))
699 			return B_OK;
700 
701 		// Set the new one
702 
703 		_SuspendDirectFrameBufferAccess();
704 
705 		AutoWriteLocker locker(fScreenLock);
706 
707 		status_t status = screen->SetMode(mode);
708 		if (status != B_OK) {
709 			locker.Unlock();
710 
711 			_ResumeDirectFrameBufferAccess();
712 			return status;
713 		}
714 	} else {
715 		// retrieve from settings
716 		screen_configuration* configuration
717 			= fWorkspaces[workspace].CurrentScreenConfiguration().CurrentByID(
718 				screen->ID());
719 		if (configuration != NULL
720 			&& !memcmp(&configuration->mode, &mode, sizeof(display_mode)))
721 			return B_OK;
722 	}
723 
724 	// Update our configurations
725 
726 	monitor_info info;
727 	bool hasInfo = screen->GetMonitorInfo(info) == B_OK;
728 
729 	fWorkspaces[workspace].CurrentScreenConfiguration().Set(id,
730 		hasInfo ? &info : NULL, screen->Frame(), mode);
731 	if (makeDefault) {
732 		fWorkspaces[workspace].StoredScreenConfiguration().Set(id,
733 			hasInfo ? &info : NULL, screen->Frame(), mode);
734 		StoreWorkspaceConfiguration(workspace);
735 	}
736 
737 	_ScreenChanged(screen);
738 	if (workspace == fCurrentWorkspace)
739 		_ResumeDirectFrameBufferAccess();
740 
741 	return B_OK;
742 }
743 
744 
745 status_t
746 Desktop::GetScreenMode(int32 workspace, int32 id, display_mode& mode)
747 {
748 	AutoReadLocker _(fScreenLock);
749 
750 	if (workspace == B_CURRENT_WORKSPACE_INDEX)
751 		workspace = fCurrentWorkspace;
752 
753 	if (workspace < 0 || workspace >= kMaxWorkspaces)
754 		return B_BAD_VALUE;
755 
756 	if (workspace == fCurrentWorkspace) {
757 		// retrieve from current screen
758 		Screen* screen = fVirtualScreen.ScreenByID(id);
759 		if (screen == NULL)
760 			return B_NAME_NOT_FOUND;
761 
762 		screen->GetMode(mode);
763 		return B_OK;
764 	}
765 
766 	// retrieve from settings
767 	screen_configuration* configuration
768 		= fWorkspaces[workspace].CurrentScreenConfiguration().CurrentByID(id);
769 	if (configuration == NULL)
770 		return B_NAME_NOT_FOUND;
771 
772 	mode = configuration->mode;
773 	return B_OK;
774 }
775 
776 
777 status_t
778 Desktop::GetScreenFrame(int32 workspace, int32 id, BRect& frame)
779 {
780 	AutoReadLocker _(fScreenLock);
781 
782 	if (workspace == B_CURRENT_WORKSPACE_INDEX)
783 		workspace = fCurrentWorkspace;
784 
785 	if (workspace < 0 || workspace >= kMaxWorkspaces)
786 		return B_BAD_VALUE;
787 
788 	if (workspace == fCurrentWorkspace) {
789 		// retrieve from current screen
790 		Screen* screen = fVirtualScreen.ScreenByID(id);
791 		if (screen == NULL)
792 			return B_NAME_NOT_FOUND;
793 
794 		frame = screen->Frame();
795 		return B_OK;
796 	}
797 
798 	// retrieve from settings
799 	screen_configuration* configuration
800 		= fWorkspaces[workspace].CurrentScreenConfiguration().CurrentByID(id);
801 	if (configuration == NULL)
802 		return B_NAME_NOT_FOUND;
803 
804 	frame = configuration->frame;
805 	return B_OK;
806 }
807 
808 
809 void
810 Desktop::RevertScreenModes(uint32 workspaces)
811 {
812 	if (workspaces == 0)
813 		return;
814 
815 	AutoWriteLocker _(fWindowLock);
816 
817 	for (int32 workspace = 0; workspace < kMaxWorkspaces; workspace++) {
818 		if ((workspaces & (1U << workspace)) == 0)
819 			continue;
820 
821 		// Revert all screens on this workspace
822 
823 		// TODO: ideally, we would know which screens to revert - this way, too
824 		// many of them could be reverted
825 
826 		for (int32 index = 0; index < fVirtualScreen.CountScreens(); index++) {
827 			Screen* screen = fVirtualScreen.ScreenAt(index);
828 
829 			// retrieve configurations
830 			screen_configuration* stored = fWorkspaces[workspace]
831 				.StoredScreenConfiguration().CurrentByID(screen->ID());
832 			screen_configuration* current = fWorkspaces[workspace]
833 				.CurrentScreenConfiguration().CurrentByID(screen->ID());
834 
835 			if ((stored != NULL && current != NULL
836 					&& !memcmp(&stored->mode, &current->mode,
837 							sizeof(display_mode)))
838 				|| (stored == NULL && current == NULL))
839 				continue;
840 
841 			if (stored == NULL) {
842 				fWorkspaces[workspace].CurrentScreenConfiguration()
843 					.Remove(current);
844 
845 				if (workspace == fCurrentWorkspace) {
846 					_SuspendDirectFrameBufferAccess();
847 					_SetCurrentWorkspaceConfiguration();
848 					_ResumeDirectFrameBufferAccess();
849 				}
850 			} else
851 				SetScreenMode(workspace, screen->ID(), stored->mode, false);
852 		}
853 	}
854 }
855 
856 
857 status_t
858 Desktop::LockDirectScreen(team_id team)
859 {
860 	// TODO: BWindowScreens should use the same mechanism as BDirectWindow,
861 	// which would make this method superfluous.
862 
863 	status_t status = fDirectScreenLock.LockWithTimeout(1000000L);
864 	if (status == B_OK)
865 		fDirectScreenTeam = team;
866 
867 	return status;
868 }
869 
870 
871 status_t
872 Desktop::UnlockDirectScreen(team_id team)
873 {
874 	if (fDirectScreenTeam == team) {
875 		fDirectScreenLock.Unlock();
876 		fDirectScreenTeam = -1;
877 		return B_OK;
878 	}
879 
880 	return B_PERMISSION_DENIED;
881 }
882 
883 
884 // #pragma mark - Workspaces methods
885 
886 
887 /*!	Changes the current workspace to the one specified by \a index.
888 */
889 void
890 Desktop::SetWorkspaceAsync(int32 index, bool moveFocusWindow)
891 {
892 	BPrivate::LinkSender link(MessagePort());
893 	link.StartMessage(AS_ACTIVATE_WORKSPACE);
894 	link.Attach<int32>(index);
895 	link.Attach<bool>(moveFocusWindow);
896 	link.Flush();
897 }
898 
899 
900 /*!	Changes the current workspace to the one specified by \a index.
901 	You must not hold any window lock when calling this method.
902 */
903 void
904 Desktop::SetWorkspace(int32 index, bool moveFocusWindow)
905 {
906 	LockAllWindows();
907 	DesktopSettings settings(this);
908 
909 	if (index < 0 || index >= settings.WorkspacesCount()
910 		|| index == fCurrentWorkspace) {
911 		UnlockAllWindows();
912 		return;
913 	}
914 
915 	_SetWorkspace(index, moveFocusWindow);
916 	UnlockAllWindows();
917 
918 	_SendFakeMouseMoved();
919 }
920 
921 
922 status_t
923 Desktop::SetWorkspacesLayout(int32 newColumns, int32 newRows)
924 {
925 	int32 newCount = newColumns * newRows;
926 	if (newCount < 1 || newCount > kMaxWorkspaces)
927 		return B_BAD_VALUE;
928 
929 	if (!LockAllWindows())
930 		return B_ERROR;
931 
932 	fSettings->SetWorkspacesLayout(newColumns, newRows);
933 
934 	// either update the workspaces window, or switch to
935 	// the last available workspace - which will update
936 	// the workspaces window automatically
937 	bool workspaceChanged = CurrentWorkspace() >= newCount;
938 	if (workspaceChanged)
939 		_SetWorkspace(newCount - 1);
940 	else
941 		_WindowChanged(NULL);
942 
943 	UnlockAllWindows();
944 
945 	if (workspaceChanged)
946 		_SendFakeMouseMoved();
947 
948 	return B_OK;
949 }
950 
951 
952 /*!	Returns the virtual screen frame of the workspace specified by \a index.
953 */
954 BRect
955 Desktop::WorkspaceFrame(int32 index) const
956 {
957 	BRect frame;
958 	if (index == fCurrentWorkspace)
959 		frame = fVirtualScreen.Frame();
960 	else if (index >= 0 && index < fSettings->WorkspacesCount()) {
961 		BMessage screenData;
962 		if (fSettings->WorkspacesMessage(index)->FindMessage("screen",
963 				&screenData) != B_OK
964 			|| screenData.FindRect("frame", &frame) != B_OK) {
965 			frame = fVirtualScreen.Frame();
966 		}
967 	}
968 
969 	return frame;
970 }
971 
972 
973 /*!	\brief Stores the workspace configuration.
974 	You must hold the window lock when calling this method.
975 */
976 void
977 Desktop::StoreWorkspaceConfiguration(int32 index)
978 {
979 	// Retrieve settings
980 
981 	BMessage settings;
982 	fWorkspaces[index].StoreConfiguration(settings);
983 
984 	// and store them
985 
986 	fSettings->SetWorkspacesMessage(index, settings);
987 	fSettings->Save(kWorkspacesSettings);
988 }
989 
990 
991 void
992 Desktop::AddWorkspacesView(WorkspacesView* view)
993 {
994 	if (view->Window() == NULL || view->Window()->IsHidden())
995 		return;
996 
997 	BAutolock _(fWorkspacesLock);
998 
999 	if (!fWorkspacesViews.HasItem(view))
1000 		fWorkspacesViews.AddItem(view);
1001 }
1002 
1003 
1004 void
1005 Desktop::RemoveWorkspacesView(WorkspacesView* view)
1006 {
1007 	BAutolock _(fWorkspacesLock);
1008 	fWorkspacesViews.RemoveItem(view);
1009 }
1010 
1011 
1012 //	#pragma mark - Methods for Window manipulation
1013 
1014 
1015 /*!	\brief Activates or focusses the window based on the pointer position.
1016 */
1017 void
1018 Desktop::SelectWindow(Window* window)
1019 {
1020 	if (fSettings->MouseMode() == B_CLICK_TO_FOCUS_MOUSE) {
1021 		// Only bring the window to front when it is not the window under the
1022 		// mouse pointer. This should result in sensible behaviour.
1023 		if (window != fWindowUnderMouse
1024 			|| (window == fWindowUnderMouse && window != FocusWindow()))
1025 			ActivateWindow(window);
1026 		else
1027 			SetFocusWindow(window);
1028 	} else
1029 		ActivateWindow(window);
1030 }
1031 
1032 
1033 /*!	\brief Tries to move the specified window to the front of the screen,
1034 		and make it the focus window.
1035 
1036 	If there are any modal windows on this screen, it might not actually
1037 	become the frontmost window, though, as modal windows stay in front
1038 	of their subset.
1039 */
1040 void
1041 Desktop::ActivateWindow(Window* window)
1042 {
1043 	STRACE(("ActivateWindow(%p, %s)\n", window, window
1044 		? window->Title() : "<none>"));
1045 
1046 	if (window == NULL) {
1047 		fBack = NULL;
1048 		fFront = NULL;
1049 		return;
1050 	}
1051 	if (window->Workspaces() == 0 && window->IsNormal())
1052 		return;
1053 
1054 	AutoWriteLocker _(fWindowLock);
1055 
1056 	NotifyWindowActivated(window);
1057 
1058 	bool windowOnOtherWorkspace = !window->InWorkspace(fCurrentWorkspace);
1059 	if (windowOnOtherWorkspace
1060 		&& (window->Flags() & B_NOT_ANCHORED_ON_ACTIVATE) == 0) {
1061 		if ((window->Flags() & B_NO_WORKSPACE_ACTIVATION) == 0) {
1062 			// Switch to the workspace on which this window is
1063 			// (we'll take the first one that the window is on)
1064 			uint32 workspaces = window->Workspaces();
1065 			for (int32 i = 0; i < fSettings->WorkspacesCount(); i++) {
1066 				uint32 workspace = workspace_to_workspaces(i);
1067 				if (workspaces & workspace) {
1068 					SetWorkspace(i);
1069 					windowOnOtherWorkspace = false;
1070 					break;
1071 				}
1072 			}
1073 		} else
1074 			return;
1075 	}
1076 
1077 	if (windowOnOtherWorkspace) {
1078 		if (!window->IsNormal()) {
1079 			// Bring a window to front that this floating window belongs to
1080 			Window* front = _LastFocusSubsetWindow(window);
1081 			if (front == NULL) {
1082 				// We can't do anything about those.
1083 				return;
1084 			}
1085 
1086 			ActivateWindow(front);
1087 
1088 			if (!window->InWorkspace(fCurrentWorkspace)) {
1089 				// This window can't be made active
1090 				return;
1091 			}
1092 		} else {
1093 			// Bring the window to the current workspace
1094 			// TODO: what if this window is on multiple workspaces?!?
1095 			uint32 workspaces = workspace_to_workspaces(fCurrentWorkspace);
1096 			SetWindowWorkspaces(window, workspaces);
1097 		}
1098 	}
1099 
1100 	if (window->IsMinimized()) {
1101 		// Unlike WindowAction(), this is called from the application itself,
1102 		// so we will just unminimize the window here.
1103 		window->SetMinimized(false);
1104 		ShowWindow(window);
1105 	}
1106 
1107 	if (window == FrontWindow()) {
1108 		// see if there is a normal B_AVOID_FRONT window still in front of us
1109 		Window* avoidsFront = window->NextWindow(fCurrentWorkspace);
1110 		while (avoidsFront && avoidsFront->IsNormal()
1111 			&& (avoidsFront->Flags() & B_AVOID_FRONT) == 0) {
1112 			avoidsFront = avoidsFront->NextWindow(fCurrentWorkspace);
1113 		}
1114 
1115 		if (avoidsFront == NULL) {
1116 			// we're already the frontmost window, we might just not have focus
1117 			// yet
1118 			if ((window->Flags() & B_AVOID_FOCUS) == 0)
1119 				SetFocusWindow(window);
1120 			return;
1121 		}
1122 	}
1123 
1124 	WindowList windows(kWorkingList);
1125 	Window* frontmost = window->Frontmost();
1126 
1127 	CurrentWindows().RemoveWindow(window);
1128 	windows.AddWindow(window);
1129 	window->MoveToTopStackLayer();
1130 
1131 	if (frontmost != NULL && frontmost->IsModal()) {
1132 		// all modal windows follow their subsets to the front
1133 		// (ie. they are staying in front of them, but they are
1134 		// not supposed to change their order because of that)
1135 
1136 		Window* nextModal;
1137 		for (Window* modal = frontmost; modal != NULL; modal = nextModal) {
1138 			// get the next modal window
1139 			nextModal = modal->NextWindow(fCurrentWorkspace);
1140 			while (nextModal != NULL && !nextModal->IsModal()) {
1141 				nextModal = nextModal->NextWindow(fCurrentWorkspace);
1142 			}
1143 			if (nextModal != NULL && !nextModal->HasInSubset(window))
1144 				nextModal = NULL;
1145 
1146 			CurrentWindows().RemoveWindow(modal);
1147 			windows.AddWindow(modal);
1148 		}
1149 	}
1150 
1151 	_BringWindowsToFront(windows, kWorkingList, true);
1152 
1153 	if ((window->Flags() & B_AVOID_FOCUS) == 0)
1154 		SetFocusWindow(window);
1155 }
1156 
1157 
1158 void
1159 Desktop::SendWindowBehind(Window* window, Window* behindOf, bool sendStack)
1160 {
1161 	if (!LockAllWindows())
1162 		return;
1163 
1164 	Window* orgWindow = window;
1165 	WindowStack* stack = window->GetWindowStack();
1166 	if (sendStack && stack != NULL)
1167 		window = stack->TopLayerWindow();
1168 
1169 	// TODO: should the "not in current workspace" be handled anyway?
1170 	//	(the code below would have to be changed then, though)
1171 	if (window == BackWindow()
1172 		|| !window->InWorkspace(fCurrentWorkspace)
1173 		|| (behindOf != NULL && !behindOf->InWorkspace(fCurrentWorkspace))) {
1174 		UnlockAllWindows();
1175 		return;
1176 	}
1177 
1178 	// Is this a valid behindOf window?
1179 	if (behindOf != NULL && window->HasInSubset(behindOf))
1180 		behindOf = NULL;
1181 
1182 	// what is currently visible of the window
1183 	// might be dirty after the window is send to back
1184 	BRegion dirty(window->VisibleRegion());
1185 
1186 	Window* backmost = window->Backmost(behindOf);
1187 
1188 	CurrentWindows().RemoveWindow(window);
1189 	CurrentWindows().AddWindow(window, backmost
1190 		? backmost->NextWindow(fCurrentWorkspace) : BackWindow());
1191 
1192 	BRegion dummy;
1193 	_RebuildClippingForAllWindows(dummy);
1194 
1195 	// only redraw the top layer window to avoid flicker
1196 	if (sendStack) {
1197 		// mark everything dirty that is no longer visible
1198 		BRegion clean(window->VisibleRegion());
1199 		dirty.Exclude(&clean);
1200 		MarkDirty(dirty);
1201 	}
1202 
1203 	_UpdateFronts();
1204 	if (fSettings->MouseMode() == B_FOCUS_FOLLOWS_MOUSE)
1205 		SetFocusWindow(WindowAt(fLastMousePosition));
1206 	else if (fSettings->MouseMode() == B_NORMAL_MOUSE)
1207 		SetFocusWindow(NULL);
1208 
1209 	bool sendFakeMouseMoved = false;
1210 	if (FocusWindow() != window)
1211 		sendFakeMouseMoved = true;
1212 
1213 	_WindowChanged(window);
1214 
1215 	if (sendStack && stack != NULL) {
1216 		for (int32 i = 0; i < stack->CountWindows(); i++) {
1217 			Window* stackWindow = stack->LayerOrder().ItemAt(i);
1218 			if (stackWindow == window)
1219 				continue;
1220 			SendWindowBehind(stackWindow, behindOf, false);
1221 		}
1222 	}
1223 
1224 	NotifyWindowSentBehind(orgWindow, behindOf);
1225 
1226 	UnlockAllWindows();
1227 
1228 	if (sendFakeMouseMoved)
1229 		_SendFakeMouseMoved();
1230 }
1231 
1232 
1233 void
1234 Desktop::ShowWindow(Window* window)
1235 {
1236 	if (!window->IsHidden())
1237 		return;
1238 
1239 	AutoWriteLocker locker(fWindowLock);
1240 
1241 	window->SetHidden(false);
1242 	fFocusList.AddWindow(window);
1243 
1244 	// If the window is on the current workspace, we'll show it. Special
1245 	// handling for floating windows, as they can only be shown if their
1246 	// subset is.
1247 	if (window->InWorkspace(fCurrentWorkspace)
1248 		|| (window->IsFloating() && _LastFocusSubsetWindow(window) != NULL)) {
1249 		_ShowWindow(window, true);
1250 		_UpdateSubsetWorkspaces(window);
1251 		ActivateWindow(window);
1252 	} else {
1253 		// then we don't need to send the fake mouse event either
1254 		_WindowChanged(window);
1255 		return;
1256 	}
1257 
1258 	if (window->HasWorkspacesViews()) {
1259 		// find workspaces views in view hierarchy
1260 		BAutolock _(fWorkspacesLock);
1261 		window->FindWorkspacesViews(fWorkspacesViews);
1262 	}
1263 
1264 	// If the mouse cursor is directly over the newly visible window,
1265 	// we'll send a fake mouse moved message to the window, so that
1266 	// it knows the mouse is over it.
1267 
1268 	_SendFakeMouseMoved(window);
1269 }
1270 
1271 
1272 void
1273 Desktop::HideWindow(Window* window, bool fromMinimize)
1274 {
1275 	if (window->IsHidden())
1276 		return;
1277 
1278 	if (!LockAllWindows())
1279 		return;
1280 
1281 	window->SetHidden(true);
1282 	fFocusList.RemoveWindow(window);
1283 
1284 	if (fMouseEventWindow == window) {
1285 		// Make its decorator lose the current mouse action
1286 		BMessage message;
1287 		int32 viewToken;
1288 		window->MouseUp(&message, fLastMousePosition, &viewToken);
1289 
1290 		fMouseEventWindow = NULL;
1291 	}
1292 
1293 	if (fLockedFocusWindow == window) {
1294 		// Remove the focus lock so the focus can be changed below
1295 		fLockedFocusWindow = NULL;
1296 	}
1297 
1298 	if (window->InWorkspace(fCurrentWorkspace)) {
1299 		_UpdateSubsetWorkspaces(window);
1300 		_HideWindow(window);
1301 		_UpdateFronts();
1302 	} else
1303 		_WindowChanged(window);
1304 
1305 	if (FocusWindow() == window)
1306 		SetFocusWindow();
1307 
1308 	_WindowRemoved(window);
1309 
1310 	if (window->HasWorkspacesViews()) {
1311 		// remove workspaces views from this window
1312 		BObjectList<WorkspacesView> list(false);
1313 		window->FindWorkspacesViews(list);
1314 
1315 		BAutolock _(fWorkspacesLock);
1316 
1317 		while (WorkspacesView* view = list.RemoveItemAt(0)) {
1318 			fWorkspacesViews.RemoveItem(view);
1319 		}
1320 	}
1321 
1322 	NotifyWindowHidden(window, fromMinimize);
1323 
1324 	UnlockAllWindows();
1325 
1326 	if (window == fWindowUnderMouse)
1327 		_SendFakeMouseMoved();
1328 }
1329 
1330 
1331 void
1332 Desktop::MinimizeWindow(Window* window, bool minimize)
1333 {
1334 	if (!LockAllWindows())
1335 		return;
1336 
1337 	if (minimize && !window->IsHidden()) {
1338 		HideWindow(window, true);
1339 		window->SetMinimized(minimize);
1340 		NotifyWindowMinimized(window, minimize);
1341 	} else if (!minimize && window->IsHidden()) {
1342 		ActivateWindow(window);
1343 			// this will unminimize the window for us
1344 		NotifyWindowMinimized(window, minimize);
1345 	}
1346 
1347 	UnlockAllWindows();
1348 }
1349 
1350 
1351 void
1352 Desktop::MoveWindowBy(Window* window, float x, float y, int32 workspace)
1353 {
1354 	if (x == 0 && y == 0)
1355 		return;
1356 
1357 	AutoWriteLocker _(fWindowLock);
1358 
1359 	Window* topWindow = window->TopLayerStackWindow();
1360 	if (topWindow != NULL)
1361 		window = topWindow;
1362 
1363 	if (workspace == -1)
1364 		workspace = fCurrentWorkspace;
1365 	if (!window->IsVisible() || workspace != fCurrentWorkspace) {
1366 		if (workspace != fCurrentWorkspace) {
1367 			WindowStack* stack = window->GetWindowStack();
1368 			if (stack != NULL) {
1369 				for (int32 s = 0; s < stack->CountWindows(); s++) {
1370 					Window* stackWindow = stack->WindowAt(s);
1371 					// move the window on another workspace - this doesn't
1372 					// change it's current position
1373 					if (stackWindow->Anchor(workspace).position
1374 						== kInvalidWindowPosition) {
1375 						stackWindow->Anchor(workspace).position
1376 							= stackWindow->Frame().LeftTop();
1377 					}
1378 
1379 					stackWindow->Anchor(workspace).position += BPoint(x, y);
1380 					stackWindow->SetCurrentWorkspace(workspace);
1381 					_WindowChanged(stackWindow);
1382 				}
1383 			}
1384 		} else
1385 			window->MoveBy((int32)x, (int32)y);
1386 
1387 		NotifyWindowMoved(window);
1388 		return;
1389 	}
1390 
1391 	// the dirty region starts with the visible area of the window being moved
1392 	BRegion newDirtyRegion(window->VisibleRegion());
1393 
1394 	// stop direct frame buffer access
1395 	bool direct = false;
1396 	if (window->ServerWindow()->IsDirectlyAccessing()) {
1397 		window->ServerWindow()->HandleDirectConnection(B_DIRECT_STOP);
1398 		direct = true;
1399 	}
1400 
1401 	window->MoveBy((int32)x, (int32)y);
1402 
1403 	BRegion background;
1404 	_RebuildClippingForAllWindows(background);
1405 
1406 	// construct the region that is possible to be blitted
1407 	// to move the contents of the window
1408 	BRegion copyRegion(window->VisibleRegion());
1409 	copyRegion.OffsetBy((int32)-x, (int32)-y);
1410 	copyRegion.IntersectWith(&newDirtyRegion);
1411 		// newDirtyRegion == the windows old visible region
1412 
1413 	// include the the new visible region of the window being
1414 	// moved into the dirty region (for now)
1415 	newDirtyRegion.Include(&window->VisibleRegion());
1416 
1417 	// NOTE: Having all windows locked should prevent any
1418 	// problems with locking the drawing engine here.
1419 	if (GetDrawingEngine()->LockParallelAccess()) {
1420 		GetDrawingEngine()->CopyRegion(&copyRegion, (int32)x, (int32)y);
1421 		GetDrawingEngine()->UnlockParallelAccess();
1422 	}
1423 
1424 	// in the dirty region, exclude the parts that we
1425 	// could move by blitting
1426 	copyRegion.OffsetBy((int32)x, (int32)y);
1427 	newDirtyRegion.Exclude(&copyRegion);
1428 
1429 	MarkDirty(newDirtyRegion);
1430 	_SetBackground(background);
1431 	_WindowChanged(window);
1432 
1433 	// resume direct frame buffer access
1434 	if (direct) {
1435 		// TODO: the clipping actually only changes when we move our window
1436 		// off screen, or behind some other window
1437 		window->ServerWindow()->HandleDirectConnection(
1438 			B_DIRECT_START | B_BUFFER_MOVED | B_CLIPPING_MODIFIED);
1439 	}
1440 
1441 	NotifyWindowMoved(window);
1442 }
1443 
1444 
1445 void
1446 Desktop::ResizeWindowBy(Window* window, float x, float y)
1447 {
1448 	if (x == 0 && y == 0)
1449 		return;
1450 
1451 	AutoWriteLocker _(fWindowLock);
1452 
1453 	Window* topWindow = window->TopLayerStackWindow();
1454 	if (topWindow)
1455 		window = topWindow;
1456 
1457 	if (!window->IsVisible()) {
1458 		window->ResizeBy((int32)x, (int32)y, NULL);
1459 		NotifyWindowResized(window);
1460 		return;
1461 	}
1462 
1463 	// the dirty region for the inside of the window is
1464 	// constructed by the window itself in ResizeBy()
1465 	BRegion newDirtyRegion;
1466 	// track the dirty region outside the window in case
1467 	// it is shrunk in "previouslyOccupiedRegion"
1468 	BRegion previouslyOccupiedRegion(window->VisibleRegion());
1469 
1470 	// stop direct frame buffer access
1471 	bool direct = false;
1472 	if (window->ServerWindow()->IsDirectlyAccessing()) {
1473 		window->ServerWindow()->HandleDirectConnection(B_DIRECT_STOP);
1474 		direct = true;
1475 	}
1476 
1477 	window->ResizeBy((int32)x, (int32)y, &newDirtyRegion);
1478 
1479 	BRegion background;
1480 	_RebuildClippingForAllWindows(background);
1481 
1482 	// we just care for the region outside the window
1483 	previouslyOccupiedRegion.Exclude(&window->VisibleRegion());
1484 
1485 	// make sure the window cannot mark stuff dirty outside
1486 	// its visible region...
1487 	newDirtyRegion.IntersectWith(&window->VisibleRegion());
1488 	// ...because we do this outself
1489 	newDirtyRegion.Include(&previouslyOccupiedRegion);
1490 
1491 	MarkDirty(newDirtyRegion);
1492 	_SetBackground(background);
1493 	_WindowChanged(window);
1494 
1495 	// resume direct frame buffer access
1496 	if (direct) {
1497 		window->ServerWindow()->HandleDirectConnection(
1498 			B_DIRECT_START | B_BUFFER_RESIZED | B_CLIPPING_MODIFIED);
1499 	}
1500 
1501 	NotifyWindowResized(window);
1502 }
1503 
1504 
1505 bool
1506 Desktop::SetWindowTabLocation(Window* window, float location, bool isShifting)
1507 {
1508 	AutoWriteLocker _(fWindowLock);
1509 
1510 	BRegion dirty;
1511 	bool changed = window->SetTabLocation(location, isShifting, dirty);
1512 	if (changed)
1513 		RebuildAndRedrawAfterWindowChange(window, dirty);
1514 
1515 	NotifyWindowTabLocationChanged(window, location, isShifting);
1516 
1517 	return changed;
1518 }
1519 
1520 
1521 bool
1522 Desktop::SetWindowDecoratorSettings(Window* window, const BMessage& settings)
1523 {
1524 	AutoWriteLocker _(fWindowLock);
1525 
1526 	BRegion dirty;
1527 	bool changed = window->SetDecoratorSettings(settings, dirty);
1528 	bool listenerChanged = SetDecoratorSettings(window, settings);
1529 	if (changed || listenerChanged)
1530 		RebuildAndRedrawAfterWindowChange(window, dirty);
1531 
1532 	return changed;
1533 }
1534 
1535 
1536 void
1537 Desktop::SetWindowWorkspaces(Window* window, uint32 workspaces)
1538 {
1539 	LockAllWindows();
1540 
1541 	if (window->IsNormal() && workspaces == B_CURRENT_WORKSPACE)
1542 		workspaces = workspace_to_workspaces(CurrentWorkspace());
1543 
1544 	WindowStack* stack = window->GetWindowStack();
1545 	if (stack != NULL) {
1546 		for (int32 s = 0; s < stack->CountWindows(); s++) {
1547 			window = stack->LayerOrder().ItemAt(s);
1548 
1549 			uint32 oldWorkspaces = window->Workspaces();
1550 			window->WorkspacesChanged(oldWorkspaces, workspaces);
1551 			_ChangeWindowWorkspaces(window, oldWorkspaces, workspaces);
1552 		}
1553 	}
1554 	UnlockAllWindows();
1555 }
1556 
1557 
1558 /*!	\brief Adds the window to the desktop.
1559 	At this point, the window is still hidden and must be shown explicetly
1560 	via ShowWindow().
1561 */
1562 void
1563 Desktop::AddWindow(Window *window)
1564 {
1565 	LockAllWindows();
1566 
1567 	fAllWindows.AddWindow(window);
1568 	if (!window->IsNormal())
1569 		fSubsetWindows.AddWindow(window);
1570 
1571 	if (window->IsNormal()) {
1572 		if (window->Workspaces() == B_CURRENT_WORKSPACE)
1573 			window->SetWorkspaces(workspace_to_workspaces(CurrentWorkspace()));
1574 	} else {
1575 		// subset windows are visible on all workspaces their subset is on
1576 		window->SetWorkspaces(window->SubsetWorkspaces());
1577 	}
1578 
1579 	_ChangeWindowWorkspaces(window, 0, window->Workspaces());
1580 
1581 	NotifyWindowAdded(window);
1582 
1583 	UnlockAllWindows();
1584 }
1585 
1586 
1587 void
1588 Desktop::RemoveWindow(Window *window)
1589 {
1590 	LockAllWindows();
1591 
1592 	if (!window->IsHidden())
1593 		HideWindow(window);
1594 
1595 	fAllWindows.RemoveWindow(window);
1596 	if (!window->IsNormal())
1597 		fSubsetWindows.RemoveWindow(window);
1598 
1599 	_ChangeWindowWorkspaces(window, window->Workspaces(), 0);
1600 
1601 	NotifyWindowRemoved(window);
1602 
1603 	UnlockAllWindows();
1604 
1605 	// make sure this window won't get any events anymore
1606 
1607 	EventDispatcher().RemoveTarget(window->EventTarget());
1608 }
1609 
1610 
1611 bool
1612 Desktop::AddWindowToSubset(Window* subset, Window* window)
1613 {
1614 	if (!subset->AddToSubset(window))
1615 		return false;
1616 
1617 	_ChangeWindowWorkspaces(subset, subset->Workspaces(),
1618 		subset->SubsetWorkspaces());
1619 	return true;
1620 }
1621 
1622 
1623 void
1624 Desktop::RemoveWindowFromSubset(Window* subset, Window* window)
1625 {
1626 	subset->RemoveFromSubset(window);
1627 	_ChangeWindowWorkspaces(subset, subset->Workspaces(),
1628 		subset->SubsetWorkspaces());
1629 }
1630 
1631 
1632 void
1633 Desktop::FontsChanged(Window* window)
1634 {
1635 	AutoWriteLocker _(fWindowLock);
1636 
1637 	BRegion dirty;
1638 	window->FontsChanged(&dirty);
1639 
1640 	RebuildAndRedrawAfterWindowChange(window, dirty);
1641 }
1642 
1643 
1644 void
1645 Desktop::SetWindowLook(Window* window, window_look newLook)
1646 {
1647 	if (window->Look() == newLook)
1648 		return;
1649 
1650 	AutoWriteLocker _(fWindowLock);
1651 
1652 	BRegion dirty;
1653 	window->SetLook(newLook, &dirty);
1654 		// TODO: test what happens when the window
1655 		// finds out it needs to resize itself...
1656 
1657 	RebuildAndRedrawAfterWindowChange(window, dirty);
1658 
1659 	NotifyWindowLookChanged(window, newLook);
1660 }
1661 
1662 
1663 void
1664 Desktop::SetWindowFeel(Window* window, window_feel newFeel)
1665 {
1666 	if (window->Feel() == newFeel)
1667 		return;
1668 
1669 	LockAllWindows();
1670 
1671 	bool wasNormal = window->IsNormal();
1672 
1673 	window->SetFeel(newFeel);
1674 
1675 	// move the window out of or into the subset window list as needed
1676 	if (window->IsNormal() && !wasNormal)
1677 		fSubsetWindows.RemoveWindow(window);
1678 	else if (!window->IsNormal() && wasNormal)
1679 		fSubsetWindows.AddWindow(window);
1680 
1681 	// A normal window that was once a floating or modal window will
1682 	// adopt the window's current workspaces
1683 
1684 	if (!window->IsNormal()) {
1685 		_ChangeWindowWorkspaces(window, window->Workspaces(),
1686 			window->SubsetWorkspaces());
1687 	}
1688 
1689 	// make sure the window has the correct position in the window lists
1690 	// (ie. all floating windows have to be on the top, ...)
1691 
1692 	for (int32 i = 0; i < kMaxWorkspaces; i++) {
1693 		if (!workspace_in_workspaces(i, window->Workspaces()))
1694 			continue;
1695 
1696 		bool changed = false;
1697 		BRegion visibleBefore;
1698 		if (i == fCurrentWorkspace && window->IsVisible())
1699 			visibleBefore = window->VisibleRegion();
1700 
1701 		Window* backmost = window->Backmost(_Windows(i).LastWindow(), i);
1702 		if (backmost != NULL) {
1703 			// check if the backmost window is really behind it
1704 			Window* previous = window->PreviousWindow(i);
1705 			while (previous != NULL) {
1706 				if (previous == backmost)
1707 					break;
1708 
1709 				previous = previous->PreviousWindow(i);
1710 			}
1711 
1712 			if (previous == NULL) {
1713 				// need to reinsert window before its backmost window
1714 				_Windows(i).RemoveWindow(window);
1715 				_Windows(i).AddWindow(window, backmost->NextWindow(i));
1716 				changed = true;
1717 			}
1718 		}
1719 
1720 		Window* frontmost = window->Frontmost(_Windows(i).FirstWindow(), i);
1721 		if (frontmost != NULL) {
1722 			// check if the frontmost window is really in front of it
1723 			Window* next = window->NextWindow(i);
1724 			while (next != NULL) {
1725 				if (next == frontmost)
1726 					break;
1727 
1728 				next = next->NextWindow(i);
1729 			}
1730 
1731 			if (next == NULL) {
1732 				// need to reinsert window behind its frontmost window
1733 				_Windows(i).RemoveWindow(window);
1734 				_Windows(i).AddWindow(window, frontmost);
1735 				changed = true;
1736 			}
1737 		}
1738 
1739 		if (i == fCurrentWorkspace && changed) {
1740 			BRegion dummy;
1741 			_RebuildClippingForAllWindows(dummy);
1742 
1743 			// mark everything dirty that is no longer visible, or
1744 			// is now visible and wasn't before
1745 			BRegion visibleAfter(window->VisibleRegion());
1746 			BRegion dirty(visibleAfter);
1747 			dirty.Exclude(&visibleBefore);
1748 			visibleBefore.Exclude(&visibleAfter);
1749 			dirty.Include(&visibleBefore);
1750 
1751 			MarkDirty(dirty);
1752 		}
1753 	}
1754 
1755 	_UpdateFronts();
1756 
1757 	if (window == FocusWindow() && !window->IsVisible())
1758 		SetFocusWindow();
1759 
1760 	NotifyWindowFeelChanged(window, newFeel);
1761 
1762 	UnlockAllWindows();
1763 }
1764 
1765 
1766 void
1767 Desktop::SetWindowFlags(Window *window, uint32 newFlags)
1768 {
1769 	if (window->Flags() == newFlags)
1770 		return;
1771 
1772 	AutoWriteLocker _(fWindowLock);
1773 
1774 	BRegion dirty;
1775 	window->SetFlags(newFlags, &dirty);
1776 		// TODO: test what happens when the window
1777 		// finds out it needs to resize itself...
1778 
1779 	RebuildAndRedrawAfterWindowChange(window, dirty);
1780 }
1781 
1782 
1783 void
1784 Desktop::SetWindowTitle(Window *window, const char* title)
1785 {
1786 	AutoWriteLocker _(fWindowLock);
1787 
1788 	BRegion dirty;
1789 	window->SetTitle(title, dirty);
1790 
1791 	RebuildAndRedrawAfterWindowChange(window, dirty);
1792 }
1793 
1794 
1795 /*!	Returns the window under the mouse cursor.
1796 	You need to have acquired the All Windows lock when calling this method.
1797 */
1798 Window*
1799 Desktop::WindowAt(BPoint where)
1800 {
1801 	for (Window* window = CurrentWindows().LastWindow(); window;
1802 			window = window->PreviousWindow(fCurrentWorkspace)) {
1803 		if (window->IsVisible() && window->VisibleRegion().Contains(where))
1804 			return window->StackedWindowAt(where);
1805 	}
1806 
1807 	return NULL;
1808 }
1809 
1810 
1811 void
1812 Desktop::SetMouseEventWindow(Window* window)
1813 {
1814 	fMouseEventWindow = window;
1815 }
1816 
1817 
1818 void
1819 Desktop::SetViewUnderMouse(const Window* window, int32 viewToken)
1820 {
1821 	fWindowUnderMouse = window;
1822 	fViewUnderMouse = viewToken;
1823 }
1824 
1825 
1826 int32
1827 Desktop::ViewUnderMouse(const Window* window)
1828 {
1829 	if (window != NULL && fWindowUnderMouse == window)
1830 		return fViewUnderMouse;
1831 
1832 	return B_NULL_TOKEN;
1833 }
1834 
1835 
1836 /*!	Returns the current keyboard event target candidate - which is either the
1837 	top-most window (in case it has the kAcceptKeyboardFocusFlag flag set), or
1838 	the one having focus.
1839 	The window lock must be held when calling this function.
1840 */
1841 EventTarget*
1842 Desktop::KeyboardEventTarget()
1843 {
1844 	// Get the top most non-hidden window
1845 	Window* window = CurrentWindows().LastWindow();
1846 	while (window != NULL && window->IsHidden()) {
1847 		window = window->PreviousWindow(fCurrentWorkspace);
1848 	}
1849 
1850 	if (window != NULL && (window->Flags() & kAcceptKeyboardFocusFlag) != 0)
1851 		return &window->EventTarget();
1852 
1853 	if (FocusWindow() != NULL)
1854 		return &FocusWindow()->EventTarget();
1855 
1856 	return NULL;
1857 }
1858 
1859 
1860 /*!	Tries to set the focus to the specified \a focus window. It will make sure,
1861 	however, that the window actually can have focus. You are allowed to pass
1862 	in a NULL pointer for \a focus.
1863 
1864 	Besides the B_AVOID_FOCUS flag, a modal window, or a BWindowScreen can both
1865 	prevent it from getting focus.
1866 
1867 	In any case, this method makes sure that there is a focus window, if there
1868 	is any window at all, that is.
1869 */
1870 void
1871 Desktop::SetFocusWindow(Window* focus)
1872 {
1873 	if (!LockAllWindows())
1874 		return;
1875 
1876 	// test for B_LOCK_WINDOW_FOCUS
1877 	if (fLockedFocusWindow && focus != fLockedFocusWindow) {
1878 		UnlockAllWindows();
1879 		return;
1880 	}
1881 
1882 	bool hasModal = _WindowHasModal(focus);
1883 	bool hasWindowScreen = false;
1884 
1885 	if (!hasModal && focus != NULL) {
1886 		// Check whether or not a window screen is in front of the window
1887 		// (if it has a modal, the right thing is done, anyway)
1888 		Window* window = focus;
1889 		while (true) {
1890 			window = window->NextWindow(fCurrentWorkspace);
1891 			if (window == NULL || window->Feel() == kWindowScreenFeel)
1892 				break;
1893 		}
1894 		if (window != NULL)
1895 			hasWindowScreen = true;
1896 	}
1897 
1898 	if (focus == fFocus && focus != NULL && !focus->IsHidden()
1899 		&& (focus->Flags() & B_AVOID_FOCUS) == 0
1900 		&& !hasModal && !hasWindowScreen) {
1901 		// the window that is supposed to get focus already has focus
1902 		UnlockAllWindows();
1903 		return;
1904 	}
1905 
1906 	uint32 list = /*fCurrentWorkspace;
1907 	if (fSettings->FocusFollowsMouse())
1908 		list = */kFocusList;
1909 
1910 	if (focus == NULL || hasModal || hasWindowScreen) {
1911 		/*if (!fSettings->FocusFollowsMouse())
1912 			focus = CurrentWindows().LastWindow();
1913 		else*/
1914 			focus = fFocusList.LastWindow();
1915 	}
1916 
1917 	// make sure no window is chosen that doesn't want focus or cannot have it
1918 	while (focus != NULL
1919 		&& (!focus->InWorkspace(fCurrentWorkspace)
1920 			|| (focus->Flags() & B_AVOID_FOCUS) != 0
1921 			|| _WindowHasModal(focus)
1922 			|| focus->IsHidden())) {
1923 		focus = focus->PreviousWindow(list);
1924 	}
1925 
1926 	if (fFocus == focus) {
1927 		// turns out the window that is supposed to get focus now already has it
1928 		UnlockAllWindows();
1929 		return;
1930 	}
1931 
1932 	team_id oldActiveApp = -1;
1933 	team_id newActiveApp = -1;
1934 
1935 	if (fFocus != NULL) {
1936 		fFocus->SetFocus(false);
1937 		oldActiveApp = fFocus->ServerWindow()->App()->ClientTeam();
1938 	}
1939 
1940 	fFocus = focus;
1941 
1942 	if (fFocus != NULL) {
1943 		fFocus->SetFocus(true);
1944 		newActiveApp = fFocus->ServerWindow()->App()->ClientTeam();
1945 
1946 		// move current focus to the end of the focus list
1947 		fFocusList.RemoveWindow(fFocus);
1948 		fFocusList.AddWindow(fFocus);
1949 	}
1950 
1951 	if (newActiveApp == -1) {
1952 		// make sure the cursor is visible
1953 		HWInterface()->SetCursorVisible(true);
1954 	}
1955 
1956 	UnlockAllWindows();
1957 
1958 	// change the "active" app if appropriate
1959 	if (oldActiveApp == newActiveApp)
1960 		return;
1961 
1962 	BAutolock locker(fApplicationsLock);
1963 
1964 	for (int32 i = 0; i < fApplications.CountItems(); i++) {
1965 		ServerApp* app = fApplications.ItemAt(i);
1966 
1967 		if (oldActiveApp != -1 && app->ClientTeam() == oldActiveApp)
1968 			app->Activate(false);
1969 		else if (newActiveApp != -1 && app->ClientTeam() == newActiveApp)
1970 			app->Activate(true);
1971 	}
1972 }
1973 
1974 
1975 void
1976 Desktop::SetFocusLocked(const Window* window)
1977 {
1978 	AutoWriteLocker _(fWindowLock);
1979 
1980 	if (window != NULL) {
1981 		// Don't allow this to be set when no mouse buttons
1982 		// are pressed. (BView::SetMouseEventMask() should only be called
1983 		// from mouse hooks.)
1984 		if (fLastMouseButtons == 0)
1985 			return;
1986 	}
1987 
1988 	fLockedFocusWindow = window;
1989 }
1990 
1991 
1992 Window*
1993 Desktop::FindWindowByClientToken(int32 token, team_id teamID)
1994 {
1995 	for (Window *window = fAllWindows.FirstWindow(); window != NULL;
1996 			window = window->NextWindow(kAllWindowList)) {
1997 		if (window->ServerWindow()->ClientToken() == token
1998 			&& window->ServerWindow()->ClientTeam() == teamID) {
1999 			return window;
2000 		}
2001 	}
2002 
2003 	return NULL;
2004 }
2005 
2006 
2007 ::EventTarget*
2008 Desktop::FindTarget(BMessenger& messenger)
2009 {
2010 	for (Window *window = fAllWindows.FirstWindow(); window != NULL;
2011 			window = window->NextWindow(kAllWindowList)) {
2012 		if (window->EventTarget().Messenger() == messenger)
2013 			return &window->EventTarget();
2014 	}
2015 
2016 	return NULL;
2017 }
2018 
2019 
2020 void
2021 Desktop::MarkDirty(BRegion& region)
2022 {
2023 	if (region.CountRects() == 0)
2024 		return;
2025 
2026 	if (LockAllWindows()) {
2027 		// send redraw messages to all windows intersecting the dirty region
2028 		_TriggerWindowRedrawing(region);
2029 
2030 		UnlockAllWindows();
2031 	}
2032 }
2033 
2034 
2035 void
2036 Desktop::Redraw()
2037 {
2038 	BRegion dirty(fVirtualScreen.Frame());
2039 	MarkDirty(dirty);
2040 }
2041 
2042 
2043 /*!	\brief Redraws the background (ie. the desktop window, if any).
2044 */
2045 void
2046 Desktop::RedrawBackground()
2047 {
2048 	LockAllWindows();
2049 
2050 	BRegion redraw;
2051 
2052 	Window* window = CurrentWindows().FirstWindow();
2053 	if (window->Feel() == kDesktopWindowFeel) {
2054 		redraw = window->VisibleContentRegion();
2055 
2056 		// look for desktop background view, and update its background color
2057 		// TODO: is there a better way to do this?
2058 		View* view = window->TopView();
2059 		if (view != NULL)
2060 			view = view->FirstChild();
2061 
2062 		while (view) {
2063 			if (view->IsDesktopBackground()) {
2064 				view->SetViewColor(fWorkspaces[fCurrentWorkspace].Color());
2065 				break;
2066 			}
2067 			view = view->NextSibling();
2068 		}
2069 
2070 		window->ProcessDirtyRegion(redraw);
2071 	} else {
2072 		redraw = BackgroundRegion();
2073 		fBackgroundRegion.MakeEmpty();
2074 		_SetBackground(redraw);
2075 	}
2076 
2077 	_WindowChanged(NULL);
2078 		// update workspaces view as well
2079 
2080 	UnlockAllWindows();
2081 }
2082 
2083 
2084 bool
2085 Desktop::ReloadDecor(DecorAddOn* oldDecor)
2086 {
2087 	AutoWriteLocker _(fWindowLock);
2088 
2089 	bool returnValue = true;
2090 
2091 	if (oldDecor != NULL) {
2092 		const DesktopListenerList* oldListeners
2093 			= &oldDecor->GetDesktopListeners();
2094 		for (int i = 0; i < oldListeners->CountItems(); i++)
2095 			UnregisterListener(oldListeners->ItemAt(i));
2096 	}
2097 
2098 	for (Window* window = fAllWindows.FirstWindow(); window != NULL;
2099 			window = window->NextWindow(kAllWindowList)) {
2100 		BRegion oldBorder;
2101 		window->GetBorderRegion(&oldBorder);
2102 
2103 		if (!window->ReloadDecor()) {
2104 			// prevent unloading previous add-on
2105 			returnValue = false;
2106 		}
2107 
2108 		BRegion border;
2109 		window->GetBorderRegion(&border);
2110 
2111 		border.Include(&oldBorder);
2112 		RebuildAndRedrawAfterWindowChange(window, border);
2113 	}
2114 
2115 	// register new listeners
2116 	const DesktopListenerList& newListeners
2117 		= gDecorManager.GetDesktopListeners();
2118 	for (int i = 0; i < newListeners.CountItems(); i++)
2119  		RegisterListener(newListeners.ItemAt(i));
2120 
2121  	return returnValue;
2122 }
2123 
2124 
2125 void
2126 Desktop::MinimizeApplication(team_id team)
2127 {
2128 	AutoWriteLocker locker(fWindowLock);
2129 
2130 	// Just minimize all windows of that application
2131 
2132 	for (Window *window = fAllWindows.FirstWindow(); window != NULL;
2133 			window = window->NextWindow(kAllWindowList)) {
2134 		if (window->ServerWindow()->ClientTeam() != team)
2135 			continue;
2136 
2137 		window->ServerWindow()->NotifyMinimize(true);
2138 	}
2139 }
2140 
2141 
2142 void
2143 Desktop::BringApplicationToFront(team_id team)
2144 {
2145 	AutoWriteLocker locker(fWindowLock);
2146 
2147 	// TODO: for now, just maximize all windows of that application
2148 	// TODO: have the ability to lock the current workspace
2149 
2150 	for (Window *window = fAllWindows.FirstWindow(); window != NULL;
2151 			window = window->NextWindow(kAllWindowList)) {
2152 		if (window->ServerWindow()->ClientTeam() != team)
2153 			continue;
2154 
2155 		window->ServerWindow()->NotifyMinimize(false);
2156 	}
2157 }
2158 
2159 
2160 void
2161 Desktop::WindowAction(int32 windowToken, int32 action)
2162 {
2163 	if (action != B_MINIMIZE_WINDOW && action != B_BRING_TO_FRONT)
2164 		return;
2165 
2166 	LockAllWindows();
2167 
2168 	::ServerWindow* serverWindow;
2169 	Window* window;
2170 	if (BPrivate::gDefaultTokens.GetToken(windowToken,
2171 			B_SERVER_TOKEN, (void**)&serverWindow) != B_OK
2172 		|| (window = serverWindow->Window()) == NULL) {
2173 		UnlockAllWindows();
2174 		return;
2175 	}
2176 
2177 	if (action == B_BRING_TO_FRONT && !window->IsMinimized()) {
2178 		// the window is visible, we just need to make it the front window
2179 		ActivateWindow(window);
2180 	} else {
2181 		// if not, ask the window if it wants to be unminimized
2182 		serverWindow->NotifyMinimize(action == B_MINIMIZE_WINDOW);
2183 	}
2184 
2185 	UnlockAllWindows();
2186 }
2187 
2188 
2189 void
2190 Desktop::WriteWindowList(team_id team, BPrivate::LinkSender& sender)
2191 {
2192 	AutoWriteLocker locker(fWindowLock);
2193 
2194 	// compute the number of windows
2195 
2196 	int32 count = 0;
2197 
2198 	for (Window *window = fAllWindows.FirstWindow(); window != NULL;
2199 			window = window->NextWindow(kAllWindowList)) {
2200 		if (team < B_OK || window->ServerWindow()->ClientTeam() == team)
2201 			count++;
2202 	}
2203 
2204 	// write list
2205 
2206 	sender.StartMessage(B_OK);
2207 	sender.Attach<int32>(count);
2208 
2209 	// first write the windows of the current workspace correctly ordered
2210 	for (Window *window = CurrentWindows().LastWindow(); window != NULL;
2211 			window = window->PreviousWindow(fCurrentWorkspace)) {
2212 		if (team >= B_OK && window->ServerWindow()->ClientTeam() != team)
2213 			continue;
2214 
2215 		sender.Attach<int32>(window->ServerWindow()->ServerToken());
2216 	}
2217 
2218 	// then write all the other windows
2219 	for (Window *window = fAllWindows.FirstWindow(); window != NULL;
2220 			window = window->NextWindow(kAllWindowList)) {
2221 		if ((team >= B_OK && window->ServerWindow()->ClientTeam() != team)
2222 			|| window->InWorkspace(fCurrentWorkspace))
2223 			continue;
2224 
2225 		sender.Attach<int32>(window->ServerWindow()->ServerToken());
2226 	}
2227 
2228 	sender.Flush();
2229 }
2230 
2231 
2232 void
2233 Desktop::WriteWindowInfo(int32 serverToken, BPrivate::LinkSender& sender)
2234 {
2235 	AutoWriteLocker locker(fWindowLock);
2236 	BAutolock tokenLocker(BPrivate::gDefaultTokens);
2237 
2238 	::ServerWindow* window;
2239 	if (BPrivate::gDefaultTokens.GetToken(serverToken,
2240 			B_SERVER_TOKEN, (void**)&window) != B_OK) {
2241 		sender.StartMessage(B_ENTRY_NOT_FOUND);
2242 		sender.Flush();
2243 		return;
2244 	}
2245 
2246 	window_info info;
2247 	window->GetInfo(info);
2248 
2249 	float tabSize = 0.0;
2250 	float borderSize = 0.0;
2251 	::Window* tmp = window->Window();
2252 	if (tmp) {
2253 		BMessage message;
2254 		if (tmp->GetDecoratorSettings(&message)) {
2255 			BRect tabFrame;
2256 			message.FindRect("tab frame", &tabFrame);
2257 			tabSize = tabFrame.bottom - tabFrame.top;
2258 			message.FindFloat("border width", &borderSize);
2259 		}
2260 	}
2261 
2262 	int32 length = window->Title() ? strlen(window->Title()) : 0;
2263 
2264 	sender.StartMessage(B_OK);
2265 	sender.Attach<int32>(sizeof(client_window_info) + length);
2266 	sender.Attach(&info, sizeof(window_info));
2267 	sender.Attach<float>(tabSize);
2268 	sender.Attach<float>(borderSize);
2269 
2270 	if (length > 0)
2271 		sender.Attach(window->Title(), length + 1);
2272 	else
2273 		sender.Attach<char>('\0');
2274 
2275 	sender.Flush();
2276 }
2277 
2278 
2279 void
2280 Desktop::WriteWindowOrder(int32 workspace, BPrivate::LinkSender& sender)
2281 {
2282 	LockSingleWindow();
2283 
2284 	if (workspace < 0)
2285 		workspace = fCurrentWorkspace;
2286 	else if (workspace >= kMaxWorkspaces) {
2287 		sender.StartMessage(B_BAD_VALUE);
2288 		sender.Flush();
2289 		UnlockSingleWindow();
2290 		return;
2291 	}
2292 
2293 	int32 count = _Windows(workspace).Count();
2294 
2295 	// write list
2296 
2297 	sender.StartMessage(B_OK);
2298 	sender.Attach<int32>(count);
2299 
2300 	for (Window *window = _Windows(workspace).LastWindow(); window != NULL;
2301 			window = window->PreviousWindow(workspace)) {
2302 		sender.Attach<int32>(window->ServerWindow()->ServerToken());
2303 	}
2304 
2305 	sender.Flush();
2306 
2307 	UnlockSingleWindow();
2308 }
2309 
2310 
2311 void
2312 Desktop::WriteApplicationOrder(int32 workspace, BPrivate::LinkSender& sender)
2313 {
2314 	fApplicationsLock.Lock();
2315 	LockSingleWindow();
2316 
2317 	int32 maxCount = fApplications.CountItems();
2318 
2319 	fApplicationsLock.Unlock();
2320 		// as long as we hold the window lock, no new window can appear
2321 
2322 	if (workspace < 0)
2323 		workspace = fCurrentWorkspace;
2324 	else if (workspace >= kMaxWorkspaces) {
2325 		sender.StartMessage(B_BAD_VALUE);
2326 		sender.Flush();
2327 		UnlockSingleWindow();
2328 		return;
2329 	}
2330 
2331 	// compute the list of applications on this workspace
2332 
2333 	team_id* teams = (team_id*)malloc(maxCount * sizeof(team_id));
2334 	if (teams == NULL) {
2335 		sender.StartMessage(B_NO_MEMORY);
2336 		sender.Flush();
2337 		UnlockSingleWindow();
2338 		return;
2339 	}
2340 
2341 	int32 count = 0;
2342 
2343 	for (Window *window = _Windows(workspace).LastWindow(); window != NULL;
2344 			window = window->PreviousWindow(workspace)) {
2345 		team_id team = window->ServerWindow()->ClientTeam();
2346 		if (count > 1) {
2347 			// see if we already have this team
2348 			bool found = false;
2349 			for (int32 i = 0; i < count; i++) {
2350 				if (teams[i] == team) {
2351 					found = true;
2352 					break;
2353 				}
2354 			}
2355 			if (found)
2356 				continue;
2357 		}
2358 
2359 		ASSERT(count < maxCount);
2360 		teams[count++] = team;
2361 	}
2362 
2363 	UnlockSingleWindow();
2364 
2365 	// write list
2366 
2367 	sender.StartMessage(B_OK);
2368 	sender.Attach<int32>(count);
2369 
2370 	for (int32 i = 0; i < count; i++) {
2371 		sender.Attach<int32>(teams[i]);
2372 	}
2373 
2374 	sender.Flush();
2375 	free(teams);
2376 }
2377 
2378 
2379 void
2380 Desktop::_LaunchInputServer()
2381 {
2382 	BRoster roster;
2383 	status_t status = roster.Launch("application/x-vnd.Be-input_server");
2384 	if (status == B_OK || status == B_ALREADY_RUNNING)
2385 		return;
2386 
2387 	// Could not load input_server by signature, try well-known location
2388 
2389 	BEntry entry;
2390 	BPath inputServerPath;
2391 	if (find_directory(B_SYSTEM_SERVERS_DIRECTORY, &inputServerPath) == B_OK
2392 		&& inputServerPath.Append("input_server") == B_OK) {
2393 		entry.SetTo(inputServerPath.Path());
2394 	} else
2395 		entry.SetTo("/system/servers/input_server");
2396 	entry_ref ref;
2397 	status_t entryStatus = entry.GetRef(&ref);
2398 	if (entryStatus == B_OK)
2399 		entryStatus = roster.Launch(&ref);
2400 	if (entryStatus == B_OK || entryStatus == B_ALREADY_RUNNING) {
2401 		syslog(LOG_ERR, "Failed to launch the input server by signature: %s!\n",
2402 			strerror(status));
2403 		return;
2404 	}
2405 
2406 	syslog(LOG_ERR, "Failed to launch the input server: %s!\n",
2407 		strerror(entryStatus));
2408 }
2409 
2410 
2411 void
2412 Desktop::_GetLooperName(char* name, size_t length)
2413 {
2414 	snprintf(name, length, "d:%d:%s", fUserID,
2415 		fTargetScreen == NULL ? "baron" : fTargetScreen);
2416 }
2417 
2418 
2419 void
2420 Desktop::_PrepareQuit()
2421 {
2422 	// let's kill all remaining applications
2423 
2424 	fApplicationsLock.Lock();
2425 
2426 	int32 count = fApplications.CountItems();
2427 	for (int32 i = 0; i < count; i++) {
2428 		ServerApp *app = fApplications.ItemAt(i);
2429 		team_id clientTeam = app->ClientTeam();
2430 
2431 		app->Quit();
2432 		kill_team(clientTeam);
2433 	}
2434 
2435 	// wait for the last app to die
2436 	if (count > 0) {
2437 		acquire_sem_etc(fShutdownSemaphore, fShutdownCount, B_RELATIVE_TIMEOUT,
2438 			250000);
2439 	}
2440 
2441 	fApplicationsLock.Unlock();
2442 }
2443 
2444 
2445 void
2446 Desktop::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
2447 {
2448 	switch (code) {
2449 		case AS_CREATE_APP:
2450 		{
2451 			// Create the ServerApp to node monitor a new BApplication
2452 
2453 			// Attached data:
2454 			// 1) port_id - receiver port of a regular app
2455 			// 2) port_id - client looper port - for sending messages to the
2456 			//		client
2457 			// 2) team_id - app's team ID
2458 			// 3) int32 - handler token of the regular app
2459 			// 4) char * - signature of the regular app
2460 
2461 			// Find the necessary data
2462 			team_id	clientTeamID = -1;
2463 			port_id	clientLooperPort = -1;
2464 			port_id clientReplyPort = -1;
2465 			int32 htoken = B_NULL_TOKEN;
2466 			char* appSignature = NULL;
2467 
2468 			link.Read<port_id>(&clientReplyPort);
2469 			link.Read<port_id>(&clientLooperPort);
2470 			link.Read<team_id>(&clientTeamID);
2471 			link.Read<int32>(&htoken);
2472 			if (link.ReadString(&appSignature) != B_OK)
2473 				break;
2474 
2475 			ServerApp* app = new ServerApp(this, clientReplyPort,
2476 				clientLooperPort, clientTeamID, htoken, appSignature);
2477 			if (app->InitCheck() == B_OK
2478 				&& app->Run()) {
2479 				// add the new ServerApp to the known list of ServerApps
2480 				fApplicationsLock.Lock();
2481 				fApplications.AddItem(app);
2482 				fApplicationsLock.Unlock();
2483 			} else {
2484 				delete app;
2485 
2486 				// if everything went well, ServerApp::Run() will notify
2487 				// the client - but since it didn't, we do it here
2488 				BPrivate::LinkSender reply(clientReplyPort);
2489 				reply.StartMessage(B_ERROR);
2490 				reply.Flush();
2491 			}
2492 
2493 			// This is necessary because BPortLink::ReadString allocates memory
2494 			free(appSignature);
2495 			break;
2496 		}
2497 
2498 		case AS_DELETE_APP:
2499 		{
2500 			// Delete a ServerApp. Received only from the respective ServerApp
2501 			// when a BApplication asks it to quit.
2502 
2503 			// Attached Data:
2504 			// 1) thread_id - thread ID of the ServerApp to be deleted
2505 
2506 			thread_id thread = -1;
2507 			if (link.Read<thread_id>(&thread) < B_OK)
2508 				break;
2509 
2510 			fApplicationsLock.Lock();
2511 
2512 			// Run through the list of apps and nuke the proper one
2513 
2514 			int32 count = fApplications.CountItems();
2515 			ServerApp* removeApp = NULL;
2516 
2517 			for (int32 i = 0; i < count; i++) {
2518 				ServerApp* app = fApplications.ItemAt(i);
2519 
2520 				if (app->Thread() == thread) {
2521 					fApplications.RemoveItemAt(i);
2522 					removeApp = app;
2523 					break;
2524 				}
2525 			}
2526 
2527 			fApplicationsLock.Unlock();
2528 
2529 			if (removeApp != NULL)
2530 				removeApp->Quit(fShutdownSemaphore);
2531 
2532 			if (fQuitting && count <= 1) {
2533 				// wait for the last app to die
2534 				acquire_sem_etc(fShutdownSemaphore, fShutdownCount,
2535 					B_RELATIVE_TIMEOUT, 500000);
2536 				PostMessage(kMsgQuitLooper);
2537 			}
2538 			break;
2539 		}
2540 
2541 		case AS_ACTIVATE_APP:
2542 		{
2543 			// Someone is requesting to activation of a certain app.
2544 
2545 			// Attached data:
2546 			// 1) port_id reply port
2547 			// 2) team_id team
2548 
2549 			status_t status;
2550 
2551 			// get the parameters
2552 			port_id replyPort;
2553 			team_id team;
2554 			if (link.Read(&replyPort) == B_OK
2555 				&& link.Read(&team) == B_OK)
2556 				status = _ActivateApp(team);
2557 			else
2558 				status = B_ERROR;
2559 
2560 			// send the reply
2561 			BPrivate::PortLink replyLink(replyPort);
2562 			replyLink.StartMessage(status);
2563 			replyLink.Flush();
2564 			break;
2565 		}
2566 
2567 		case AS_APP_CRASHED:
2568 		case AS_DUMP_ALLOCATOR:
2569 		case AS_DUMP_BITMAPS:
2570 		{
2571 			BAutolock locker(fApplicationsLock);
2572 
2573 			team_id team;
2574 			if (link.Read(&team) != B_OK)
2575 				break;
2576 
2577 			for (int32 i = 0; i < fApplications.CountItems(); i++) {
2578 				ServerApp* app = fApplications.ItemAt(i);
2579 
2580 				if (app->ClientTeam() == team)
2581 					app->PostMessage(code);
2582 			}
2583 			break;
2584 		}
2585 
2586 		case AS_EVENT_STREAM_CLOSED:
2587 			_LaunchInputServer();
2588 			break;
2589 
2590 		case B_QUIT_REQUESTED:
2591 			// We've been asked to quit, so (for now) broadcast to all
2592 			// test apps to quit. This situation will occur only when the
2593 			// server is compiled as a regular Be application.
2594 
2595 			fApplicationsLock.Lock();
2596 			fShutdownSemaphore = create_sem(0, "desktop shutdown");
2597 			fShutdownCount = fApplications.CountItems();
2598 			fApplicationsLock.Unlock();
2599 
2600 			fQuitting = true;
2601 			BroadcastToAllApps(AS_QUIT_APP);
2602 
2603 			// We now need to process the remaining AS_DELETE_APP messages and
2604 			// wait for the kMsgShutdownServer message.
2605 			// If an application does not quit as asked, the picasso thread
2606 			// will send us this message in 2-3 seconds.
2607 
2608 			// if there are no apps to quit, shutdown directly
2609 			if (fShutdownCount == 0)
2610 				PostMessage(kMsgQuitLooper);
2611 			break;
2612 
2613 		case AS_ACTIVATE_WORKSPACE:
2614 		{
2615 			int32 index;
2616 			link.Read<int32>(&index);
2617 			if (index == -1)
2618 				index = fPreviousWorkspace;
2619 
2620 			bool moveFocusWindow;
2621 			link.Read<bool>(&moveFocusWindow);
2622 
2623 			SetWorkspace(index, moveFocusWindow);
2624 			break;
2625 		}
2626 
2627 		case AS_TALK_TO_DESKTOP_LISTENER:
2628 		{
2629 			port_id clientReplyPort;
2630 			if (link.Read<port_id>(&clientReplyPort) != B_OK)
2631 				break;
2632 
2633 			BPrivate::LinkSender reply(clientReplyPort);
2634 			AutoWriteLocker locker(fWindowLock);
2635 			if (MessageForListener(NULL, link, reply) != true) {
2636 				// unhandled message, at least send an error if needed
2637 				if (link.NeedsReply()) {
2638 					reply.StartMessage(B_ERROR);
2639 					reply.Flush();
2640 				}
2641 			}
2642 			break;
2643 		}
2644 
2645 		// ToDo: Remove this again. It is a message sent by the
2646 		// invalidate_on_exit kernel debugger add-on to trigger a redraw
2647 		// after exiting a kernel debugger session.
2648 		case 'KDLE':
2649 		{
2650 			BRegion dirty;
2651 			dirty.Include(fVirtualScreen.Frame());
2652 			MarkDirty(dirty);
2653 			break;
2654 		}
2655 
2656 		default:
2657 			printf("Desktop %d:%s received unexpected code %" B_PRId32 "\n", 0,
2658 				"baron", code);
2659 
2660 			if (link.NeedsReply()) {
2661 				// the client is now blocking and waiting for a reply!
2662 				fLink.StartMessage(B_ERROR);
2663 				fLink.Flush();
2664 			}
2665 			break;
2666 	}
2667 }
2668 
2669 
2670 WindowList&
2671 Desktop::CurrentWindows()
2672 {
2673 	return fWorkspaces[fCurrentWorkspace].Windows();
2674 }
2675 
2676 
2677 WindowList&
2678 Desktop::AllWindows()
2679 {
2680 	return fAllWindows;
2681 }
2682 
2683 
2684 Window*
2685 Desktop::WindowForClientLooperPort(port_id port)
2686 {
2687 	ASSERT_MULTI_LOCKED(fWindowLock);
2688 
2689 	for (Window* window = fAllWindows.FirstWindow(); window != NULL;
2690 			window = window->NextWindow(kAllWindowList)) {
2691 		if (window->ServerWindow()->ClientLooperPort() == port)
2692 			return window;
2693 	}
2694 	return NULL;
2695 }
2696 
2697 
2698 WindowList&
2699 Desktop::_Windows(int32 index)
2700 {
2701 	return fWorkspaces[index].Windows();
2702 }
2703 
2704 
2705 void
2706 Desktop::_UpdateFloating(int32 previousWorkspace, int32 nextWorkspace,
2707 	Window* mouseEventWindow)
2708 {
2709 	if (previousWorkspace == -1)
2710 		previousWorkspace = fCurrentWorkspace;
2711 	if (nextWorkspace == -1)
2712 		nextWorkspace = previousWorkspace;
2713 
2714 	for (Window* floating = fSubsetWindows.FirstWindow(); floating != NULL;
2715 			floating = floating->NextWindow(kSubsetList)) {
2716 		// we only care about app/subset floating windows
2717 		if (floating->Feel() != B_FLOATING_SUBSET_WINDOW_FEEL
2718 			&& floating->Feel() != B_FLOATING_APP_WINDOW_FEEL)
2719 			continue;
2720 
2721 		if (fFront != NULL && fFront->IsNormal()
2722 			&& floating->HasInSubset(fFront)) {
2723 			// is now visible
2724 			if (_Windows(previousWorkspace).HasWindow(floating)
2725 				&& previousWorkspace != nextWorkspace
2726 				&& !floating->InSubsetWorkspace(previousWorkspace)) {
2727 				// but no longer on the previous workspace
2728 				_Windows(previousWorkspace).RemoveWindow(floating);
2729 				floating->SetCurrentWorkspace(-1);
2730 			}
2731 
2732 			if (!_Windows(nextWorkspace).HasWindow(floating)) {
2733 				// but wasn't before
2734 				_Windows(nextWorkspace).AddWindow(floating,
2735 					floating->Frontmost(_Windows(nextWorkspace).FirstWindow(),
2736 					nextWorkspace));
2737 				floating->SetCurrentWorkspace(nextWorkspace);
2738 				if (mouseEventWindow != fFront)
2739 					_ShowWindow(floating);
2740 
2741 				// TODO: put the floating last in the floating window list to
2742 				// preserve the on screen window order
2743 			}
2744 		} else if (_Windows(previousWorkspace).HasWindow(floating)
2745 			&& !floating->InSubsetWorkspace(previousWorkspace)) {
2746 			// was visible, but is no longer
2747 
2748 			_Windows(previousWorkspace).RemoveWindow(floating);
2749 			floating->SetCurrentWorkspace(-1);
2750 			_HideWindow(floating);
2751 
2752 			if (FocusWindow() == floating)
2753 				SetFocusWindow();
2754 		}
2755 	}
2756 }
2757 
2758 
2759 /*!	Search the visible windows for a valid back window
2760 	(only desktop windows can't be back windows)
2761 */
2762 void
2763 Desktop::_UpdateBack()
2764 {
2765 	fBack = NULL;
2766 
2767 	for (Window* window = CurrentWindows().FirstWindow(); window != NULL;
2768 			window = window->NextWindow(fCurrentWorkspace)) {
2769 		if (window->IsHidden() || window->Feel() == kDesktopWindowFeel)
2770 			continue;
2771 
2772 		fBack = window;
2773 		break;
2774 	}
2775 }
2776 
2777 
2778 /*!	Search the visible windows for a valid front window
2779 	(only normal and modal windows can be front windows)
2780 
2781 	The only place where you don't want to update floating windows is
2782 	during a workspace change - because then you'll call _UpdateFloating()
2783 	yourself.
2784 */
2785 void
2786 Desktop::_UpdateFront(bool updateFloating)
2787 {
2788 	fFront = NULL;
2789 
2790 	for (Window* window = CurrentWindows().LastWindow(); window != NULL;
2791 			window = window->PreviousWindow(fCurrentWorkspace)) {
2792 		if (window->IsHidden() || window->IsFloating()
2793 			|| !window->SupportsFront())
2794 			continue;
2795 
2796 		fFront = window;
2797 		break;
2798 	}
2799 
2800 	if (updateFloating)
2801 		_UpdateFloating();
2802 }
2803 
2804 
2805 void
2806 Desktop::_UpdateFronts(bool updateFloating)
2807 {
2808 	_UpdateBack();
2809 	_UpdateFront(updateFloating);
2810 }
2811 
2812 
2813 bool
2814 Desktop::_WindowHasModal(Window* window)
2815 {
2816 	if (window == NULL)
2817 		return false;
2818 
2819 	for (Window* modal = fSubsetWindows.FirstWindow(); modal != NULL;
2820 			modal = modal->NextWindow(kSubsetList)) {
2821 		// only visible modal windows count
2822 		if (!modal->IsModal() || modal->IsHidden())
2823 			continue;
2824 
2825 		if (modal->HasInSubset(window))
2826 			return true;
2827 	}
2828 
2829 	return false;
2830 }
2831 
2832 
2833 /*!	You must at least hold a single window lock when calling this method.
2834 */
2835 void
2836 Desktop::_WindowChanged(Window* window)
2837 {
2838 	ASSERT_MULTI_LOCKED(fWindowLock);
2839 
2840 	BAutolock _(fWorkspacesLock);
2841 
2842 	for (uint32 i = fWorkspacesViews.CountItems(); i-- > 0;) {
2843 		WorkspacesView* view = fWorkspacesViews.ItemAt(i);
2844 		view->WindowChanged(window);
2845 	}
2846 }
2847 
2848 
2849 /*!	You must at least hold a single window lock when calling this method.
2850 */
2851 void
2852 Desktop::_WindowRemoved(Window* window)
2853 {
2854 	ASSERT_MULTI_LOCKED(fWindowLock);
2855 
2856 	BAutolock _(fWorkspacesLock);
2857 
2858 	for (uint32 i = fWorkspacesViews.CountItems(); i-- > 0;) {
2859 		WorkspacesView* view = fWorkspacesViews.ItemAt(i);
2860 		view->WindowRemoved(window);
2861 	}
2862 }
2863 
2864 
2865 /*!	Shows the window on the screen - it does this independently of the
2866 	Window::IsHidden() state.
2867 */
2868 void
2869 Desktop::_ShowWindow(Window* window, bool affectsOtherWindows)
2870 {
2871 	BRegion background;
2872 	_RebuildClippingForAllWindows(background);
2873 	_SetBackground(background);
2874 	_WindowChanged(window);
2875 
2876 	BRegion dirty(window->VisibleRegion());
2877 
2878 	if (!affectsOtherWindows) {
2879 		// everything that is now visible in the
2880 		// window needs a redraw, but other windows
2881 		// are not affected, we can call ProcessDirtyRegion()
2882 		// of the window, and don't have to use MarkDirty()
2883 		window->ProcessDirtyRegion(dirty);
2884 	} else
2885 		MarkDirty(dirty);
2886 
2887 	if (window->ServerWindow()->HasDirectFrameBufferAccess()) {
2888 		window->ServerWindow()->HandleDirectConnection(
2889 			B_DIRECT_START | B_BUFFER_RESET);
2890 	}
2891 }
2892 
2893 
2894 /*!	Hides the window from the screen - it does this independently of the
2895 	Window::IsHidden() state.
2896 */
2897 void
2898 Desktop::_HideWindow(Window* window)
2899 {
2900 	if (window->ServerWindow()->IsDirectlyAccessing())
2901 		window->ServerWindow()->HandleDirectConnection(B_DIRECT_STOP);
2902 
2903 	// after rebuilding the clipping,
2904 	// this window will not have a visible
2905 	// region anymore, so we need to remember
2906 	// it now
2907 	// (actually that's not true, since
2908 	// hidden windows are excluded from the
2909 	// clipping calculation, but anyways)
2910 	BRegion dirty(window->VisibleRegion());
2911 
2912 	BRegion background;
2913 	_RebuildClippingForAllWindows(background);
2914 	_SetBackground(background);
2915 	_WindowChanged(window);
2916 
2917 	MarkDirty(dirty);
2918 }
2919 
2920 
2921 /*!	Updates the workspaces of all subset windows with regard to the
2922 	specifed window.
2923 	If newIndex is not -1, it will move all subset windows that belong to
2924 	the specifed window to the new workspace; this form is only called by
2925 	SetWorkspace().
2926 */
2927 void
2928 Desktop::_UpdateSubsetWorkspaces(Window* window, int32 previousIndex,
2929 	int32 newIndex)
2930 {
2931 	STRACE(("_UpdateSubsetWorkspaces(window %p, %s)\n", window,
2932 		window->Title()));
2933 
2934 	// if the window is hidden, the subset windows are up-to-date already
2935 	if (!window->IsNormal() || window->IsHidden())
2936 		return;
2937 
2938 	for (Window* subset = fSubsetWindows.FirstWindow(); subset != NULL;
2939 			subset = subset->NextWindow(kSubsetList)) {
2940 		if (subset->Feel() == B_MODAL_ALL_WINDOW_FEEL
2941 			|| subset->Feel() == B_FLOATING_ALL_WINDOW_FEEL) {
2942 			// These windows are always visible on all workspaces,
2943 			// no need to update them.
2944 			continue;
2945 		}
2946 
2947 		if (subset->IsFloating()) {
2948 			// Floating windows are inserted and removed to the current
2949 			// workspace as the need arises - they are not handled here
2950 			// but in _UpdateFront()
2951 			continue;
2952 		}
2953 
2954 		if (subset->HasInSubset(window)) {
2955 			// adopt the workspace change
2956 			SetWindowWorkspaces(subset, subset->SubsetWorkspaces());
2957 		}
2958 	}
2959 }
2960 
2961 
2962 /*!	\brief Adds or removes the window to or from the workspaces it's on.
2963 */
2964 void
2965 Desktop::_ChangeWindowWorkspaces(Window* window, uint32 oldWorkspaces,
2966 	uint32 newWorkspaces)
2967 {
2968 	if (oldWorkspaces == newWorkspaces)
2969 		return;
2970 
2971 	// apply changes to the workspaces' window lists
2972 
2973 	LockAllWindows();
2974 
2975 	// NOTE: we bypass the anchor-mechanism by intention when switching
2976 	// the workspace programmatically.
2977 
2978 	for (int32 i = 0; i < kMaxWorkspaces; i++) {
2979 		if (workspace_in_workspaces(i, oldWorkspaces)) {
2980 			// window is on this workspace, is it anymore?
2981 			if (!workspace_in_workspaces(i, newWorkspaces)) {
2982 				_Windows(i).RemoveWindow(window);
2983 				if (fLastWorkspaceFocus[i] == window)
2984 					fLastWorkspaceFocus[i] = NULL;
2985 
2986 				if (i == CurrentWorkspace()) {
2987 					// remove its appearance from the current workspace
2988 					window->SetCurrentWorkspace(-1);
2989 
2990 					if (!window->IsHidden())
2991 						_HideWindow(window);
2992 				}
2993 			}
2994 		} else {
2995 			// window was not on this workspace, is it now?
2996 			if (workspace_in_workspaces(i, newWorkspaces)) {
2997 				_Windows(i).AddWindow(window,
2998 					window->Frontmost(_Windows(i).FirstWindow(), i));
2999 
3000 				if (i == CurrentWorkspace()) {
3001 					// make the window visible in current workspace
3002 					window->SetCurrentWorkspace(fCurrentWorkspace);
3003 
3004 					if (!window->IsHidden()) {
3005 						// This only affects other windows if this window has
3006 						// floating or modal windows that need to be shown as
3007 						// well
3008 						// TODO: take care of this
3009 						_ShowWindow(window, FrontWindow() == window);
3010 					}
3011 				}
3012 			}
3013 		}
3014 	}
3015 
3016 	// If the window is visible only on one workspace, we set it's current
3017 	// position in that workspace (so that WorkspacesView will find us).
3018 	int32 firstWorkspace = -1;
3019 	for (int32 i = 0; i < kMaxWorkspaces; i++) {
3020 		if ((newWorkspaces & (1L << i)) != 0) {
3021 			if (firstWorkspace != -1) {
3022 				firstWorkspace = -1;
3023 				break;
3024 			}
3025 			firstWorkspace = i;
3026 		}
3027 	}
3028 	if (firstWorkspace >= 0)
3029 		window->Anchor(firstWorkspace).position = window->Frame().LeftTop();
3030 
3031 	// take care about modals and floating windows
3032 	_UpdateSubsetWorkspaces(window);
3033 
3034 	NotifyWindowWorkspacesChanged(window, newWorkspaces);
3035 
3036 	UnlockAllWindows();
3037 }
3038 
3039 
3040 void
3041 Desktop::_BringWindowsToFront(WindowList& windows, int32 list,
3042 	bool wereVisible)
3043 {
3044 	// we don't need to redraw what is currently
3045 	// visible of the window
3046 	BRegion clean;
3047 
3048 	for (Window* window = windows.FirstWindow(); window != NULL;
3049 			window = window->NextWindow(list)) {
3050 		if (wereVisible)
3051 			clean.Include(&window->VisibleRegion());
3052 
3053 		CurrentWindows().AddWindow(window,
3054 			window->Frontmost(CurrentWindows().FirstWindow(),
3055 				fCurrentWorkspace));
3056 
3057 		_WindowChanged(window);
3058 	}
3059 
3060 	BRegion dummy;
3061 	_RebuildClippingForAllWindows(dummy);
3062 
3063 	// redraw what became visible of the window(s)
3064 
3065 	BRegion dirty;
3066 	for (Window* window = windows.FirstWindow(); window != NULL;
3067 			window = window->NextWindow(list)) {
3068 		dirty.Include(&window->VisibleRegion());
3069 	}
3070 
3071 	dirty.Exclude(&clean);
3072 	MarkDirty(dirty);
3073 
3074 	_UpdateFront();
3075 
3076 	if (windows.FirstWindow() == fBack || fBack == NULL)
3077 		_UpdateBack();
3078 }
3079 
3080 
3081 /*!	Returns the last focussed non-hidden subset window belonging to the
3082 	specified \a window.
3083 */
3084 Window*
3085 Desktop::_LastFocusSubsetWindow(Window* window)
3086 {
3087 	if (window == NULL)
3088 		return NULL;
3089 
3090 	for (Window* front = fFocusList.LastWindow(); front != NULL;
3091 			front = front->PreviousWindow(kFocusList)) {
3092 		if (front != window && !front->IsHidden()
3093 			&& window->HasInSubset(front))
3094 			return front;
3095 	}
3096 
3097 	return NULL;
3098 }
3099 
3100 
3101 /*!	\brief Sends a fake B_MOUSE_MOVED event to the window under the mouse,
3102 		and also updates the current view under the mouse.
3103 
3104 	This has only to be done in case the view changed without user interaction,
3105 	ie. because of a workspace change or a closing window.
3106 */
3107 void
3108 Desktop::_SendFakeMouseMoved(Window* window)
3109 {
3110 	int32 viewToken = B_NULL_TOKEN;
3111 	EventTarget* target = NULL;
3112 
3113 	LockAllWindows();
3114 
3115 	if (window == NULL)
3116 		window = MouseEventWindow();
3117 	if (window == NULL)
3118 		window = WindowAt(fLastMousePosition);
3119 
3120 	if (window != NULL) {
3121 		BMessage message;
3122 		window->MouseMoved(&message, fLastMousePosition, &viewToken, true,
3123 			true);
3124 
3125 		if (viewToken != B_NULL_TOKEN)
3126 			target = &window->EventTarget();
3127 	}
3128 
3129 	if (viewToken != B_NULL_TOKEN)
3130 		SetViewUnderMouse(window, viewToken);
3131 	else {
3132 		SetViewUnderMouse(NULL, B_NULL_TOKEN);
3133 		SetCursor(NULL);
3134 	}
3135 
3136 	UnlockAllWindows();
3137 
3138 	if (target != NULL)
3139 		EventDispatcher().SendFakeMouseMoved(*target, viewToken);
3140 }
3141 
3142 
3143 Screen*
3144 Desktop::_DetermineScreenFor(BRect frame)
3145 {
3146 	AutoReadLocker _(fScreenLock);
3147 
3148 	// TODO: choose the screen depending on where most of the area is
3149 	return fVirtualScreen.ScreenAt(0);
3150 }
3151 
3152 
3153 void
3154 Desktop::_RebuildClippingForAllWindows(BRegion& stillAvailableOnScreen)
3155 {
3156 	// the available region on screen starts with the entire screen area
3157 	// each window on the screen will take a portion from that area
3158 
3159 	// figure out what the entire screen area is
3160 	stillAvailableOnScreen = fScreenRegion;
3161 
3162 	// set clipping of each window
3163 	for (Window* window = CurrentWindows().LastWindow(); window != NULL;
3164 			window = window->PreviousWindow(fCurrentWorkspace)) {
3165 		if (!window->IsHidden()) {
3166 			window->SetClipping(&stillAvailableOnScreen);
3167 			window->SetScreen(_DetermineScreenFor(window->Frame()));
3168 
3169 			if (window->ServerWindow()->IsDirectlyAccessing()) {
3170 				window->ServerWindow()->HandleDirectConnection(
3171 					B_DIRECT_MODIFY | B_CLIPPING_MODIFIED);
3172 			}
3173 
3174 			// that windows region is not available on screen anymore
3175 			stillAvailableOnScreen.Exclude(&window->VisibleRegion());
3176 		}
3177 	}
3178 }
3179 
3180 
3181 void
3182 Desktop::_TriggerWindowRedrawing(BRegion& newDirtyRegion)
3183 {
3184 	// send redraw messages to all windows intersecting the dirty region
3185 	for (Window* window = CurrentWindows().LastWindow(); window != NULL;
3186 			window = window->PreviousWindow(fCurrentWorkspace)) {
3187 		if (!window->IsHidden()
3188 			&& newDirtyRegion.Intersects(window->VisibleRegion().Frame()))
3189 			window->ProcessDirtyRegion(newDirtyRegion);
3190 	}
3191 }
3192 
3193 
3194 void
3195 Desktop::_SetBackground(BRegion& background)
3196 {
3197 	// NOTE: the drawing operation is caried out
3198 	// in the clipping region rebuild, but it is
3199 	// ok actually, because it also avoids trails on
3200 	// moving windows
3201 
3202 	// remember the region not covered by any windows
3203 	// and redraw the dirty background
3204 	BRegion dirtyBackground(background);
3205 	dirtyBackground.Exclude(&fBackgroundRegion);
3206 	dirtyBackground.IntersectWith(&background);
3207 	fBackgroundRegion = background;
3208 	if (dirtyBackground.Frame().IsValid()) {
3209 		if (GetDrawingEngine()->LockParallelAccess()) {
3210 			GetDrawingEngine()->FillRegion(dirtyBackground,
3211 				fWorkspaces[fCurrentWorkspace].Color());
3212 
3213 			GetDrawingEngine()->UnlockParallelAccess();
3214 		}
3215 	}
3216 }
3217 
3218 
3219 //!	The all window lock must be held when calling this function.
3220 void
3221 Desktop::RebuildAndRedrawAfterWindowChange(Window* changedWindow,
3222 	BRegion& dirty)
3223 {
3224 	ASSERT_MULTI_WRITE_LOCKED(fWindowLock);
3225 	if (!changedWindow->IsVisible() || dirty.CountRects() == 0)
3226 		return;
3227 
3228 	// The following loop is pretty much a copy of
3229 	// _RebuildClippingForAllWindows(), but will also
3230 	// take care about restricting our dirty region.
3231 
3232 	// figure out what the entire screen area is
3233 	BRegion stillAvailableOnScreen(fScreenRegion);
3234 
3235 	// set clipping of each window
3236 	for (Window* window = CurrentWindows().LastWindow(); window != NULL;
3237 			window = window->PreviousWindow(fCurrentWorkspace)) {
3238 		if (!window->IsHidden()) {
3239 			if (window == changedWindow)
3240 				dirty.IntersectWith(&stillAvailableOnScreen);
3241 
3242 			window->SetClipping(&stillAvailableOnScreen);
3243 			window->SetScreen(_DetermineScreenFor(window->Frame()));
3244 
3245 			if (window->ServerWindow()->IsDirectlyAccessing()) {
3246 				window->ServerWindow()->HandleDirectConnection(
3247 					B_DIRECT_MODIFY | B_CLIPPING_MODIFIED);
3248 			}
3249 
3250 			// that windows region is not available on screen anymore
3251 			stillAvailableOnScreen.Exclude(&window->VisibleRegion());
3252 		}
3253 	}
3254 
3255 	_SetBackground(stillAvailableOnScreen);
3256 	_WindowChanged(changedWindow);
3257 
3258 	_TriggerWindowRedrawing(dirty);
3259 }
3260 
3261 
3262 //! Suspend all windows with direct access to the frame buffer
3263 void
3264 Desktop::_SuspendDirectFrameBufferAccess()
3265 {
3266 	ASSERT_MULTI_LOCKED(fWindowLock);
3267 
3268 	for (Window* window = fAllWindows.FirstWindow(); window != NULL;
3269 			window = window->NextWindow(kAllWindowList)) {
3270 		if (window->ServerWindow()->IsDirectlyAccessing())
3271 			window->ServerWindow()->HandleDirectConnection(B_DIRECT_STOP);
3272 	}
3273 }
3274 
3275 
3276 //! Resume all windows with direct access to the frame buffer
3277 void
3278 Desktop::_ResumeDirectFrameBufferAccess()
3279 {
3280 	ASSERT_MULTI_LOCKED(fWindowLock);
3281 
3282 	for (Window* window = fAllWindows.FirstWindow(); window != NULL;
3283 			window = window->NextWindow(kAllWindowList)) {
3284 		if (window->IsHidden() || !window->InWorkspace(fCurrentWorkspace))
3285 			continue;
3286 
3287 		if (window->ServerWindow()->HasDirectFrameBufferAccess()) {
3288 			window->ServerWindow()->HandleDirectConnection(
3289 				B_DIRECT_START | B_BUFFER_RESET, B_MODE_CHANGED);
3290 		}
3291 	}
3292 }
3293 
3294 
3295 void
3296 Desktop::_ScreenChanged(Screen* screen)
3297 {
3298 	ASSERT_MULTI_WRITE_LOCKED(fWindowLock);
3299 
3300 	// the entire screen is dirty, because we're actually
3301 	// operating on an all new buffer in memory
3302 	BRegion dirty(screen->Frame());
3303 
3304 	// update our cached screen region
3305 	fScreenRegion.Set(screen->Frame());
3306 	gInputManager->UpdateScreenBounds(screen->Frame());
3307 
3308 	BRegion background;
3309 	_RebuildClippingForAllWindows(background);
3310 
3311 	fBackgroundRegion.MakeEmpty();
3312 		// makes sure that the complete background is redrawn
3313 	_SetBackground(background);
3314 
3315 	// figure out dirty region
3316 	dirty.Exclude(&background);
3317 	_TriggerWindowRedrawing(dirty);
3318 
3319 	// send B_SCREEN_CHANGED to windows on that screen
3320 	BMessage update(B_SCREEN_CHANGED);
3321 	update.AddInt64("when", real_time_clock_usecs());
3322 	update.AddRect("frame", screen->Frame());
3323 	update.AddInt32("mode", screen->ColorSpace());
3324 
3325 	fVirtualScreen.UpdateFrame();
3326 
3327 	for (Window* window = fAllWindows.FirstWindow(); window != NULL;
3328 			window = window->NextWindow(kAllWindowList)) {
3329 		if (window->Screen() == screen)
3330 			window->ServerWindow()->ScreenChanged(&update);
3331 	}
3332 }
3333 
3334 
3335 /*!	\brief activate one of the app's windows.
3336 */
3337 status_t
3338 Desktop::_ActivateApp(team_id team)
3339 {
3340 	// search for an unhidden window in the current workspace
3341 
3342 	AutoWriteLocker locker(fWindowLock);
3343 
3344 	for (Window* window = CurrentWindows().LastWindow(); window != NULL;
3345 			window = window->PreviousWindow(fCurrentWorkspace)) {
3346 		if (!window->IsHidden() && window->IsNormal()
3347 			&& window->ServerWindow()->ClientTeam() == team) {
3348 			ActivateWindow(window);
3349 			return B_OK;
3350 		}
3351 	}
3352 
3353 	// search for an unhidden window to give focus to
3354 
3355 	for (Window* window = fAllWindows.FirstWindow(); window != NULL;
3356 			window = window->NextWindow(kAllWindowList)) {
3357 		// if window is a normal window of the team, and not hidden,
3358 		// we've found our target
3359 		if (!window->IsHidden() && window->IsNormal()
3360 			&& window->ServerWindow()->ClientTeam() == team) {
3361 			ActivateWindow(window);
3362 			return B_OK;
3363 		}
3364 	}
3365 
3366 	// TODO: we cannot maximize minimized windows here (with the window lock
3367 	// write locked). To work-around this, we could forward the request to
3368 	// the ServerApp of this team - it maintains its own window list, and can
3369 	// therefore call ActivateWindow() without holding the window lock.
3370 	return B_BAD_VALUE;
3371 }
3372 
3373 
3374 void
3375 Desktop::_SetCurrentWorkspaceConfiguration()
3376 {
3377 	ASSERT_MULTI_WRITE_LOCKED(fWindowLock);
3378 
3379 	status_t status = fDirectScreenLock.LockWithTimeout(1000000L);
3380 	if (status != B_OK) {
3381 		// The application having the direct screen lock didn't give it up in
3382 		// time, make it crash
3383 		syslog(LOG_ERR, "Team %" B_PRId32 " did not give up its direct screen "
3384 			"lock.\n", fDirectScreenTeam);
3385 
3386 		debug_thread(fDirectScreenTeam);
3387 		fDirectScreenTeam = -1;
3388 	} else
3389 		fDirectScreenLock.Unlock();
3390 
3391 	AutoWriteLocker _(fScreenLock);
3392 
3393 	uint32 changedScreens;
3394 	fVirtualScreen.SetConfiguration(*this,
3395 		fWorkspaces[fCurrentWorkspace].CurrentScreenConfiguration(),
3396 		&changedScreens);
3397 
3398 	for (int32 i = 0; changedScreens != 0; i++, changedScreens /= 2) {
3399 		if ((changedScreens & (1 << i)) != 0)
3400 			_ScreenChanged(fVirtualScreen.ScreenAt(i));
3401 	}
3402 }
3403 
3404 
3405 /*!	Changes the current workspace to the one specified by \a index.
3406 	You must hold the all window lock when calling this method.
3407 */
3408 void
3409 Desktop::_SetWorkspace(int32 index, bool moveFocusWindow)
3410 {
3411 	ASSERT_MULTI_WRITE_LOCKED(fWindowLock);
3412 
3413 	int32 previousIndex = fCurrentWorkspace;
3414 	rgb_color previousColor = fWorkspaces[fCurrentWorkspace].Color();
3415 	bool movedMouseEventWindow = false;
3416 	Window* movedWindow = NULL;
3417 	if (moveFocusWindow) {
3418 		if (fMouseEventWindow != NULL)
3419 			movedWindow = fMouseEventWindow;
3420 		else
3421 			movedWindow = FocusWindow();
3422 	}
3423 
3424 	if (movedWindow != NULL) {
3425 		if (movedWindow->IsNormal()) {
3426 			if (!movedWindow->InWorkspace(index)) {
3427 				// The window currently being dragged will follow us to this
3428 				// workspace if it's not already on it.
3429 				// But only normal windows are following
3430 				uint32 oldWorkspaces = movedWindow->Workspaces();
3431 
3432 				WindowStack* stack = movedWindow->GetWindowStack();
3433 				if (stack != NULL) {
3434 					for (int32 s = 0; s < stack->CountWindows(); s++) {
3435 						Window* stackWindow = stack->LayerOrder().ItemAt(s);
3436 
3437 						_Windows(previousIndex).RemoveWindow(stackWindow);
3438 						_Windows(index).AddWindow(stackWindow,
3439 							stackWindow->Frontmost(
3440 								_Windows(index).FirstWindow(), index));
3441 
3442 						// send B_WORKSPACES_CHANGED message
3443 						stackWindow->WorkspacesChanged(oldWorkspaces,
3444 							stackWindow->Workspaces());
3445 					}
3446 				}
3447 				// TODO: subset windows will always flicker this way
3448 
3449 				movedMouseEventWindow = true;
3450 
3451 				NotifyWindowWorkspacesChanged(movedWindow,
3452 					movedWindow->Workspaces());
3453 			} else {
3454 				// make sure it's frontmost
3455 				_Windows(index).RemoveWindow(movedWindow);
3456 				_Windows(index).AddWindow(movedWindow,
3457 					movedWindow->Frontmost(_Windows(index).FirstWindow(),
3458 					index));
3459 			}
3460 		}
3461 
3462 		movedWindow->Anchor(index).position = movedWindow->Frame().LeftTop();
3463 	}
3464 
3465 	if (movedWindow == NULL || movedWindow->InWorkspace(previousIndex))
3466 		fLastWorkspaceFocus[previousIndex] = FocusWindow();
3467 	else
3468 		fLastWorkspaceFocus[previousIndex] = NULL;
3469 
3470 	// build region of windows that are no longer visible in the new workspace
3471 
3472 	BRegion dirty;
3473 
3474 	for (Window* window = CurrentWindows().FirstWindow();
3475 			window != NULL; window = window->NextWindow(previousIndex)) {
3476 		// store current position in Workspace anchor
3477 		window->Anchor(previousIndex).position = window->Frame().LeftTop();
3478 
3479 		if (!window->IsHidden()
3480 			&& window->ServerWindow()->IsDirectlyAccessing())
3481 			window->ServerWindow()->HandleDirectConnection(B_DIRECT_STOP);
3482 
3483 		window->WorkspaceActivated(previousIndex, false);
3484 
3485 		if (window->InWorkspace(index))
3486 			continue;
3487 
3488 		if (!window->IsHidden()) {
3489 			// this window will no longer be visible
3490 			dirty.Include(&window->VisibleRegion());
3491 		}
3492 
3493 		window->SetCurrentWorkspace(-1);
3494 	}
3495 
3496 	fPreviousWorkspace = fCurrentWorkspace;
3497 	fCurrentWorkspace = index;
3498 
3499 	// Change the display modes, if needed
3500 	_SetCurrentWorkspaceConfiguration();
3501 
3502 	// Show windows, and include them in the changed region - but only
3503 	// those that were not visible before (or whose position changed)
3504 
3505 	WindowList windows(kWorkingList);
3506 	BList previousRegions;
3507 
3508 	for (Window* window = _Windows(index).FirstWindow();
3509 			window != NULL; window = window->NextWindow(index)) {
3510 		BPoint position = window->Anchor(index).position;
3511 
3512 		window->SetCurrentWorkspace(index);
3513 
3514 		if (window->IsHidden())
3515 			continue;
3516 
3517 		if (position == kInvalidWindowPosition) {
3518 			// if you enter a workspace for the first time, the position
3519 			// of the window in the previous workspace is adopted
3520 			position = window->Frame().LeftTop();
3521 				// TODO: make sure the window is still on-screen if it
3522 				//	was before!
3523 		}
3524 
3525 		if (!window->InWorkspace(previousIndex)) {
3526 			// This window was not visible before, make sure its frame
3527 			// is up-to-date
3528 			if (window->Frame().LeftTop() != position) {
3529 				BPoint offset = position - window->Frame().LeftTop();
3530 				window->MoveBy((int32)offset.x, (int32)offset.y);
3531 			}
3532 			continue;
3533 		}
3534 
3535 		if (window->Frame().LeftTop() != position) {
3536 			// the window was visible before, but its on-screen location changed
3537 			BPoint offset = position - window->Frame().LeftTop();
3538 			MoveWindowBy(window, offset.x, offset.y);
3539 				// TODO: be a bit smarter than this...
3540 		} else {
3541 			// We need to remember the previous visible region of the
3542 			// window if they changed their order
3543 			BRegion* region = new (std::nothrow)
3544 				BRegion(window->VisibleRegion());
3545 			if (region != NULL) {
3546 				if (previousRegions.AddItem(region))
3547 					windows.AddWindow(window);
3548 				else
3549 					delete region;
3550 			}
3551 		}
3552 	}
3553 
3554 	_UpdateFronts(false);
3555 	_UpdateFloating(previousIndex, index,
3556 		movedMouseEventWindow ? movedWindow : NULL);
3557 
3558 	BRegion stillAvailableOnScreen;
3559 	_RebuildClippingForAllWindows(stillAvailableOnScreen);
3560 	_SetBackground(stillAvailableOnScreen);
3561 
3562 	for (Window* window = _Windows(index).FirstWindow(); window != NULL;
3563 			window = window->NextWindow(index)) {
3564 		// send B_WORKSPACE_ACTIVATED message
3565 		window->WorkspaceActivated(index, true);
3566 
3567 		if (!window->IsHidden()
3568 			&& window->ServerWindow()->HasDirectFrameBufferAccess()) {
3569 			window->ServerWindow()->HandleDirectConnection(
3570 				B_DIRECT_START | B_BUFFER_RESET, B_MODE_CHANGED);
3571 		}
3572 
3573 		if (window->InWorkspace(previousIndex) || window->IsHidden()
3574 			|| (window == movedWindow && movedWindow->IsNormal())
3575 			|| (!window->IsNormal()
3576 				&& window->HasInSubset(movedWindow))) {
3577 			// This window was visible before, and is already handled in the
3578 			// above loop
3579 			continue;
3580 		}
3581 
3582 		dirty.Include(&window->VisibleRegion());
3583 	}
3584 
3585 	// Catch order changes in the new workspaces window list
3586 	int32 i = 0;
3587 	for (Window* window = windows.FirstWindow(); window != NULL;
3588 			window = window->NextWindow(kWorkingList), i++) {
3589 		BRegion* region = (BRegion*)previousRegions.ItemAt(i);
3590 		region->ExclusiveInclude(&window->VisibleRegion());
3591 		dirty.Include(region);
3592 		delete region;
3593 	}
3594 
3595 	// Set new focus, but keep focus to a floating window if still visible
3596 	if (movedWindow != NULL)
3597 		SetFocusWindow(movedWindow);
3598 	else if (!_Windows(index).HasWindow(FocusWindow())
3599 		|| (FocusWindow() != NULL && !FocusWindow()->IsFloating()))
3600 		SetFocusWindow(fLastWorkspaceFocus[index]);
3601 
3602 	_WindowChanged(NULL);
3603 	MarkDirty(dirty);
3604 
3605 #if 0
3606 	// Show the dirty regions of this workspace switch
3607 	if (GetDrawingEngine()->LockParallelAccess()) {
3608 		GetDrawingEngine()->FillRegion(dirty, (rgb_color){255, 0, 0});
3609 		GetDrawingEngine()->UnlockParallelAccess();
3610 		snooze(100000);
3611 	}
3612 #endif
3613 
3614 	if (previousColor != fWorkspaces[fCurrentWorkspace].Color())
3615 		RedrawBackground();
3616 }
3617