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