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