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