xref: /haiku/src/servers/app/ServerWindow.cpp (revision 2f470aec1c92ce6917b8a903e343795dc77af41f)
1 /*
2  * Copyright 2001-2007, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		DarkWyrm <bpmagic@columbus.rr.com>
7  *		Adrian Oanca <adioanca@gmail.com>
8  *		Stephan Aßmus <superstippi@gmx.de>
9  *		Stefano Ceccherini (burton666@libero.it)
10  *		Axel Dörfler, axeld@pinc-software.de
11  */
12 
13 /*!
14 	\class ServerWindow
15 	\brief Shadow BWindow class
16 
17 	A ServerWindow handles all the intraserver tasks required of it by its BWindow. There are
18 	too many tasks to list as being done by them, but they include handling View transactions,
19 	coordinating and linking a window's WindowLayer half with its messaging half, dispatching
20 	mouse and key events from the server to its window, and other such things.
21 */
22 
23 
24 #include "ServerWindow.h"
25 
26 #include "AppServer.h"
27 #include "DebugInfoManager.h"
28 #include "Desktop.h"
29 #include "DrawingEngine.h"
30 #include "HWInterface.h"
31 #include "Overlay.h"
32 #include "RAMLinkMsgReader.h"
33 #include "RenderingBuffer.h"
34 #include "ServerApp.h"
35 #include "ServerBitmap.h"
36 #include "ServerPicture.h"
37 #include "ServerProtocol.h"
38 #include "WindowLayer.h"
39 #include "WorkspacesLayer.h"
40 
41 #include "clipping.h"
42 
43 #include <DirectWindowPrivate.h>
44 #include <MessagePrivate.h>
45 #include <PortLink.h>
46 #include <WindowInfo.h>
47 #include <WindowPrivate.h>
48 
49 #include <AppDefs.h>
50 #include <Autolock.h>
51 #include <DirectWindow.h>
52 #include <TokenSpace.h>
53 #include <View.h>
54 
55 #include <new>
56 
57 using std::nothrow;
58 
59 //#define TRACE_SERVER_WINDOW
60 //#define TRACE_SERVER_WINDOW_MESSAGES
61 //#define PROFILE_MESSAGE_LOOP
62 
63 
64 #ifdef TRACE_SERVER_WINDOW
65 #	include <stdio.h>
66 #	define STRACE(x) printf x
67 #else
68 #	define STRACE(x) ;
69 #endif
70 
71 #ifdef TRACE_SERVER_WINDOW_MESSAGES
72 #	include <stdio.h>
73 #	define DTRACE(x) printf x
74 #else
75 #	define DTRACE(x) ;
76 #endif
77 
78 #ifdef PROFILE_MESSAGE_LOOP
79 static struct profile { int32 count; bigtime_t time; } sMessageProfile[AS_LAST_CODE];
80 #endif
81 
82 
83 struct direct_window_data {
84 	direct_window_data();
85 	~direct_window_data();
86 
87 	status_t InitCheck() const;
88 
89 	sem_id	sem;
90 	sem_id	sem_ack;
91 	area_id	area;
92 	bool	started;
93 	direct_buffer_info *buffer_info;
94 };
95 
96 
97 direct_window_data::direct_window_data()
98 	:
99 	sem(-1),
100 	sem_ack(-1),
101 	area(-1),
102 	started(false),
103 	buffer_info(NULL)
104 {
105 	area = create_area("direct area", (void **)&buffer_info,
106 		B_ANY_ADDRESS, B_PAGE_SIZE, B_NO_LOCK, B_READ_WRITE);
107 
108 	sem = create_sem(0, "direct sem");
109 	sem_ack = create_sem(0, "direct sem ack");
110 }
111 
112 
113 direct_window_data::~direct_window_data()
114 {
115 	// this should make the client die in case it's still running
116 	buffer_info->bits = NULL;
117 	buffer_info->bytes_per_row = 0;
118 
119 	delete_area(area);
120 	delete_sem(sem);
121 	delete_sem(sem_ack);
122 }
123 
124 
125 status_t
126 direct_window_data::InitCheck() const
127 {
128 	if (area < B_OK)
129 		return area;
130 	if (sem < B_OK)
131 		return sem;
132 	if (sem_ack < B_OK)
133 		return sem_ack;
134 
135 	return B_OK;
136 }
137 
138 
139 //	#pragma mark -
140 
141 
142 /*!
143 	Sets up the basic BWindow counterpart - you have to call Init() before
144 	you can actually use it, though.
145 */
146 ServerWindow::ServerWindow(const char *title, ServerApp *app,
147 	port_id clientPort, port_id looperPort, int32 clientToken)
148 	: MessageLooper(title && *title ? title : "Unnamed Window"),
149 	fTitle(NULL),
150 	fDesktop(app->GetDesktop()),
151 	fServerApp(app),
152 	fWindowLayer(NULL),
153 	fWindowAddedToDesktop(false),
154 
155 	fClientTeam(app->ClientTeam()),
156 
157 	fMessagePort(-1),
158 	fClientReplyPort(clientPort),
159 	fClientLooperPort(looperPort),
160 
161 	fClientToken(clientToken),
162 
163 	fCurrentLayer(NULL),
164 	fCurrentDrawingRegion(),
165 	fCurrentDrawingRegionValid(false),
166 
167 	fDirectWindowData(NULL)
168 {
169 	STRACE(("ServerWindow(%s)::ServerWindow()\n", title));
170 
171 	SetTitle(title);
172 	fServerToken = BPrivate::gDefaultTokens.NewToken(B_SERVER_TOKEN, this);
173 
174 	BMessenger::Private(fFocusMessenger).SetTo(fClientTeam,
175 		looperPort, B_PREFERRED_TOKEN);
176 	BMessenger::Private(fHandlerMessenger).SetTo(fClientTeam,
177 		looperPort, clientToken);
178 
179 	fEventTarget.SetTo(fFocusMessenger);
180 
181 	fDeathSemaphore = create_sem(0, "window death");
182 }
183 
184 
185 //! Tears down all connections the main app_server objects, and deletes some internals.
186 ServerWindow::~ServerWindow()
187 {
188 	STRACE(("ServerWindow(%s@%p):~ServerWindow()\n", fTitle, this));
189 
190 	if (!fWindowLayer->IsOffscreenWindow()) {
191 		fWindowAddedToDesktop = false;
192 		fDesktop->RemoveWindow(fWindowLayer);
193 	}
194 
195 	if (App() != NULL)
196 		App()->RemoveWindow(this);
197 
198 	delete fWindowLayer;
199 
200 	free(fTitle);
201 	delete_port(fMessagePort);
202 
203 	BPrivate::gDefaultTokens.RemoveToken(fServerToken);
204 
205 	delete fDirectWindowData;
206 	STRACE(("ServerWindow(%p) will exit NOW\n", this));
207 
208 	delete_sem(fDeathSemaphore);
209 
210 #ifdef PROFILE_MESSAGE_LOOP
211 	for (int32 i = 0; i < AS_LAST_CODE; i++) {
212 		if (sMessageProfile[i].count == 0)
213 			continue;
214 		printf("[%ld] called %ld times, %g secs (%Ld usecs per call)\n",
215 			i, sMessageProfile[i].count, sMessageProfile[i].time / 1000000.0,
216 			sMessageProfile[i].time / sMessageProfile[i].count);
217 	}
218 #endif
219 }
220 
221 
222 status_t
223 ServerWindow::Init(BRect frame, window_look look, window_feel feel,
224 	uint32 flags, uint32 workspace)
225 {
226 	if (!App()->AddWindow(this)) {
227 		fServerApp = NULL;
228 		return B_NO_MEMORY;
229 	}
230 
231 	if (fTitle == NULL)
232 		return B_NO_MEMORY;
233 
234 	// fMessagePort is the port to which the app sends messages for the server
235 	fMessagePort = create_port(100, fTitle);
236 	if (fMessagePort < B_OK)
237 		return fMessagePort;
238 
239 	fLink.SetSenderPort(fClientReplyPort);
240 	fLink.SetReceiverPort(fMessagePort);
241 
242 	// We cannot call MakeWindowLayer in the constructor, since it
243 	// is a virtual function!
244 	fWindowLayer = MakeWindowLayer(frame, fTitle, look, feel, flags, workspace);
245 	if (!fWindowLayer)
246 		return B_NO_MEMORY;
247 
248 	if (!fWindowLayer->IsOffscreenWindow()) {
249 		fDesktop->AddWindow(fWindowLayer);
250 		fWindowAddedToDesktop = true;
251 	}
252 
253 	return B_OK;
254 }
255 
256 
257 bool
258 ServerWindow::Run()
259 {
260 	if (!MessageLooper::Run())
261 		return false;
262 
263 	// Send a reply to our window - it is expecting fMessagePort
264 	// port and some other info
265 
266 	fLink.StartMessage(B_OK);
267 	fLink.Attach<port_id>(fMessagePort);
268 
269 	int32 minWidth, maxWidth, minHeight, maxHeight;
270 	fWindowLayer->GetSizeLimits(&minWidth, &maxWidth, &minHeight, &maxHeight);
271 
272 	fLink.Attach<BRect>(fWindowLayer->Frame());
273 	fLink.Attach<float>((float)minWidth);
274 	fLink.Attach<float>((float)maxWidth);
275 	fLink.Attach<float>((float)minHeight);
276 	fLink.Attach<float>((float)maxHeight);
277 	fLink.Flush();
278 
279 	return true;
280 }
281 
282 
283 void
284 ServerWindow::_PrepareQuit()
285 {
286 	if (fThread == find_thread(NULL)) {
287 		// make sure we're hidden
288 		fDesktop->LockSingleWindow();
289 		_Hide();
290 		fDesktop->UnlockSingleWindow();
291 	} else if (fThread >= B_OK)
292 		PostMessage(AS_HIDE_WINDOW);
293 }
294 
295 
296 void
297 ServerWindow::_GetLooperName(char* name, size_t length)
298 {
299 	const char *title = Title();
300 	if (title == NULL || !title[0])
301 		title = "Unnamed Window";
302 
303 	snprintf(name, length, "w:%ld:%s", ClientTeam(), title);
304 }
305 
306 
307 //! Forces the window layer to update its decorator
308 void
309 ServerWindow::ReplaceDecorator()
310 {
311 	if (!IsLocked())
312 		debugger("you must lock a ServerWindow object before calling ::ReplaceDecorator()\n");
313 
314 	STRACE(("ServerWindow %s: Replace Decorator\n", fTitle));
315 	//fWindowLayer->UpdateDecorator();
316 }
317 
318 
319 //! Shows the window's WindowLayer
320 void
321 ServerWindow::_Show()
322 {
323 	// NOTE: if you do something else, other than sending a port message, PLEASE lock
324 	STRACE(("ServerWindow %s: _Show\n", Title()));
325 
326 	if (fQuitting || !fWindowLayer->IsHidden() || fWindowLayer->IsOffscreenWindow())
327 		return;
328 
329 // TODO: race condition? maybe we need to dispatch a message to the desktop to show/hide us
330 // instead of doing it from this thread.
331 fDesktop->UnlockSingleWindow();
332 	fDesktop->ShowWindow(fWindowLayer);
333 fDesktop->LockSingleWindow();
334 
335 	if (fDirectWindowData != NULL)
336 		HandleDirectConnection(B_DIRECT_START | B_BUFFER_RESET);
337 }
338 
339 
340 //! Hides the window's WindowLayer
341 void
342 ServerWindow::_Hide()
343 {
344 	// NOTE: if you do something else, other than sending a port message, PLEASE lock
345 	STRACE(("ServerWindow %s: _Hide\n", Title()));
346 
347 	if (fWindowLayer->IsHidden() || fWindowLayer->IsOffscreenWindow())
348 		return;
349 
350 	if (fDirectWindowData != NULL)
351 		HandleDirectConnection(B_DIRECT_STOP);
352 
353 // TODO: race condition? maybe we need to dispatch a message to the desktop to show/hide us
354 // instead of doing it from this thread.
355 fDesktop->UnlockSingleWindow();
356 	fDesktop->HideWindow(fWindowLayer);
357 fDesktop->LockSingleWindow();
358 }
359 
360 
361 void
362 ServerWindow::RequestRedraw()
363 {
364 	PostMessage(AS_REDRAW, 0);
365 		// we don't care if this fails - it's only a notification, and if
366 		// it fails, there are obviously enough messages in the queue
367 		// already
368 
369 	atomic_add(&fRedrawRequested, 1);
370 }
371 
372 
373 void
374 ServerWindow::SetTitle(const char* newTitle)
375 {
376 	char* oldTitle = fTitle;
377 
378 	if (newTitle == NULL)
379 		newTitle = "";
380 
381 	fTitle = strdup(newTitle);
382 	if (fTitle == NULL) {
383 		// out of memory condition
384 		fTitle = oldTitle;
385 		return;
386 	}
387 
388 	free(oldTitle);
389 
390 	if (Thread() >= B_OK) {
391 		char name[B_OS_NAME_LENGTH];
392 		_GetLooperName(name, sizeof(name));
393 		rename_thread(Thread(), name);
394 	}
395 
396 	if (fWindowLayer != NULL) {
397 fDesktop->UnlockSingleWindow();
398 		fDesktop->SetWindowTitle(fWindowLayer, newTitle);
399 fDesktop->LockSingleWindow();
400 	}
401 }
402 
403 
404 //! Requests that the ServerWindow's BWindow quit
405 void
406 ServerWindow::NotifyQuitRequested()
407 {
408 	// NOTE: if you do something else, other than sending a port message, PLEASE lock
409 	STRACE(("ServerWindow %s: Quit\n", fTitle));
410 
411 	BMessage msg(B_QUIT_REQUESTED);
412 	SendMessageToClient(&msg);
413 }
414 
415 
416 void
417 ServerWindow::NotifyMinimize(bool minimize)
418 {
419 	if (fWindowLayer->Feel() != B_NORMAL_WINDOW_FEEL)
420 		return;
421 
422 	// The client is responsible for the actual minimization
423 
424 	BMessage msg(B_MINIMIZE);
425 	msg.AddInt64("when", real_time_clock_usecs());
426 	msg.AddBool("minimize", minimize);
427 
428 	SendMessageToClient(&msg);
429 }
430 
431 
432 //! Sends a message to the client to perform a Zoom
433 void
434 ServerWindow::NotifyZoom()
435 {
436 	// NOTE: if you do something else, other than sending a port message, PLEASE lock
437 	BMessage msg(B_ZOOM);
438 	SendMessageToClient(&msg);
439 }
440 
441 
442 void
443 ServerWindow::GetInfo(window_info& info)
444 {
445 	info.team = ClientTeam();
446 	info.server_token = ServerToken();
447 
448 	info.thread = Thread();
449 	info.client_token = ClientToken();
450 	info.client_port = fClientLooperPort;
451 	info.workspaces = fWindowLayer->Workspaces();
452 
453 	info.layer = 0; // ToDo: what is this???
454 	info.feel = fWindowLayer->Feel();
455 	info.flags = fWindowLayer->Flags();
456 	info.window_left = (int)floor(fWindowLayer->Frame().left);
457 	info.window_top = (int)floor(fWindowLayer->Frame().top);
458 	info.window_right = (int)floor(fWindowLayer->Frame().right);
459 	info.window_bottom = (int)floor(fWindowLayer->Frame().bottom);
460 
461 	info.show_hide_level = fWindowLayer->IsHidden() ? 1 : 0; // ???
462 	info.is_mini = fWindowLayer->IsMinimized();
463 }
464 
465 
466 /*!
467 	Returns the ServerWindow's WindowLayer, if it exists and has been
468 	added to the Desktop already.
469 	In other words, you cannot assume this method will always give you
470 	a valid pointer.
471 */
472 WindowLayer*
473 ServerWindow::Window() const
474 {
475 	// TODO: ensure desktop is locked!
476 	if (!fWindowAddedToDesktop)
477 		return NULL;
478 
479 	return fWindowLayer;
480 }
481 
482 
483 ViewLayer*
484 ServerWindow::_CreateLayerTree(BPrivate::LinkReceiver &link, ViewLayer **_parent)
485 {
486 	// NOTE: no need to check for a lock. This is a private method.
487 
488 	int32 token;
489 	BRect frame;
490 	uint32 resizeMask;
491 	uint32 eventMask;
492 	uint32 eventOptions;
493 	uint32 flags;
494 	bool hidden;
495 	int32 parentToken;
496 	char* name = NULL;
497 	rgb_color viewColor;
498 	BPoint scrollingOffset;
499 
500 	link.Read<int32>(&token);
501 	link.ReadString(&name);
502 	link.Read<BRect>(&frame);
503 	link.Read<BPoint>(&scrollingOffset);
504 	link.Read<uint32>(&resizeMask);
505 	link.Read<uint32>(&eventMask);
506 	link.Read<uint32>(&eventOptions);
507 	link.Read<uint32>(&flags);
508 	link.Read<bool>(&hidden);
509 	link.Read<rgb_color>(&viewColor);
510 	link.Read<int32>(&parentToken);
511 
512 	STRACE(("ServerWindow(%s)::_CreateLayerTree()-> layer %s, token %ld\n",
513 		fTitle, name, token));
514 
515 	ViewLayer* newLayer;
516 
517 	if (link.Code() == AS_LAYER_CREATE_ROOT
518 		&& (fWindowLayer->Flags() & kWorkspacesWindowFlag) != 0) {
519 		// this is a workspaces window!
520 		newLayer = new (nothrow) WorkspacesLayer(frame, scrollingOffset, name,
521 			token, resizeMask, flags);
522 	} else {
523 		newLayer = new (nothrow) ViewLayer(frame, scrollingOffset, name, token,
524 			resizeMask, flags);
525 	}
526 
527 	free(name);
528 
529 	if (newLayer == NULL)
530 		return NULL;
531 
532 	// there is no way of setting this, other than manually :-)
533 	newLayer->SetViewColor(viewColor);
534 	newLayer->SetHidden(hidden);
535 	newLayer->SetEventMask(eventMask, eventOptions);
536 
537 	if (eventMask != 0 || eventOptions != 0) {
538 		fDesktop->UnlockSingleWindow();
539 		fDesktop->EventDispatcher().AddListener(EventTarget(),
540 			newLayer->Token(), eventMask, eventOptions);
541 		fDesktop->LockSingleWindow();
542 	}
543 
544 	DesktopSettings settings(fDesktop);
545 	ServerFont font;
546 	settings.GetDefaultPlainFont(font);
547 	newLayer->CurrentState()->SetFont(font);
548 
549 	if (_parent) {
550 		ViewLayer *parent;
551 		if (App()->ViewTokens().GetToken(parentToken, B_HANDLER_TOKEN,
552 				(void**)&parent) != B_OK
553 			|| parent->Window()->ServerWindow() != this) {
554 			CRITICAL("View token not found!\n");
555 			parent = NULL;
556 		}
557 
558 		*_parent = parent;
559 	}
560 
561 	return newLayer;
562 }
563 
564 
565 /*!
566 	Dispatches all window messages, and those view messages that
567 	don't need a valid fCurrentLayer (ie. layer creation).
568 */
569 void
570 ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
571 {
572 	switch (code) {
573 		case AS_SHOW_WINDOW:
574 			STRACE(("ServerWindow %s: Message AS_SHOW_WINDOW\n", Title()));
575 			_Show();
576 			break;
577 
578 		case AS_HIDE_WINDOW:
579 			STRACE(("ServerWindow %s: Message AS_HIDE_WINDOW\n", Title()));
580 			_Hide();
581 			break;
582 
583 		case AS_MINIMIZE_WINDOW:
584 		{
585 			DTRACE(("ServerWindow %s: Message AS_MINIMIZE_WINDOW\n", Title()));
586 			int32 showLevel;
587 			bool minimize;
588 
589 			link.Read<bool>(&minimize);
590 			if (link.Read<int32>(&showLevel) == B_OK) {
591 				if (showLevel <= 0) {
592 					// window is currently hidden - ignore the minimize request
593 					break;
594 				}
595 
596 				if (minimize && !fWindowLayer->IsHidden())
597 					_Hide();
598 				else if (!minimize && fWindowLayer->IsHidden())
599 					_Show();
600 
601 				fWindowLayer->SetMinimized(minimize);
602 			}
603 			break;
604 		}
605 
606 		case AS_ACTIVATE_WINDOW:
607 		{
608 			DTRACE(("ServerWindow %s: Message AS_ACTIVATE_WINDOW: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
609 			bool activate = true;
610 
611 			link.Read<bool>(&activate);
612 
613 fDesktop->UnlockSingleWindow();
614 			if (activate)
615 				fDesktop->ActivateWindow(fWindowLayer);
616 			else
617 				fDesktop->SendWindowBehind(fWindowLayer, NULL);
618 fDesktop->LockSingleWindow();
619 			break;
620 		}
621 		case AS_SEND_BEHIND:
622 		{
623 			STRACE(("ServerWindow %s: Message AS_SEND_BEHIND\n", Title()));
624 			int32 token;
625 			team_id teamID;
626 			status_t status;
627 
628 			link.Read<int32>(&token);
629 			link.Read<team_id>(&teamID);
630 
631 			WindowLayer *behindOf;
632 			if ((behindOf = fDesktop->FindWindowLayerByClientToken(token, teamID)) != NULL) {
633 fDesktop->UnlockSingleWindow();
634 // TODO: there is a big race condition when we unlock here (window could be gone by now)!
635 				fDesktop->SendWindowBehind(fWindowLayer, behindOf);
636 fDesktop->LockSingleWindow();
637 				status = B_OK;
638 			} else
639 				status = B_NAME_NOT_FOUND;
640 
641 			fLink.StartMessage(status);
642 			fLink.Flush();
643 			break;
644 		}
645 
646 		case B_QUIT_REQUESTED:
647 			STRACE(("ServerWindow %s received quit request\n", Title()));
648 			NotifyQuitRequested();
649 			break;
650 
651 		case AS_ENABLE_UPDATES:
652 		{
653 			STRACE(("ServerWindow %s: Message AS_ENABLE_UPDATES unimplemented\n",
654 				Title()));
655 // TODO: AS_ENABLE_UPDATES
656 			//fWindowLayer->EnableUpdateRequests();
657 			break;
658 		}
659 		case AS_DISABLE_UPDATES:
660 		{
661 			STRACE(("ServerWindow %s: Message AS_DISABLE_UPDATES unimplemented\n",
662 				Title()));
663 // TODO: AS_DISABLE_UPDATES
664 			//fWindowLayer->DisableUpdateRequests();
665 			break;
666 		}
667 		case AS_NEEDS_UPDATE:
668 		{
669 			STRACE(("ServerWindow %s: Message AS_NEEDS_UPDATE\n", Title()));
670 			if (fWindowLayer->NeedsUpdate())
671 				fLink.StartMessage(B_OK);
672 			else
673 				fLink.StartMessage(B_ERROR);
674 			fLink.Flush();
675 			break;
676 		}
677 		case AS_SET_WINDOW_TITLE:
678 		{
679 			char* newTitle;
680 			if (link.ReadString(&newTitle) == B_OK) {
681 				SetTitle(newTitle);
682 				free(newTitle);
683 			}
684 			break;
685 		}
686 
687 		case AS_ADD_TO_SUBSET:
688 		{
689 			STRACE(("ServerWindow %s: Message AS_ADD_TO_SUBSET\n", Title()));
690 			status_t status = B_ERROR;
691 
692 			int32 token;
693 			if (link.Read<int32>(&token) == B_OK) {
694 				WindowLayer* windowLayer = fDesktop->FindWindowLayerByClientToken(
695 					token, App()->ClientTeam());
696 				if (windowLayer == NULL
697 					|| windowLayer->Feel() != B_NORMAL_WINDOW_FEEL) {
698 					status = B_BAD_VALUE;
699 				} else {
700 fDesktop->UnlockSingleWindow();
701 // TODO: there is a big race condition when we unlock here (window could be gone by now)!
702 					status = fDesktop->AddWindowToSubset(fWindowLayer, windowLayer)
703 						? B_OK : B_NO_MEMORY;
704 fDesktop->LockSingleWindow();
705 				}
706 			}
707 
708 			fLink.StartMessage(status);
709 			fLink.Flush();
710 			break;
711 		}
712 		case AS_REMOVE_FROM_SUBSET:
713 		{
714 			STRACE(("ServerWindow %s: Message AS_REM_FROM_SUBSET\n", Title()));
715 			status_t status = B_ERROR;
716 
717 			int32 token;
718 			if (link.Read<int32>(&token) == B_OK) {
719 				WindowLayer* windowLayer = fDesktop->FindWindowLayerByClientToken(
720 					token, App()->ClientTeam());
721 				if (windowLayer != NULL) {
722 fDesktop->UnlockSingleWindow();
723 // TODO: there is a big race condition when we unlock here (window could be gone by now)!
724 					fDesktop->RemoveWindowFromSubset(fWindowLayer, windowLayer);
725 fDesktop->LockSingleWindow();
726 					status = B_OK;
727 				} else
728 					status = B_BAD_VALUE;
729 			}
730 
731 			fLink.StartMessage(status);
732 			fLink.Flush();
733 			break;
734 		}
735 
736 		case AS_SET_LOOK:
737 		{
738 			STRACE(("ServerWindow %s: Message AS_SET_LOOK\n", Title()));
739 
740 			status_t status = B_ERROR;
741 			int32 look;
742 			if (link.Read<int32>(&look) == B_OK) {
743 				// test if look is valid
744 				status = WindowLayer::IsValidLook((window_look)look)
745 					? B_OK : B_BAD_VALUE;
746 			}
747 
748 			if (status == B_OK && !fWindowLayer->IsOffscreenWindow()) {
749 fDesktop->UnlockSingleWindow();
750 				fDesktop->SetWindowLook(fWindowLayer, (window_look)look);
751 fDesktop->LockSingleWindow();
752 			}
753 
754 			fLink.StartMessage(status);
755 			fLink.Flush();
756 			break;
757 		}
758 		case AS_SET_FEEL:
759 		{
760 			STRACE(("ServerWindow %s: Message AS_SET_FEEL\n", Title()));
761 
762 			status_t status = B_ERROR;
763 			int32 feel;
764 			if (link.Read<int32>(&feel) == B_OK) {
765 				// test if feel is valid
766 				status = WindowLayer::IsValidFeel((window_feel)feel)
767 					? B_OK : B_BAD_VALUE;
768 			}
769 
770 			if (status == B_OK && !fWindowLayer->IsOffscreenWindow()) {
771 fDesktop->UnlockSingleWindow();
772 				fDesktop->SetWindowFeel(fWindowLayer, (window_feel)feel);
773 fDesktop->LockSingleWindow();
774 			}
775 
776 			fLink.StartMessage(status);
777 			fLink.Flush();
778 			break;
779 		}
780 		case AS_SET_FLAGS:
781 		{
782 			STRACE(("ServerWindow %s: Message AS_SET_FLAGS\n", Title()));
783 
784 			status_t status = B_ERROR;
785 			uint32 flags;
786 			if (link.Read<uint32>(&flags) == B_OK) {
787 				// test if flags are valid
788 				status = (flags & ~WindowLayer::ValidWindowFlags()) == 0
789 					? B_OK : B_BAD_VALUE;
790 			}
791 
792 			if (status == B_OK && !fWindowLayer->IsOffscreenWindow()) {
793 fDesktop->UnlockSingleWindow();
794 				fDesktop->SetWindowFlags(fWindowLayer, flags);
795 fDesktop->LockSingleWindow();
796 			}
797 
798 			fLink.StartMessage(status);
799 			fLink.Flush();
800 			break;
801 		}
802 #if 0
803 		case AS_SET_ALIGNMENT:
804 		{
805 			// TODO: Implement AS_SET_ALIGNMENT
806 			STRACE(("ServerWindow %s: Message Set_Alignment unimplemented\n", Title()));
807 			break;
808 		}
809 		case AS_GET_ALIGNMENT:
810 		{
811 			// TODO: Implement AS_GET_ALIGNMENT
812 			STRACE(("ServerWindow %s: Message Get_Alignment unimplemented\n", Title()));
813 			break;
814 		}
815 #endif
816 		case AS_IS_FRONT_WINDOW:
817 			fLink.StartMessage(fDesktop->FrontWindow() == fWindowLayer ? B_OK : B_ERROR);
818 			fLink.Flush();
819 			break;
820 
821 		case AS_GET_WORKSPACES:
822 		{
823 			STRACE(("ServerWindow %s: Message AS_GET_WORKSPACES\n", Title()));
824 			fLink.StartMessage(B_OK);
825 			fLink.Attach<uint32>(fWindowLayer->Workspaces());
826 			fLink.Flush();
827 			break;
828 		}
829 		case AS_SET_WORKSPACES:
830 		{
831 			uint32 newWorkspaces;
832 			if (link.Read<uint32>(&newWorkspaces) != B_OK)
833 				break;
834 
835 			STRACE(("ServerWindow %s: Message AS_SET_WORKSPACES %lx\n",
836 				Title(), newWorkspaces));
837 
838 fDesktop->UnlockSingleWindow();
839 			fDesktop->SetWindowWorkspaces(fWindowLayer, newWorkspaces);
840 fDesktop->LockSingleWindow();
841 			break;
842 		}
843 		case AS_WINDOW_RESIZE:
844 		{
845 			float xResizeBy;
846 			float yResizeBy;
847 			link.Read<float>(&xResizeBy);
848 			if (link.Read<float>(&yResizeBy) != B_OK)
849 				break;
850 
851 			STRACE(("ServerWindow %s: Message AS_WINDOW_RESIZE %.1f, %.1f\n",
852 				Title(), xResizeBy, yResizeBy));
853 
854 			if (fWindowLayer->IsResizing()) {
855 				// While the user resizes the window, we ignore
856 				// pragmatically set window bounds
857 				fLink.StartMessage(B_BUSY);
858 			} else {
859 fDesktop->UnlockSingleWindow();
860 				fDesktop->ResizeWindowBy(fWindowLayer, xResizeBy, yResizeBy);
861 fDesktop->LockSingleWindow();
862 				fLink.StartMessage(B_OK);
863 			}
864 			fLink.Flush();
865 			break;
866 		}
867 		case AS_WINDOW_MOVE:
868 		{
869 			float xMoveBy;
870 			float yMoveBy;
871 			link.Read<float>(&xMoveBy);
872 			if (link.Read<float>(&yMoveBy) != B_OK)
873 				break;
874 
875 			STRACE(("ServerWindow %s: Message AS_WINDOW_MOVE: %.1f, %.1f\n",
876 				Title(), xMoveBy, yMoveBy));
877 
878 			if (fWindowLayer->IsDragging()) {
879 				// While the user moves the window, we ignore
880 				// pragmatically set window positions
881 				fLink.StartMessage(B_BUSY);
882 			} else {
883 fDesktop->UnlockSingleWindow();
884 				fDesktop->MoveWindowBy(fWindowLayer, xMoveBy, yMoveBy);
885 fDesktop->LockSingleWindow();
886 				fLink.StartMessage(B_OK);
887 			}
888 			fLink.Flush();
889 			break;
890 		}
891 		case AS_SET_SIZE_LIMITS:
892 		{
893 			// Attached Data:
894 			// 1) float minimum width
895 			// 2) float maximum width
896 			// 3) float minimum height
897 			// 4) float maximum height
898 
899 			// TODO: for now, move the client to int32 as well!
900 			int32 minWidth, maxWidth, minHeight, maxHeight;
901 			float value;
902 			link.Read<float>(&value);	minWidth = (int32)value;
903 			link.Read<float>(&value);	maxWidth = (int32)value;
904 			link.Read<float>(&value);	minHeight = (int32)value;
905 			link.Read<float>(&value);	maxHeight = (int32)value;
906 /*
907 			link.Read<int32>(&minWidth);
908 			link.Read<int32>(&maxWidth);
909 			link.Read<int32>(&minHeight);
910 			link.Read<int32>(&maxHeight);
911 */
912 			fDesktop->UnlockSingleWindow();
913 
914 			if (fDesktop->LockAllWindows()) {
915 				fWindowLayer->SetSizeLimits(minWidth, maxWidth,
916 					minHeight, maxHeight);
917 				fDesktop->UnlockAllWindows();
918 			}
919 
920 			fDesktop->LockSingleWindow();
921 
922 			// and now, sync the client to the limits that we were able to enforce
923 			fWindowLayer->GetSizeLimits(&minWidth, &maxWidth,
924 				&minHeight, &maxHeight);
925 
926 			fLink.StartMessage(B_OK);
927 			fLink.Attach<BRect>(fWindowLayer->Frame());
928 			fLink.Attach<float>((float)minWidth);
929 			fLink.Attach<float>((float)maxWidth);
930 			fLink.Attach<float>((float)minHeight);
931 			fLink.Attach<float>((float)maxHeight);
932 
933 			fLink.Flush();
934 			break;
935 		}
936 
937 		case AS_SET_DECORATOR_SETTINGS:
938 		{
939 			STRACE(("ServerWindow %s: Message AS_SET_DECORATOR_SETTINGS\n"));
940 
941 			int32 size;
942 			if (fWindowLayer && link.Read<int32>(&size) == B_OK) {
943 				char buffer[size];
944 				if (link.Read(buffer, size) == B_OK) {
945 					BMessage settings;
946 					if (settings.Unflatten(buffer) == B_OK) {
947 fDesktop->UnlockSingleWindow();
948 						fDesktop->SetWindowDecoratorSettings(fWindowLayer, settings);
949 fDesktop->LockSingleWindow();
950 					}
951 				}
952 			}
953 			break;
954 		}
955 
956 		case AS_GET_DECORATOR_SETTINGS:
957 		{
958 			STRACE(("ServerWindow %s: Message AS_GET_DECORATOR_SETTINGS\n"));
959 
960 			bool success = false;
961 
962 			BMessage settings;
963 			if (fWindowLayer->GetDecoratorSettings(&settings)) {
964 				int32 size = settings.FlattenedSize();
965 				char buffer[size];
966 				if (settings.Flatten(buffer, size) == B_OK) {
967 					success = true;
968 					fLink.StartMessage(B_OK);
969 					fLink.Attach<int32>(size);
970 					fLink.Attach(buffer, size);
971 				}
972 			}
973 
974 			if (!success)
975 				fLink.StartMessage(B_ERROR);
976 
977 			fLink.Flush();
978 			break;
979 		}
980 
981 		case AS_REDRAW:
982 			// Nothing to do here - the redraws are actually handled by looking
983 			// at the fRedrawRequested member variable in _MessageLooper().
984 			break;
985 
986 		case AS_BEGIN_UPDATE:
987 			DTRACE(("ServerWindowo %s: AS_BEGIN_UPDATE\n", Title()));
988 			fWindowLayer->BeginUpdate(fLink);
989 			break;
990 
991 		case AS_END_UPDATE:
992 			DTRACE(("ServerWindowo %s: AS_END_UPDATE\n", Title()));
993 			fWindowLayer->EndUpdate();
994 			break;
995 
996 		case AS_GET_MOUSE:
997 		{
998 			DTRACE(("ServerWindow %s: Message AS_GET_MOUSE\n", fTitle));
999 
1000 			fDesktop->UnlockSingleWindow();
1001 			// Returns
1002 			// 1) BPoint mouse location
1003 			// 2) int32 button state
1004 
1005 			BPoint where;
1006 			int32 buttons;
1007 			fDesktop->EventDispatcher().GetMouse(where, buttons);
1008 			fDesktop->LockSingleWindow();
1009 
1010 			fLink.StartMessage(B_OK);
1011 			fLink.Attach<BPoint>(where);
1012 			fLink.Attach<int32>(buttons);
1013 			fLink.Flush();
1014 			break;
1015 		}
1016 
1017 		// BDirectWindow communication
1018 
1019 		case AS_DIRECT_WINDOW_GET_SYNC_DATA:
1020 		{
1021 			status_t status = _EnableDirectWindowMode();
1022 
1023 			fLink.StartMessage(status);
1024 			if (status == B_OK) {
1025 				struct direct_window_sync_data syncData = {
1026 					fDirectWindowData->area,
1027 					fDirectWindowData->sem,
1028 					fDirectWindowData->sem_ack
1029 				};
1030 
1031 				fLink.Attach(&syncData, sizeof(syncData));
1032 			}
1033 
1034 			fLink.Flush();
1035 			break;
1036 		}
1037 		case AS_DIRECT_WINDOW_SET_FULLSCREEN:
1038 		{
1039 			// TODO: maybe there is more to do than this?
1040 			bool enable;
1041 			link.Read<bool>(&enable);
1042 
1043 			status_t status = B_OK;
1044 			if (!fWindowLayer->IsOffscreenWindow()) {
1045 				fDesktop->UnlockSingleWindow();
1046 				fDesktop->SetWindowFeel(fWindowLayer,
1047 					enable ? kWindowScreenFeel : B_NORMAL_WINDOW_FEEL);
1048 				fDesktop->LockSingleWindow();
1049 			} else
1050 				status = B_BAD_TYPE;
1051 
1052 			fLink.StartMessage(status);
1053 			fLink.Flush();
1054 			break;
1055 		}
1056 
1057 		// View creation and destruction (don't need a valid fCurrentLayer)
1058 
1059 		case AS_SET_CURRENT_LAYER:
1060 		{
1061 			int32 token;
1062 			if (link.Read<int32>(&token) != B_OK)
1063 				break;
1064 
1065 			ViewLayer *current;
1066 			if (App()->ViewTokens().GetToken(token, B_HANDLER_TOKEN,
1067 					(void**)&current) != B_OK
1068 				|| current->Window()->ServerWindow() != this) {
1069 				// ToDo: if this happens, we probably want to kill the app and clean up
1070 				fprintf(stderr, "ServerWindow %s: Message AS_SET_CURRENT_LAYER: layer not found, token %ld\n", fTitle, token);
1071 				current = NULL;
1072 			} else {
1073 				DTRACE(("ServerWindow %s: Message AS_SET_CURRENT_LAYER: %s, token %ld\n", fTitle, current->Name(), token));
1074 				_SetCurrentLayer(current);
1075 			}
1076 			break;
1077 		}
1078 
1079 		case AS_LAYER_CREATE_ROOT:
1080 		{
1081 			STRACE(("ServerWindow %s: Message AS_LAYER_CREATE_ROOT\n", fTitle));
1082 
1083 			// Start receiving top_view data -- pass NULL as the parent view.
1084 			// This should be the *only* place where this happens.
1085 			if (fCurrentLayer != NULL) {
1086 				fprintf(stderr, "ServerWindow %s: Message AS_LAYER_CREATE_ROOT: fCurrentLayer already set!!\n", fTitle);
1087 				break;
1088 			}
1089 
1090 			_SetCurrentLayer(_CreateLayerTree(link, NULL));
1091 			fWindowLayer->SetTopLayer(fCurrentLayer);
1092 			break;
1093 		}
1094 
1095 		case AS_LAYER_CREATE:
1096 		{
1097 			STRACE(("ServerWindow %s: Message AS_LAYER_CREATE: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name()));
1098 
1099 			ViewLayer* parent = NULL;
1100 			ViewLayer* newLayer = _CreateLayerTree(link, &parent);
1101 			if (parent != NULL && newLayer != NULL)
1102 				parent->AddChild(newLayer);
1103 			else
1104 				fprintf(stderr, "ServerWindow %s: Message AS_LAYER_CREATE: parent or newLayer NULL!!\n", fTitle);
1105 			break;
1106 		}
1107 
1108 		default:
1109 			// TODO: when creating a ViewLayer, check for yet non-existing ViewLayer::InitCheck()
1110 			// and take appropriate actions, then checking for fCurrentLayer->CurrentState()
1111 			// is unnecessary
1112 			if (fCurrentLayer == NULL || fCurrentLayer->CurrentState() == NULL) {
1113 				printf("ServerWindow %s received unexpected code - message offset %ld before top_view attached.\n", Title(), code - B_OK);
1114 				return;
1115 			}
1116 
1117 			_DispatchViewMessage(code, link);
1118 			break;
1119 	}
1120 }
1121 
1122 
1123 /*!
1124 	Dispatches all view messages that need a valid fCurrentLayer.
1125 */
1126 void
1127 ServerWindow::_DispatchViewMessage(int32 code,
1128 	BPrivate::LinkReceiver &link)
1129 {
1130 	if (_DispatchPictureMessage(code, link))
1131 		return;
1132 
1133 	switch (code) {
1134 		case AS_LAYER_SCROLL:
1135 		{
1136 			DTRACE(("ServerWindow %s: Message AS_LAYER_SCROLL: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name()));
1137 			float dh;
1138 			float dv;
1139 
1140 			link.Read<float>(&dh);
1141 			link.Read<float>(&dv);
1142 			fWindowLayer->ScrollViewBy(fCurrentLayer, dh, dv);
1143 			break;
1144 		}
1145 		case AS_LAYER_COPY_BITS:
1146 		{
1147 			BRect src;
1148 			BRect dst;
1149 
1150 			link.Read<BRect>(&src);
1151 			link.Read<BRect>(&dst);
1152 
1153 			BRegion contentRegion;
1154 			// TODO: avoid copy operation maybe?
1155 			fWindowLayer->GetContentRegion(&contentRegion);
1156 			fCurrentLayer->CopyBits(src, dst, contentRegion);
1157 			break;
1158 		}
1159 		case AS_LAYER_DELETE:
1160 		{
1161 			// Received when a view is detached from a window
1162 
1163 			int32 token;
1164 			if (link.Read<int32>(&token) != B_OK)
1165 				break;
1166 
1167 			ViewLayer *view;
1168 			if (App()->ViewTokens().GetToken(token, B_HANDLER_TOKEN,
1169 					(void**)&view) == B_OK
1170 				&& view->Window()->ServerWindow() == this) {
1171 				ViewLayer* parent = view->Parent();
1172 
1173 				STRACE(("ServerWindow %s: AS_LAYER_DELETE view: %p, parent: %p\n",
1174 					fTitle, view, parent));
1175 
1176 				if (parent != NULL) {
1177 					parent->RemoveChild(view);
1178 
1179 					if (view->EventMask() != 0) {
1180 						fDesktop->EventDispatcher().RemoveListener(EventTarget(),
1181 							token);
1182 					}
1183 					delete view;
1184 				}
1185 			}
1186 			break;
1187 		}
1188 		case AS_LAYER_SET_STATE:
1189 		{
1190 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_STATE: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name()));
1191 
1192 			fCurrentLayer->CurrentState()->ReadFromLink(link);
1193 			// TODO: When is this used?!?
1194 			fCurrentLayer->RebuildClipping(true);
1195 			break;
1196 		}
1197 		case AS_LAYER_SET_FONT_STATE:
1198 		{
1199 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_FONT_STATE: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name()));
1200 			fCurrentLayer->CurrentState()->ReadFontFromLink(link);
1201 			break;
1202 		}
1203 		case AS_LAYER_GET_STATE:
1204 		{
1205 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_STATE: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name()));
1206 
1207 			fLink.StartMessage(B_OK);
1208 
1209 			// attach state data
1210 			fCurrentLayer->CurrentState()->WriteToLink(fLink.Sender());
1211 			fLink.Flush();
1212 			break;
1213 		}
1214 		case AS_LAYER_SET_EVENT_MASK:
1215 		{
1216 			STRACE(("ServerWindow %s: Message AS_LAYER_SET_MOUSE_EVENT_MASK: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name()));
1217 			uint32 eventMask, options;
1218 
1219 			link.Read<uint32>(&eventMask);
1220 			if (link.Read<uint32>(&options) == B_OK) {
1221 				fDesktop->UnlockSingleWindow();
1222 				fCurrentLayer->SetEventMask(eventMask, options);
1223 
1224 				if (eventMask != 0 || options != 0) {
1225 					fDesktop->EventDispatcher().AddListener(EventTarget(),
1226 						fCurrentLayer->Token(), eventMask, options);
1227 				} else {
1228 					fDesktop->EventDispatcher().RemoveListener(EventTarget(),
1229 						fCurrentLayer->Token());
1230 				}
1231 				fDesktop->LockSingleWindow();
1232 			}
1233 			break;
1234 		}
1235 		case AS_LAYER_SET_MOUSE_EVENT_MASK:
1236 		{
1237 			STRACE(("ServerWindow %s: Message AS_LAYER_SET_MOUSE_EVENT_MASK: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name()));
1238 			uint32 eventMask, options;
1239 
1240 			link.Read<uint32>(&eventMask);
1241 			if (link.Read<uint32>(&options) == B_OK) {
1242 				fDesktop->UnlockSingleWindow();
1243 				if (eventMask != 0 || options != 0) {
1244 					fDesktop->EventDispatcher().AddTemporaryListener(EventTarget(),
1245 						fCurrentLayer->Token(), eventMask, options);
1246 				} else {
1247 					fDesktop->EventDispatcher().RemoveTemporaryListener(EventTarget(),
1248 						fCurrentLayer->Token());
1249 				}
1250 				fDesktop->LockSingleWindow();
1251 			}
1252 
1253 			// TODO: support B_LOCK_WINDOW_FOCUS option in Desktop
1254 			break;
1255 		}
1256 		case AS_LAYER_MOVE_TO:
1257 		{
1258 			STRACE(("ServerWindow %s: Message AS_LAYER_MOVE_TO: ViewLayer name: %s\n",
1259 				fTitle, fCurrentLayer->Name()));
1260 
1261 			float x, y;
1262 			link.Read<float>(&x);
1263 			link.Read<float>(&y);
1264 
1265 			float offsetX = x - fCurrentLayer->Frame().left;
1266 			float offsetY = y - fCurrentLayer->Frame().top;
1267 
1268 			BRegion dirty;
1269 			fCurrentLayer->MoveBy(offsetX, offsetY, &dirty);
1270 
1271 			// TODO: think about how to avoid this hack:
1272 			// the parent clipping needs to be updated, it is not
1273 			// done in ResizeBy() since it would need to avoid
1274 			// too much computations when children are resized because
1275 			// follow modes
1276 			if (ViewLayer* parent = fCurrentLayer->Parent())
1277 				parent->RebuildClipping(false);
1278 
1279 			fWindowLayer->MarkContentDirty(dirty);
1280 			break;
1281 		}
1282 		case AS_LAYER_RESIZE_TO:
1283 		{
1284 			STRACE(("ServerWindow %s: Message AS_LAYER_RESIZE_TO: ViewLayer name: %s\n",
1285 				fTitle, fCurrentLayer->Name()));
1286 
1287 			float newWidth, newHeight;
1288 			link.Read<float>(&newWidth);
1289 			link.Read<float>(&newHeight);
1290 
1291 			float deltaWidth = newWidth - fCurrentLayer->Frame().Width();
1292 			float deltaHeight = newHeight - fCurrentLayer->Frame().Height();
1293 
1294 			BRegion dirty;
1295 			fCurrentLayer->ResizeBy(deltaWidth, deltaHeight, &dirty);
1296 
1297 			// TODO: see above
1298 			if (ViewLayer* parent = fCurrentLayer->Parent())
1299 				parent->RebuildClipping(false);
1300 
1301 			fWindowLayer->MarkContentDirty(dirty);
1302 			break;
1303 		}
1304 		case AS_LAYER_GET_COORD:
1305 		{
1306 			STRACE(("ServerWindow %s: Message AS_LAYER_GET_COORD: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1307 			fLink.StartMessage(B_OK);
1308 			// our offset in the parent -> will be originX and originY in BView
1309 			fLink.Attach<float>(fCurrentLayer->Frame().left);
1310 			fLink.Attach<float>(fCurrentLayer->Frame().top);
1311 			fLink.Attach<BRect>(fCurrentLayer->Bounds());
1312 			fLink.Flush();
1313 			break;
1314 		}
1315 		case AS_LAYER_SET_ORIGIN:
1316 		{
1317 			STRACE(("ServerWindow %s: Message AS_LAYER_SET_ORIGIN: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1318 
1319 			float x, y;
1320 			link.Read<float>(&x);
1321 			link.Read<float>(&y);
1322 
1323 			fCurrentLayer->SetDrawingOrigin(BPoint(x, y));
1324 			break;
1325 		}
1326 		case AS_LAYER_GET_ORIGIN:
1327 		{
1328 			STRACE(("ServerWindow %s: Message AS_LAYER_GET_ORIGIN: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1329 			fLink.StartMessage(B_OK);
1330 			// TODO: rename this where it is used in the BView code!
1331 			// (it wants to know scrolling offset, not drawing origin)
1332 			fLink.Attach<BPoint>(fCurrentLayer->ScrollingOffset());
1333 			fLink.Flush();
1334 			break;
1335 		}
1336 		case AS_LAYER_RESIZE_MODE:
1337 		{
1338 			STRACE(("ServerWindow %s: Message AS_LAYER_RESIZE_MODE: ViewLayer: %s\n",
1339 				Title(), fCurrentLayer->Name()));
1340 
1341 			uint32 resizeMode;
1342 			if (link.Read<uint32>(&resizeMode) == B_OK)
1343 				fCurrentLayer->SetResizeMode(resizeMode);
1344 			break;
1345 		}
1346 		case AS_LAYER_SET_CURSOR:
1347 		{
1348 			DTRACE(("ServerWindow %s: Message AS_LAYER_CURSOR: ViewLayer: %s\n", Title(),
1349 				fCurrentLayer->Name()));
1350 
1351 			int32 token;
1352 			bool sync;
1353 			link.Read<int32>(&token);
1354 			if (link.Read<bool>(&sync) != B_OK)
1355 				break;
1356 
1357 			if (!fDesktop->GetCursorManager().Lock())
1358 				break;
1359 
1360 			ServerCursor* cursor = fDesktop->GetCursorManager().FindCursor(token);
1361 			fCurrentLayer->SetCursor(cursor);
1362 
1363 			fDesktop->GetCursorManager().Unlock();
1364 
1365 			if (fWindowLayer->IsFocus()) {
1366 				// The cursor might need to be updated now
1367 				if (fDesktop->ViewUnderMouse(fWindowLayer) == fCurrentLayer->Token())
1368 					fServerApp->SetCurrentCursor(cursor);
1369 			}
1370 			if (sync) {
1371 				// sync the client (it can now delete the cursor)
1372 				fLink.StartMessage(B_OK);
1373 				fLink.Flush();
1374 			}
1375 
1376 			break;
1377 		}
1378 		case AS_LAYER_SET_FLAGS:
1379 		{
1380 			uint32 flags;
1381 			link.Read<uint32>(&flags);
1382 			fCurrentLayer->SetFlags(flags);
1383 
1384 			STRACE(("ServerWindow %s: Message AS_LAYER_SET_FLAGS: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1385 			break;
1386 		}
1387 		case AS_LAYER_HIDE:
1388 		{
1389 			STRACE(("ServerWindow %s: Message AS_LAYER_HIDE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1390 			fCurrentLayer->SetHidden(true);
1391 			break;
1392 		}
1393 		case AS_LAYER_SHOW:
1394 		{
1395 			STRACE(("ServerWindow %s: Message AS_LAYER_SHOW: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1396 			fCurrentLayer->SetHidden(false);
1397 			break;
1398 		}
1399 		case AS_LAYER_SET_LINE_MODE:
1400 		{
1401 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_LINE_MODE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1402 			int8 lineCap, lineJoin;
1403 			float miterLimit;
1404 
1405 			link.Read<int8>(&lineCap);
1406 			link.Read<int8>(&lineJoin);
1407 			link.Read<float>(&miterLimit);
1408 
1409 			fCurrentLayer->CurrentState()->SetLineCapMode((cap_mode)lineCap);
1410 			fCurrentLayer->CurrentState()->SetLineJoinMode((join_mode)lineJoin);
1411 			fCurrentLayer->CurrentState()->SetMiterLimit(miterLimit);
1412 
1413 			break;
1414 		}
1415 		case AS_LAYER_GET_LINE_MODE:
1416 		{
1417 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_LINE_MODE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1418 			fLink.StartMessage(B_OK);
1419 			fLink.Attach<int8>((int8)(fCurrentLayer->CurrentState()->LineCapMode()));
1420 			fLink.Attach<int8>((int8)(fCurrentLayer->CurrentState()->LineJoinMode()));
1421 			fLink.Attach<float>(fCurrentLayer->CurrentState()->MiterLimit());
1422 			fLink.Flush();
1423 
1424 			break;
1425 		}
1426 		case AS_LAYER_PUSH_STATE:
1427 		{
1428 			DTRACE(("ServerWindow %s: Message AS_LAYER_PUSH_STATE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1429 
1430 			fCurrentLayer->PushState();
1431 
1432 			break;
1433 		}
1434 		case AS_LAYER_POP_STATE:
1435 		{
1436 			DTRACE(("ServerWindow %s: Message AS_LAYER_POP_STATE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1437 
1438 			fCurrentLayer->PopState();
1439 
1440 			break;
1441 		}
1442 		case AS_LAYER_SET_SCALE:
1443 		{
1444 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_SCALE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1445 			float scale;
1446 			link.Read<float>(&scale);
1447 
1448 			fCurrentLayer->SetScale(scale);
1449 			break;
1450 		}
1451 		case AS_LAYER_GET_SCALE:
1452 		{
1453 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_SCALE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1454 
1455 			fLink.StartMessage(B_OK);
1456 			fLink.Attach<float>(fCurrentLayer->CurrentState()->Scale());
1457 			fLink.Flush();
1458 			break;
1459 		}
1460 		case AS_LAYER_SET_PEN_LOC:
1461 		{
1462 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_PEN_LOC: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1463 			float x, y;
1464 
1465 			link.Read<float>(&x);
1466 			link.Read<float>(&y);
1467 
1468 			fCurrentLayer->CurrentState()->SetPenLocation(BPoint(x, y));
1469 			break;
1470 		}
1471 		case AS_LAYER_GET_PEN_LOC:
1472 		{
1473 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_PEN_LOC: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1474 			fLink.StartMessage(B_OK);
1475 			fLink.Attach<BPoint>(fCurrentLayer->CurrentState()->PenLocation());
1476 			fLink.Flush();
1477 
1478 			break;
1479 		}
1480 		case AS_LAYER_SET_PEN_SIZE:
1481 		{
1482 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_PEN_SIZE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1483 			float penSize;
1484 			link.Read<float>(&penSize);
1485 			fCurrentLayer->CurrentState()->SetPenSize(penSize);
1486 
1487 			break;
1488 		}
1489 		case AS_LAYER_GET_PEN_SIZE:
1490 		{
1491 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_PEN_SIZE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1492 			fLink.StartMessage(B_OK);
1493 			fLink.Attach<float>(fCurrentLayer->CurrentState()->PenSize());
1494 			fLink.Flush();
1495 
1496 			break;
1497 		}
1498 		case AS_LAYER_SET_VIEW_COLOR:
1499 		{
1500 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_VIEW_COLOR: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1501 			rgb_color c;
1502 
1503 			link.Read(&c, sizeof(rgb_color));
1504 
1505 			fCurrentLayer->SetViewColor(RGBColor(c));
1506 			break;
1507 		}
1508 
1509 		case AS_LAYER_GET_HIGH_COLOR:
1510 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_HIGH_COLOR: ViewLayer: %s\n",
1511 				Title(), fCurrentLayer->Name()));
1512 
1513 			fLink.StartMessage(B_OK);
1514 			fLink.Attach<rgb_color>(fCurrentLayer->CurrentState()->HighColor().GetColor32());
1515 			fLink.Flush();
1516 			break;
1517 
1518 		case AS_LAYER_GET_LOW_COLOR:
1519 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_LOW_COLOR: ViewLayer: %s\n",
1520 				Title(), fCurrentLayer->Name()));
1521 
1522 			fLink.StartMessage(B_OK);
1523 			fLink.Attach<rgb_color>(fCurrentLayer->CurrentState()->LowColor().GetColor32());
1524 			fLink.Flush();
1525 			break;
1526 
1527 		case AS_LAYER_GET_VIEW_COLOR:
1528 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_VIEW_COLOR: ViewLayer: %s\n",
1529 				Title(), fCurrentLayer->Name()));
1530 
1531 			fLink.StartMessage(B_OK);
1532 			fLink.Attach<rgb_color>(fCurrentLayer->ViewColor().GetColor32());
1533 			fLink.Flush();
1534 			break;
1535 
1536 		case AS_LAYER_SET_BLENDING_MODE:
1537 		{
1538 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_BLEND_MODE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1539 			int8 srcAlpha, alphaFunc;
1540 
1541 			link.Read<int8>(&srcAlpha);
1542 			link.Read<int8>(&alphaFunc);
1543 
1544 			fCurrentLayer->CurrentState()->SetBlendingMode((source_alpha)srcAlpha,
1545 											(alpha_function)alphaFunc);
1546 
1547 			break;
1548 		}
1549 		case AS_LAYER_GET_BLENDING_MODE:
1550 		{
1551 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_BLEND_MODE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1552 			fLink.StartMessage(B_OK);
1553 			fLink.Attach<int8>((int8)(fCurrentLayer->CurrentState()->AlphaSrcMode()));
1554 			fLink.Attach<int8>((int8)(fCurrentLayer->CurrentState()->AlphaFncMode()));
1555 			fLink.Flush();
1556 
1557 			break;
1558 		}
1559 		case AS_LAYER_SET_DRAWING_MODE:
1560 		{
1561 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_DRAW_MODE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1562 			int8 drawingMode;
1563 
1564 			link.Read<int8>(&drawingMode);
1565 
1566 			fCurrentLayer->CurrentState()->SetDrawingMode((drawing_mode)drawingMode);
1567 
1568 			break;
1569 		}
1570 		case AS_LAYER_GET_DRAWING_MODE:
1571 		{
1572 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_DRAW_MODE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1573 			fLink.StartMessage(B_OK);
1574 			fLink.Attach<int8>((int8)(fCurrentLayer->CurrentState()->GetDrawingMode()));
1575 			fLink.Flush();
1576 
1577 			break;
1578 		}
1579 		case AS_LAYER_SET_VIEW_BITMAP:
1580 		{
1581 			int32 bitmapToken, resizingMode, options;
1582 			BRect srcRect, dstRect;
1583 
1584 			link.Read<int32>(&bitmapToken);
1585 			link.Read<BRect>(&srcRect);
1586 			link.Read<BRect>(&dstRect);
1587 			link.Read<int32>(&resizingMode);
1588 			status_t status = link.Read<int32>(&options);
1589 
1590 			rgb_color colorKey = {0};
1591 
1592 			if (status == B_OK) {
1593 				ServerBitmap* bitmap = fServerApp->FindBitmap(bitmapToken);
1594 				if (bitmapToken == -1 || bitmap != NULL) {
1595 					bool wasOverlay = fCurrentLayer->ViewBitmap() != NULL
1596 						&& fCurrentLayer->ViewBitmap()->Overlay() != NULL;
1597 
1598 					// TODO: this is a race condition: the bitmap could have been
1599 					//	deleted in the mean time!!
1600 					fCurrentLayer->SetViewBitmap(bitmap, srcRect, dstRect,
1601 						resizingMode, options);
1602 
1603 					// TODO: if we revert the view color overlay handling
1604 					//	in ViewLayer::Draw() to the R5 version, we never
1605 					//	need to invalidate the view for overlays.
1606 
1607 					// invalidate view - but only if this is a non-overlay switch
1608 					if (bitmap == NULL || bitmap->Overlay() == NULL || !wasOverlay) {
1609 						BRegion dirty(fCurrentLayer->Bounds());
1610 						fWindowLayer->InvalidateView(fCurrentLayer, dirty);
1611 					}
1612 
1613 					if (bitmap != NULL && bitmap->Overlay() != NULL) {
1614 						bitmap->Overlay()->SetFlags(options);
1615 						colorKey = bitmap->Overlay()->Color().GetColor32();
1616 					}
1617 				} else
1618 					status = B_BAD_VALUE;
1619 			}
1620 
1621 			fLink.StartMessage(status);
1622 			if (status == B_OK && (options & AS_REQUEST_COLOR_KEY) != 0) {
1623 				// Attach color key for the overlay bitmap
1624 				fLink.Attach<rgb_color>(colorKey);
1625 			}
1626 
1627 			fLink.Flush();
1628 			break;
1629 		}
1630 		case AS_LAYER_PRINT_ALIASING:
1631 		{
1632 			DTRACE(("ServerWindow %s: Message AS_LAYER_PRINT_ALIASING: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1633 			bool fontAliasing;
1634 			if (link.Read<bool>(&fontAliasing) == B_OK)
1635 				fCurrentLayer->CurrentState()->SetForceFontAliasing(fontAliasing);
1636 			break;
1637 		}
1638 		case AS_LAYER_CLIP_TO_PICTURE:
1639 		{
1640 			DTRACE(("ServerWindow %s: Message AS_LAYER_CLIP_TO_PICTURE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1641 			// TODO: you are not allowed to use ViewLayer regions here!!!
1642 
1643 			int32 pictureToken;
1644 			BPoint where;
1645 			bool inverse = false;
1646 
1647 			link.Read<int32>(&pictureToken);
1648 			link.Read<BPoint>(&where);
1649 			link.Read<bool>(&inverse);
1650 
1651 			// search for a picture with the specified token.
1652 			ServerPicture *picture = fServerApp->FindPicture(pictureToken);
1653 			// TODO: Increase that picture's reference count.(~ allocate a picture)
1654 			if (picture == NULL)
1655 				break;
1656 
1657 			BRegion region;
1658 			// TODO: I think we also need the BView's token
1659 			// I think PictureToRegion would fit better into the ViewLayer class (?)
1660 			if (PictureToRegion(picture, region, inverse, where) < B_OK)
1661 				break;
1662 
1663 			fCurrentLayer->SetUserClipping(&region);
1664 
1665 // TODO: reenable AS_LAYER_CLIP_TO_PICTURE
1666 #if 0
1667 			if (rootLayer && !(fCurrentLayer->IsHidden()) && !fWindowLayer->InUpdate()) {
1668 				BRegion invalidRegion;
1669 				fCurrentLayer->GetOnScreenRegion(invalidRegion);
1670 
1671 				// TODO: this is broken! a smaller area may be invalidated!
1672 
1673 				fCurrentLayer->fParent->MarkForRebuild(invalidRegion);
1674 				fCurrentLayer->fParent->TriggerRebuild();
1675 				rootLayer->MarkForRedraw(invalidRegion);
1676 				rootLayer->TriggerRedraw();
1677 			}
1678 #endif
1679 			break;
1680 		}
1681 
1682 		case AS_LAYER_GET_CLIP_REGION:
1683 		{
1684 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_CLIP_REGION: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1685 
1686 			// if this ViewLayer is hidden, it is clear that its visible region is void.
1687 			if (fCurrentLayer->IsHidden()) {
1688 				fLink.StartMessage(B_OK);
1689 				fLink.Attach<int32>(0L);
1690 				fLink.Flush();
1691 			} else {
1692 				BRegion drawingRegion = fCurrentLayer->LocalClipping();
1693 				int32 rectCount = drawingRegion.CountRects();
1694 
1695 				fLink.StartMessage(B_OK);
1696 				fLink.Attach<int32>(rectCount);
1697 
1698 				for (int32 i = 0; i < rectCount; i++) {
1699 					fLink.Attach<BRect>(drawingRegion.RectAt(i));
1700 				}
1701 
1702 				fLink.Flush();
1703 			}
1704 
1705 			break;
1706 		}
1707 		case AS_LAYER_SET_CLIP_REGION:
1708 		{
1709 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_CLIP_REGION: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1710 
1711 			int32 rectCount;
1712 			status_t status = link.Read<int32>(&rectCount);
1713 				// a negative count means no
1714 				// region for the current draw state,
1715 				// but an *empty* region is actually valid!
1716 				// even if it means no drawing is allowed
1717 			BRegion region;
1718 			if (status == B_OK && rectCount >= 0) {
1719 				for (int32 i = 0; i < rectCount; i++) {
1720 					clipping_rect r;
1721 					status = link.Read<clipping_rect>(&r);
1722 					if (status < B_OK)
1723 						break;
1724 					// TODO: optimize (use AttachRegion()+ReadRegion())
1725 					region.Include(r);
1726 				}
1727 			} else
1728 				status = B_ERROR;
1729 
1730 			if (status == B_OK) {
1731 				fCurrentLayer->SetUserClipping(&region);
1732 			} else {
1733 				// passing NULL sets this states region
1734 				// to that of the previous state
1735 				fCurrentLayer->SetUserClipping(NULL);
1736 			}
1737 
1738 			break;
1739 		}
1740 
1741 		case AS_LAYER_INVALIDATE_RECT:
1742 		{
1743 			DTRACE(("ServerWindow %s: Message AS_LAYER_INVALIDATE_RECT: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1744 
1745 			// NOTE: looks like this call is NOT affected by origin and scale on R5
1746 			// so this implementation is "correct"
1747 			BRect invalidRect;
1748 			if (link.Read<BRect>(&invalidRect) == B_OK) {
1749 				BRegion dirty(invalidRect);
1750 				fWindowLayer->InvalidateView(fCurrentLayer, dirty);
1751 			}
1752 			break;
1753 		}
1754 		case AS_LAYER_INVALIDATE_REGION:
1755 		{
1756 			DTRACE(("ServerWindow %s: Message AS_LAYER_INVALIDATE_RECT: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1757 
1758 			// NOTE: looks like this call is NOT affected by origin and scale on R5
1759 			// so this implementation is "correct"
1760 			BRegion dirty;
1761 			int32 rectCount;
1762 			BRect rect;
1763 
1764 			link.Read<int32>(&rectCount);
1765 
1766 			for (int i = 0; i < rectCount; i++) {
1767 				link.Read<BRect>(&rect);
1768 				dirty.Include(rect);
1769 			}
1770 
1771 			fWindowLayer->InvalidateView(fCurrentLayer, dirty);
1772 			break;
1773 		}
1774 
1775 		case AS_LAYER_SET_HIGH_COLOR:
1776 		{
1777 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_HIGH_COLOR: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1778 
1779 			rgb_color c;
1780 			link.Read(&c, sizeof(rgb_color));
1781 
1782 			fCurrentLayer->CurrentState()->SetHighColor(RGBColor(c));
1783 			break;
1784 		}
1785 		case AS_LAYER_SET_LOW_COLOR:
1786 		{
1787 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_LOW_COLOR: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1788 
1789 			rgb_color c;
1790 			link.Read(&c, sizeof(rgb_color));
1791 
1792 			fCurrentLayer->CurrentState()->SetLowColor(RGBColor(c));
1793 			break;
1794 		}
1795 		case AS_LAYER_SET_PATTERN:
1796 		{
1797 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_PATTERN: ViewLayer: %s\n", fTitle, fCurrentLayer->Name()));
1798 
1799 			pattern pat;
1800 			link.Read(&pat, sizeof(pattern));
1801 
1802 			fCurrentLayer->CurrentState()->SetPattern(Pattern(pat));
1803 			break;
1804 		}
1805 		case AS_SET_FONT:
1806 		{
1807 			DTRACE(("ServerWindow %s: Message AS_SET_FONT\n", Title()));
1808 			// TODO: Implement AS_SET_FONT?
1809 			// Confusing!! But it works already!
1810 			break;
1811 		}
1812 		case AS_SET_FONT_SIZE:
1813 		{
1814 			DTRACE(("ServerWindow %s: Message AS_SET_FONT_SIZE\n", Title()));
1815 			// TODO: Implement AS_SET_FONT_SIZE?
1816 			break;
1817 		}
1818 		case AS_SYNC:
1819 		{
1820 			// TODO: AS_SYNC is a no-op for now, just to get things working
1821 			fLink.StartMessage(B_OK);
1822 			fLink.Flush();
1823 			break;
1824 		}
1825 		case AS_LAYER_DRAG_IMAGE:
1826 		{
1827 			// TODO: flesh out AS_LAYER_DRAG_IMAGE
1828 			STRACE(("ServerWindow %s: Message AS_DRAG_IMAGE\n", Title()));
1829 
1830 			int32 bitmapToken;
1831 			drawing_mode dragMode;
1832 			BPoint offset;
1833 			int32 bufferSize;
1834 
1835 			link.Read<int32>(&bitmapToken);
1836 			link.Read<int32>((int32*)&dragMode);
1837 			link.Read<BPoint>(&offset);
1838 			link.Read<int32>(&bufferSize);
1839 
1840 			if (bufferSize > 0) {
1841 				char* buffer = new (nothrow) char[bufferSize];
1842 				BMessage dragMessage;
1843 				if (link.Read(buffer, bufferSize) == B_OK
1844 					&& dragMessage.Unflatten(buffer) == B_OK) {
1845 						ServerBitmap* bitmap = fServerApp->FindBitmap(bitmapToken);
1846 						fDesktop->EventDispatcher().SetDragMessage(dragMessage,
1847 																   bitmap, offset);
1848 				}
1849 				delete[] buffer;
1850 			}
1851 			// sync the client (it can now delete the bitmap)
1852 			fLink.StartMessage(B_OK);
1853 			fLink.Flush();
1854 
1855 			break;
1856 		}
1857 		case AS_LAYER_DRAG_RECT:
1858 		{
1859 			// TODO: flesh out AS_LAYER_DRAG_RECT
1860 			STRACE(("ServerWindow %s: Message AS_DRAG_RECT\n", Title()));
1861 
1862 			BRect dragRect;
1863 			BPoint offset;
1864 			int32 bufferSize;
1865 
1866 			link.Read<BRect>(&dragRect);
1867 			link.Read<BPoint>(&offset);
1868 			link.Read<int32>(&bufferSize);
1869 
1870 			if (bufferSize > 0) {
1871 				char* buffer = new (nothrow) char[bufferSize];
1872 				BMessage dragMessage;
1873 				if (link.Read(buffer, bufferSize) == B_OK
1874 					&& dragMessage.Unflatten(buffer) == B_OK) {
1875 						fDesktop->EventDispatcher().SetDragMessage(dragMessage,
1876 							NULL /* should be dragRect */, offset);
1877 				}
1878 				delete[] buffer;
1879 			}
1880 
1881 			break;
1882 		}
1883 
1884 		case AS_LAYER_BEGIN_PICTURE:
1885 		{
1886 			DTRACE(("ServerWindow %s: Message AS_LAYER_BEGIN_PICTURE\n", Title()));
1887 			ServerPicture *picture = App()->CreatePicture();
1888 			picture->SyncState(fCurrentLayer);
1889 			fCurrentLayer->SetPicture(picture);
1890 			break;
1891 		}
1892 
1893 		case AS_LAYER_APPEND_TO_PICTURE:
1894 		{
1895 			DTRACE(("ServerWindow %s: Message AS_LAYER_APPEND_TO_PICTURE\n", Title()));
1896 
1897 			int32 pictureToken;
1898 			link.Read<int32>(&pictureToken);
1899 			ServerPicture *picture = App()->FindPicture(pictureToken);
1900 			if (picture)
1901 				picture->SyncState(fCurrentLayer);
1902 			fCurrentLayer->SetPicture(picture);
1903 				// we don't care if it's NULL
1904 			break;
1905 		}
1906 
1907 		case AS_LAYER_END_PICTURE:
1908 		{
1909 			DTRACE(("ServerWindow %s: Message AS_LAYER_END_PICTURE\n", Title()));
1910 
1911 			ServerPicture *picture = fCurrentLayer->Picture();
1912 			if (picture != NULL) {
1913 				fCurrentLayer->SetPicture(NULL);
1914 				fLink.StartMessage(B_OK);
1915 				fLink.Attach<int32>(picture->Token());
1916 			} else
1917 				fLink.StartMessage(B_ERROR);
1918 
1919 			fLink.Flush();
1920 			break;
1921 		}
1922 
1923 		default:
1924 			_DispatchViewDrawingMessage(code, link);
1925 			break;
1926 	}
1927 }
1928 
1929 
1930 /*!
1931 	Dispatches all view drawing messages.
1932 	The desktop clipping must be read locked when entering this method.
1933 	Requires a valid fCurrentLayer.
1934 */
1935 void
1936 ServerWindow::_DispatchViewDrawingMessage(int32 code, BPrivate::LinkReceiver &link)
1937 {
1938 	if (!fCurrentLayer->IsVisible() || !fWindowLayer->IsVisible()) {
1939 		if (link.NeedsReply()) {
1940 			printf("ServerWindow::DispatchViewDrawingMessage() got message %ld that needs a reply!\n", code);
1941 			// the client is now blocking and waiting for a reply!
1942 			fLink.StartMessage(B_ERROR);
1943 			fLink.Flush();
1944 		}
1945 		return;
1946 	}
1947 
1948 	DrawingEngine* drawingEngine = fWindowLayer->GetDrawingEngine();
1949 	if (!drawingEngine) {
1950 		// ?!?
1951 		DTRACE(("ServerWindow %s: no drawing engine!!\n", Title()));
1952 		if (link.NeedsReply()) {
1953 			// the client is now blocking and waiting for a reply!
1954 			fLink.StartMessage(B_ERROR);
1955 			fLink.Flush();
1956 		}
1957 		return;
1958 	}
1959 
1960 	if (!fCurrentDrawingRegionValid || fWindowLayer->DrawingRegionChanged(fCurrentLayer)) {
1961 		fWindowLayer->GetEffectiveDrawingRegion(fCurrentLayer, fCurrentDrawingRegion);
1962 		fCurrentDrawingRegionValid = true;
1963 	}
1964 
1965 	if (fCurrentDrawingRegion.CountRects() <= 0) {
1966 		if (link.NeedsReply()) {
1967 			// the client is now blocking and waiting for a reply!
1968 			fLink.StartMessage(B_ERROR);
1969 			fLink.Flush();
1970 		}
1971 		return;
1972 	}
1973 
1974 	drawingEngine->LockParallelAccess();
1975 	// TODO: avoid setting the region each time
1976 	drawingEngine->ConstrainClippingRegion(&fCurrentDrawingRegion);
1977 
1978 	switch (code) {
1979 		case AS_STROKE_LINE:
1980 		{
1981 			DTRACE(("ServerWindow %s: Message AS_STROKE_LINE\n", Title()));
1982 
1983 			float x1, y1, x2, y2;
1984 
1985 			link.Read<float>(&x1);
1986 			link.Read<float>(&y1);
1987 			link.Read<float>(&x2);
1988 			link.Read<float>(&y2);
1989 
1990 			BPoint p1(x1, y1);
1991 			BPoint p2(x2, y2);
1992 			BPoint penPos = p2;
1993 			fCurrentLayer->ConvertToScreenForDrawing(&p1);
1994 			fCurrentLayer->ConvertToScreenForDrawing(&p2);
1995 			drawingEngine->StrokeLine(p1, p2, fCurrentLayer->CurrentState());
1996 
1997 			// We update the pen here because many DrawingEngine calls which do not update the
1998 			// pen position actually call StrokeLine
1999 
2000 			// TODO: Decide where to put this, for example, it cannot be done
2001 			// for DrawString(), also there needs to be a decision, if penlocation
2002 			// is in View coordinates (I think it should be) or in screen coordinates.
2003 			fCurrentLayer->CurrentState()->SetPenLocation(penPos);
2004 			break;
2005 		}
2006 		case AS_LAYER_INVERT_RECT:
2007 		{
2008 			DTRACE(("ServerWindow %s: Message AS_INVERT_RECT\n", Title()));
2009 
2010 			BRect rect;
2011 			link.Read<BRect>(&rect);
2012 
2013 			fCurrentLayer->ConvertToScreenForDrawing(&rect);
2014 			drawingEngine->InvertRect(rect);
2015 			break;
2016 		}
2017 		case AS_STROKE_RECT:
2018 		{
2019 			DTRACE(("ServerWindow %s: Message AS_STROKE_RECT\n", Title()));
2020 
2021 			float left, top, right, bottom;
2022 			link.Read<float>(&left);
2023 			link.Read<float>(&top);
2024 			link.Read<float>(&right);
2025 			link.Read<float>(&bottom);
2026 			BRect rect(left,top,right,bottom);
2027 
2028 			fCurrentLayer->ConvertToScreenForDrawing(&rect);
2029 			drawingEngine->StrokeRect(rect, fCurrentLayer->CurrentState());
2030 			break;
2031 		}
2032 		case AS_FILL_RECT:
2033 		{
2034 			DTRACE(("ServerWindow %s: Message AS_FILL_RECT\n", Title()));
2035 
2036 			BRect rect;
2037 			link.Read<BRect>(&rect);
2038 
2039 			fCurrentLayer->ConvertToScreenForDrawing(&rect);
2040 			drawingEngine->FillRect(rect, fCurrentLayer->CurrentState());
2041 			break;
2042 		}
2043 		case AS_LAYER_DRAW_BITMAP:
2044 		{
2045 			DTRACE(("ServerWindow %s: Message AS_LAYER_DRAW_BITMAP: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name()));
2046 			int32 bitmapToken;
2047 			BRect srcRect, dstRect;
2048 
2049 			link.Read<int32>(&bitmapToken);
2050 			link.Read<BRect>(&dstRect);
2051 			link.Read<BRect>(&srcRect);
2052 
2053 			ServerBitmap* bitmap = fServerApp->FindBitmap(bitmapToken);
2054 			if (bitmap) {
2055 				fCurrentLayer->ConvertToScreenForDrawing(&dstRect);
2056 
2057 				drawingEngine->DrawBitmap(bitmap, srcRect, dstRect, fCurrentLayer->CurrentState());
2058 			}
2059 
2060 			break;
2061 		}
2062 		case AS_STROKE_ARC:
2063 		case AS_FILL_ARC:
2064 		{
2065 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ARC\n", Title()));
2066 
2067 			float angle, span;
2068 			BRect r;
2069 
2070 			link.Read<BRect>(&r);
2071 			link.Read<float>(&angle);
2072 			link.Read<float>(&span);
2073 
2074 			fCurrentLayer->ConvertToScreenForDrawing(&r);
2075 			drawingEngine->DrawArc(r, angle, span, fCurrentLayer->CurrentState(),
2076 								   code == AS_FILL_ARC);
2077 			break;
2078 		}
2079 		case AS_STROKE_BEZIER:
2080 		case AS_FILL_BEZIER:
2081 		{
2082 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_BEZIER\n", Title()));
2083 
2084 			BPoint pts[4];
2085 			for (int32 i = 0; i < 4; i++) {
2086 				link.Read<BPoint>(&(pts[i]));
2087 				fCurrentLayer->ConvertToScreenForDrawing(&pts[i]);
2088 			}
2089 
2090 			drawingEngine->DrawBezier(pts, fCurrentLayer->CurrentState(),
2091 									  code == AS_FILL_BEZIER);
2092 			break;
2093 		}
2094 		case AS_STROKE_ELLIPSE:
2095 		case AS_FILL_ELLIPSE:
2096 		{
2097 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ELLIPSE\n", Title()));
2098 
2099 			BRect rect;
2100 			link.Read<BRect>(&rect);
2101 
2102 			fCurrentLayer->ConvertToScreenForDrawing(&rect);
2103 			drawingEngine->DrawEllipse(rect, fCurrentLayer->CurrentState(), code == AS_FILL_ELLIPSE);
2104 			break;
2105 		}
2106 		case AS_STROKE_ROUNDRECT:
2107 		case AS_FILL_ROUNDRECT:
2108 		{
2109 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ROUNDRECT\n", Title()));
2110 
2111 			BRect rect;
2112 			float xrad,yrad;
2113 			link.Read<BRect>(&rect);
2114 			link.Read<float>(&xrad);
2115 			link.Read<float>(&yrad);
2116 
2117 			fCurrentLayer->ConvertToScreenForDrawing(&rect);
2118 			drawingEngine->DrawRoundRect(rect, xrad, yrad, fCurrentLayer->CurrentState(), code == AS_FILL_ROUNDRECT);
2119 			break;
2120 		}
2121 		case AS_STROKE_TRIANGLE:
2122 		case AS_FILL_TRIANGLE:
2123 		{
2124 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_TRIANGLE\n", Title()));
2125 
2126 			BPoint pts[3];
2127 			BRect rect;
2128 
2129 			for (int32 i = 0; i < 3; i++) {
2130 				link.Read<BPoint>(&(pts[i]));
2131 				fCurrentLayer->ConvertToScreenForDrawing(&pts[i]);
2132 			}
2133 
2134 			link.Read<BRect>(&rect);
2135 
2136 			fCurrentLayer->ConvertToScreenForDrawing(&rect);
2137 			drawingEngine->DrawTriangle(pts, rect, fCurrentLayer->CurrentState(), code == AS_FILL_TRIANGLE);
2138 			break;
2139 		}
2140 		case AS_STROKE_POLYGON:
2141 		case AS_FILL_POLYGON:
2142 		{
2143 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_POLYGON\n", Title()));
2144 
2145 			BRect polyFrame;
2146 			bool isClosed = true;
2147 			int32 pointCount;
2148 
2149 			link.Read<BRect>(&polyFrame);
2150 			if (code == AS_STROKE_POLYGON)
2151 				link.Read<bool>(&isClosed);
2152 			link.Read<int32>(&pointCount);
2153 
2154 			BPoint* pointList = new(nothrow) BPoint[pointCount];
2155 			if (link.Read(pointList, pointCount * sizeof(BPoint)) >= B_OK) {
2156 				for (int32 i = 0; i < pointCount; i++)
2157 					fCurrentLayer->ConvertToScreenForDrawing(&pointList[i]);
2158 				fCurrentLayer->ConvertToScreenForDrawing(&polyFrame);
2159 
2160 				drawingEngine->DrawPolygon(pointList, pointCount, polyFrame,
2161 					fCurrentLayer->CurrentState(), code == AS_FILL_POLYGON,
2162 					isClosed && pointCount > 2);
2163 			}
2164 			delete[] pointList;
2165 			break;
2166 		}
2167 		case AS_STROKE_SHAPE:
2168 		case AS_FILL_SHAPE:
2169 		{
2170 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_SHAPE\n", Title()));
2171 
2172 			BRect shapeFrame;
2173 			int32 opCount;
2174 			int32 ptCount;
2175 
2176 			link.Read<BRect>(&shapeFrame);
2177 			link.Read<int32>(&opCount);
2178 			link.Read<int32>(&ptCount);
2179 
2180 			uint32* opList = new(nothrow) uint32[opCount];
2181 			BPoint* ptList = new(nothrow) BPoint[ptCount];
2182 			if (link.Read(opList, opCount * sizeof(uint32)) >= B_OK &&
2183 				link.Read(ptList, ptCount * sizeof(BPoint)) >= B_OK) {
2184 
2185 				for (int32 i = 0; i < ptCount; i++)
2186 					fCurrentLayer->ConvertToScreenForDrawing(&ptList[i]);
2187 
2188 				drawingEngine->DrawShape(shapeFrame, opCount, opList, ptCount, ptList,
2189 					fCurrentLayer->CurrentState(), code == AS_FILL_SHAPE);
2190 			}
2191 
2192 			delete[] opList;
2193 			delete[] ptList;
2194 			break;
2195 		}
2196 		case AS_FILL_REGION:
2197 		{
2198 			DTRACE(("ServerWindow %s: Message AS_FILL_REGION\n", Title()));
2199 
2200 			BRegion region;
2201 			if (link.ReadRegion(&region) < B_OK)
2202 				break;
2203 
2204 			fCurrentLayer->ConvertToScreenForDrawing(&region);
2205 			drawingEngine->FillRegion(region, fCurrentLayer->CurrentState());
2206 
2207 			break;
2208 		}
2209 		case AS_STROKE_LINEARRAY:
2210 		{
2211 			DTRACE(("ServerWindow %s: Message AS_STROKE_LINEARRAY\n", Title()));
2212 
2213 			// Attached Data:
2214 			// 1) int32 Number of lines in the array
2215 			// 2) LineArrayData
2216 
2217 			int32 lineCount;
2218 
2219 			link.Read<int32>(&lineCount);
2220 			if (lineCount > 0) {
2221 				LineArrayData lineData[lineCount];
2222 
2223 				for (int32 i = 0; i < lineCount; i++) {
2224 					LineArrayData* index = &lineData[i];
2225 
2226 					link.Read<float>(&(index->pt1.x));
2227 					link.Read<float>(&(index->pt1.y));
2228 					link.Read<float>(&(index->pt2.x));
2229 					link.Read<float>(&(index->pt2.y));
2230 					link.Read<rgb_color>(&(index->color));
2231 
2232 					fCurrentLayer->ConvertToScreenForDrawing(&index->pt1);
2233 					fCurrentLayer->ConvertToScreenForDrawing(&index->pt2);
2234 				}
2235 				drawingEngine->StrokeLineArray(lineCount, lineData,
2236 					fCurrentLayer->CurrentState());
2237 			}
2238 			break;
2239 		}
2240 		case AS_DRAW_STRING:
2241 		{
2242 			DTRACE(("ServerWindow %s: Message AS_DRAW_STRING\n", Title()));
2243 			char* string;
2244 			int32 length;
2245 			BPoint location;
2246 			escapement_delta delta;
2247 
2248 			link.Read<int32>(&length);
2249 			link.Read<BPoint>(&location);
2250 			link.Read<escapement_delta>(&delta);
2251 			link.ReadString(&string);
2252 
2253 			fCurrentLayer->ConvertToScreenForDrawing(&location);
2254 			BPoint penLocation = drawingEngine->DrawString(string, length, location,
2255 				fCurrentLayer->CurrentState(), &delta);
2256 
2257 			fCurrentLayer->ConvertFromScreenForDrawing(&penLocation);
2258 			fCurrentLayer->CurrentState()->SetPenLocation(penLocation);
2259 
2260 			free(string);
2261 			break;
2262 		}
2263 
2264 		case AS_LAYER_DRAW_PICTURE:
2265 		{
2266 			int32 token;
2267 			if (link.Read<int32>(&token) == B_OK) {
2268 				BPoint where;
2269 				link.Read<BPoint>(&where);
2270 
2271 				ServerPicture *picture = App()->FindPicture(token);
2272 				if (picture != NULL) {
2273 					fCurrentLayer->ConvertToScreenForDrawing(&where);
2274 					fCurrentLayer->CurrentState()->SetPenLocation(where);
2275 					// TODO: pass the location to the play method and handle it there
2276 					picture->Play(fCurrentLayer);
2277 				}
2278 			}
2279 			break;
2280 		}
2281 
2282 		default:
2283 			printf("ServerWindow %s received unexpected code - message offset %ld\n",
2284 				Title(), code - B_OK);
2285 
2286 			if (link.NeedsReply()) {
2287 				// the client is now blocking and waiting for a reply!
2288 				fLink.StartMessage(B_ERROR);
2289 				fLink.Flush();
2290 			}
2291 			break;
2292 	}
2293 
2294 	drawingEngine->UnlockParallelAccess();
2295 }
2296 
2297 
2298 bool
2299 ServerWindow::_DispatchPictureMessage(int32 code, BPrivate::LinkReceiver &link)
2300 {
2301 	ServerPicture *picture = fCurrentLayer->Picture();
2302 	if (picture == NULL)
2303 		return false;
2304 
2305 	switch (code) {
2306 		case AS_LAYER_SET_ORIGIN:
2307 		{
2308 			float x, y;
2309 			link.Read<float>(&x);
2310 			link.Read<float>(&y);
2311 
2312 			picture->WriteSetOrigin(BPoint(x, y));
2313 			break;
2314 		}
2315 
2316 		case AS_LAYER_INVERT_RECT:
2317 		{
2318 			BRect rect;
2319 			link.Read<BRect>(&rect);
2320 			picture->WriteInvertRect(rect);
2321 
2322 			break;
2323 		}
2324 
2325 		case AS_LAYER_PUSH_STATE:
2326 		{
2327 			picture->WritePushState();
2328 			break;
2329 		}
2330 
2331 		case AS_LAYER_POP_STATE:
2332 		{
2333 			picture->WritePopState();
2334 			break;
2335 		}
2336 
2337 		case AS_LAYER_SET_DRAWING_MODE:
2338 		{
2339 			int8 drawingMode;
2340 			link.Read<int8>(&drawingMode);
2341 
2342 			picture->WriteSetDrawingMode((drawing_mode)drawingMode);
2343 			break;
2344 		}
2345 
2346 		case AS_LAYER_SET_PEN_SIZE:
2347 		{
2348 			float penSize;
2349 			link.Read<float>(&penSize);
2350 			picture->WriteSetPenSize(penSize);
2351 			break;
2352 		}
2353 
2354 		case AS_LAYER_SET_LINE_MODE:
2355 		{
2356 			int8 lineCap, lineJoin;
2357 			float miterLimit;
2358 
2359 			link.Read<int8>(&lineCap);
2360 			link.Read<int8>(&lineJoin);
2361 			link.Read<float>(&miterLimit);
2362 
2363 			picture->WriteSetLineMode((cap_mode)lineCap, (join_mode)lineJoin, miterLimit);
2364 
2365 			break;
2366 		}
2367 		case AS_LAYER_SET_SCALE:
2368 		{
2369 			float scale;
2370 			link.Read<float>(&scale);
2371 			picture->WriteSetScale(scale);
2372 			break;
2373 		}
2374 
2375 		case AS_FILL_RECT:
2376 		case AS_STROKE_RECT:
2377 		{
2378 			BRect rect;
2379 			link.Read<BRect>(&rect);
2380 
2381 			picture->WriteDrawRect(rect, code == AS_FILL_RECT);
2382 			break;
2383 		}
2384 
2385 		case AS_STROKE_ROUNDRECT:
2386 		case AS_FILL_ROUNDRECT:
2387 		{
2388 			BRect rect;
2389 			link.Read<BRect>(&rect);
2390 
2391 			BPoint radii;
2392 			link.Read<float>(&radii.x);
2393 			link.Read<float>(&radii.y);
2394 
2395 			picture->WriteDrawRoundRect(rect, radii, code == AS_FILL_ROUNDRECT);
2396 			break;
2397 		}
2398 
2399 		case AS_STROKE_ELLIPSE:
2400 		case AS_FILL_ELLIPSE:
2401 		{
2402 			BRect rect;
2403 			link.Read<BRect>(&rect);
2404 			picture->WriteDrawEllipse(rect, code == AS_FILL_ELLIPSE);
2405 			break;
2406 		}
2407 
2408 		case AS_STROKE_ARC:
2409 		case AS_FILL_ARC:
2410 		{
2411 			BRect rect;
2412 			link.Read<BRect>(&rect);
2413 			float startTheta, arcTheta;
2414 			link.Read<float>(&startTheta);
2415 			link.Read<float>(&arcTheta);
2416 
2417 			BPoint radii((rect.Width() + 1) / 2, (rect.Height() + 1) / 2);
2418 			BPoint center = rect.LeftTop() + radii;
2419 
2420 			picture->WriteDrawArc(center, radii, startTheta, arcTheta, code == AS_FILL_ARC);
2421 			break;
2422 		}
2423 
2424 		case AS_STROKE_LINE:
2425 		{
2426 			float x1, y1, x2, y2;
2427 
2428 			link.Read<float>(&x1);
2429 			link.Read<float>(&y1);
2430 			link.Read<float>(&x2);
2431 			link.Read<float>(&y2);
2432 
2433 			picture->WriteStrokeLine(BPoint(x1, y1), BPoint(x2, y2));
2434 			break;
2435 		}
2436 
2437 		case AS_STROKE_LINEARRAY:
2438 		{
2439 			int32 lineCount;
2440 			link.Read<int32>(&lineCount);
2441 			if (lineCount <= 0)
2442 				break;
2443 
2444 			picture->WritePushState();
2445 
2446 			for (int32 i = 0; i < lineCount; i++) {
2447 				float x1, y1, x2, y2;
2448 				link.Read<float>(&x1);
2449 				link.Read<float>(&y1);
2450 				link.Read<float>(&x2);
2451 				link.Read<float>(&y2);
2452 
2453 				rgb_color color;
2454 				link.Read<rgb_color>(&color);
2455 
2456 				picture->WriteSetHighColor(color);
2457 				picture->WriteStrokeLine(BPoint(x1, y1), BPoint(x2, y2));
2458 			}
2459 
2460 			picture->WritePopState();
2461 			break;
2462 		}
2463 
2464 		case AS_LAYER_SET_LOW_COLOR:
2465 		case AS_LAYER_SET_HIGH_COLOR:
2466 		{
2467 			rgb_color color;
2468 			link.Read(&color, sizeof(rgb_color));
2469 
2470 			if (code == AS_LAYER_SET_HIGH_COLOR)
2471 				picture->WriteSetHighColor(color);
2472 			else
2473 				picture->WriteSetLowColor(color);
2474 			break;
2475 		}
2476 
2477 		case AS_DRAW_STRING:
2478 		{
2479 			char* string = NULL;
2480 			int32 length;
2481 			BPoint location;
2482 			escapement_delta delta;
2483 
2484 			link.Read<int32>(&length);
2485 			link.Read<BPoint>(&location);
2486 			link.Read<escapement_delta>(&delta);
2487 			link.ReadString(&string);
2488 
2489 			picture->WriteDrawString(location, string, length, delta);
2490 
2491 			free(string);
2492 			break;
2493 		}
2494 
2495 		case AS_STROKE_SHAPE:
2496 		case AS_FILL_SHAPE:
2497 		{
2498 			BRect shapeFrame;
2499 			int32 opCount;
2500 			int32 ptCount;
2501 
2502 			link.Read<BRect>(&shapeFrame);
2503 			link.Read<int32>(&opCount);
2504 			link.Read<int32>(&ptCount);
2505 
2506 			uint32 *opList = new(nothrow) uint32[opCount];
2507 			BPoint *ptList = new(nothrow) BPoint[ptCount];
2508 			if (opList != NULL && ptList != NULL
2509 				&& link.Read(opList, opCount * sizeof(uint32)) >= B_OK
2510 				&& link.Read(ptList, ptCount * sizeof(BPoint)) >= B_OK) {
2511 
2512 				const bool fill = (code == AS_FILL_SHAPE);
2513 				picture->WriteDrawShape(opCount, opList, ptCount, ptList, fill);
2514 			}
2515 			delete[] opList;
2516 			delete[] ptList;
2517 
2518 			break;
2519 		}
2520 
2521 		case AS_LAYER_DRAW_BITMAP:
2522 		{
2523 			int32 token;
2524 			link.Read<int32>(&token);
2525 
2526 			BRect destRect;
2527 			link.Read<BRect>(&destRect);
2528 
2529 			BRect sourceRect;
2530 			link.Read<BRect>(&sourceRect);
2531 
2532 			ServerBitmap *bitmap = App()->FindBitmap(token);
2533 			if (bitmap == NULL)
2534 				break;
2535 
2536 			picture->WriteDrawBitmap(sourceRect, destRect, bitmap->Width(), bitmap->Height(),
2537 						bitmap->BytesPerRow(), bitmap->ColorSpace(), /*bitmap->Flags()*/0,
2538 						bitmap->Bits(), bitmap->BitsLength());
2539 
2540 			break;
2541 		}
2542 /*
2543 		case AS_LAYER_SET_BLENDING_MODE:
2544 		{
2545 			int8 srcAlpha, alphaFunc;
2546 
2547 			link.Read<int8>(&srcAlpha);
2548 			link.Read<int8>(&alphaFunc);
2549 
2550 			picture->BeginOp(B_PIC_SET_BLENDING_MODE);
2551 			picture->AddInt16((int16)srcAlpha);
2552 			picture->AddInt16((int16)alphaFunc);
2553 			picture->EndOp();
2554 
2555 			break;
2556 		}*/
2557 		default:
2558 			return false;
2559 	}
2560 
2561 	if (link.NeedsReply()) {
2562 		fLink.StartMessage(B_ERROR);
2563 		fLink.Flush();
2564 	}
2565 	return true;
2566 }
2567 
2568 
2569 /*!
2570 	\brief Message-dispatching loop for the ServerWindow
2571 
2572 	Watches the ServerWindow's message port and dispatches as necessary
2573 */
2574 void
2575 ServerWindow::_MessageLooper()
2576 {
2577 	BPrivate::LinkReceiver& receiver = fLink.Receiver();
2578 	bool quitLoop = false;
2579 
2580 	while (!quitLoop) {
2581 		//STRACE(("info: ServerWindow::MonitorWin listening on port %ld.\n",
2582 		//	fMessagePort));
2583 
2584 		int32 code;
2585 		status_t status = receiver.GetNextMessage(code);
2586 		if (status < B_OK) {
2587 			// that shouldn't happen, it's our port
2588 			printf("Someone deleted our message port!\n");
2589 
2590 			// try to let our client die happily
2591 			NotifyQuitRequested();
2592 			break;
2593 		}
2594 
2595 #ifdef PROFILE_MESSAGE_LOOP
2596 		bigtime_t start = system_time();
2597 #endif
2598 
2599 		Lock();
2600 
2601 #ifdef PROFILE_MESSAGE_LOOP
2602 		bigtime_t diff = system_time() - start;
2603 		if (diff > 10000)
2604 			printf("ServerWindow %s: lock acquisition took %Ld usecs\n", Title(), diff);
2605 #endif
2606 
2607 		int32 messagesProcessed = 0;
2608 		bool lockedDesktop = false;
2609 
2610 		while (true) {
2611 			if (code == AS_DELETE_WINDOW || code == kMsgQuitLooper) {
2612 				// this means the client has been killed
2613 				STRACE(("ServerWindow %s received 'AS_DELETE_WINDOW' message code\n",
2614 					Title()));
2615 
2616 				if (code == AS_DELETE_WINDOW) {
2617 					fLink.StartMessage(B_OK);
2618 					fLink.Flush();
2619 				}
2620 
2621 				if (lockedDesktop)
2622 					fDesktop->UnlockSingleWindow();
2623 
2624 				quitLoop = true;
2625 
2626 				// ServerWindow's destructor takes care of pulling this object off the desktop.
2627 				if (!fWindowLayer->IsHidden())
2628 					CRITICAL("ServerWindow: a window must be hidden before it's deleted\n");
2629 
2630 				break;
2631 			}
2632 
2633 			if (!lockedDesktop) {
2634 				// only lock it once
2635 				fDesktop->LockSingleWindow();
2636 				lockedDesktop = true;
2637 			}
2638 
2639 			if (atomic_and(&fRedrawRequested, 0) != 0)
2640 				fWindowLayer->RedrawDirtyRegion();
2641 
2642 			_DispatchMessage(code, receiver);
2643 
2644 #ifdef PROFILE_MESSAGE_LOOP
2645 			if (code >= 0 && code < AS_LAST_CODE) {
2646 				diff = system_time() - start;
2647 				atomic_add(&sMessageProfile[code].count, 1);
2648 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
2649 				atomic_add64(&sMessageProfile[code].time, diff);
2650 #else
2651 				sMessageProfile[code].time += diff;
2652 #endif
2653 				if (diff > 10000)
2654 					printf("ServerWindow %s: message %ld took %Ld usecs\n", Title(), code, diff);
2655 			}
2656 #endif
2657 
2658 			// only process up to 70 waiting messages at once (we have the Desktop locked)
2659 			if (!receiver.HasMessages() || ++messagesProcessed > 70) {
2660 				fDesktop->UnlockSingleWindow();
2661 				break;
2662 			}
2663 
2664 			status_t status = receiver.GetNextMessage(code);
2665 			if (status < B_OK) {
2666 				// that shouldn't happen, it's our port
2667 				printf("Someone deleted our message port!\n");
2668 				fDesktop->UnlockSingleWindow();
2669 
2670 				// try to let our client die happily
2671 				NotifyQuitRequested();
2672 				break;
2673 			}
2674 		}
2675 
2676 		Unlock();
2677 	}
2678 
2679 	// we were asked to quit the message loop - either on request or because of an error
2680 	Quit();
2681 		// does not return
2682 }
2683 
2684 
2685 status_t
2686 ServerWindow::SendMessageToClient(const BMessage* msg, int32 target) const
2687 {
2688 	if (target == B_NULL_TOKEN)
2689 		target = fClientToken;
2690 
2691 	BMessenger reply;
2692 	BMessage::Private messagePrivate((BMessage *)msg);
2693 	return messagePrivate.SendMessage(fClientLooperPort, fClientTeam, target,
2694 		0, false, reply);
2695 }
2696 
2697 
2698 WindowLayer*
2699 ServerWindow::MakeWindowLayer(BRect frame, const char* name,
2700 	window_look look, window_feel feel, uint32 flags, uint32 workspace)
2701 {
2702 	// The non-offscreen ServerWindow uses the DrawingEngine instance from the desktop.
2703 	return new (nothrow) WindowLayer(frame, name, look, feel, flags,
2704 //		workspace, this, fDesktop->GetDrawingEngine());
2705 		workspace, this, new DrawingEngine(fDesktop->HWInterface()));
2706 }
2707 
2708 
2709 status_t
2710 ServerWindow::_EnableDirectWindowMode()
2711 {
2712 	if (fDirectWindowData != NULL) {
2713 		// already in direct window mode
2714 		return B_ERROR;
2715 	}
2716 
2717 	fDirectWindowData = new (nothrow) direct_window_data;
2718 	if (fDirectWindowData == NULL)
2719 		return B_NO_MEMORY;
2720 
2721 	status_t status = fDirectWindowData->InitCheck();
2722 	if (status < B_OK) {
2723 		delete fDirectWindowData;
2724 		fDirectWindowData = NULL;
2725 
2726 		return status;
2727 	}
2728 
2729 	return B_OK;
2730 }
2731 
2732 
2733 void
2734 ServerWindow::HandleDirectConnection(int32 bufferState, int32 driverState)
2735 {
2736 	STRACE(("HandleDirectConnection(bufferState = %ld, driverState = %ld)\n",
2737 		bufferState, driverState));
2738 
2739 	if (fDirectWindowData == NULL
2740 		|| (!fDirectWindowData->started
2741 			&& (bufferState & B_DIRECT_MODE_MASK) != B_DIRECT_START))
2742 		return;
2743 
2744 	fDirectWindowData->started = true;
2745 
2746 	if (bufferState != -1)
2747 		fDirectWindowData->buffer_info->buffer_state = (direct_buffer_state)bufferState;
2748 
2749 	if (driverState != -1)
2750 		fDirectWindowData->buffer_info->driver_state = (direct_driver_state)driverState;
2751 
2752 	if ((bufferState & B_DIRECT_MODE_MASK) != B_DIRECT_STOP) {
2753 		// TODO: Locking ?
2754 		RenderingBuffer *buffer = fDesktop->HWInterface()->FrontBuffer();
2755 		fDirectWindowData->buffer_info->bits = buffer->Bits();
2756 		fDirectWindowData->buffer_info->pci_bits = NULL; // TODO
2757 		fDirectWindowData->buffer_info->bytes_per_row = buffer->BytesPerRow();
2758 		switch (buffer->ColorSpace()) {
2759 			case B_RGB32:
2760 			case B_RGBA32:
2761 			case B_RGB32_BIG:
2762 			case B_RGBA32_BIG:
2763 				fDirectWindowData->buffer_info->bits_per_pixel = 32;
2764 				break;
2765 			case B_RGB24:
2766 			case B_RGB24_BIG:
2767 				fDirectWindowData->buffer_info->bits_per_pixel = 24;
2768 				break;
2769 			case B_RGB16:
2770 			case B_RGB16_BIG:
2771 			case B_RGB15:
2772 			case B_RGB15_BIG:
2773 				fDirectWindowData->buffer_info->bits_per_pixel = 16;
2774 				break;
2775 			case B_CMAP8:
2776 				fDirectWindowData->buffer_info->bits_per_pixel = 8;
2777 				break;
2778 			default:
2779 				fprintf(stderr, "unkown colorspace in HandleDirectConnection()!\n");
2780 				fDirectWindowData->buffer_info->bits_per_pixel = 0;
2781 				break;
2782 		}
2783 		fDirectWindowData->buffer_info->pixel_format = buffer->ColorSpace();
2784 		fDirectWindowData->buffer_info->layout = B_BUFFER_NONINTERLEAVED;
2785 		fDirectWindowData->buffer_info->orientation = B_BUFFER_TOP_TO_BOTTOM; // TODO
2786 
2787 		fDirectWindowData->buffer_info->window_bounds = to_clipping_rect(fWindowLayer->Frame());
2788 
2789 		// TODO: Review this
2790 		const int32 kMaxClipRectsCount = (B_PAGE_SIZE - sizeof(direct_buffer_info))
2791 			/ sizeof(clipping_rect);
2792 
2793 		// We just want the region inside the window, border excluded.
2794 		BRegion clipRegion = fWindowLayer->VisibleContentRegion();
2795 
2796 		fDirectWindowData->buffer_info->clip_list_count = min_c(clipRegion.CountRects(),
2797 			kMaxClipRectsCount);
2798 		fDirectWindowData->buffer_info->clip_bounds = clipRegion.FrameInt();
2799 
2800 		for (uint32 i = 0; i < fDirectWindowData->buffer_info->clip_list_count; i++)
2801 			fDirectWindowData->buffer_info->clip_list[i] = clipRegion.RectAtInt(i);
2802 	}
2803 
2804 	// Releasing this sem causes the client to call BDirectWindow::DirectConnected()
2805 	release_sem(fDirectWindowData->sem);
2806 
2807 	// TODO: Waiting half a second in the ServerWindow thread is not a problem,
2808 	// but since we are called from the Desktop's thread too, very bad things could happen.
2809 	// Find some way to call this method only within ServerWindow's thread (messaging ?)
2810 	status_t status;
2811 	do {
2812 		// TODO: The timeout is 3000000 usecs (3 seconds) on beos.
2813 		// Test, but I think half a second is enough.
2814 		status = acquire_sem_etc(fDirectWindowData->sem_ack, 1, B_TIMEOUT, 500000);
2815 	} while (status == B_INTERRUPTED);
2816 
2817 	if (status < B_OK) {
2818 		// The client application didn't release the semaphore
2819 		// within the given timeout. Or something else went wrong.
2820 		// Deleting this member should make it crash.
2821 		delete fDirectWindowData;
2822 		fDirectWindowData = NULL;
2823 	}
2824 }
2825 
2826 
2827 void
2828 ServerWindow::_SetCurrentLayer(ViewLayer* layer)
2829 {
2830 	if (fCurrentLayer != layer) {
2831 		fCurrentLayer = layer;
2832 		fCurrentDrawingRegionValid = false;
2833 #if 0
2834 #if DELAYED_BACKGROUND_CLEARING
2835 		if (fCurrentLayer && fCurrentLayer->IsBackgroundDirty() && fWindowLayer->InUpdate()) {
2836 			DrawingEngine* drawingEngine = fWindowLayer->GetDrawingEngine();
2837 			if (drawingEngine->LockParallelAccess()) {
2838 
2839 				fWindowLayer->GetEffectiveDrawingRegion(fCurrentLayer, fCurrentDrawingRegion);
2840 				fCurrentDrawingRegionValid = true;
2841 				BRegion dirty(fCurrentDrawingRegion);
2842 
2843 				BRegion content;
2844 				fWindowLayer->GetContentRegion(&content);
2845 
2846 				fCurrentLayer->Draw(drawingEngine, &dirty, &content, false);
2847 
2848 				drawingEngine->UnlockParallelAccess();
2849 			}
2850 		}
2851 #endif
2852 #endif // 0
2853 	}
2854 }
2855 
2856 
2857 status_t
2858 ServerWindow::PictureToRegion(ServerPicture *picture, BRegion &region,
2859 	bool inverse, BPoint where)
2860 {
2861 	fprintf(stderr, "ServerWindow::PictureToRegion() not implemented\n");
2862 	region.MakeEmpty();
2863 	return B_ERROR;
2864 }
2865