xref: /haiku/src/servers/app/ServerWindow.cpp (revision 9ecf9d1c1d4888d341a6eac72112c72d1ae3a4cb)
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_MOVEPENTO:
1802 		{
1803 			DTRACE(("ServerWindow %s: Message AS_MOVEPENTO\n", Title()));
1804 
1805 			float x,y;
1806 			link.Read<float>(&x);
1807 			link.Read<float>(&y);
1808 
1809 			fCurrentLayer->CurrentState()->SetPenLocation(BPoint(x, y));
1810 			break;
1811 		}
1812 		case AS_SETPENSIZE:
1813 		{
1814 			DTRACE(("ServerWindow %s: Message AS_SETPENSIZE\n", Title()));
1815 
1816 			float size;
1817 			link.Read<float>(&size);
1818 
1819 			fCurrentLayer->CurrentState()->SetPenSize(size);
1820 			break;
1821 		}
1822 		case AS_SET_FONT:
1823 		{
1824 			DTRACE(("ServerWindow %s: Message AS_SET_FONT\n", Title()));
1825 			// TODO: Implement AS_SET_FONT?
1826 			// Confusing!! But it works already!
1827 			break;
1828 		}
1829 		case AS_SET_FONT_SIZE:
1830 		{
1831 			DTRACE(("ServerWindow %s: Message AS_SET_FONT_SIZE\n", Title()));
1832 			// TODO: Implement AS_SET_FONT_SIZE?
1833 			break;
1834 		}
1835 		case AS_SYNC:
1836 		{
1837 			// TODO: AS_SYNC is a no-op for now, just to get things working
1838 			fLink.StartMessage(B_OK);
1839 			fLink.Flush();
1840 			break;
1841 		}
1842 		case AS_LAYER_DRAG_IMAGE:
1843 		{
1844 			// TODO: flesh out AS_LAYER_DRAG_IMAGE
1845 			STRACE(("ServerWindow %s: Message AS_DRAG_IMAGE\n", Title()));
1846 
1847 			int32 bitmapToken;
1848 			drawing_mode dragMode;
1849 			BPoint offset;
1850 			int32 bufferSize;
1851 
1852 			link.Read<int32>(&bitmapToken);
1853 			link.Read<int32>((int32*)&dragMode);
1854 			link.Read<BPoint>(&offset);
1855 			link.Read<int32>(&bufferSize);
1856 
1857 			if (bufferSize > 0) {
1858 				char* buffer = new (nothrow) char[bufferSize];
1859 				BMessage dragMessage;
1860 				if (link.Read(buffer, bufferSize) == B_OK
1861 					&& dragMessage.Unflatten(buffer) == B_OK) {
1862 						ServerBitmap* bitmap = fServerApp->FindBitmap(bitmapToken);
1863 						fDesktop->EventDispatcher().SetDragMessage(dragMessage,
1864 																   bitmap, offset);
1865 				}
1866 				delete[] buffer;
1867 			}
1868 			// sync the client (it can now delete the bitmap)
1869 			fLink.StartMessage(B_OK);
1870 			fLink.Flush();
1871 
1872 			break;
1873 		}
1874 		case AS_LAYER_DRAG_RECT:
1875 		{
1876 			// TODO: flesh out AS_LAYER_DRAG_RECT
1877 			STRACE(("ServerWindow %s: Message AS_DRAG_RECT\n", Title()));
1878 
1879 			BRect dragRect;
1880 			BPoint offset;
1881 			int32 bufferSize;
1882 
1883 			link.Read<BRect>(&dragRect);
1884 			link.Read<BPoint>(&offset);
1885 			link.Read<int32>(&bufferSize);
1886 
1887 			if (bufferSize > 0) {
1888 				char* buffer = new (nothrow) char[bufferSize];
1889 				BMessage dragMessage;
1890 				if (link.Read(buffer, bufferSize) == B_OK
1891 					&& dragMessage.Unflatten(buffer) == B_OK) {
1892 						fDesktop->EventDispatcher().SetDragMessage(dragMessage,
1893 							NULL /* should be dragRect */, offset);
1894 				}
1895 				delete[] buffer;
1896 			}
1897 
1898 			break;
1899 		}
1900 
1901 		case AS_LAYER_BEGIN_PICTURE:
1902 		{
1903 			DTRACE(("ServerWindow %s: Message AS_LAYER_BEGIN_PICTURE\n", Title()));
1904 			ServerPicture *picture = App()->CreatePicture();
1905 			picture->SyncState(fCurrentLayer);
1906 			fCurrentLayer->SetPicture(picture);
1907 			break;
1908 		}
1909 
1910 		case AS_LAYER_APPEND_TO_PICTURE:
1911 		{
1912 			DTRACE(("ServerWindow %s: Message AS_LAYER_APPEND_TO_PICTURE\n", Title()));
1913 
1914 			int32 pictureToken;
1915 			link.Read<int32>(&pictureToken);
1916 			ServerPicture *picture = App()->FindPicture(pictureToken);
1917 			if (picture)
1918 				picture->SyncState(fCurrentLayer);
1919 			fCurrentLayer->SetPicture(picture);
1920 				// we don't care if it's NULL
1921 			break;
1922 		}
1923 
1924 		case AS_LAYER_END_PICTURE:
1925 		{
1926 			DTRACE(("ServerWindow %s: Message AS_LAYER_END_PICTURE\n", Title()));
1927 
1928 			ServerPicture *picture = fCurrentLayer->Picture();
1929 			if (picture != NULL) {
1930 				fCurrentLayer->SetPicture(NULL);
1931 				fLink.StartMessage(B_OK);
1932 				fLink.Attach<int32>(picture->Token());
1933 			} else
1934 				fLink.StartMessage(B_ERROR);
1935 
1936 			fLink.Flush();
1937 			break;
1938 		}
1939 
1940 		default:
1941 			_DispatchViewDrawingMessage(code, link);
1942 			break;
1943 	}
1944 }
1945 
1946 
1947 /*!
1948 	Dispatches all view drawing messages.
1949 	The desktop clipping must be read locked when entering this method.
1950 	Requires a valid fCurrentLayer.
1951 */
1952 void
1953 ServerWindow::_DispatchViewDrawingMessage(int32 code, BPrivate::LinkReceiver &link)
1954 {
1955 	if (!fCurrentLayer->IsVisible() || !fWindowLayer->IsVisible()) {
1956 		if (link.NeedsReply()) {
1957 			printf("ServerWindow::DispatchViewDrawingMessage() got message %ld that needs a reply!\n", code);
1958 			// the client is now blocking and waiting for a reply!
1959 			fLink.StartMessage(B_ERROR);
1960 			fLink.Flush();
1961 		}
1962 		return;
1963 	}
1964 
1965 	DrawingEngine* drawingEngine = fWindowLayer->GetDrawingEngine();
1966 	if (!drawingEngine) {
1967 		// ?!?
1968 		DTRACE(("ServerWindow %s: no drawing engine!!\n", Title()));
1969 		if (link.NeedsReply()) {
1970 			// the client is now blocking and waiting for a reply!
1971 			fLink.StartMessage(B_ERROR);
1972 			fLink.Flush();
1973 		}
1974 		return;
1975 	}
1976 
1977 	if (!fCurrentDrawingRegionValid || fWindowLayer->DrawingRegionChanged(fCurrentLayer)) {
1978 		fWindowLayer->GetEffectiveDrawingRegion(fCurrentLayer, fCurrentDrawingRegion);
1979 		fCurrentDrawingRegionValid = true;
1980 	}
1981 
1982 	if (fCurrentDrawingRegion.CountRects() <= 0) {
1983 		if (link.NeedsReply()) {
1984 			// the client is now blocking and waiting for a reply!
1985 			fLink.StartMessage(B_ERROR);
1986 			fLink.Flush();
1987 		}
1988 		return;
1989 	}
1990 
1991 	// prevent other ServerWindows from messing with the drawing engine
1992 	// as long as each uses the same instance... TODO: remove the locking
1993 	// when each has its own
1994 	drawingEngine->Lock();
1995 	drawingEngine->ConstrainClippingRegion(&fCurrentDrawingRegion);
1996 
1997 	switch (code) {
1998 		case AS_STROKE_LINE:
1999 		{
2000 			DTRACE(("ServerWindow %s: Message AS_STROKE_LINE\n", Title()));
2001 
2002 			float x1, y1, x2, y2;
2003 
2004 			link.Read<float>(&x1);
2005 			link.Read<float>(&y1);
2006 			link.Read<float>(&x2);
2007 			link.Read<float>(&y2);
2008 
2009 			BPoint p1(x1, y1);
2010 			BPoint p2(x2, y2);
2011 			BPoint penPos = p2;
2012 			fCurrentLayer->ConvertToScreenForDrawing(&p1);
2013 			fCurrentLayer->ConvertToScreenForDrawing(&p2);
2014 			drawingEngine->StrokeLine(p1, p2, fCurrentLayer->CurrentState());
2015 
2016 			// We update the pen here because many DrawingEngine calls which do not update the
2017 			// pen position actually call StrokeLine
2018 
2019 			// TODO: Decide where to put this, for example, it cannot be done
2020 			// for DrawString(), also there needs to be a decision, if penlocation
2021 			// is in View coordinates (I think it should be) or in screen coordinates.
2022 			fCurrentLayer->CurrentState()->SetPenLocation(penPos);
2023 			break;
2024 		}
2025 		case AS_LAYER_INVERT_RECT:
2026 		{
2027 			DTRACE(("ServerWindow %s: Message AS_INVERT_RECT\n", Title()));
2028 
2029 			BRect rect;
2030 			link.Read<BRect>(&rect);
2031 
2032 			fCurrentLayer->ConvertToScreenForDrawing(&rect);
2033 			drawingEngine->InvertRect(rect);
2034 			break;
2035 		}
2036 		case AS_STROKE_RECT:
2037 		{
2038 			DTRACE(("ServerWindow %s: Message AS_STROKE_RECT\n", Title()));
2039 
2040 			float left, top, right, bottom;
2041 			link.Read<float>(&left);
2042 			link.Read<float>(&top);
2043 			link.Read<float>(&right);
2044 			link.Read<float>(&bottom);
2045 			BRect rect(left,top,right,bottom);
2046 
2047 			fCurrentLayer->ConvertToScreenForDrawing(&rect);
2048 			drawingEngine->StrokeRect(rect, fCurrentLayer->CurrentState());
2049 			break;
2050 		}
2051 		case AS_FILL_RECT:
2052 		{
2053 			DTRACE(("ServerWindow %s: Message AS_FILL_RECT\n", Title()));
2054 
2055 			BRect rect;
2056 			link.Read<BRect>(&rect);
2057 
2058 			fCurrentLayer->ConvertToScreenForDrawing(&rect);
2059 			drawingEngine->FillRect(rect, fCurrentLayer->CurrentState());
2060 			break;
2061 		}
2062 		case AS_LAYER_DRAW_BITMAP:
2063 		{
2064 			DTRACE(("ServerWindow %s: Message AS_LAYER_DRAW_BITMAP: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name()));
2065 			int32 bitmapToken;
2066 			BRect srcRect, dstRect;
2067 
2068 			link.Read<int32>(&bitmapToken);
2069 			link.Read<BRect>(&dstRect);
2070 			link.Read<BRect>(&srcRect);
2071 
2072 			ServerBitmap* bitmap = fServerApp->FindBitmap(bitmapToken);
2073 			if (bitmap) {
2074 				fCurrentLayer->ConvertToScreenForDrawing(&dstRect);
2075 
2076 				drawingEngine->DrawBitmap(bitmap, srcRect, dstRect, fCurrentLayer->CurrentState());
2077 			}
2078 
2079 			break;
2080 		}
2081 		case AS_STROKE_ARC:
2082 		case AS_FILL_ARC:
2083 		{
2084 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ARC\n", Title()));
2085 
2086 			float angle, span;
2087 			BRect r;
2088 
2089 			link.Read<BRect>(&r);
2090 			link.Read<float>(&angle);
2091 			link.Read<float>(&span);
2092 
2093 			fCurrentLayer->ConvertToScreenForDrawing(&r);
2094 			drawingEngine->DrawArc(r, angle, span, fCurrentLayer->CurrentState(),
2095 								   code == AS_FILL_ARC);
2096 			break;
2097 		}
2098 		case AS_STROKE_BEZIER:
2099 		case AS_FILL_BEZIER:
2100 		{
2101 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_BEZIER\n", Title()));
2102 
2103 			BPoint pts[4];
2104 			for (int32 i = 0; i < 4; i++) {
2105 				link.Read<BPoint>(&(pts[i]));
2106 				fCurrentLayer->ConvertToScreenForDrawing(&pts[i]);
2107 			}
2108 
2109 			drawingEngine->DrawBezier(pts, fCurrentLayer->CurrentState(),
2110 									  code == AS_FILL_BEZIER);
2111 			break;
2112 		}
2113 		case AS_STROKE_ELLIPSE:
2114 		case AS_FILL_ELLIPSE:
2115 		{
2116 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ELLIPSE\n", Title()));
2117 
2118 			BRect rect;
2119 			link.Read<BRect>(&rect);
2120 
2121 			fCurrentLayer->ConvertToScreenForDrawing(&rect);
2122 			drawingEngine->DrawEllipse(rect, fCurrentLayer->CurrentState(), code == AS_FILL_ELLIPSE);
2123 			break;
2124 		}
2125 		case AS_STROKE_ROUNDRECT:
2126 		case AS_FILL_ROUNDRECT:
2127 		{
2128 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ROUNDRECT\n", Title()));
2129 
2130 			BRect rect;
2131 			float xrad,yrad;
2132 			link.Read<BRect>(&rect);
2133 			link.Read<float>(&xrad);
2134 			link.Read<float>(&yrad);
2135 
2136 			fCurrentLayer->ConvertToScreenForDrawing(&rect);
2137 			drawingEngine->DrawRoundRect(rect, xrad, yrad, fCurrentLayer->CurrentState(), code == AS_FILL_ROUNDRECT);
2138 			break;
2139 		}
2140 		case AS_STROKE_TRIANGLE:
2141 		case AS_FILL_TRIANGLE:
2142 		{
2143 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_TRIANGLE\n", Title()));
2144 
2145 			BPoint pts[3];
2146 			BRect rect;
2147 
2148 			for (int32 i = 0; i < 3; i++) {
2149 				link.Read<BPoint>(&(pts[i]));
2150 				fCurrentLayer->ConvertToScreenForDrawing(&pts[i]);
2151 			}
2152 
2153 			link.Read<BRect>(&rect);
2154 
2155 			fCurrentLayer->ConvertToScreenForDrawing(&rect);
2156 			drawingEngine->DrawTriangle(pts, rect, fCurrentLayer->CurrentState(), code == AS_FILL_TRIANGLE);
2157 			break;
2158 		}
2159 		case AS_STROKE_POLYGON:
2160 		case AS_FILL_POLYGON:
2161 		{
2162 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_POLYGON\n", Title()));
2163 
2164 			BRect polyFrame;
2165 			bool isClosed = true;
2166 			int32 pointCount;
2167 
2168 			link.Read<BRect>(&polyFrame);
2169 			if (code == AS_STROKE_POLYGON)
2170 				link.Read<bool>(&isClosed);
2171 			link.Read<int32>(&pointCount);
2172 
2173 			BPoint* pointList = new(nothrow) BPoint[pointCount];
2174 			if (link.Read(pointList, pointCount * sizeof(BPoint)) >= B_OK) {
2175 				for (int32 i = 0; i < pointCount; i++)
2176 					fCurrentLayer->ConvertToScreenForDrawing(&pointList[i]);
2177 				fCurrentLayer->ConvertToScreenForDrawing(&polyFrame);
2178 
2179 				drawingEngine->DrawPolygon(pointList, pointCount, polyFrame,
2180 					fCurrentLayer->CurrentState(), code == AS_FILL_POLYGON,
2181 					isClosed && pointCount > 2);
2182 			}
2183 			delete[] pointList;
2184 			break;
2185 		}
2186 		case AS_STROKE_SHAPE:
2187 		case AS_FILL_SHAPE:
2188 		{
2189 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_SHAPE\n", Title()));
2190 
2191 			BRect shapeFrame;
2192 			int32 opCount;
2193 			int32 ptCount;
2194 
2195 			link.Read<BRect>(&shapeFrame);
2196 			link.Read<int32>(&opCount);
2197 			link.Read<int32>(&ptCount);
2198 
2199 			uint32* opList = new(nothrow) uint32[opCount];
2200 			BPoint* ptList = new(nothrow) BPoint[ptCount];
2201 			if (link.Read(opList, opCount * sizeof(uint32)) >= B_OK &&
2202 				link.Read(ptList, ptCount * sizeof(BPoint)) >= B_OK) {
2203 
2204 				for (int32 i = 0; i < ptCount; i++)
2205 					fCurrentLayer->ConvertToScreenForDrawing(&ptList[i]);
2206 
2207 				drawingEngine->DrawShape(shapeFrame, opCount, opList, ptCount, ptList,
2208 					fCurrentLayer->CurrentState(), code == AS_FILL_SHAPE);
2209 			}
2210 
2211 			delete[] opList;
2212 			delete[] ptList;
2213 			break;
2214 		}
2215 		case AS_FILL_REGION:
2216 		{
2217 			DTRACE(("ServerWindow %s: Message AS_FILL_REGION\n", Title()));
2218 
2219 			BRegion region;
2220 			if (link.ReadRegion(&region) < B_OK)
2221 				break;
2222 
2223 			fCurrentLayer->ConvertToScreenForDrawing(&region);
2224 			drawingEngine->FillRegion(region, fCurrentLayer->CurrentState());
2225 
2226 			break;
2227 		}
2228 		case AS_STROKE_LINEARRAY:
2229 		{
2230 			DTRACE(("ServerWindow %s: Message AS_STROKE_LINEARRAY\n", Title()));
2231 
2232 			// Attached Data:
2233 			// 1) int32 Number of lines in the array
2234 			// 2) LineArrayData
2235 
2236 			int32 lineCount;
2237 
2238 			link.Read<int32>(&lineCount);
2239 			if (lineCount > 0) {
2240 				LineArrayData lineData[lineCount];
2241 
2242 				for (int32 i = 0; i < lineCount; i++) {
2243 					LineArrayData* index = &lineData[i];
2244 
2245 					link.Read<float>(&(index->pt1.x));
2246 					link.Read<float>(&(index->pt1.y));
2247 					link.Read<float>(&(index->pt2.x));
2248 					link.Read<float>(&(index->pt2.y));
2249 					link.Read<rgb_color>(&(index->color));
2250 
2251 					fCurrentLayer->ConvertToScreenForDrawing(&index->pt1);
2252 					fCurrentLayer->ConvertToScreenForDrawing(&index->pt2);
2253 				}
2254 				drawingEngine->StrokeLineArray(lineCount, lineData,
2255 					fCurrentLayer->CurrentState());
2256 			}
2257 			break;
2258 		}
2259 		case AS_DRAW_STRING:
2260 		{
2261 			DTRACE(("ServerWindow %s: Message AS_DRAW_STRING\n", Title()));
2262 			char* string;
2263 			int32 length;
2264 			BPoint location;
2265 			escapement_delta delta;
2266 
2267 			link.Read<int32>(&length);
2268 			link.Read<BPoint>(&location);
2269 			link.Read<escapement_delta>(&delta);
2270 			link.ReadString(&string);
2271 
2272 			fCurrentLayer->ConvertToScreenForDrawing(&location);
2273 			BPoint penLocation = drawingEngine->DrawString(string, length, location,
2274 				fCurrentLayer->CurrentState(), &delta);
2275 
2276 			fCurrentLayer->ConvertFromScreenForDrawing(&penLocation);
2277 			fCurrentLayer->CurrentState()->SetPenLocation(penLocation);
2278 
2279 			free(string);
2280 			break;
2281 		}
2282 
2283 		case AS_LAYER_DRAW_PICTURE:
2284 		{
2285 			int32 token;
2286 			if (link.Read<int32>(&token) == B_OK) {
2287 				BPoint where;
2288 				link.Read<BPoint>(&where);
2289 
2290 				ServerPicture *picture = App()->FindPicture(token);
2291 				if (picture != NULL) {
2292 					fCurrentLayer->ConvertToScreenForDrawing(&where);
2293 					fCurrentLayer->CurrentState()->SetPenLocation(where);
2294 					// TODO: pass the location to the play method and handle it there
2295 					picture->Play(fCurrentLayer);
2296 				}
2297 			}
2298 			break;
2299 		}
2300 
2301 		default:
2302 			printf("ServerWindow %s received unexpected code - message offset %ld\n",
2303 				Title(), code - B_OK);
2304 
2305 			if (link.NeedsReply()) {
2306 				// the client is now blocking and waiting for a reply!
2307 				fLink.StartMessage(B_ERROR);
2308 				fLink.Flush();
2309 			}
2310 			break;
2311 	}
2312 
2313 	drawingEngine->Unlock();
2314 }
2315 
2316 
2317 bool
2318 ServerWindow::_DispatchPictureMessage(int32 code, BPrivate::LinkReceiver &link)
2319 {
2320 	ServerPicture *picture = fCurrentLayer->Picture();
2321 	if (picture == NULL)
2322 		return false;
2323 
2324 	switch (code) {
2325 		case AS_LAYER_SET_ORIGIN:
2326 		{
2327 			float x, y;
2328 			link.Read<float>(&x);
2329 			link.Read<float>(&y);
2330 
2331 			picture->BeginOp(B_PIC_SET_ORIGIN);
2332 			picture->AddCoord(BPoint(x, y));
2333 			picture->EndOp();
2334 			break;
2335 		}
2336 
2337 		case AS_LAYER_INVERT_RECT:
2338 		{
2339 			picture->BeginOp(B_PIC_SET_DRAWING_MODE);
2340 			picture->AddInt16((int16)B_OP_INVERT);
2341 			picture->EndOp();
2342 
2343 			BRect rect;
2344 			link.Read<BRect>(&rect);
2345 			picture->BeginOp(B_PIC_FILL_RECT);
2346 			picture->AddRect(rect);
2347 			picture->EndOp();
2348 
2349 			picture->BeginOp(B_PIC_SET_DRAWING_MODE);
2350 			picture->AddInt16((int16)B_OP_COPY);
2351 			picture->EndOp();
2352 
2353 			break;
2354 		}
2355 		case AS_LAYER_PUSH_STATE:
2356 		{
2357 			picture->BeginOp(B_PIC_PUSH_STATE);
2358 			picture->EndOp();
2359 			break;
2360 		}
2361 
2362 		case AS_LAYER_POP_STATE:
2363 		{
2364 			picture->BeginOp(B_PIC_POP_STATE);
2365 			picture->EndOp();
2366 			break;
2367 		}
2368 
2369 		case AS_LAYER_SET_DRAWING_MODE:
2370 		{
2371 			int8 drawingMode;
2372 			link.Read<int8>(&drawingMode);
2373 
2374 			picture->BeginOp(B_PIC_SET_DRAWING_MODE);
2375 			picture->AddInt16((int16)drawingMode);
2376 			picture->EndOp();
2377 			break;
2378 		}
2379 
2380 		case AS_LAYER_SET_PEN_SIZE:
2381 		{
2382 			float penSize;
2383 			link.Read<float>(&penSize);
2384 			picture->BeginOp(B_PIC_SET_PEN_SIZE);
2385 			picture->AddFloat(penSize);
2386 			picture->EndOp();
2387 			break;
2388 		}
2389 
2390 		case AS_FILL_RECT:
2391 		case AS_STROKE_RECT:
2392 		{
2393 			BRect rect;
2394 			link.Read<BRect>(&rect);
2395 
2396 			picture->BeginOp(code == AS_FILL_RECT ? B_PIC_FILL_RECT : B_PIC_STROKE_RECT);
2397 			picture->AddRect(rect);
2398 			picture->EndOp();
2399 			break;
2400 		}
2401 
2402 		case AS_STROKE_ROUNDRECT:
2403 		case AS_FILL_ROUNDRECT:
2404 		{
2405 			BRect rect;
2406 			link.Read<BRect>(&rect);
2407 
2408 			BPoint radii;
2409 			link.Read<float>(&radii.x);
2410 			link.Read<float>(&radii.y);
2411 
2412 			picture->BeginOp(code == AS_FILL_ROUNDRECT ? B_PIC_FILL_ROUND_RECT : B_PIC_STROKE_ROUND_RECT);
2413 			picture->AddRect(rect);
2414 			picture->AddCoord(radii);
2415 			picture->EndOp();
2416 			break;
2417 		}
2418 
2419 		case AS_STROKE_LINE:
2420 		{
2421 			float x1, y1, x2, y2;
2422 
2423 			link.Read<float>(&x1);
2424 			link.Read<float>(&y1);
2425 			link.Read<float>(&x2);
2426 			link.Read<float>(&y2);
2427 
2428 			picture->BeginOp(B_PIC_STROKE_LINE);
2429 			picture->AddCoord(BPoint(x1, y1));
2430 			picture->AddCoord(BPoint(x2, y2));
2431 			picture->EndOp();
2432 			break;
2433 		}
2434 
2435 		case AS_STROKE_LINEARRAY:
2436 		{
2437 			int32 lineCount;
2438 			link.Read<int32>(&lineCount);
2439 			if (lineCount <= 0)
2440 				break;
2441 
2442 			picture->BeginOp(B_PIC_PUSH_STATE);
2443 			picture->EndOp();
2444 
2445 			for (int32 i = 0; i < lineCount; i++) {
2446 				float x1, y1, x2, y2;
2447 				link.Read<float>(&x1);
2448 				link.Read<float>(&y1);
2449 				link.Read<float>(&x2);
2450 				link.Read<float>(&y2);
2451 
2452 				rgb_color color;
2453 				link.Read<rgb_color>(&color);
2454 
2455 				picture->BeginOp(B_PIC_SET_FORE_COLOR);
2456 				picture->AddColor(color);
2457 				picture->EndOp();
2458 
2459 				picture->BeginOp(B_PIC_STROKE_LINE);
2460 				picture->AddCoord(BPoint(x1, y1));
2461 				picture->AddCoord(BPoint(x2, y2));
2462 				picture->EndOp();
2463 			}
2464 
2465 			picture->BeginOp(B_PIC_POP_STATE);
2466 			picture->EndOp();
2467 			break;
2468 		}
2469 
2470 		case AS_LAYER_SET_LOW_COLOR:
2471 		case AS_LAYER_SET_HIGH_COLOR:
2472 		{
2473 			rgb_color color;
2474 			link.Read(&color, sizeof(rgb_color));
2475 
2476 			picture->BeginOp(code == AS_LAYER_SET_HIGH_COLOR ? B_PIC_SET_FORE_COLOR : B_PIC_SET_BACK_COLOR);
2477 			picture->AddColor(color);
2478 			picture->EndOp();
2479 			break;
2480 		}
2481 
2482 		case AS_DRAW_STRING:
2483 		{
2484 			char* string;
2485 			int32 length;
2486 			BPoint location;
2487 			escapement_delta delta;
2488 
2489 			link.Read<int32>(&length);
2490 			link.Read<BPoint>(&location);
2491 			link.Read<escapement_delta>(&delta);
2492 			link.ReadString(&string);
2493 
2494 			picture->BeginOp(B_PIC_SET_PEN_LOCATION);
2495 			picture->AddCoord(location);
2496 			picture->EndOp();
2497 
2498 			picture->BeginOp(B_PIC_DRAW_STRING);
2499 			picture->AddInt32(length);
2500 			picture->AddData(string, length);
2501 			picture->AddFloat(delta.space);
2502 			picture->AddFloat(delta.nonspace);
2503 			picture->EndOp();
2504 
2505 			break;
2506 		}
2507 
2508 		case AS_LAYER_DRAW_BITMAP:
2509 		{
2510 			int32 token;
2511 			link.Read<int32>(&token);
2512 
2513 			BRect destRect;
2514 			link.Read<BRect>(&destRect);
2515 
2516 			BRect sourceRect;
2517 			link.Read<BRect>(&sourceRect);
2518 
2519 			ServerBitmap *bitmap = App()->FindBitmap(token);
2520 			if (bitmap == NULL)
2521 				break;
2522 
2523 			picture->BeginOp(B_PIC_DRAW_PIXELS);
2524 			picture->AddRect(sourceRect);
2525 			picture->AddRect(destRect);
2526 			picture->AddInt32(bitmap->Width());
2527 			picture->AddInt32(bitmap->Height());
2528 			picture->AddInt32(bitmap->BytesPerRow());
2529 			picture->AddInt32(bitmap->ColorSpace());
2530 			picture->AddInt32(/*bitmap->Flags()*/0);
2531 			picture->AddData((void *)bitmap->Bits(), bitmap->BitsLength());
2532 			picture->EndOp();
2533 
2534 			break;
2535 		}
2536 
2537 		case AS_LAYER_SET_BLENDING_MODE:
2538 		{
2539 			int8 srcAlpha, alphaFunc;
2540 
2541 			link.Read<int8>(&srcAlpha);
2542 			link.Read<int8>(&alphaFunc);
2543 
2544 			picture->BeginOp(B_PIC_SET_BLENDING_MODE);
2545 			picture->AddInt16((int16)srcAlpha);
2546 			picture->AddInt16((int16)alphaFunc);
2547 			picture->EndOp();
2548 
2549 			break;
2550 		}
2551 		default:
2552 			return false;
2553 	}
2554 
2555 	if (link.NeedsReply()) {
2556 		fLink.StartMessage(B_ERROR);
2557 		fLink.Flush();
2558 	}
2559 	return true;
2560 }
2561 
2562 
2563 /*!
2564 	\brief Message-dispatching loop for the ServerWindow
2565 
2566 	Watches the ServerWindow's message port and dispatches as necessary
2567 */
2568 void
2569 ServerWindow::_MessageLooper()
2570 {
2571 	BPrivate::LinkReceiver& receiver = fLink.Receiver();
2572 	bool quitLoop = false;
2573 
2574 	while (!quitLoop) {
2575 		//STRACE(("info: ServerWindow::MonitorWin listening on port %ld.\n",
2576 		//	fMessagePort));
2577 
2578 		int32 code;
2579 		status_t status = receiver.GetNextMessage(code);
2580 		if (status < B_OK) {
2581 			// that shouldn't happen, it's our port
2582 			printf("Someone deleted our message port!\n");
2583 
2584 			// try to let our client die happily
2585 			NotifyQuitRequested();
2586 			break;
2587 		}
2588 
2589 #ifdef PROFILE_MESSAGE_LOOP
2590 		bigtime_t start = system_time();
2591 #endif
2592 
2593 		Lock();
2594 
2595 #ifdef PROFILE_MESSAGE_LOOP
2596 		bigtime_t diff = system_time() - start;
2597 		if (diff > 10000)
2598 			printf("ServerWindow %s: lock acquisition took %Ld usecs\n", Title(), diff);
2599 #endif
2600 
2601 		int32 messagesProcessed = 0;
2602 		bool lockedDesktop = false;
2603 
2604 		while (true) {
2605 			if (code == AS_DELETE_WINDOW || code == kMsgQuitLooper) {
2606 				// this means the client has been killed
2607 				STRACE(("ServerWindow %s received 'AS_DELETE_WINDOW' message code\n",
2608 					Title()));
2609 
2610 				if (code == AS_DELETE_WINDOW) {
2611 					fLink.StartMessage(B_OK);
2612 					fLink.Flush();
2613 				}
2614 
2615 				if (lockedDesktop)
2616 					fDesktop->UnlockSingleWindow();
2617 
2618 				quitLoop = true;
2619 
2620 				// ServerWindow's destructor takes care of pulling this object off the desktop.
2621 				if (!fWindowLayer->IsHidden())
2622 					CRITICAL("ServerWindow: a window must be hidden before it's deleted\n");
2623 
2624 				break;
2625 			}
2626 
2627 			if (!lockedDesktop) {
2628 				// only lock it once
2629 				fDesktop->LockSingleWindow();
2630 				lockedDesktop = true;
2631 			}
2632 
2633 			if (atomic_and(&fRedrawRequested, 0) != 0)
2634 				fWindowLayer->RedrawDirtyRegion();
2635 
2636 			_DispatchMessage(code, receiver);
2637 
2638 #ifdef PROFILE_MESSAGE_LOOP
2639 			if (code >= 0 && code < AS_LAST_CODE) {
2640 				diff = system_time() - start;
2641 				atomic_add(&sMessageProfile[code].count, 1);
2642 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
2643 				atomic_add64(&sMessageProfile[code].time, diff);
2644 #else
2645 				sMessageProfile[code].time += diff;
2646 #endif
2647 				if (diff > 10000)
2648 					printf("ServerWindow %s: message %ld took %Ld usecs\n", Title(), code, diff);
2649 			}
2650 #endif
2651 
2652 			// only process up to 70 waiting messages at once (we have the Desktop locked)
2653 			if (!receiver.HasMessages() || ++messagesProcessed > 70) {
2654 				fDesktop->UnlockSingleWindow();
2655 				break;
2656 			}
2657 
2658 			status_t status = receiver.GetNextMessage(code);
2659 			if (status < B_OK) {
2660 				// that shouldn't happen, it's our port
2661 				printf("Someone deleted our message port!\n");
2662 				fDesktop->UnlockSingleWindow();
2663 
2664 				// try to let our client die happily
2665 				NotifyQuitRequested();
2666 				break;
2667 			}
2668 		}
2669 
2670 		Unlock();
2671 	}
2672 
2673 	// we were asked to quit the message loop - either on request or because of an error
2674 	Quit();
2675 		// does not return
2676 }
2677 
2678 
2679 status_t
2680 ServerWindow::SendMessageToClient(const BMessage* msg, int32 target) const
2681 {
2682 	if (target == B_NULL_TOKEN)
2683 		target = fClientToken;
2684 
2685 	BMessenger reply;
2686 	BMessage::Private messagePrivate((BMessage *)msg);
2687 	return messagePrivate.SendMessage(fClientLooperPort, target, 0,
2688 		false, reply);
2689 }
2690 
2691 
2692 WindowLayer*
2693 ServerWindow::MakeWindowLayer(BRect frame, const char* name,
2694 	window_look look, window_feel feel, uint32 flags, uint32 workspace)
2695 {
2696 	// The non-offscreen ServerWindow uses the DrawingEngine instance from the desktop.
2697 	return new (nothrow) WindowLayer(frame, name, look, feel, flags,
2698 		workspace, this, fDesktop->GetDrawingEngine());
2699 }
2700 
2701 
2702 status_t
2703 ServerWindow::_EnableDirectWindowMode()
2704 {
2705 	if (fDirectWindowData != NULL) {
2706 		// already in direct window mode
2707 		return B_ERROR;
2708 	}
2709 
2710 	fDirectWindowData = new (nothrow) direct_window_data;
2711 	if (fDirectWindowData == NULL)
2712 		return B_NO_MEMORY;
2713 
2714 	status_t status = fDirectWindowData->InitCheck();
2715 	if (status < B_OK) {
2716 		delete fDirectWindowData;
2717 		fDirectWindowData = NULL;
2718 
2719 		return status;
2720 	}
2721 
2722 	return B_OK;
2723 }
2724 
2725 
2726 void
2727 ServerWindow::HandleDirectConnection(int32 bufferState, int32 driverState)
2728 {
2729 	STRACE(("HandleDirectConnection(bufferState = %ld, driverState = %ld)\n",
2730 		bufferState, driverState));
2731 
2732 	if (fDirectWindowData == NULL
2733 		|| (!fDirectWindowData->started
2734 			&& (bufferState & B_DIRECT_MODE_MASK) != B_DIRECT_START))
2735 		return;
2736 
2737 	fDirectWindowData->started = true;
2738 
2739 	if (bufferState != -1)
2740 		fDirectWindowData->buffer_info->buffer_state = (direct_buffer_state)bufferState;
2741 
2742 	if (driverState != -1)
2743 		fDirectWindowData->buffer_info->driver_state = (direct_driver_state)driverState;
2744 
2745 	if ((bufferState & B_DIRECT_MODE_MASK) != B_DIRECT_STOP) {
2746 		// TODO: Locking ?
2747 		RenderingBuffer *buffer = fDesktop->HWInterface()->FrontBuffer();
2748 		fDirectWindowData->buffer_info->bits = buffer->Bits();
2749 		fDirectWindowData->buffer_info->pci_bits = NULL; // TODO
2750 		fDirectWindowData->buffer_info->bytes_per_row = buffer->BytesPerRow();
2751 		switch (buffer->ColorSpace()) {
2752 			case B_RGB32:
2753 			case B_RGBA32:
2754 			case B_RGB32_BIG:
2755 			case B_RGBA32_BIG:
2756 				fDirectWindowData->buffer_info->bits_per_pixel = 32;
2757 				break;
2758 			case B_RGB24:
2759 			case B_RGB24_BIG:
2760 				fDirectWindowData->buffer_info->bits_per_pixel = 24;
2761 				break;
2762 			case B_RGB16:
2763 			case B_RGB16_BIG:
2764 			case B_RGB15:
2765 			case B_RGB15_BIG:
2766 				fDirectWindowData->buffer_info->bits_per_pixel = 16;
2767 				break;
2768 			case B_CMAP8:
2769 				fDirectWindowData->buffer_info->bits_per_pixel = 8;
2770 				break;
2771 			default:
2772 				fprintf(stderr, "unkown colorspace in HandleDirectConnection()!\n");
2773 				fDirectWindowData->buffer_info->bits_per_pixel = 0;
2774 				break;
2775 		}
2776 		fDirectWindowData->buffer_info->pixel_format = buffer->ColorSpace();
2777 		fDirectWindowData->buffer_info->layout = B_BUFFER_NONINTERLEAVED;
2778 		fDirectWindowData->buffer_info->orientation = B_BUFFER_TOP_TO_BOTTOM; // TODO
2779 
2780 		fDirectWindowData->buffer_info->window_bounds = to_clipping_rect(fWindowLayer->Frame());
2781 
2782 		// TODO: Review this
2783 		const int32 kMaxClipRectsCount = (B_PAGE_SIZE - sizeof(direct_buffer_info))
2784 			/ sizeof(clipping_rect);
2785 
2786 		// We just want the region inside the window, border excluded.
2787 		BRegion clipRegion = fWindowLayer->VisibleContentRegion();
2788 
2789 		fDirectWindowData->buffer_info->clip_list_count = min_c(clipRegion.CountRects(),
2790 			kMaxClipRectsCount);
2791 		fDirectWindowData->buffer_info->clip_bounds = clipRegion.FrameInt();
2792 
2793 		for (uint32 i = 0; i < fDirectWindowData->buffer_info->clip_list_count; i++)
2794 			fDirectWindowData->buffer_info->clip_list[i] = clipRegion.RectAtInt(i);
2795 	}
2796 
2797 	// Releasing this sem causes the client to call BDirectWindow::DirectConnected()
2798 	release_sem(fDirectWindowData->sem);
2799 
2800 	// TODO: Waiting half a second in the ServerWindow thread is not a problem,
2801 	// but since we are called from the Desktop's thread too, very bad things could happen.
2802 	// Find some way to call this method only within ServerWindow's thread (messaging ?)
2803 	status_t status;
2804 	do {
2805 		// TODO: The timeout is 3000000 usecs (3 seconds) on beos.
2806 		// Test, but I think half a second is enough.
2807 		status = acquire_sem_etc(fDirectWindowData->sem_ack, 1, B_TIMEOUT, 500000);
2808 	} while (status == B_INTERRUPTED);
2809 
2810 	if (status < B_OK) {
2811 		// The client application didn't release the semaphore
2812 		// within the given timeout. Or something else went wrong.
2813 		// Deleting this member should make it crash.
2814 		delete fDirectWindowData;
2815 		fDirectWindowData = NULL;
2816 	}
2817 }
2818 
2819 
2820 void
2821 ServerWindow::_SetCurrentLayer(ViewLayer* layer)
2822 {
2823 	if (fCurrentLayer != layer) {
2824 		fCurrentLayer = layer;
2825 		fCurrentDrawingRegionValid = false;
2826 #if 0
2827 #if DELAYED_BACKGROUND_CLEARING
2828 		if (fCurrentLayer && fCurrentLayer->IsBackgroundDirty() && fWindowLayer->InUpdate()) {
2829 			DrawingEngine* drawingEngine = fWindowLayer->GetDrawingEngine();
2830 			if (drawingEngine->Lock()) {
2831 
2832 				fWindowLayer->GetEffectiveDrawingRegion(fCurrentLayer, fCurrentDrawingRegion);
2833 				fCurrentDrawingRegionValid = true;
2834 				BRegion dirty(fCurrentDrawingRegion);
2835 
2836 				BRegion content;
2837 				fWindowLayer->GetContentRegion(&content);
2838 
2839 				fCurrentLayer->Draw(drawingEngine, &dirty, &content, false);
2840 
2841 				drawingEngine->Unlock();
2842 			}
2843 		}
2844 #endif
2845 #endif // 0
2846 	}
2847 }
2848 
2849 
2850 status_t
2851 ServerWindow::PictureToRegion(ServerPicture *picture, BRegion &region,
2852 	bool inverse, BPoint where)
2853 {
2854 	fprintf(stderr, "ServerWindow::PictureToRegion() not implemented\n");
2855 	region.MakeEmpty();
2856 	return B_ERROR;
2857 }
2858