xref: /haiku/src/servers/app/ServerWindow.cpp (revision 6953cef14ef864cccdbab6218585475cef7f8d68)
1 /*
2  * Copyright 2001-2019, 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 <stefano.ceccherini@gmail.com>
10  *		Axel Dörfler <axeld@pinc-software.de>
11  *		Artur Wyszynski <harakash@gmail.com>
12  *		Philippe Saint-Pierre <stpere@gmail.com>
13  *		Brecht Machiels <brecht@mos6581.org>
14  *		Julian Harnath <julian.harnath@rwth-aachen.de>
15  *		Joseph Groover <looncraz@looncraz.net>
16  */
17 
18 
19 /*!	\class ServerWindow
20 
21 	The ServerWindow class handles all BWindow messaging; it forwards all
22 	BWindow requests to the corresponding app_server classes, that is Desktop,
23 	Window, and View.
24 	Furthermore, it also sends app_server requests/notices to its BWindow. There
25 	is one ServerWindow per BWindow.
26 */
27 
28 
29 #include "ServerWindow.h"
30 
31 #include <syslog.h>
32 #include <new>
33 
34 #include <AppDefs.h>
35 #include <Autolock.h>
36 #include <Debug.h>
37 #include <DirectWindow.h>
38 #include <TokenSpace.h>
39 #include <View.h>
40 #include <GradientLinear.h>
41 #include <GradientRadial.h>
42 #include <GradientRadialFocus.h>
43 #include <GradientDiamond.h>
44 #include <GradientConic.h>
45 
46 #include <MessagePrivate.h>
47 #include <PortLink.h>
48 #include <ShapePrivate.h>
49 #include <ServerProtocolStructs.h>
50 #include <StackOrHeapArray.h>
51 #include <ViewPrivate.h>
52 #include <WindowInfo.h>
53 #include <WindowPrivate.h>
54 
55 #include "clipping.h"
56 #include "utf8_functions.h"
57 
58 #include "AlphaMask.h"
59 #include "AppServer.h"
60 #include "AutoDeleter.h"
61 #include "BBitmapBuffer.h"
62 #include "BitmapManager.h"
63 #include "Desktop.h"
64 #include "DirectWindowInfo.h"
65 #include "DrawingEngine.h"
66 #include "DrawState.h"
67 #include "HWInterface.h"
68 #include "Layer.h"
69 #include "Overlay.h"
70 #include "ProfileMessageSupport.h"
71 #include "RenderingBuffer.h"
72 #include "ServerApp.h"
73 #include "ServerBitmap.h"
74 #include "ServerPicture.h"
75 #include "ServerProtocol.h"
76 #include "Window.h"
77 #include "WorkspacesView.h"
78 
79 
80 using std::nothrow;
81 
82 
83 //#define TRACE_SERVER_WINDOW
84 #ifdef TRACE_SERVER_WINDOW
85 #	include <stdio.h>
86 #	define STRACE(x) debug_printf x
87 #else
88 #	define STRACE(x) ;
89 #endif
90 
91 //#define TRACE_SERVER_WINDOW_MESSAGES
92 #ifdef TRACE_SERVER_WINDOW_MESSAGES
93 #	include <stdio.h>
94 static const char* kDrawingModeMap[] = {
95 	"B_OP_COPY",
96 	"B_OP_OVER",
97 	"B_OP_ERASE",
98 	"B_OP_INVERT",
99 	"B_OP_ADD",
100 	"B_OP_SUBTRACT",
101 	"B_OP_BLEND",
102 	"B_OP_MIN",
103 	"B_OP_MAX",
104 	"B_OP_SELECT",
105 	"B_OP_ALPHA",
106 
107 	"fix kDrawingModeMap",
108 	"fix kDrawingModeMap",
109 	"fix kDrawingModeMap",
110 	"fix kDrawingModeMap",
111 	"fix kDrawingModeMap",
112 };
113 #	define DTRACE(x) debug_printf x
114 #else
115 #	define DTRACE(x) ;
116 #endif
117 
118 //#define TRACE_SERVER_GRADIENTS
119 #ifdef TRACE_SERVER_GRADIENTS
120 #	include <OS.h>
121 #	define GTRACE(x) debug_printf x
122 #else
123 #	define GTRACE(x) ;
124 #endif
125 
126 //#define PROFILE_MESSAGE_LOOP
127 #ifdef PROFILE_MESSAGE_LOOP
128 struct profile { int32 code; int32 count; bigtime_t time; };
129 static profile sMessageProfile[AS_LAST_CODE];
130 static profile sRedrawProcessingTime;
131 //static profile sNextMessageTime;
132 #endif
133 
134 
135 //	#pragma mark -
136 
137 
138 #ifdef PROFILE_MESSAGE_LOOP
139 static int
140 compare_message_profiles(const void* _a, const void* _b)
141 {
142 	profile* a = (profile*)*(void**)_a;
143 	profile* b = (profile*)*(void**)_b;
144 	if (a->time < b->time)
145 		return 1;
146 	if (a->time > b->time)
147 		return -1;
148 	return 0;
149 }
150 #endif
151 
152 
153 //	#pragma mark -
154 
155 
156 /*!	Sets up the basic BWindow counterpart - you have to call Init() before
157 	you can actually use it, though.
158 */
159 ServerWindow::ServerWindow(const char* title, ServerApp* app,
160 		port_id clientPort, port_id looperPort, int32 clientToken)
161 	:
162 	MessageLooper(title && *title ? title : "Unnamed Window"),
163 	fTitle(NULL),
164 	fDesktop(app->GetDesktop()),
165 	fServerApp(app),
166 	fWindow(NULL),
167 	fWindowAddedToDesktop(false),
168 
169 	fClientTeam(app->ClientTeam()),
170 
171 	fMessagePort(-1),
172 	fClientReplyPort(clientPort),
173 	fClientLooperPort(looperPort),
174 
175 	fClientToken(clientToken),
176 
177 	fCurrentView(NULL),
178 	fCurrentDrawingRegion(),
179 	fCurrentDrawingRegionValid(false),
180 
181 	fDirectWindowInfo(NULL),
182 	fIsDirectlyAccessing(false)
183 {
184 	STRACE(("ServerWindow(%s)::ServerWindow()\n", title));
185 
186 	SetTitle(title);
187 	fServerToken = BPrivate::gDefaultTokens.NewToken(B_SERVER_TOKEN, this);
188 
189 	BMessenger::Private(fFocusMessenger).SetTo(fClientTeam,
190 		looperPort, B_PREFERRED_TOKEN);
191 	BMessenger::Private(fHandlerMessenger).SetTo(fClientTeam,
192 		looperPort, clientToken);
193 
194 	fEventTarget.SetTo(fFocusMessenger);
195 
196 	fDeathSemaphore = create_sem(0, "window death");
197 }
198 
199 
200 /*! Tears down all connections the main app_server objects, and deletes some
201 	internals.
202 */
203 ServerWindow::~ServerWindow()
204 {
205 	STRACE(("ServerWindow(%s@%p):~ServerWindow()\n", fTitle, this));
206 
207 	if (!fWindow->IsOffscreenWindow()) {
208 		fWindowAddedToDesktop = false;
209 		fDesktop->RemoveWindow(fWindow);
210 	}
211 
212 	if (App() != NULL) {
213 		App()->RemoveWindow(this);
214 		fServerApp = NULL;
215 	}
216 
217 	delete fWindow;
218 
219 	free(fTitle);
220 	delete_port(fMessagePort);
221 
222 	BPrivate::gDefaultTokens.RemoveToken(fServerToken);
223 
224 	delete fDirectWindowInfo;
225 	STRACE(("ServerWindow(%p) will exit NOW\n", this));
226 
227 	delete_sem(fDeathSemaphore);
228 
229 #ifdef PROFILE_MESSAGE_LOOP
230 	BList profiles;
231 	for (int32 i = 0; i < AS_LAST_CODE; i++) {
232 		if (sMessageProfile[i].count == 0)
233 			continue;
234 		sMessageProfile[i].code = i;
235 		profiles.AddItem(&sMessageProfile[i]);
236 	}
237 
238 	profiles.SortItems(compare_message_profiles);
239 
240 	int32 count = profiles.CountItems();
241 	for (int32 i = 0; i < count; i++) {
242 		profile* p = (profile*)profiles.ItemAtFast(i);
243 		printf("[%s] called %" B_PRId32 " times, %g secs (%" B_PRId64 " usecs "
244 			"per call)\n", string_for_message_code(p->code), p->count, p->time / 1000000.0,
245 			p->time / p->count);
246 	}
247 	if (sRedrawProcessingTime.count > 0) {
248 		printf("average redraw processing time: %g secs, count: %" B_PRId32 " "
249 			"(%" B_PRId64 " usecs per call)\n",
250 			sRedrawProcessingTime.time / 1000000.0, sRedrawProcessingTime.count,
251 			sRedrawProcessingTime.time / sRedrawProcessingTime.count);
252 	}
253 //	if (sNextMessageTime.count > 0) {
254 //		printf("average NextMessage() time: %g secs, count: %ld (%lld usecs per call)\n",
255 //			sNextMessageTime.time / 1000000.0, sNextMessageTime.count,
256 //			sNextMessageTime.time / sNextMessageTime.count);
257 //	}
258 #endif
259 }
260 
261 
262 status_t
263 ServerWindow::Init(BRect frame, window_look look, window_feel feel,
264 	uint32 flags, uint32 workspace)
265 {
266 	if (!App()->AddWindow(this)) {
267 		fServerApp = NULL;
268 		return B_NO_MEMORY;
269 	}
270 
271 	if (fTitle == NULL)
272 		return B_NO_MEMORY;
273 
274 	// fMessagePort is the port to which the app sends messages for the server
275 	fMessagePort = create_port(100, fTitle);
276 	if (fMessagePort < B_OK)
277 		return fMessagePort;
278 
279 	fLink.SetSenderPort(fClientReplyPort);
280 	fLink.SetReceiverPort(fMessagePort);
281 
282 	// We cannot call MakeWindow in the constructor, since it
283 	// is a virtual function!
284 	fWindow = MakeWindow(frame, fTitle, look, feel, flags, workspace);
285 	if (!fWindow || fWindow->InitCheck() != B_OK) {
286 		delete fWindow;
287 		fWindow = NULL;
288 		return B_NO_MEMORY;
289 	}
290 
291 	if (!fWindow->IsOffscreenWindow()) {
292 		fDesktop->AddWindow(fWindow);
293 		fWindowAddedToDesktop = true;
294 	}
295 
296 	return B_OK;
297 }
298 
299 
300 /*!	Returns the ServerWindow's Window, if it exists and has been
301 	added to the Desktop already.
302 	In other words, you cannot assume this method will always give you
303 	a valid pointer.
304 */
305 Window*
306 ServerWindow::Window() const
307 {
308 	if (!fWindowAddedToDesktop)
309 		return NULL;
310 
311 	return fWindow;
312 }
313 
314 
315 void
316 ServerWindow::_PrepareQuit()
317 {
318 	if (fThread == find_thread(NULL)) {
319 		// make sure we're hidden
320 		fDesktop->LockSingleWindow();
321 		_Hide();
322 		fDesktop->UnlockSingleWindow();
323 	} else if (fThread >= B_OK)
324 		PostMessage(AS_INTERNAL_HIDE_WINDOW);
325 }
326 
327 
328 void
329 ServerWindow::_GetLooperName(char* name, size_t length)
330 {
331 	const char *title = Title();
332 	if (title == NULL || !title[0])
333 		title = "Unnamed Window";
334 
335 	snprintf(name, length, "w:%" B_PRId32 ":%s", ClientTeam(), title);
336 }
337 
338 
339 /*! Shows the window's Window.
340 */
341 void
342 ServerWindow::_Show()
343 {
344 	// NOTE: if you do something else, other than sending a port message, PLEASE lock
345 	STRACE(("ServerWindow %s: _Show\n", Title()));
346 
347 	if (fQuitting || fWindow->IsMinimized() || !fWindow->IsHidden()
348 		|| fWindow->IsOffscreenWindow() || fWindow->TopView() == NULL)
349 		return;
350 
351 	// TODO: Maybe we need to dispatch a message to the desktop to show/hide us
352 	// instead of doing it from this thread.
353 	fDesktop->UnlockSingleWindow();
354 	fDesktop->ShowWindow(fWindow);
355 	if (fDirectWindowInfo && fDirectWindowInfo->IsFullScreen())
356 		_ResizeToFullScreen();
357 
358 	fDesktop->LockSingleWindow();
359 }
360 
361 
362 /*! Hides the window's Window. You need to have all windows locked when
363 	calling this function.
364 */
365 void
366 ServerWindow::_Hide()
367 {
368 	STRACE(("ServerWindow %s: _Hide\n", Title()));
369 
370 	if (fWindow->IsHidden() || fWindow->IsOffscreenWindow())
371 		return;
372 
373 	fDesktop->UnlockSingleWindow();
374 	fDesktop->HideWindow(fWindow);
375 	fDesktop->LockSingleWindow();
376 }
377 
378 
379 void
380 ServerWindow::RequestRedraw()
381 {
382 	PostMessage(AS_REDRAW, 0);
383 		// we don't care if this fails - it's only a notification, and if
384 		// it fails, there are obviously enough messages in the queue
385 		// already
386 
387 	atomic_add(&fRedrawRequested, 1);
388 }
389 
390 
391 void
392 ServerWindow::SetTitle(const char* newTitle)
393 {
394 	char* oldTitle = fTitle;
395 
396 	if (newTitle == NULL)
397 		newTitle = "";
398 
399 	fTitle = strdup(newTitle);
400 	if (fTitle == NULL) {
401 		// out of memory condition
402 		fTitle = oldTitle;
403 		return;
404 	}
405 
406 	free(oldTitle);
407 
408 	if (Thread() >= B_OK) {
409 		char name[B_OS_NAME_LENGTH];
410 		_GetLooperName(name, sizeof(name));
411 		rename_thread(Thread(), name);
412 	}
413 
414 	if (fWindow != NULL)
415 		fDesktop->SetWindowTitle(fWindow, newTitle);
416 }
417 
418 
419 //! Requests that the ServerWindow's BWindow quit
420 void
421 ServerWindow::NotifyQuitRequested()
422 {
423 	// NOTE: if you do something else, other than sending a port message,
424 	// PLEASE lock
425 	STRACE(("ServerWindow %s: Quit\n", fTitle));
426 
427 	BMessage msg(B_QUIT_REQUESTED);
428 	SendMessageToClient(&msg);
429 }
430 
431 
432 void
433 ServerWindow::NotifyMinimize(bool minimize)
434 {
435 	if (fWindow->Feel() != B_NORMAL_WINDOW_FEEL)
436 		return;
437 
438 	// The client is responsible for the actual minimization
439 
440 	BMessage msg(B_MINIMIZE);
441 	msg.AddInt64("when", real_time_clock_usecs());
442 	msg.AddBool("minimize", minimize);
443 
444 	SendMessageToClient(&msg);
445 }
446 
447 
448 //! Sends a message to the client to perform a Zoom
449 void
450 ServerWindow::NotifyZoom()
451 {
452 	// NOTE: if you do something else, other than sending a port message,
453 	// PLEASE lock
454 	BMessage msg(B_ZOOM);
455 	SendMessageToClient(&msg);
456 }
457 
458 
459 void
460 ServerWindow::GetInfo(window_info& info)
461 {
462 	info.team = ClientTeam();
463 	info.server_token = ServerToken();
464 
465 	info.thread = Thread();
466 	info.client_token = ClientToken();
467 	info.client_port = fClientLooperPort;
468 	info.workspaces = fWindow->Workspaces();
469 
470 	// logic taken from Switcher comments and experiments
471 	if (fWindow->IsHidden())
472 		info.layer = 0;
473 	else if (fWindow->IsVisible()) {
474 		if (fWindow->Feel() == kDesktopWindowFeel)
475 			info.layer = 2;
476 		else if (fWindow->IsFloating() || fWindow->IsModal())
477 			info.layer = 4;
478 		else
479 			info.layer = 3;
480 	} else
481 		info.layer = 1;
482 
483 	info.feel = fWindow->Feel();
484 	info.flags = fWindow->Flags();
485 	info.window_left = (int)floor(fWindow->Frame().left);
486 	info.window_top = (int)floor(fWindow->Frame().top);
487 	info.window_right = (int)floor(fWindow->Frame().right);
488 	info.window_bottom = (int)floor(fWindow->Frame().bottom);
489 
490 	info.show_hide_level = fWindow->ShowLevel();
491 	info.is_mini = fWindow->IsMinimized();
492 }
493 
494 
495 void
496 ServerWindow::ResyncDrawState()
497 {
498 	_UpdateDrawState(fCurrentView);
499 }
500 
501 
502 View*
503 ServerWindow::_CreateView(BPrivate::LinkReceiver& link, View** _parent)
504 {
505 	// NOTE: no need to check for a lock. This is a private method.
506 
507 	int32 token;
508 	BRect frame;
509 	uint32 resizeMask;
510 	uint32 eventMask;
511 	uint32 eventOptions;
512 	uint32 flags;
513 	bool hidden;
514 	int32 parentToken;
515 	char* name = NULL;
516 	rgb_color viewColor;
517 	BPoint scrollingOffset;
518 
519 	link.Read<int32>(&token);
520 	link.ReadString(&name);
521 	link.Read<BRect>(&frame);
522 	link.Read<BPoint>(&scrollingOffset);
523 	link.Read<uint32>(&resizeMask);
524 	link.Read<uint32>(&eventMask);
525 	link.Read<uint32>(&eventOptions);
526 	link.Read<uint32>(&flags);
527 	link.Read<bool>(&hidden);
528 	link.Read<rgb_color>(&viewColor);
529 	link.Read<int32>(&parentToken);
530 
531 	STRACE(("ServerWindow(%s)::_CreateView()-> view %s, token %" B_PRId32 "\n",
532 		fTitle, name, token));
533 
534 	View* newView;
535 
536 	if ((flags & kWorkspacesViewFlag) != 0) {
537 		newView = new (nothrow) WorkspacesView(frame, scrollingOffset, name,
538 			token, resizeMask, flags);
539 	} else {
540 		newView = new (nothrow) View(frame, scrollingOffset, name, token,
541 			resizeMask, flags);
542 	}
543 
544 	free(name);
545 
546 	if (newView == NULL)
547 		return NULL;
548 
549 	if (newView->InitCheck() != B_OK) {
550 		delete newView;
551 		return NULL;
552 	}
553 
554 	// there is no way of setting this, other than manually :-)
555 	newView->SetViewColor(viewColor);
556 	newView->SetHidden(hidden);
557 	newView->SetEventMask(eventMask, eventOptions);
558 
559 	if (eventMask != 0 || eventOptions != 0) {
560 //		fDesktop->UnlockSingleWindow();
561 //		fDesktop->LockAllWindows();
562 fDesktop->UnlockAllWindows();
563 		// TODO: possible deadlock
564 		fDesktop->EventDispatcher().AddListener(EventTarget(),
565 			newView->Token(), eventMask, eventOptions);
566 fDesktop->LockAllWindows();
567 //		fDesktop->UnlockAllWindows();
568 //		fDesktop->LockSingleWindow();
569 	}
570 
571 	// Initialize the view with the current application plain font.
572 	// NOTE: This might be out of sync with the global app_server plain
573 	// font, but that is so on purpose! The client needs to resync itself
574 	// with the app_server fonts upon notification, but if we just use
575 	// the current font here, the be_plain_font on the client may still
576 	// hold old values. So this needs to be an update initiated by the
577 	// client application.
578 	newView->CurrentState()->SetFont(App()->PlainFont());
579 
580 	if (_parent) {
581 		View *parent;
582 		if (App()->ViewTokens().GetToken(parentToken, B_HANDLER_TOKEN,
583 				(void**)&parent) != B_OK
584 			|| parent->Window()->ServerWindow() != this) {
585 			debug_printf("View token not found!\n");
586 			parent = NULL;
587 		}
588 
589 		*_parent = parent;
590 	}
591 
592 	return newView;
593 }
594 
595 
596 /*!	Dispatches all window messages, and those view messages that
597 	don't need a valid fCurrentView (ie. view creation).
598 */
599 void
600 ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
601 {
602 	switch (code) {
603 		case AS_SHOW_OR_HIDE_WINDOW:
604 		{
605 			int32 showLevel;
606 			if (link.Read<int32>(&showLevel) == B_OK) {
607 				DTRACE(("ServerWindow %s: Message AS_SHOW_OR_HIDE_WINDOW, "
608 					"show level: %" B_PRId32 "\n", Title(), showLevel));
609 
610 				fWindow->SetShowLevel(showLevel);
611 				if (showLevel <= 0)
612 					_Show();
613 				else
614 					_Hide();
615 			}
616 			break;
617 		}
618 		// Only for internal use within this class
619 		case AS_INTERNAL_HIDE_WINDOW:
620 			_Hide();
621 			break;
622 		case AS_MINIMIZE_WINDOW:
623 		{
624 			bool minimize;
625 			if (link.Read<bool>(&minimize) == B_OK) {
626 				DTRACE(("ServerWindow %s: Message AS_MINIMIZE_WINDOW, "
627 					"minimize: %d\n", Title(), minimize));
628 
629 				fDesktop->UnlockSingleWindow();
630 				fDesktop->MinimizeWindow(fWindow, minimize);
631 				fDesktop->LockSingleWindow();
632 			}
633 			break;
634 		}
635 
636 		case AS_ACTIVATE_WINDOW:
637 		{
638 			bool activate = true;
639 			if (link.Read<bool>(&activate) != B_OK)
640 				break;
641 
642 			DTRACE(("ServerWindow %s: Message AS_ACTIVATE_WINDOW: activate: "
643 				"%d\n", Title(), activate));
644 
645 			fDesktop->UnlockSingleWindow();
646 
647 			if (activate)
648 				fDesktop->SelectWindow(fWindow);
649 			else
650 				fDesktop->SendWindowBehind(fWindow, NULL);
651 
652 			fDesktop->LockSingleWindow();
653 			break;
654 		}
655 		case AS_SEND_BEHIND:
656 		{
657 			// Has the all-window lock
658 			int32 token;
659 			team_id teamID;
660 			status_t status = B_ERROR;
661 
662 			link.Read<int32>(&token);
663 			if (link.Read<team_id>(&teamID) == B_OK) {
664 				::Window* behindOf = fDesktop->FindWindowByClientToken(token,
665 					teamID);
666 
667 				DTRACE(("ServerWindow %s: Message AS_SEND_BEHIND %s\n",
668 					Title(), behindOf != NULL ? behindOf->Title() : "NULL"));
669 
670 				if (behindOf != NULL || token == -1) {
671 					fDesktop->SendWindowBehind(fWindow, behindOf);
672 					status = B_OK;
673 				} else
674 					status = B_NAME_NOT_FOUND;
675 			}
676 
677 			fLink.StartMessage(status);
678 			fLink.Flush();
679 			break;
680 		}
681 
682 		case B_QUIT_REQUESTED:
683 			DTRACE(("ServerWindow %s received quit request\n", Title()));
684 			NotifyQuitRequested();
685 			break;
686 
687 		case AS_ENABLE_UPDATES:
688 			DTRACE(("ServerWindow %s: Message AS_ENABLE_UPDATES\n", Title()));
689 			fWindow->EnableUpdateRequests();
690 			break;
691 
692 		case AS_DISABLE_UPDATES:
693 			DTRACE(("ServerWindow %s: Message AS_DISABLE_UPDATES\n", Title()));
694 			fWindow->DisableUpdateRequests();
695 			break;
696 
697 		case AS_NEEDS_UPDATE:
698 			DTRACE(("ServerWindow %s: Message AS_NEEDS_UPDATE: %d\n",
699 				Title(), fWindow->NeedsUpdate()));
700 			if (fWindow->NeedsUpdate())
701 				fLink.StartMessage(B_OK);
702 			else
703 				fLink.StartMessage(B_ERROR);
704 			fLink.Flush();
705 			break;
706 
707 		case AS_SET_WINDOW_TITLE:
708 		{
709 			char* newTitle;
710 			if (link.ReadString(&newTitle) == B_OK) {
711 				DTRACE(("ServerWindow %s: Message AS_SET_WINDOW_TITLE: %s\n",
712 					Title(), newTitle));
713 
714 				SetTitle(newTitle);
715 				free(newTitle);
716 			}
717 			break;
718 		}
719 
720 		case AS_ADD_TO_SUBSET:
721 		{
722 			// Has the all-window lock
723 			DTRACE(("ServerWindow %s: Message AS_ADD_TO_SUBSET\n", Title()));
724 			status_t status = B_ERROR;
725 
726 			int32 token;
727 			if (link.Read<int32>(&token) == B_OK) {
728 				::Window* window = fDesktop->FindWindowByClientToken(token,
729 					App()->ClientTeam());
730 				if (window == NULL || window->Feel() != B_NORMAL_WINDOW_FEEL) {
731 					status = B_BAD_VALUE;
732 				} else {
733 					status = fDesktop->AddWindowToSubset(fWindow, window)
734 						? B_OK : B_NO_MEMORY;
735 				}
736 			}
737 
738 			fLink.StartMessage(status);
739 			fLink.Flush();
740 			break;
741 		}
742 		case AS_REMOVE_FROM_SUBSET:
743 		{
744 			// Has the all-window lock
745 			DTRACE(("ServerWindow %s: Message AS_REM_FROM_SUBSET\n", Title()));
746 			status_t status = B_ERROR;
747 
748 			int32 token;
749 			if (link.Read<int32>(&token) == B_OK) {
750 				::Window* window = fDesktop->FindWindowByClientToken(token,
751 					App()->ClientTeam());
752 				if (window != NULL) {
753 					fDesktop->RemoveWindowFromSubset(fWindow, window);
754 					status = B_OK;
755 				} else
756 					status = B_BAD_VALUE;
757 			}
758 
759 			fLink.StartMessage(status);
760 			fLink.Flush();
761 			break;
762 		}
763 
764 		case AS_SET_LOOK:
765 		{
766 			// Has the all-window look
767 			DTRACE(("ServerWindow %s: Message AS_SET_LOOK\n", Title()));
768 
769 			status_t status = B_ERROR;
770 			int32 look;
771 			if (link.Read<int32>(&look) == B_OK) {
772 				// test if look is valid
773 				status = Window::IsValidLook((window_look)look)
774 					? B_OK : B_BAD_VALUE;
775 			}
776 
777 			if (status == B_OK && !fWindow->IsOffscreenWindow())
778 				fDesktop->SetWindowLook(fWindow, (window_look)look);
779 
780 			fLink.StartMessage(status);
781 			fLink.Flush();
782 			break;
783 		}
784 		case AS_SET_FEEL:
785 		{
786 			// Has the all-window look
787 			DTRACE(("ServerWindow %s: Message AS_SET_FEEL\n", Title()));
788 
789 			status_t status = B_ERROR;
790 			int32 feel;
791 			if (link.Read<int32>(&feel) == B_OK) {
792 				// test if feel is valid
793 				status = Window::IsValidFeel((window_feel)feel)
794 					? B_OK : B_BAD_VALUE;
795 			}
796 
797 			if (status == B_OK && !fWindow->IsOffscreenWindow())
798 				fDesktop->SetWindowFeel(fWindow, (window_feel)feel);
799 
800 			fLink.StartMessage(status);
801 			fLink.Flush();
802 			break;
803 		}
804 		case AS_SET_FLAGS:
805 		{
806 			// Has the all-window look
807 			DTRACE(("ServerWindow %s: Message AS_SET_FLAGS\n", Title()));
808 
809 			status_t status = B_ERROR;
810 			uint32 flags;
811 			if (link.Read<uint32>(&flags) == B_OK) {
812 				// test if flags are valid
813 				status = (flags & ~Window::ValidWindowFlags()) == 0
814 					? B_OK : B_BAD_VALUE;
815 			}
816 
817 			if (status == B_OK && !fWindow->IsOffscreenWindow())
818 				fDesktop->SetWindowFlags(fWindow, flags);
819 
820 			fLink.StartMessage(status);
821 			fLink.Flush();
822 			break;
823 		}
824 #if 0
825 		case AS_SET_ALIGNMENT:
826 		{
827 			// TODO: Implement AS_SET_ALIGNMENT
828 			DTRACE(("ServerWindow %s: Message Set_Alignment unimplemented\n",
829 				Title()));
830 			break;
831 		}
832 		case AS_GET_ALIGNMENT:
833 		{
834 			// TODO: Implement AS_GET_ALIGNMENT
835 			DTRACE(("ServerWindow %s: Message Get_Alignment unimplemented\n",
836 				Title()));
837 			break;
838 		}
839 #endif
840 		case AS_IS_FRONT_WINDOW:
841 		{
842 			bool isFront = fDesktop->FrontWindow() == fWindow;
843 			DTRACE(("ServerWindow %s: Message AS_IS_FRONT_WINDOW: %d\n",
844 				Title(), isFront));
845 			fLink.StartMessage(isFront ? B_OK : B_ERROR);
846 			fLink.Flush();
847 			break;
848 		}
849 
850 		case AS_GET_WORKSPACES:
851 		{
852 			DTRACE(("ServerWindow %s: Message AS_GET_WORKSPACES\n", Title()));
853 			fLink.StartMessage(B_OK);
854 			fLink.Attach<uint32>(fWindow->Workspaces());
855 			fLink.Flush();
856 			break;
857 		}
858 		case AS_SET_WORKSPACES:
859 		{
860 			// Has the all-window lock (but would actually not need to lock at
861 			// all)
862 			uint32 newWorkspaces;
863 			if (link.Read<uint32>(&newWorkspaces) != B_OK)
864 				break;
865 
866 			DTRACE(("ServerWindow %s: Message AS_SET_WORKSPACES %" B_PRIx32 "\n",
867 				Title(), newWorkspaces));
868 
869 			fDesktop->SetWindowWorkspaces(fWindow, newWorkspaces);
870 			break;
871 		}
872 		case AS_WINDOW_RESIZE:
873 		{
874 			// Has the all-window look
875 			float xResizeTo;
876 			float yResizeTo;
877 			link.Read<float>(&xResizeTo);
878 			if (link.Read<float>(&yResizeTo) != B_OK)
879 				break;
880 
881 			DTRACE(("ServerWindow %s: Message AS_WINDOW_RESIZE %.1f, %.1f\n",
882 				Title(), xResizeTo, yResizeTo));
883 
884 			// comment this code for the time being, as some apps rely
885 			// on the programmatically resize behavior during user resize
886 //			if (fWindow->IsResizing()) {
887 				// While the user resizes the window, we ignore
888 				// pragmatically set window bounds
889 //				fLink.StartMessage(B_BUSY);
890 //			} else {
891 				fDesktop->ResizeWindowBy(fWindow,
892 					xResizeTo - fWindow->Frame().Width(),
893 					yResizeTo - fWindow->Frame().Height());
894 				fLink.StartMessage(B_OK);
895 //			}
896 			fLink.Flush();
897 			break;
898 		}
899 		case AS_WINDOW_MOVE:
900 		{
901 			// Has the all-window look
902 			float xMoveTo;
903 			float yMoveTo;
904 			link.Read<float>(&xMoveTo);
905 			if (link.Read<float>(&yMoveTo) != B_OK)
906 				break;
907 
908 			DTRACE(("ServerWindow %s: Message AS_WINDOW_MOVE: %.1f, %.1f\n",
909 				Title(), xMoveTo, yMoveTo));
910 
911 			if (fWindow->IsDragging()) {
912 				// While the user moves the window, we ignore
913 				// pragmatically set window positions
914 				fLink.StartMessage(B_BUSY);
915 			} else {
916 				fDesktop->MoveWindowBy(fWindow, xMoveTo - fWindow->Frame().left,
917 					yMoveTo - fWindow->Frame().top);
918 				fLink.StartMessage(B_OK);
919 			}
920 			fLink.Flush();
921 			break;
922 		}
923 		case AS_SET_SIZE_LIMITS:
924 		{
925 			// Has the all-window look
926 
927 			// Attached Data:
928 			// 1) float minimum width
929 			// 2) float maximum width
930 			// 3) float minimum height
931 			// 4) float maximum height
932 
933 			// TODO: for now, move the client to int32 as well!
934 			int32 minWidth, maxWidth, minHeight, maxHeight;
935 			float value;
936 			link.Read<float>(&value);	minWidth = (int32)value;
937 			link.Read<float>(&value);	maxWidth = (int32)value;
938 			link.Read<float>(&value);	minHeight = (int32)value;
939 			link.Read<float>(&value);	maxHeight = (int32)value;
940 /*
941 			link.Read<int32>(&minWidth);
942 			link.Read<int32>(&maxWidth);
943 			link.Read<int32>(&minHeight);
944 			link.Read<int32>(&maxHeight);
945 */
946 			DTRACE(("ServerWindow %s: Message AS_SET_SIZE_LIMITS: "
947 				"x: %" B_PRId32 "-%" B_PRId32 ", y: %" B_PRId32 "-%" B_PRId32
948 				"\n", Title(), minWidth, maxWidth, minHeight, maxHeight));
949 
950 			fWindow->SetSizeLimits(minWidth, maxWidth, minHeight, maxHeight);
951 
952 			// and now, sync the client to the limits that we were able to enforce
953 			fWindow->GetSizeLimits(&minWidth, &maxWidth,
954 				&minHeight, &maxHeight);
955 
956 			fLink.StartMessage(B_OK);
957 			fLink.Attach<BRect>(fWindow->Frame());
958 			fLink.Attach<float>((float)minWidth);
959 			fLink.Attach<float>((float)maxWidth);
960 			fLink.Attach<float>((float)minHeight);
961 			fLink.Attach<float>((float)maxHeight);
962 
963 			fLink.Flush();
964 
965 			fDesktop->NotifySizeLimitsChanged(fWindow, minWidth, maxWidth,
966 				minHeight, maxHeight);
967 			break;
968 		}
969 
970 		case AS_SET_DECORATOR_SETTINGS:
971 		{
972 			// Has the all-window look
973 			DTRACE(("ServerWindow %s: Message AS_SET_DECORATOR_SETTINGS\n",
974 				Title()));
975 
976 			int32 size;
977 			if (fWindow && link.Read<int32>(&size) == B_OK) {
978 				char buffer[size];
979 				if (link.Read(buffer, size) == B_OK) {
980 					BMessage settings;
981 					if (settings.Unflatten(buffer) == B_OK)
982 						fDesktop->SetWindowDecoratorSettings(fWindow, settings);
983 				}
984 			}
985 			break;
986 		}
987 
988 		case AS_GET_DECORATOR_SETTINGS:
989 		{
990 			DTRACE(("ServerWindow %s: Message AS_GET_DECORATOR_SETTINGS\n",
991 				Title()));
992 
993 			bool success = false;
994 
995 			BMessage settings;
996 			if (fWindow->GetDecoratorSettings(&settings)) {
997 				int32 size = settings.FlattenedSize();
998 				char buffer[size];
999 				if (settings.Flatten(buffer, size) == B_OK) {
1000 					success = true;
1001 					fLink.StartMessage(B_OK);
1002 					fLink.Attach<int32>(size);
1003 					fLink.Attach(buffer, size);
1004 				}
1005 			}
1006 
1007 			if (!success)
1008 				fLink.StartMessage(B_ERROR);
1009 
1010 			fLink.Flush();
1011 			break;
1012 		}
1013 
1014 		case AS_SYSTEM_FONT_CHANGED:
1015 		{
1016 			// Has the all-window look
1017 			fDesktop->FontsChanged(fWindow);
1018 			break;
1019 		}
1020 
1021 		// Forward to client
1022 		case B_FONTS_UPDATED:
1023 		{
1024 			// TODO: would knowing which font was changed be useful?
1025 			BMessage message(code);
1026 			SendMessageToClient(&message);
1027 			break;
1028 		}
1029 
1030 		case AS_REDRAW:
1031 			// Nothing to do here - the redraws are actually handled by looking
1032 			// at the fRedrawRequested member variable in _MessageLooper().
1033 			break;
1034 
1035 		case AS_SYNC:
1036 			DTRACE(("ServerWindow %s: Message AS_SYNC\n", Title()));
1037 			// the synchronisation works by the fact that the client
1038 			// window is waiting for this reply, after having received it,
1039 			// client and server queues are in sync (earlier, the client
1040 			// may have pushed drawing commands at the server and now it
1041 			// knows they have all been carried out)
1042 			fLink.StartMessage(B_OK);
1043 			fLink.Flush();
1044 			break;
1045 
1046 		case AS_BEGIN_UPDATE:
1047 			DTRACE(("ServerWindow %s: Message AS_BEGIN_UPDATE\n", Title()));
1048 			fWindow->BeginUpdate(fLink);
1049 			break;
1050 
1051 		case AS_END_UPDATE:
1052 			DTRACE(("ServerWindow %s: Message AS_END_UPDATE\n", Title()));
1053 			fWindow->EndUpdate();
1054 			break;
1055 
1056 		case AS_GET_MOUSE:
1057 		{
1058 			// Has the all-window look
1059 			DTRACE(("ServerWindow %s: Message AS_GET_MOUSE\n", fTitle));
1060 
1061 			// Returns
1062 			// 1) BPoint mouse location
1063 			// 2) int32 button state
1064 
1065 			BPoint where;
1066 			int32 buttons;
1067 			fDesktop->GetLastMouseState(&where, &buttons);
1068 
1069 			fLink.StartMessage(B_OK);
1070 			fLink.Attach<BPoint>(where);
1071 			fLink.Attach<int32>(buttons);
1072 			fLink.Flush();
1073 			break;
1074 		}
1075 
1076 		// BDirectWindow communication
1077 
1078 		case AS_DIRECT_WINDOW_GET_SYNC_DATA:
1079 		{
1080 			status_t status = _EnableDirectWindowMode();
1081 
1082 			fLink.StartMessage(status);
1083 			if (status == B_OK) {
1084 				struct direct_window_sync_data syncData;
1085 				fDirectWindowInfo->GetSyncData(syncData);
1086 
1087 				fLink.Attach(&syncData, sizeof(syncData));
1088 			}
1089 
1090 			fLink.Flush();
1091 			break;
1092 		}
1093 		case AS_DIRECT_WINDOW_SET_FULLSCREEN:
1094 		{
1095 			// Has the all-window look
1096 			bool enable;
1097 			link.Read<bool>(&enable);
1098 
1099 			status_t status = B_OK;
1100 			if (fDirectWindowInfo != NULL)
1101 				_DirectWindowSetFullScreen(enable);
1102 			else
1103 				status = B_BAD_TYPE;
1104 
1105 			fLink.StartMessage(status);
1106 			fLink.Flush();
1107 			break;
1108 		}
1109 
1110 		// View creation and destruction (don't need a valid fCurrentView)
1111 
1112 		case AS_SET_CURRENT_VIEW:
1113 		{
1114 			int32 token;
1115 			if (link.Read<int32>(&token) != B_OK)
1116 				break;
1117 
1118 			View *current;
1119 			if (App()->ViewTokens().GetToken(token, B_HANDLER_TOKEN,
1120 					(void**)&current) != B_OK
1121 				|| current->Window()->ServerWindow() != this) {
1122 				// TODO: if this happens, we probably want to kill the app and
1123 				// clean up
1124 				debug_printf("ServerWindow %s: Message "
1125 					"\n\n\nAS_SET_CURRENT_VIEW: view not found, token %"
1126 					B_PRId32 "\n", fTitle, token);
1127 				current = NULL;
1128 			} else {
1129 				DTRACE(("\n\n\nServerWindow %s: Message AS_SET_CURRENT_VIEW: %s, "
1130 					"token %" B_PRId32 "\n", fTitle, current->Name(), token));
1131 				_SetCurrentView(current);
1132 			}
1133 			break;
1134 		}
1135 
1136 		case AS_VIEW_CREATE_ROOT:
1137 		{
1138 			DTRACE(("ServerWindow %s: Message AS_VIEW_CREATE_ROOT\n", fTitle));
1139 
1140 			// Start receiving top_view data -- pass NULL as the parent view.
1141 			// This should be the *only* place where this happens.
1142 			if (fCurrentView != NULL) {
1143 				debug_printf("ServerWindow %s: Message "
1144 					"AS_VIEW_CREATE_ROOT: fCurrentView already set!!\n",
1145 					fTitle);
1146 				break;
1147 			}
1148 
1149 			_SetCurrentView(_CreateView(link, NULL));
1150 			fWindow->SetTopView(fCurrentView);
1151 			break;
1152 		}
1153 
1154 		case AS_VIEW_CREATE:
1155 		{
1156 			DTRACE(("ServerWindow %s: Message AS_VIEW_CREATE: View name: "
1157 				"%s\n", fTitle, fCurrentView->Name()));
1158 
1159 			View* parent = NULL;
1160 			View* newView = _CreateView(link, &parent);
1161 			if (parent != NULL && newView != NULL)
1162 				parent->AddChild(newView);
1163 			else {
1164 				delete newView;
1165 				debug_printf("ServerWindow %s: Message AS_VIEW_CREATE: "
1166 					"parent or newView NULL!!\n", fTitle);
1167 			}
1168 			break;
1169 		}
1170 
1171 		case AS_TALK_TO_DESKTOP_LISTENER:
1172 		{
1173 			if (fDesktop->MessageForListener(fWindow, fLink.Receiver(),
1174 				fLink.Sender()))
1175 				break;
1176 			// unhandled message at least send an error if needed
1177 			if (link.NeedsReply()) {
1178 				fLink.StartMessage(B_ERROR);
1179 				fLink.Flush();
1180 			}
1181 			break;
1182 		}
1183 
1184 		default:
1185 			if (fCurrentView == NULL) {
1186 				debug_printf("ServerWindow %s received unexpected code - "
1187 					"message '%s' before top_view attached.\n",
1188 					Title(), string_for_message_code(code));
1189 				if (link.NeedsReply()) {
1190 					fLink.StartMessage(B_ERROR);
1191 					fLink.Flush();
1192 				}
1193 				return;
1194 			}
1195 
1196 			_DispatchViewMessage(code, link);
1197 			break;
1198 	}
1199 }
1200 
1201 
1202 /*!
1203 	Dispatches all view messages that need a valid fCurrentView.
1204 */
1205 void
1206 ServerWindow::_DispatchViewMessage(int32 code,
1207 	BPrivate::LinkReceiver &link)
1208 {
1209 	if (_DispatchPictureMessage(code, link))
1210 		return;
1211 
1212 	switch (code) {
1213 		case AS_VIEW_SCROLL:
1214 		{
1215 			float dh;
1216 			float dv;
1217 			link.Read<float>(&dh);
1218 			if (link.Read<float>(&dv) != B_OK)
1219 				break;
1220 
1221 			DTRACE(("ServerWindow %s: Message AS_VIEW_SCROLL: View name: "
1222 				"%s, %.1f x %.1f\n", fTitle, fCurrentView->Name(), dh, dv));
1223 			fWindow->ScrollViewBy(fCurrentView, dh, dv);
1224 			break;
1225 		}
1226 		case AS_VIEW_COPY_BITS:
1227 		{
1228 			BRect src;
1229 			BRect dst;
1230 
1231 			link.Read<BRect>(&src);
1232 			if (link.Read<BRect>(&dst) != B_OK)
1233 				break;
1234 
1235 			DTRACE(("ServerWindow %s: Message AS_VIEW_COPY_BITS: View name: "
1236 				"%s, BRect(%.1f, %.1f, %.1f, %.1f) -> "
1237 				"BRect(%.1f, %.1f, %.1f, %.1f)\n", fTitle,
1238 				fCurrentView->Name(), src.left, src.top, src.right, src.bottom,
1239 				dst.left, dst.top, dst.right, dst.bottom));
1240 
1241 			BRegion contentRegion;
1242 			// TODO: avoid copy operation maybe?
1243 			fWindow->GetContentRegion(&contentRegion);
1244 			fCurrentView->CopyBits(src, dst, contentRegion);
1245 			break;
1246 		}
1247 		case AS_VIEW_DELETE:
1248 		{
1249 			// Received when a view is detached from a window
1250 
1251 			int32 token;
1252 			if (link.Read<int32>(&token) != B_OK)
1253 				break;
1254 
1255 			View *view;
1256 			if (App()->ViewTokens().GetToken(token, B_HANDLER_TOKEN,
1257 					(void**)&view) == B_OK
1258 				&& view->Window()->ServerWindow() == this) {
1259 				View* parent = view->Parent();
1260 
1261 				DTRACE(("ServerWindow %s: AS_VIEW_DELETE view: %p, "
1262 					"parent: %p\n", fTitle, view, parent));
1263 
1264 				if (parent != NULL) {
1265 					parent->RemoveChild(view);
1266 
1267 					if (view->EventMask() != 0) {
1268 						// TODO: possible deadlock (event dispatcher already
1269 						// locked itself, waits for Desktop write lock, but
1270 						// we have it, now we are trying to lock the event
1271 						// dispatcher -> deadlock)
1272 fDesktop->UnlockSingleWindow();
1273 						fDesktop->EventDispatcher().RemoveListener(
1274 							EventTarget(), token);
1275 fDesktop->LockSingleWindow();
1276 					}
1277 
1278 					if (fCurrentView == view || fCurrentView->HasParent(view))
1279 						_SetCurrentView(parent);
1280 
1281 					delete view;
1282 				} // else we don't delete the root view
1283 			}
1284 			break;
1285 		}
1286 		case AS_VIEW_SET_STATE:
1287 		{
1288 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_STATE: "
1289 				"View name: %s\n", fTitle, fCurrentView->Name()));
1290 
1291 			fCurrentView->CurrentState()->ReadFromLink(link);
1292 			// TODO: When is this used?!?
1293 			fCurrentView->RebuildClipping(true);
1294 			_UpdateDrawState(fCurrentView);
1295 
1296 			break;
1297 		}
1298 		case AS_VIEW_SET_FONT_STATE:
1299 		{
1300 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_FONT_STATE: "
1301 				"View name: %s\n", fTitle, fCurrentView->Name()));
1302 
1303 			fCurrentView->CurrentState()->ReadFontFromLink(link);
1304 			fWindow->GetDrawingEngine()->SetFont(
1305 				fCurrentView->CurrentState());
1306 			break;
1307 		}
1308 		case AS_VIEW_GET_STATE:
1309 		{
1310 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_STATE: "
1311 				"View name: %s\n", fTitle, fCurrentView->Name()));
1312 
1313 			fLink.StartMessage(B_OK);
1314 
1315 			// attach state data
1316 			fCurrentView->CurrentState()->WriteToLink(fLink.Sender());
1317 			fLink.Flush();
1318 			break;
1319 		}
1320 		case AS_VIEW_SET_EVENT_MASK:
1321 		{
1322 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_EVENT_MASK: "
1323 				"View name: %s\n", fTitle, fCurrentView->Name()));
1324 			uint32 eventMask, options;
1325 
1326 			link.Read<uint32>(&eventMask);
1327 			if (link.Read<uint32>(&options) == B_OK) {
1328 				fCurrentView->SetEventMask(eventMask, options);
1329 
1330 fDesktop->UnlockSingleWindow();
1331 				// TODO: possible deadlock!
1332 				if (eventMask != 0 || options != 0) {
1333 					fDesktop->EventDispatcher().AddListener(EventTarget(),
1334 						fCurrentView->Token(), eventMask, options);
1335 				} else {
1336 					fDesktop->EventDispatcher().RemoveListener(EventTarget(),
1337 						fCurrentView->Token());
1338 				}
1339 fDesktop->LockSingleWindow();
1340 			}
1341 			break;
1342 		}
1343 		case AS_VIEW_SET_MOUSE_EVENT_MASK:
1344 		{
1345 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_MOUSE_EVENT_MASK: "
1346 				"View name: %s\n", fTitle, fCurrentView->Name()));
1347 			uint32 eventMask, options;
1348 
1349 			link.Read<uint32>(&eventMask);
1350 			if (link.Read<uint32>(&options) == B_OK) {
1351 fDesktop->UnlockSingleWindow();
1352 				// TODO: possible deadlock
1353 				if (eventMask != 0 || options != 0) {
1354 					if (options & B_LOCK_WINDOW_FOCUS)
1355 						fDesktop->SetFocusLocked(fWindow);
1356 					fDesktop->EventDispatcher().AddTemporaryListener(EventTarget(),
1357 						fCurrentView->Token(), eventMask, options);
1358 				} else {
1359 					fDesktop->EventDispatcher().RemoveTemporaryListener(EventTarget(),
1360 						fCurrentView->Token());
1361 				}
1362 fDesktop->LockSingleWindow();
1363 			}
1364 
1365 			// TODO: support B_LOCK_WINDOW_FOCUS option in Desktop
1366 			break;
1367 		}
1368 		case AS_VIEW_MOVE_TO:
1369 		{
1370 			float x, y;
1371 			link.Read<float>(&x);
1372 			if (link.Read<float>(&y) != B_OK)
1373 				break;
1374 
1375 			DTRACE(("ServerWindow %s: Message AS_VIEW_MOVE_TO: View name: "
1376 				"%s, x: %.1f, y: %.1f\n", fTitle, fCurrentView->Name(), x, y));
1377 
1378 			float offsetX = x - fCurrentView->Frame().left;
1379 			float offsetY = y - fCurrentView->Frame().top;
1380 
1381 			BRegion dirty;
1382 			fCurrentView->MoveBy(offsetX, offsetY, &dirty);
1383 
1384 			// TODO: think about how to avoid this hack:
1385 			// the parent clipping needs to be updated, it is not
1386 			// done in MoveBy() since it would cause
1387 			// too much computations when children are resized because
1388 			// follow modes
1389 			if (View* parent = fCurrentView->Parent())
1390 				parent->RebuildClipping(false);
1391 
1392 			fWindow->MarkContentDirty(dirty);
1393 			break;
1394 		}
1395 		case AS_VIEW_RESIZE_TO:
1396 		{
1397 			float newWidth, newHeight;
1398 			link.Read<float>(&newWidth);
1399 			if (link.Read<float>(&newHeight) != B_OK)
1400 				break;
1401 
1402 			DTRACE(("ServerWindow %s: Message AS_VIEW_RESIZE_TO: View name: "
1403 				"%s, width: %.1f, height: %.1f\n", fTitle,
1404 				fCurrentView->Name(), newWidth, newHeight));
1405 
1406 			float deltaWidth = newWidth - fCurrentView->Frame().Width();
1407 			float deltaHeight = newHeight - fCurrentView->Frame().Height();
1408 
1409 			BRegion dirty;
1410 			fCurrentView->ResizeBy(deltaWidth, deltaHeight, &dirty);
1411 
1412 			// TODO: see above
1413 			if (View* parent = fCurrentView->Parent())
1414 				parent->RebuildClipping(false);
1415 
1416 			fWindow->MarkContentDirty(dirty);
1417 			break;
1418 		}
1419 		case AS_VIEW_GET_COORD:
1420 		{
1421 			// our offset in the parent -> will be originX and originY
1422 			// in BView
1423 			BPoint parentOffset = fCurrentView->Frame().LeftTop();
1424 
1425 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_COORD: "
1426 				"View: %s -> x: %.1f, y: %.1f\n", Title(),
1427 				fCurrentView->Name(), parentOffset.x, parentOffset.y));
1428 
1429 			fLink.StartMessage(B_OK);
1430 			fLink.Attach<BPoint>(parentOffset);
1431 			fLink.Attach<BRect>(fCurrentView->Bounds());
1432 			fLink.Flush();
1433 			break;
1434 		}
1435 		case AS_VIEW_SET_ORIGIN:
1436 		{
1437 			float x, y;
1438 			link.Read<float>(&x);
1439 			if (link.Read<float>(&y) != B_OK)
1440 				break;
1441 
1442 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_ORIGIN: "
1443 				"View: %s -> x: %.1f, y: %.1f\n", Title(),
1444 				fCurrentView->Name(), x, y));
1445 
1446 			fCurrentView->SetDrawingOrigin(BPoint(x, y));
1447 			_UpdateDrawState(fCurrentView);
1448 			break;
1449 		}
1450 		case AS_VIEW_GET_ORIGIN:
1451 		{
1452 			BPoint drawingOrigin = fCurrentView->DrawingOrigin();
1453 
1454 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_ORIGIN: "
1455 				"View: %s -> x: %.1f, y: %.1f\n", Title(),
1456 				fCurrentView->Name(), drawingOrigin.x, drawingOrigin.y));
1457 
1458 			fLink.StartMessage(B_OK);
1459 			fLink.Attach<BPoint>(drawingOrigin);
1460 			fLink.Flush();
1461 			break;
1462 		}
1463 		case AS_VIEW_RESIZE_MODE:
1464 		{
1465 			uint32 resizeMode;
1466 			if (link.Read<uint32>(&resizeMode) != B_OK)
1467 				break;
1468 
1469 			DTRACE(("ServerWindow %s: Message AS_VIEW_RESIZE_MODE: "
1470 				"View: %s -> %" B_PRId32 "\n", Title(), fCurrentView->Name(),
1471 				resizeMode));
1472 
1473 			fCurrentView->SetResizeMode(resizeMode);
1474 			break;
1475 		}
1476 		case AS_VIEW_SET_FLAGS:
1477 		{
1478 			uint32 flags;
1479 			link.Read<uint32>(&flags);
1480 
1481 			// The views clipping changes when the B_DRAW_ON_CHILDREN flag is
1482 			// toggled.
1483 			bool updateClipping = (flags & B_DRAW_ON_CHILDREN)
1484 				^ (fCurrentView->Flags() & B_DRAW_ON_CHILDREN);
1485 
1486 			fCurrentView->SetFlags(flags);
1487 			_UpdateDrawState(fCurrentView);
1488 
1489 			if (updateClipping) {
1490 				fCurrentView->RebuildClipping(false);
1491 				fCurrentDrawingRegionValid = false;
1492 			}
1493 
1494 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_FLAGS: "
1495 				"View: %s -> flags: %" B_PRIu32 "\n", Title(),
1496 				fCurrentView->Name(), flags));
1497 			break;
1498 		}
1499 		case AS_VIEW_HIDE:
1500 			DTRACE(("ServerWindow %s: Message AS_VIEW_HIDE: View: %s\n",
1501 				Title(), fCurrentView->Name()));
1502 			fCurrentView->SetHidden(true);
1503 			break;
1504 
1505 		case AS_VIEW_SHOW:
1506 			DTRACE(("ServerWindow %s: Message AS_VIEW_SHOW: View: %s\n",
1507 				Title(), fCurrentView->Name()));
1508 			fCurrentView->SetHidden(false);
1509 			break;
1510 
1511 		case AS_VIEW_SET_LINE_MODE:
1512 		{
1513 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_LINE_MODE: "
1514 				"View: %s\n", Title(), fCurrentView->Name()));
1515 			ViewSetLineModeInfo info;
1516 			if (link.Read<ViewSetLineModeInfo>(&info) != B_OK)
1517 				break;
1518 
1519 			fCurrentView->CurrentState()->SetLineCapMode(info.lineCap);
1520 			fCurrentView->CurrentState()->SetLineJoinMode(info.lineJoin);
1521 			fCurrentView->CurrentState()->SetMiterLimit(info.miterLimit);
1522 
1523 			fWindow->GetDrawingEngine()->SetStrokeMode(info.lineCap,
1524 				info.lineJoin, info.miterLimit);
1525 
1526 			break;
1527 		}
1528 		case AS_VIEW_GET_LINE_MODE:
1529 		{
1530 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_LINE_MODE: "
1531 				"View: %s\n", Title(), fCurrentView->Name()));
1532 			ViewSetLineModeInfo info;
1533 			info.lineJoin = fCurrentView->CurrentState()->LineJoinMode();
1534 			info.lineCap = fCurrentView->CurrentState()->LineCapMode();
1535 			info.miterLimit = fCurrentView->CurrentState()->MiterLimit();
1536 
1537 			fLink.StartMessage(B_OK);
1538 			fLink.Attach<ViewSetLineModeInfo>(info);
1539 			fLink.Flush();
1540 
1541 			break;
1542 		}
1543 		case AS_VIEW_SET_FILL_RULE:
1544 		{
1545 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_FILL_RULE: "
1546 				"View: %s\n", Title(), fCurrentView->Name()));
1547 			int32 fillRule;
1548 			if (link.Read<int32>(&fillRule) != B_OK)
1549 				break;
1550 
1551 			fCurrentView->CurrentState()->SetFillRule(fillRule);
1552 			fWindow->GetDrawingEngine()->SetFillRule(fillRule);
1553 
1554 			break;
1555 		}
1556 		case AS_VIEW_GET_FILL_RULE:
1557 		{
1558 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_FILL_RULE: "
1559 				"View: %s\n", Title(), fCurrentView->Name()));
1560 			int32 fillRule = fCurrentView->CurrentState()->FillRule();
1561 
1562 			fLink.StartMessage(B_OK);
1563 			fLink.Attach<int32>(fillRule);
1564 			fLink.Flush();
1565 
1566 			break;
1567 		}
1568 		case AS_VIEW_PUSH_STATE:
1569 		{
1570 			DTRACE(("ServerWindow %s: Message AS_VIEW_PUSH_STATE: View: "
1571 				"%s\n", Title(), fCurrentView->Name()));
1572 
1573 			fCurrentView->PushState();
1574 			// TODO: is this necessary?
1575 //			_UpdateDrawState(fCurrentView);
1576 			break;
1577 		}
1578 		case AS_VIEW_POP_STATE:
1579 		{
1580 			DTRACE(("ServerWindow %s: Message AS_VIEW_POP_STATE: View: %s\n",
1581 				Title(), fCurrentView->Name()));
1582 
1583 			fCurrentView->PopState();
1584 			_UpdateDrawState(fCurrentView);
1585 			break;
1586 		}
1587 		case AS_VIEW_SET_SCALE:
1588 		{
1589 			float scale;
1590 			if (link.Read<float>(&scale) != B_OK)
1591 				break;
1592 
1593 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_SCALE: "
1594 				"View: %s -> scale: %.2f\n", Title(), fCurrentView->Name(),
1595 				scale));
1596 
1597 			fCurrentView->SetScale(scale);
1598 			_UpdateDrawState(fCurrentView);
1599 			break;
1600 		}
1601 		case AS_VIEW_GET_SCALE:
1602 		{
1603 			float scale = fCurrentView->CurrentState()->Scale();
1604 
1605 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_SCALE: "
1606 				"View: %s -> scale: %.2f\n",
1607 				Title(), fCurrentView->Name(), scale));
1608 
1609 			fLink.StartMessage(B_OK);
1610 			fLink.Attach<float>(scale);
1611 			fLink.Flush();
1612 			break;
1613 		}
1614 		case AS_VIEW_SET_TRANSFORM:
1615 		{
1616 			BAffineTransform transform;
1617 			if (link.Read<BAffineTransform>(&transform) != B_OK)
1618 				break;
1619 
1620 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_TRANSFORM: "
1621 				"View: %s -> transform: %.2f, %.2f, %.2f, %.2f, %.2f, %.2f\n",
1622 				Title(), fCurrentView->Name(), transform.sx, transform.shy,
1623 				transform.shx, transform.sy, transform.tx, transform.ty));
1624 
1625 			fCurrentView->CurrentState()->SetTransform(transform);
1626 			_UpdateDrawState(fCurrentView);
1627 			break;
1628 		}
1629 		case AS_VIEW_GET_TRANSFORM:
1630 		{
1631 			BAffineTransform transform
1632 				= fCurrentView->CurrentState()->Transform();
1633 
1634 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_TRANSFORM: "
1635 				"View: %s -> transform: %.2f, %.2f, %.2f, %.2f, %.2f, %.2f\n",
1636 				Title(), fCurrentView->Name(), transform.sx, transform.shy,
1637 				transform.shx, transform.sy, transform.tx, transform.ty));
1638 
1639 			fLink.StartMessage(B_OK);
1640 			fLink.Attach<BAffineTransform>(transform);
1641 			fLink.Flush();
1642 			break;
1643 		}
1644 		case AS_VIEW_AFFINE_TRANSLATE:
1645 		{
1646 			double x, y;
1647 			link.Read<double>(&x);
1648 			link.Read<double>(&y);
1649 			BAffineTransform current =
1650 				fCurrentView->CurrentState()->Transform();
1651 			current.PreTranslateBy(x, y);
1652 			fCurrentView->CurrentState()->SetTransform(current);
1653 			_UpdateDrawState(fCurrentView);
1654 			break;
1655 		}
1656 
1657 		case AS_VIEW_AFFINE_SCALE:
1658 		{
1659 			double x, y;
1660 			link.Read<double>(&x);
1661 			link.Read<double>(&y);
1662 			BAffineTransform current =
1663 				fCurrentView->CurrentState()->Transform();
1664 			current.PreScaleBy(x, y);
1665 			fCurrentView->CurrentState()->SetTransform(current);
1666 			_UpdateDrawState(fCurrentView);
1667 			break;
1668 		}
1669 
1670 		case AS_VIEW_AFFINE_ROTATE:
1671 		{
1672 			double angleRadians;
1673 			link.Read<double>(&angleRadians);
1674 			BAffineTransform current =
1675 				fCurrentView->CurrentState()->Transform();
1676 			current.PreRotateBy(angleRadians);
1677 			fCurrentView->CurrentState()->SetTransform(current);
1678 			_UpdateDrawState(fCurrentView);
1679 			break;
1680 		}
1681 
1682 		case AS_VIEW_SET_PEN_LOC:
1683 		{
1684 			BPoint location;
1685 			if (link.Read<BPoint>(&location) != B_OK)
1686 				break;
1687 
1688 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_PEN_LOC: "
1689 				"View: %s -> BPoint(%.1f, %.1f)\n", Title(),
1690 				fCurrentView->Name(), location.x, location.y));
1691 
1692 			fCurrentView->CurrentState()->SetPenLocation(location);
1693 			break;
1694 		}
1695 		case AS_VIEW_GET_PEN_LOC:
1696 		{
1697 			BPoint location = fCurrentView->CurrentState()->PenLocation();
1698 
1699 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_PEN_LOC: "
1700 				"View: %s -> BPoint(%.1f, %.1f)\n", Title(),
1701 				fCurrentView->Name(), location.x, location.y));
1702 
1703 			fLink.StartMessage(B_OK);
1704 			fLink.Attach<BPoint>(location);
1705 			fLink.Flush();
1706 
1707 			break;
1708 		}
1709 		case AS_VIEW_SET_PEN_SIZE:
1710 		{
1711 			float penSize;
1712 			if (link.Read<float>(&penSize) != B_OK)
1713 				break;
1714 
1715 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_PEN_SIZE: "
1716 				"View: %s -> %.1f\n", Title(), fCurrentView->Name(), penSize));
1717 
1718 			fCurrentView->CurrentState()->SetPenSize(penSize);
1719 			fWindow->GetDrawingEngine()->SetPenSize(
1720 				fCurrentView->CurrentState()->PenSize());
1721 			break;
1722 		}
1723 		case AS_VIEW_GET_PEN_SIZE:
1724 		{
1725 			float penSize = fCurrentView->CurrentState()->UnscaledPenSize();
1726 
1727 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_PEN_SIZE: "
1728 				"View: %s -> %.1f\n", Title(), fCurrentView->Name(), penSize));
1729 
1730 			fLink.StartMessage(B_OK);
1731 			fLink.Attach<float>(penSize);
1732 			fLink.Flush();
1733 
1734 			break;
1735 		}
1736 		case AS_VIEW_SET_VIEW_COLOR:
1737 		{
1738 			rgb_color color;
1739 			if (link.Read(&color, sizeof(rgb_color)) != B_OK)
1740 				break;
1741 
1742 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_VIEW_COLOR: "
1743 				"View: %s -> rgb_color(%d, %d, %d, %d)\n", Title(),
1744 				fCurrentView->Name(), color.red, color.green, color.blue,
1745 				color.alpha));
1746 
1747 			fCurrentView->SetViewColor(color);
1748 			break;
1749 		}
1750 		case AS_VIEW_GET_VIEW_COLOR:
1751 		{
1752 			rgb_color color = fCurrentView->ViewColor();
1753 
1754 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_VIEW_COLOR: "
1755 				"View: %s -> rgb_color(%d, %d, %d, %d)\n",
1756 				Title(), fCurrentView->Name(), color.red, color.green,
1757 				color.blue, color.alpha));
1758 
1759 			fLink.StartMessage(B_OK);
1760 			fLink.Attach<rgb_color>(color);
1761 			fLink.Flush();
1762 			break;
1763 		}
1764 		case AS_VIEW_SET_HIGH_COLOR:
1765 		{
1766 			rgb_color color;
1767 			if (link.Read(&color, sizeof(rgb_color)) != B_OK)
1768 				break;
1769 
1770 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_HIGH_COLOR: "
1771 				"View: %s -> rgb_color(%d, %d, %d, %d)\n",
1772 				Title(), fCurrentView->Name(), color.red, color.green,
1773 				color.blue, color.alpha));
1774 
1775 			fCurrentView->CurrentState()->SetHighColor(color);
1776 			fWindow->GetDrawingEngine()->SetHighColor(color);
1777 			break;
1778 		}
1779 
1780 		case AS_VIEW_SET_HIGH_UI_COLOR:
1781 		{
1782 			color_which which = B_NO_COLOR;
1783 			float tint = B_NO_TINT;
1784 
1785 			if (link.Read<color_which>(&which) != B_OK
1786 				|| link.Read<float>(&tint) != B_OK )
1787 				break;
1788 
1789 			fCurrentView->CurrentState()->SetHighUIColor(which, tint);
1790 
1791 			// TODO: should we do more color_which validity checking?
1792 			if (which != B_NO_COLOR) {
1793 				DesktopSettings settings(fDesktop);
1794 				rgb_color color = tint_color(settings.UIColor(which), tint);
1795 
1796 				fCurrentView->CurrentState()->SetHighColor(color);
1797 				fWindow->GetDrawingEngine()->SetHighColor(color);
1798 			}
1799 			break;
1800 		}
1801 		case AS_VIEW_SET_LOW_UI_COLOR:
1802 		{
1803 			color_which which = B_NO_COLOR;
1804 			float tint = B_NO_TINT;
1805 
1806 			if (link.Read<color_which>(&which) != B_OK
1807 				|| link.Read<float>(&tint) != B_OK )
1808 				break;
1809 
1810 			fCurrentView->CurrentState()->SetLowUIColor(which, tint);
1811 
1812 			// TODO: should we do more color_which validity checking?
1813 			if (which != B_NO_COLOR) {
1814 				DesktopSettings settings(fDesktop);
1815 				rgb_color color = tint_color(settings.UIColor(which), tint);
1816 
1817 				fCurrentView->CurrentState()->SetLowColor(color);
1818 				fWindow->GetDrawingEngine()->SetLowColor(color);
1819 			}
1820 			break;
1821 		}
1822 		case AS_VIEW_SET_VIEW_UI_COLOR:
1823 		{
1824 			color_which which = B_NO_COLOR;
1825 			float tint = B_NO_TINT;
1826 
1827 			if (link.Read<color_which>(&which) != B_OK
1828 				|| link.Read<float>(&tint) != B_OK )
1829 				break;
1830 
1831 			// TODO: should we do more color_which validity checking?
1832 			fCurrentView->SetViewUIColor(which, tint);
1833 			break;
1834 		}
1835 		case AS_VIEW_GET_HIGH_UI_COLOR:
1836 		{
1837 			float tint;
1838 			color_which which = fCurrentView->CurrentState()->HighUIColor(&tint);
1839 			rgb_color color = fCurrentView->CurrentState()->HighColor();
1840 
1841 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_HIGH_UI_COLOR: "
1842 				"View: %s -> color_which(%i) tint(%.3f) - rgb_color(%i, %i,"
1843 				" %i, %i)\n", Title(), fCurrentView->Name(), which, tint,
1844 				color.red, color.green, color.blue, color.alpha));
1845 
1846 			fLink.StartMessage(B_OK);
1847 			fLink.Attach<color_which>(which);
1848 			fLink.Attach<float>(tint);
1849 			fLink.Attach<rgb_color>(color);
1850 			fLink.Flush();
1851 			break;
1852 		}
1853 		case AS_VIEW_GET_LOW_UI_COLOR:
1854 		{
1855 			float tint;
1856 			color_which which = fCurrentView->CurrentState()->LowUIColor(&tint);
1857 			rgb_color color = fCurrentView->CurrentState()->LowColor();
1858 
1859 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_LOW_UI_COLOR: "
1860 				"View: %s -> color_which(%i) tint(%.3f) - rgb_color(%i, %i,"
1861 				" %i, %i)\n", Title(), fCurrentView->Name(), which, tint,
1862 				color.red, color.green, color.blue, color.alpha));
1863 
1864 			fLink.StartMessage(B_OK);
1865 			fLink.Attach<color_which>(which);
1866 			fLink.Attach<float>(tint);
1867 			fLink.Attach<rgb_color>(color);
1868 			fLink.Flush();
1869 			break;
1870 		}
1871 		case AS_VIEW_GET_VIEW_UI_COLOR:
1872 		{
1873 			float tint;
1874 			color_which which = fCurrentView->ViewUIColor(&tint);
1875 			rgb_color color = fCurrentView->ViewColor();
1876 
1877 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_VIEW_UI_COLOR: "
1878 				"View: %s -> color_which(%i) tint(%.3f) - rgb_color(%i, %i,"
1879 				" %i, %i)\n", Title(), fCurrentView->Name(), which, tint,
1880 				color.red, color.green, color.blue, color.alpha));
1881 
1882 			fLink.StartMessage(B_OK);
1883 			fLink.Attach<color_which>(which);
1884 			fLink.Attach<float>(tint);
1885 			fLink.Attach<rgb_color>(color);
1886 			fLink.Flush();
1887 			break;
1888 		}
1889 		case AS_VIEW_GET_HIGH_COLOR:
1890 		{
1891 			rgb_color color = fCurrentView->CurrentState()->HighColor();
1892 
1893 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_HIGH_COLOR: "
1894 				"View: %s -> rgb_color(%d, %d, %d, %d)\n",
1895 				Title(), fCurrentView->Name(), color.red, color.green,
1896 				color.blue, color.alpha));
1897 
1898 			fLink.StartMessage(B_OK);
1899 			fLink.Attach<rgb_color>(color);
1900 			fLink.Flush();
1901 			break;
1902 		}
1903 		case AS_VIEW_SET_LOW_COLOR:
1904 		{
1905 			rgb_color color;
1906 			if (link.Read(&color, sizeof(rgb_color)) != B_OK)
1907 				break;
1908 
1909 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_LOW_COLOR: "
1910 				"View: %s -> rgb_color(%d, %d, %d, %d)\n",
1911 				Title(), fCurrentView->Name(), color.red, color.green,
1912 				color.blue, color.alpha));
1913 
1914 			fCurrentView->CurrentState()->SetLowColor(color);
1915 			fWindow->GetDrawingEngine()->SetLowColor(color);
1916 			break;
1917 		}
1918 		case AS_VIEW_GET_LOW_COLOR:
1919 		{
1920 			rgb_color color = fCurrentView->CurrentState()->LowColor();
1921 
1922 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_LOW_COLOR: "
1923 				"View: %s -> rgb_color(%d, %d, %d, %d)\n",
1924 				Title(), fCurrentView->Name(), color.red, color.green,
1925 				color.blue, color.alpha));
1926 
1927 			fLink.StartMessage(B_OK);
1928 			fLink.Attach<rgb_color>(color);
1929 			fLink.Flush();
1930 			break;
1931 		}
1932 		case AS_VIEW_SET_PATTERN:
1933 		{
1934 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_PATTERN: "
1935 				"View: %s\n", fTitle, fCurrentView->Name()));
1936 
1937 			pattern pat;
1938 			if (link.Read(&pat, sizeof(pattern)) != B_OK)
1939 				break;
1940 
1941 			fCurrentView->CurrentState()->SetPattern(Pattern(pat));
1942 			fWindow->GetDrawingEngine()->SetPattern(pat);
1943 			break;
1944 		}
1945 
1946 		case AS_VIEW_SET_BLENDING_MODE:
1947 		{
1948 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_BLEND_MODE: "
1949 				"View: %s\n", Title(), fCurrentView->Name()));
1950 
1951 			ViewBlendingModeInfo info;
1952 			if (link.Read<ViewBlendingModeInfo>(&info) != B_OK)
1953 				break;
1954 
1955 			fCurrentView->CurrentState()->SetBlendingMode(
1956 				info.sourceAlpha, info.alphaFunction);
1957 			fWindow->GetDrawingEngine()->SetBlendingMode(
1958 				info.sourceAlpha, info.alphaFunction);
1959 			break;
1960 		}
1961 		case AS_VIEW_GET_BLENDING_MODE:
1962 		{
1963 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_BLEND_MODE: "
1964 				"View: %s\n", Title(), fCurrentView->Name()));
1965 
1966 			ViewBlendingModeInfo info;
1967 			info.sourceAlpha = fCurrentView->CurrentState()->AlphaSrcMode();
1968 			info.alphaFunction = fCurrentView->CurrentState()->AlphaFncMode();
1969 
1970 			fLink.StartMessage(B_OK);
1971 			fLink.Attach<ViewBlendingModeInfo>(info);
1972 			fLink.Flush();
1973 
1974 			break;
1975 		}
1976 		case AS_VIEW_SET_DRAWING_MODE:
1977 		{
1978 			int8 drawingMode;
1979 			if (link.Read<int8>(&drawingMode) != B_OK)
1980 				break;
1981 
1982 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_DRAW_MODE: "
1983 				"View: %s -> %s\n", Title(), fCurrentView->Name(),
1984 				kDrawingModeMap[drawingMode]));
1985 
1986 			fCurrentView->CurrentState()->SetDrawingMode(
1987 				(drawing_mode)drawingMode);
1988 			fWindow->GetDrawingEngine()->SetDrawingMode(
1989 				(drawing_mode)drawingMode);
1990 			break;
1991 		}
1992 		case AS_VIEW_GET_DRAWING_MODE:
1993 		{
1994 			int8 drawingMode
1995 				= (int8)(fCurrentView->CurrentState()->GetDrawingMode());
1996 
1997 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_DRAW_MODE: "
1998 				"View: %s -> %s\n", Title(), fCurrentView->Name(),
1999 				kDrawingModeMap[drawingMode]));
2000 
2001 			fLink.StartMessage(B_OK);
2002 			fLink.Attach<int8>(drawingMode);
2003 			fLink.Flush();
2004 
2005 			break;
2006 		}
2007 		case AS_VIEW_SET_VIEW_BITMAP:
2008 		{
2009 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_VIEW_BITMAP: "
2010 				"View: %s\n", Title(), fCurrentView->Name()));
2011 
2012 			int32 bitmapToken, resizingMode, options;
2013 			BRect srcRect, dstRect;
2014 
2015 			link.Read<int32>(&bitmapToken);
2016 			link.Read<BRect>(&srcRect);
2017 			link.Read<BRect>(&dstRect);
2018 			link.Read<int32>(&resizingMode);
2019 			status_t status = link.Read<int32>(&options);
2020 
2021 			rgb_color colorKey = {0};
2022 
2023 			if (status == B_OK) {
2024 				ServerBitmap* bitmap = fServerApp->GetBitmap(bitmapToken);
2025 				if (bitmapToken == -1 || bitmap != NULL) {
2026 					bool wasOverlay = fCurrentView->ViewBitmap() != NULL
2027 						&& fCurrentView->ViewBitmap()->Overlay() != NULL;
2028 
2029 					fCurrentView->SetViewBitmap(bitmap, srcRect, dstRect,
2030 						resizingMode, options);
2031 
2032 					// TODO: if we revert the view color overlay handling
2033 					//	in View::Draw() to the BeOS version, we never
2034 					//	need to invalidate the view for overlays.
2035 
2036 					// Invalidate view - but only if this is a non-overlay
2037 					// switch
2038 					if (bitmap == NULL || bitmap->Overlay() == NULL
2039 						|| !wasOverlay) {
2040 						BRegion dirty((BRect)fCurrentView->Bounds());
2041 						fWindow->InvalidateView(fCurrentView, dirty);
2042 					}
2043 
2044 					if (bitmap != NULL && bitmap->Overlay() != NULL) {
2045 						bitmap->Overlay()->SetFlags(options);
2046 						colorKey = bitmap->Overlay()->Color();
2047 					}
2048 
2049 					if (bitmap != NULL)
2050 						bitmap->ReleaseReference();
2051 				} else
2052 					status = B_BAD_VALUE;
2053 			}
2054 
2055 			fLink.StartMessage(status);
2056 			if (status == B_OK && (options & AS_REQUEST_COLOR_KEY) != 0) {
2057 				// Attach color key for the overlay bitmap
2058 				fLink.Attach<rgb_color>(colorKey);
2059 			}
2060 
2061 			fLink.Flush();
2062 			break;
2063 		}
2064 		case AS_VIEW_PRINT_ALIASING:
2065 		{
2066 			DTRACE(("ServerWindow %s: Message AS_VIEW_PRINT_ALIASING: "
2067 				"View: %s\n", Title(), fCurrentView->Name()));
2068 
2069 			bool fontAliasing;
2070 			if (link.Read<bool>(&fontAliasing) == B_OK) {
2071 				fCurrentView->CurrentState()->SetForceFontAliasing(fontAliasing);
2072 				_UpdateDrawState(fCurrentView);
2073 			}
2074 			break;
2075 		}
2076 		case AS_VIEW_CLIP_TO_PICTURE:
2077 		{
2078 			DTRACE(("ServerWindow %s: Message AS_VIEW_CLIP_TO_PICTURE: "
2079 				"View: %s\n", Title(), fCurrentView->Name()));
2080 
2081 			int32 pictureToken;
2082 			BPoint where;
2083 			bool inverse = false;
2084 
2085 			link.Read<int32>(&pictureToken);
2086 			if (pictureToken < 0) {
2087 				fCurrentView->SetAlphaMask(NULL);
2088 				_UpdateDrawState(fCurrentView);
2089 				break;
2090 			}
2091 
2092 			link.Read<BPoint>(&where);
2093 			if (link.Read<bool>(&inverse) != B_OK)
2094 				break;
2095 
2096 			ServerPicture* picture = fServerApp->GetPicture(pictureToken);
2097 			if (picture == NULL)
2098 				break;
2099 
2100 			AlphaMask* const mask = new(std::nothrow) PictureAlphaMask(
2101 				fCurrentView->GetAlphaMask(), picture,
2102 				*fCurrentView->CurrentState(), where, inverse);
2103 			fCurrentView->SetAlphaMask(mask);
2104 			if (mask != NULL)
2105 				mask->ReleaseReference();
2106 
2107 			_UpdateDrawState(fCurrentView);
2108 
2109 			picture->ReleaseReference();
2110 			break;
2111 		}
2112 
2113 		case AS_VIEW_GET_CLIP_REGION:
2114 		{
2115 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_CLIP_REGION: "
2116 				"View: %s\n", Title(), fCurrentView->Name()));
2117 
2118 			// if this view is hidden, it has no visible region
2119 			fLink.StartMessage(B_OK);
2120 			if (!fWindow->IsVisible() || !fCurrentView->IsVisible()) {
2121 				BRegion empty;
2122 				fLink.AttachRegion(empty);
2123 			} else {
2124 				_UpdateCurrentDrawingRegion();
2125 				BRegion region(fCurrentDrawingRegion);
2126 				fCurrentView->ScreenToLocalTransform().Apply(&region);
2127 				fLink.AttachRegion(region);
2128 			}
2129 			fLink.Flush();
2130 
2131 			break;
2132 		}
2133 		case AS_VIEW_SET_CLIP_REGION:
2134 		{
2135 			int32 rectCount;
2136 			status_t status = link.Read<int32>(&rectCount);
2137 				// a negative count means no
2138 				// region for the current draw state,
2139 				// but an *empty* region is actually valid!
2140 				// even if it means no drawing is allowed
2141 
2142 			if (status < B_OK)
2143 				break;
2144 
2145 			if (rectCount >= 0) {
2146 				// we are supposed to set the clipping region
2147 				BRegion region;
2148 				if (rectCount > 0 && link.ReadRegion(&region) < B_OK)
2149 					break;
2150 
2151 				DTRACE(("ServerWindow %s: Message AS_VIEW_SET_CLIP_REGION: "
2152 					"View: %s -> rect count: %" B_PRId32 ", frame = "
2153 					"BRect(%.1f, %.1f, %.1f, %.1f)\n",
2154 					Title(), fCurrentView->Name(), rectCount,
2155 					region.Frame().left, region.Frame().top,
2156 					region.Frame().right, region.Frame().bottom));
2157 
2158 				fCurrentView->SetUserClipping(&region);
2159 			} else {
2160 				// we are supposed to unset the clipping region
2161 				// passing NULL sets this states region to that
2162 				// of the previous state
2163 
2164 				DTRACE(("ServerWindow %s: Message AS_VIEW_SET_CLIP_REGION: "
2165 					"View: %s -> unset\n", Title(), fCurrentView->Name()));
2166 
2167 				fCurrentView->SetUserClipping(NULL);
2168 			}
2169 			fCurrentDrawingRegionValid = false;
2170 
2171 			break;
2172 		}
2173 
2174 		case AS_VIEW_CLIP_TO_RECT:
2175 		{
2176 			bool inverse;
2177 			BRect rect;
2178 
2179 			link.Read<bool>(&inverse);
2180 			link.Read<BRect>(&rect);
2181 
2182 			bool needDrawStateUpdate = fCurrentView->ClipToRect(
2183 				rect, inverse);
2184 			fCurrentDrawingRegionValid = false;
2185 
2186 			if (needDrawStateUpdate)
2187 				_UpdateDrawState(fCurrentView);
2188 
2189 			_UpdateCurrentDrawingRegion();
2190 
2191 			BRegion region(fCurrentDrawingRegion);
2192 			fCurrentView->ScreenToLocalTransform().Apply(&region);
2193 
2194 			break;
2195 		}
2196 
2197 		case AS_VIEW_CLIP_TO_SHAPE:
2198 		{
2199 			bool inverse;
2200 			link.Read<bool>(&inverse);
2201 
2202 			shape_data shape;
2203 			link.Read<int32>(&shape.opCount);
2204 			link.Read<int32>(&shape.ptCount);
2205 			shape.opSize = shape.opCount * sizeof(uint32);
2206 			shape.ptSize = shape.ptCount * sizeof(BPoint);
2207 			shape.opList = new(nothrow) uint32[shape.opCount];
2208 			shape.ptList = new(nothrow) BPoint[shape.ptCount];
2209 			if (link.Read(shape.opList, shape.opSize) >= B_OK
2210 				&& link.Read(shape.ptList, shape.ptSize) >= B_OK) {
2211 				fCurrentView->ClipToShape(&shape, inverse);
2212 				_UpdateDrawState(fCurrentView);
2213 			}
2214 
2215 			delete[] shape.opList;
2216 			delete[] shape.ptList;
2217 			break;
2218 		}
2219 
2220 		case AS_VIEW_INVALIDATE_RECT:
2221 		{
2222 			// NOTE: looks like this call is NOT affected by origin and scale
2223 			// on R5 so this implementation is "correct"
2224 			BRect invalidRect;
2225 			if (link.Read<BRect>(&invalidRect) == B_OK) {
2226 				DTRACE(("ServerWindow %s: Message AS_VIEW_INVALIDATE_RECT: "
2227 					"View: %s -> BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(),
2228 					fCurrentView->Name(), invalidRect.left, invalidRect.top,
2229 					invalidRect.right, invalidRect.bottom));
2230 
2231 				View* view = NULL;
2232 				if (link.Read<View*>(&view) != B_OK)
2233 					view = fCurrentView;
2234 
2235 				// make sure the view is still available!
2236 				if (view != fCurrentView
2237 					&& !fWindow->TopView()->HasView(view))
2238 					break;
2239 
2240 				BRegion dirty(invalidRect);
2241 				fWindow->InvalidateView(view, dirty);
2242 			}
2243 			break;
2244 		}
2245 
2246 		case AS_VIEW_DELAYED_INVALIDATE_RECT:
2247 		{
2248 			bigtime_t time = 0;
2249 			BRect invalidRect;
2250 			if (link.Read<bigtime_t>(&time) == B_OK
2251 				&& link.Read<BRect>(&invalidRect) == B_OK) {
2252 				DTRACE(("ServerWindow %s: Message "
2253 					"AS_VIEW_DELAYED_INVALIDATE_RECT: "
2254 					"View: %s -> BRect(%.1f, %.1f, %.1f, %.1f) at time %llu\n",
2255 					Title(), fCurrentView->Name(), invalidRect.left,
2256 					invalidRect.top, invalidRect.right, invalidRect.bottom,
2257 					time));
2258 
2259 				DelayedMessage delayed(AS_VIEW_INVALIDATE_RECT, time, true);
2260 				delayed.AddTarget(MessagePort());
2261 				delayed.SetMerge(DM_MERGE_DUPLICATES);
2262 
2263 				if (delayed.Attach<BRect>(invalidRect) == B_OK
2264 						&& delayed.Attach<View*>(fCurrentView) == B_OK)
2265 					delayed.Flush();
2266 			}
2267 			break;
2268 		}
2269 
2270 		case AS_VIEW_INVALIDATE_REGION:
2271 		{
2272 			// NOTE: looks like this call is NOT affected by origin and scale
2273 			// on R5 so this implementation is "correct"
2274 			BRegion region;
2275 			if (link.ReadRegion(&region) < B_OK)
2276 				break;
2277 
2278 			DTRACE(("ServerWindow %s: Message AS_VIEW_INVALIDATE_REGION: "
2279 					"View: %s -> rect count: %" B_PRId32 ", frame: BRect(%.1f, "
2280 					"%.1f, %.1f, %.1f)\n", Title(),
2281 					fCurrentView->Name(), region.CountRects(),
2282 					region.Frame().left, region.Frame().top,
2283 					region.Frame().right, region.Frame().bottom));
2284 
2285 			fWindow->InvalidateView(fCurrentView, region);
2286 			break;
2287 		}
2288 
2289 		case AS_VIEW_DRAG_IMAGE:
2290 		{
2291 			// TODO: flesh out AS_VIEW_DRAG_IMAGE
2292 			DTRACE(("ServerWindow %s: Message AS_DRAG_IMAGE\n", Title()));
2293 
2294 			int32 bitmapToken;
2295 			drawing_mode dragMode;
2296 			BPoint offset;
2297 			int32 bufferSize;
2298 
2299 			link.Read<int32>(&bitmapToken);
2300 			link.Read<int32>((int32*)&dragMode);
2301 			link.Read<BPoint>(&offset);
2302 			link.Read<int32>(&bufferSize);
2303 
2304 			if (bufferSize > 0) {
2305 				char* buffer = new (nothrow) char[bufferSize];
2306 				BMessage dragMessage;
2307 				if (link.Read(buffer, bufferSize) == B_OK
2308 					&& dragMessage.Unflatten(buffer) == B_OK) {
2309 						ServerBitmap* bitmap
2310 							= fServerApp->GetBitmap(bitmapToken);
2311 						// TODO: possible deadlock
2312 fDesktop->UnlockSingleWindow();
2313 						fDesktop->EventDispatcher().SetDragMessage(dragMessage,
2314 							bitmap, offset);
2315 fDesktop->LockSingleWindow();
2316 						if (bitmap != NULL)
2317 							bitmap->ReleaseReference();
2318 				}
2319 				delete[] buffer;
2320 			}
2321 			// sync the client (it can now delete the bitmap)
2322 			fLink.StartMessage(B_OK);
2323 			fLink.Flush();
2324 
2325 			break;
2326 		}
2327 		case AS_VIEW_DRAG_RECT:
2328 		{
2329 			// TODO: flesh out AS_VIEW_DRAG_RECT
2330 			DTRACE(("ServerWindow %s: Message AS_DRAG_RECT\n", Title()));
2331 
2332 			BRect dragRect;
2333 			BPoint offset;
2334 			int32 bufferSize;
2335 
2336 			link.Read<BRect>(&dragRect);
2337 			link.Read<BPoint>(&offset);
2338 			link.Read<int32>(&bufferSize);
2339 
2340 			if (bufferSize > 0) {
2341 				char* buffer = new (nothrow) char[bufferSize];
2342 				BMessage dragMessage;
2343 				if (link.Read(buffer, bufferSize) == B_OK
2344 					&& dragMessage.Unflatten(buffer) == B_OK) {
2345 						// TODO: possible deadlock
2346 fDesktop->UnlockSingleWindow();
2347 						fDesktop->EventDispatcher().SetDragMessage(dragMessage,
2348 							NULL /* should be dragRect */, offset);
2349 fDesktop->LockSingleWindow();
2350 				}
2351 				delete[] buffer;
2352 			}
2353 			break;
2354 		}
2355 
2356 		case AS_VIEW_BEGIN_RECT_TRACK:
2357 		{
2358 			DTRACE(("ServerWindow %s: Message AS_VIEW_BEGIN_RECT_TRACK\n",
2359 				Title()));
2360 			BRect dragRect;
2361 			uint32 style;
2362 
2363 			link.Read<BRect>(&dragRect);
2364 			link.Read<uint32>(&style);
2365 
2366 			// TODO: implement rect tracking (used sometimes for selecting
2367 			// a group of things, also sometimes used to appear to drag
2368 			// something, but without real drag message)
2369 			break;
2370 		}
2371 		case AS_VIEW_END_RECT_TRACK:
2372 		{
2373 			DTRACE(("ServerWindow %s: Message AS_VIEW_END_RECT_TRACK\n",
2374 				Title()));
2375 			// TODO: implement rect tracking
2376 			break;
2377 		}
2378 
2379 		case AS_VIEW_BEGIN_PICTURE:
2380 		{
2381 			DTRACE(("ServerWindow %s: Message AS_VIEW_BEGIN_PICTURE\n",
2382 				Title()));
2383 			ServerPicture* picture = App()->CreatePicture();
2384 			if (picture != NULL) {
2385 				picture->SyncState(fCurrentView);
2386 				fCurrentView->SetPicture(picture);
2387 			}
2388 			break;
2389 		}
2390 
2391 		case AS_VIEW_APPEND_TO_PICTURE:
2392 		{
2393 			DTRACE(("ServerWindow %s: Message AS_VIEW_APPEND_TO_PICTURE\n",
2394 				Title()));
2395 
2396 			int32 token;
2397 			link.Read<int32>(&token);
2398 
2399 			ServerPicture* picture = App()->GetPicture(token);
2400 			if (picture != NULL)
2401 				picture->SyncState(fCurrentView);
2402 
2403 			fCurrentView->SetPicture(picture);
2404 
2405 			if (picture != NULL)
2406 				picture->ReleaseReference();
2407 			break;
2408 		}
2409 
2410 		case AS_VIEW_END_PICTURE:
2411 		{
2412 			DTRACE(("ServerWindow %s: Message AS_VIEW_END_PICTURE\n",
2413 				Title()));
2414 
2415 			ServerPicture* picture = fCurrentView->Picture();
2416 			if (picture != NULL) {
2417 				fCurrentView->SetPicture(NULL);
2418 				fLink.StartMessage(B_OK);
2419 				fLink.Attach<int32>(picture->Token());
2420 			} else
2421 				fLink.StartMessage(B_ERROR);
2422 
2423 			fLink.Flush();
2424 			break;
2425 		}
2426 
2427 		case AS_VIEW_BEGIN_LAYER:
2428 		{
2429 			DTRACE(("ServerWindow %s: Message AS_VIEW_BEGIN_LAYER\n",
2430 				Title()));
2431 
2432 			uint8 opacity;
2433 			link.Read<uint8>(&opacity);
2434 
2435 			Layer* layer = new(std::nothrow) Layer(opacity);
2436 			if (layer == NULL)
2437 				break;
2438 
2439 			if (opacity != 255) {
2440 				fCurrentView->CurrentState()->SetDrawingMode(B_OP_ALPHA);
2441 				fCurrentView->CurrentState()->SetBlendingMode(B_PIXEL_ALPHA,
2442 					B_ALPHA_COMPOSITE);
2443 				fCurrentView->CurrentState()->SetDrawingModeLocked(true);
2444 			}
2445 
2446 			fCurrentView->SetPicture(layer);
2447 			break;
2448 		}
2449 
2450 		default:
2451 			// The drawing code handles allocation failures using exceptions;
2452 			// so we need to account for that here.
2453 			try {
2454 				_DispatchViewDrawingMessage(code, link);
2455 			} catch (std::bad_alloc&) {
2456 				// Cancel any message we were in the middle of sending.
2457 				fLink.CancelMessage();
2458 
2459 				if (link.NeedsReply()) {
2460 					// As done in _DispatchViewDrawingMessage, send just a
2461 					// single status_t as the reply.
2462 					fLink.StartMessage(B_NO_MEMORY);
2463 					fLink.Flush();
2464 				}
2465 			}
2466 			break;
2467 	}
2468 }
2469 
2470 
2471 /*!	Dispatches all view drawing messages.
2472 	The desktop clipping must be read locked when entering this method.
2473 	Requires a valid fCurrentView.
2474 */
2475 void
2476 ServerWindow::_DispatchViewDrawingMessage(int32 code,
2477 	BPrivate::LinkReceiver &link)
2478 {
2479 	if (!fCurrentView->IsVisible() || !fWindow->IsVisible()) {
2480 		if (link.NeedsReply()) {
2481 			debug_printf("ServerWindow::DispatchViewDrawingMessage() got "
2482 				"message %" B_PRId32 " that needs a reply!\n", code);
2483 			// the client is now blocking and waiting for a reply!
2484 			fLink.StartMessage(B_ERROR);
2485 			fLink.Flush();
2486 		}
2487 		return;
2488 	}
2489 
2490 	DrawingEngine* drawingEngine = fWindow->GetDrawingEngine();
2491 	if (!drawingEngine) {
2492 		// ?!?
2493 		debug_printf("ServerWindow %s: no drawing engine!!\n", Title());
2494 		if (link.NeedsReply()) {
2495 			// the client is now blocking and waiting for a reply!
2496 			fLink.StartMessage(B_ERROR);
2497 			fLink.Flush();
2498 		}
2499 		return;
2500 	}
2501 
2502 	_UpdateCurrentDrawingRegion();
2503 	if (fCurrentDrawingRegion.CountRects() <= 0 && code != AS_VIEW_END_LAYER) {
2504 			// If the command is AS_VIEW_END_LAYER, then we continue even if
2505 			// the clipping region is empty. The layer itself might set a valid
2506 			// clipping while its contents are drawn, and even if it doesn't,
2507 			// we must still play back its picture so that we don't leak
2508 			// nested layer instances.
2509 
2510 		DTRACE(("ServerWindow %s: _DispatchViewDrawingMessage(): View: %s, "
2511 			"INVALID CLIPPING!\n", Title(), fCurrentView->Name()));
2512 		if (link.NeedsReply()) {
2513 			// the client is now blocking and waiting for a reply!
2514 			fLink.StartMessage(B_ERROR);
2515 			fLink.Flush();
2516 		}
2517 		return;
2518 	}
2519 
2520 	drawingEngine->LockParallelAccess();
2521 	// NOTE: the region is not copied, Painter keeps a pointer,
2522 	// that's why you need to use the clipping only for as long
2523 	// as you have it locked
2524 	drawingEngine->ConstrainClippingRegion(&fCurrentDrawingRegion);
2525 
2526 	switch (code) {
2527 		case AS_STROKE_LINE:
2528 		{
2529 			ViewStrokeLineInfo info;
2530 			if (link.Read<ViewStrokeLineInfo>(&info) != B_OK)
2531 				break;
2532 
2533 			DTRACE(("ServerWindow %s: Message AS_STROKE_LINE: View: %s -> "
2534 				"BPoint(%.1f, %.1f) - BPoint(%.1f, %.1f)\n", Title(),
2535 					fCurrentView->Name(),
2536 					info.startPoint.x, info.startPoint.y,
2537 					info.endPoint.x, info.endPoint.y));
2538 
2539 			BPoint penPos = info.endPoint;
2540 			const SimpleTransform transform =
2541 				fCurrentView->PenToScreenTransform();
2542 			transform.Apply(&info.startPoint);
2543 			transform.Apply(&info.endPoint);
2544 			drawingEngine->StrokeLine(info.startPoint, info.endPoint);
2545 
2546 			// We update the pen here because many DrawingEngine calls which
2547 			// do not update the pen position actually call StrokeLine
2548 
2549 			// TODO: Decide where to put this, for example, it cannot be done
2550 			// for DrawString(), also there needs to be a decision, if the pen
2551 			// location is in View coordinates (I think it should be) or in
2552 			// screen coordinates.
2553 			fCurrentView->CurrentState()->SetPenLocation(penPos);
2554 			break;
2555 		}
2556 		case AS_VIEW_INVERT_RECT:
2557 		{
2558 			BRect rect;
2559 			if (link.Read<BRect>(&rect) != B_OK)
2560 				break;
2561 
2562 			DTRACE(("ServerWindow %s: Message AS_INVERT_RECT: View: %s -> "
2563 				"BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(),
2564 				fCurrentView->Name(), rect.left, rect.top, rect.right,
2565 				rect.bottom));
2566 
2567 			fCurrentView->PenToScreenTransform().Apply(&rect);
2568 			drawingEngine->InvertRect(rect);
2569 			break;
2570 		}
2571 		case AS_STROKE_RECT:
2572 		{
2573 			BRect rect;
2574 			if (link.Read<BRect>(&rect) != B_OK)
2575 				break;
2576 
2577 			DTRACE(("ServerWindow %s: Message AS_STROKE_RECT: View: %s -> "
2578 				"BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(),
2579 				fCurrentView->Name(), rect.left, rect.top, rect.right,
2580 				rect.bottom));
2581 
2582 			fCurrentView->PenToScreenTransform().Apply(&rect);
2583 			drawingEngine->StrokeRect(rect);
2584 			break;
2585 		}
2586 		case AS_FILL_RECT:
2587 		{
2588 			BRect rect;
2589 			if (link.Read<BRect>(&rect) != B_OK)
2590 				break;
2591 
2592 			DTRACE(("ServerWindow %s: Message AS_FILL_RECT: View: %s -> "
2593 				"BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(),
2594 				fCurrentView->Name(), rect.left, rect.top, rect.right,
2595 				rect.bottom));
2596 
2597 			fCurrentView->PenToScreenTransform().Apply(&rect);
2598 			drawingEngine->FillRect(rect);
2599 			break;
2600 		}
2601 		case AS_FILL_RECT_GRADIENT:
2602 		{
2603 			BRect rect;
2604 			link.Read<BRect>(&rect);
2605 			BGradient* gradient;
2606 			if (link.ReadGradient(&gradient) != B_OK)
2607 				break;
2608 
2609 			GTRACE(("ServerWindow %s: Message AS_FILL_RECT_GRADIENT: View: %s "
2610 				"-> BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(),
2611 				fCurrentView->Name(), rect.left, rect.top, rect.right,
2612 				rect.bottom));
2613 
2614 			const SimpleTransform transform =
2615 				fCurrentView->PenToScreenTransform();
2616 			transform.Apply(&rect);
2617 			transform.Apply(gradient);
2618 			drawingEngine->FillRect(rect, *gradient);
2619 			delete gradient;
2620 			break;
2621 		}
2622 		case AS_VIEW_DRAW_BITMAP:
2623 		{
2624 			ViewDrawBitmapInfo info;
2625 			if (link.Read<ViewDrawBitmapInfo>(&info) != B_OK)
2626 				break;
2627 
2628 #if 0
2629 			if (strcmp(fServerApp->SignatureLeaf(), "x-vnd.videolan-vlc") == 0)
2630 				info.options |= B_FILTER_BITMAP_BILINEAR;
2631 #endif
2632 
2633 			ServerBitmap* bitmap = fServerApp->GetBitmap(info.bitmapToken);
2634 			if (bitmap != NULL) {
2635 				DTRACE(("ServerWindow %s: Message AS_VIEW_DRAW_BITMAP: "
2636 					"View: %s, bitmap: %" B_PRId32 " (size %" B_PRId32 " x "
2637 					"%" B_PRId32 "), BRect(%.1f, %.1f, %.1f, %.1f) -> "
2638 					"BRect(%.1f, %.1f, %.1f, %.1f)\n",
2639 					fTitle, fCurrentView->Name(), info.bitmapToken,
2640 					bitmap->Width(), bitmap->Height(),
2641 					info.bitmapRect.left, info.bitmapRect.top,
2642 					info.bitmapRect.right, info.bitmapRect.bottom,
2643 					info.viewRect.left, info.viewRect.top,
2644 					info.viewRect.right, info.viewRect.bottom));
2645 
2646 				fCurrentView->PenToScreenTransform().Apply(&info.viewRect);
2647 
2648 // TODO: Unbreak...
2649 //				if ((info.options & B_WAIT_FOR_RETRACE) != 0)
2650 //					fDesktop->HWInterface()->WaitForRetrace(20000);
2651 
2652 				drawingEngine->DrawBitmap(bitmap, info.bitmapRect,
2653 					info.viewRect, info.options);
2654 
2655 				bitmap->ReleaseReference();
2656 			}
2657 			break;
2658 		}
2659 		case AS_STROKE_ARC:
2660 		case AS_FILL_ARC:
2661 		{
2662 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ARC\n", Title()));
2663 
2664 			float angle, span;
2665 			BRect r;
2666 
2667 			link.Read<BRect>(&r);
2668 			link.Read<float>(&angle);
2669 			if (link.Read<float>(&span) != B_OK)
2670 				break;
2671 
2672 			fCurrentView->PenToScreenTransform().Apply(&r);
2673 			drawingEngine->DrawArc(r, angle, span, code == AS_FILL_ARC);
2674 			break;
2675 		}
2676 		case AS_FILL_ARC_GRADIENT:
2677 		{
2678 			GTRACE(("ServerWindow %s: Message AS_FILL_ARC_GRADIENT\n",
2679 				Title()));
2680 
2681 			float angle, span;
2682 			BRect r;
2683 			link.Read<BRect>(&r);
2684 			link.Read<float>(&angle);
2685 			link.Read<float>(&span);
2686 			BGradient* gradient;
2687 			if (link.ReadGradient(&gradient) != B_OK)
2688 				break;
2689 			const SimpleTransform transform =
2690 				fCurrentView->PenToScreenTransform();
2691 			transform.Apply(&r);
2692 			transform.Apply(gradient);
2693 			drawingEngine->FillArc(r, angle, span, *gradient);
2694 			delete gradient;
2695 			break;
2696 		}
2697 		case AS_STROKE_BEZIER:
2698 		case AS_FILL_BEZIER:
2699 		{
2700 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_BEZIER\n",
2701 				Title()));
2702 
2703 			const SimpleTransform transform =
2704 				fCurrentView->PenToScreenTransform();
2705 			BPoint pts[4];
2706 			status_t status;
2707 			for (int32 i = 0; i < 4; i++) {
2708 				status = link.Read<BPoint>(&(pts[i]));
2709 				transform.Apply(&pts[i]);
2710 			}
2711 			if (status != B_OK)
2712 				break;
2713 
2714 			drawingEngine->DrawBezier(pts, code == AS_FILL_BEZIER);
2715 			break;
2716 		}
2717 		case AS_FILL_BEZIER_GRADIENT:
2718 		{
2719 			GTRACE(("ServerWindow %s: Message AS_FILL_BEZIER_GRADIENT\n",
2720 				Title()));
2721 
2722 			const SimpleTransform transform =
2723 				fCurrentView->PenToScreenTransform();
2724 			BPoint pts[4];
2725 			for (int32 i = 0; i < 4; i++) {
2726 				link.Read<BPoint>(&(pts[i]));
2727 				transform.Apply(&pts[i]);
2728 			}
2729 			BGradient* gradient;
2730 			if (link.ReadGradient(&gradient) != B_OK)
2731 				break;
2732 			transform.Apply(gradient);
2733 			drawingEngine->FillBezier(pts, *gradient);
2734 			delete gradient;
2735 			break;
2736 		}
2737 		case AS_STROKE_ELLIPSE:
2738 		case AS_FILL_ELLIPSE:
2739 		{
2740 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ELLIPSE\n",
2741 				Title()));
2742 
2743 			BRect rect;
2744 			if (link.Read<BRect>(&rect) != B_OK)
2745 				break;
2746 
2747 			fCurrentView->PenToScreenTransform().Apply(&rect);
2748 			drawingEngine->DrawEllipse(rect, code == AS_FILL_ELLIPSE);
2749 			break;
2750 		}
2751 		case AS_FILL_ELLIPSE_GRADIENT:
2752 		{
2753 			GTRACE(("ServerWindow %s: Message AS_FILL_ELLIPSE_GRADIENT\n",
2754 				Title()));
2755 
2756 			BRect rect;
2757 			link.Read<BRect>(&rect);
2758 			BGradient* gradient;
2759 			if (link.ReadGradient(&gradient) != B_OK)
2760 				break;
2761 			const SimpleTransform transform =
2762 				fCurrentView->PenToScreenTransform();
2763 			transform.Apply(&rect);
2764 			transform.Apply(gradient);
2765 			drawingEngine->FillEllipse(rect, *gradient);
2766 			delete gradient;
2767 			break;
2768 		}
2769 		case AS_STROKE_ROUNDRECT:
2770 		case AS_FILL_ROUNDRECT:
2771 		{
2772 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ROUNDRECT\n",
2773 				Title()));
2774 
2775 			BRect rect;
2776 			float xRadius;
2777 			float yRadius;
2778 			link.Read<BRect>(&rect);
2779 			link.Read<float>(&xRadius);
2780 			if (link.Read<float>(&yRadius) != B_OK)
2781 				break;
2782 
2783 			fCurrentView->PenToScreenTransform().Apply(&rect);
2784 			float scale = fCurrentView->CurrentState()->CombinedScale();
2785 			drawingEngine->DrawRoundRect(rect, xRadius * scale, yRadius * scale,
2786 				code == AS_FILL_ROUNDRECT);
2787 			break;
2788 		}
2789 		case AS_FILL_ROUNDRECT_GRADIENT:
2790 		{
2791 			GTRACE(("ServerWindow %s: Message AS_FILL_ROUNDRECT_GRADIENT\n",
2792 				Title()));
2793 
2794 			BRect rect;
2795 			float xrad,yrad;
2796 			link.Read<BRect>(&rect);
2797 			link.Read<float>(&xrad);
2798 			link.Read<float>(&yrad);
2799 			BGradient* gradient;
2800 			if (link.ReadGradient(&gradient) != B_OK)
2801 				break;
2802 			const SimpleTransform transform =
2803 				fCurrentView->PenToScreenTransform();
2804 			transform.Apply(&rect);
2805 			transform.Apply(gradient);
2806 			drawingEngine->FillRoundRect(rect, xrad, yrad, *gradient);
2807 			delete gradient;
2808 			break;
2809 		}
2810 		case AS_STROKE_TRIANGLE:
2811 		case AS_FILL_TRIANGLE:
2812 		{
2813 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_TRIANGLE\n",
2814 				Title()));
2815 
2816 			const SimpleTransform transform =
2817 				fCurrentView->PenToScreenTransform();
2818 			BPoint pts[3];
2819 			BRect rect;
2820 
2821 			for (int32 i = 0; i < 3; i++) {
2822 				link.Read<BPoint>(&(pts[i]));
2823 				transform.Apply(&pts[i]);
2824 			}
2825 
2826 			if (link.Read<BRect>(&rect) != B_OK)
2827 				break;
2828 
2829 			transform.Apply(&rect);
2830 			drawingEngine->DrawTriangle(pts, rect, code == AS_FILL_TRIANGLE);
2831 			break;
2832 		}
2833 		case AS_FILL_TRIANGLE_GRADIENT:
2834 		{
2835 			DTRACE(("ServerWindow %s: Message AS_FILL_TRIANGLE_GRADIENT\n",
2836 				Title()));
2837 
2838 			const SimpleTransform transform =
2839 				fCurrentView->PenToScreenTransform();
2840 			BPoint pts[3];
2841 			BRect rect;
2842 			for (int32 i = 0; i < 3; i++) {
2843 				link.Read<BPoint>(&(pts[i]));
2844 				transform.Apply(&pts[i]);
2845 			}
2846 			link.Read<BRect>(&rect);
2847 			BGradient* gradient;
2848 			if (link.ReadGradient(&gradient) != B_OK)
2849 				break;
2850 			transform.Apply(&rect);
2851 			transform.Apply(gradient);
2852 			drawingEngine->FillTriangle(pts, rect, *gradient);
2853 			delete gradient;
2854 			break;
2855 		}
2856 		case AS_STROKE_POLYGON:
2857 		case AS_FILL_POLYGON:
2858 		{
2859 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_POLYGON\n",
2860 				Title()));
2861 
2862 			BRect polyFrame;
2863 			bool isClosed = true;
2864 			int32 pointCount;
2865 
2866 			link.Read<BRect>(&polyFrame);
2867 			if (code == AS_STROKE_POLYGON)
2868 				link.Read<bool>(&isClosed);
2869 			link.Read<int32>(&pointCount);
2870 
2871 			const SimpleTransform transform =
2872 				fCurrentView->PenToScreenTransform();
2873 			BPoint* pointList = new(nothrow) BPoint[pointCount];
2874 			if (link.Read(pointList, pointCount * sizeof(BPoint)) >= B_OK) {
2875 				for (int32 i = 0; i < pointCount; i++)
2876 					transform.Apply(&pointList[i]);
2877 				transform.Apply(&polyFrame);
2878 
2879 				drawingEngine->DrawPolygon(pointList, pointCount, polyFrame,
2880 					code == AS_FILL_POLYGON, isClosed && pointCount > 2);
2881 			}
2882 			delete[] pointList;
2883 			break;
2884 		}
2885 		case AS_FILL_POLYGON_GRADIENT:
2886 		{
2887 			DTRACE(("ServerWindow %s: Message AS_FILL_POLYGON_GRADIENT\n",
2888 				Title()));
2889 
2890 			BRect polyFrame;
2891 			bool isClosed = true;
2892 			int32 pointCount;
2893 			link.Read<BRect>(&polyFrame);
2894 			link.Read<int32>(&pointCount);
2895 
2896 			const SimpleTransform transform =
2897 				fCurrentView->PenToScreenTransform();
2898 			BPoint* pointList = new(nothrow) BPoint[pointCount];
2899 			BGradient* gradient;
2900 			if (link.Read(pointList, pointCount * sizeof(BPoint)) == B_OK
2901 				&& link.ReadGradient(&gradient) == B_OK) {
2902 				for (int32 i = 0; i < pointCount; i++)
2903 					transform.Apply(&pointList[i]);
2904 				transform.Apply(&polyFrame);
2905 				transform.Apply(gradient);
2906 
2907 				drawingEngine->FillPolygon(pointList, pointCount,
2908 					polyFrame, *gradient, isClosed && pointCount > 2);
2909 				delete gradient;
2910 			}
2911 			delete[] pointList;
2912 			break;
2913 		}
2914 		case AS_STROKE_SHAPE:
2915 		case AS_FILL_SHAPE:
2916 		{
2917 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_SHAPE\n",
2918 				Title()));
2919 
2920 			BRect shapeFrame;
2921 			int32 opCount;
2922 			int32 ptCount;
2923 
2924 			link.Read<BRect>(&shapeFrame);
2925 			link.Read<int32>(&opCount);
2926 			link.Read<int32>(&ptCount);
2927 
2928 			uint32* opList = new(nothrow) uint32[opCount];
2929 			BPoint* ptList = new(nothrow) BPoint[ptCount];
2930 			if (link.Read(opList, opCount * sizeof(uint32)) >= B_OK &&
2931 				link.Read(ptList, ptCount * sizeof(BPoint)) >= B_OK) {
2932 
2933 				// this might seem a bit weird, but under R5, the shapes
2934 				// are always offset by the current pen location
2935 				BPoint screenOffset
2936 					= fCurrentView->CurrentState()->PenLocation();
2937 				shapeFrame.OffsetBy(screenOffset);
2938 
2939 				const SimpleTransform transform =
2940 					fCurrentView->PenToScreenTransform();
2941 				transform.Apply(&screenOffset);
2942 				transform.Apply(&shapeFrame);
2943 
2944 				drawingEngine->DrawShape(shapeFrame, opCount, opList, ptCount,
2945 					ptList, code == AS_FILL_SHAPE, screenOffset,
2946 					fCurrentView->Scale());
2947 			}
2948 
2949 			delete[] opList;
2950 			delete[] ptList;
2951 			break;
2952 		}
2953 		case AS_FILL_SHAPE_GRADIENT:
2954 		{
2955 			DTRACE(("ServerWindow %s: Message AS_FILL_SHAPE_GRADIENT\n",
2956 				Title()));
2957 
2958 			BRect shapeFrame;
2959 			int32 opCount;
2960 			int32 ptCount;
2961 
2962 			link.Read<BRect>(&shapeFrame);
2963 			link.Read<int32>(&opCount);
2964 			link.Read<int32>(&ptCount);
2965 
2966 			uint32* opList = new(nothrow) uint32[opCount];
2967 			BPoint* ptList = new(nothrow) BPoint[ptCount];
2968 			BGradient* gradient;
2969 			if (link.Read(opList, opCount * sizeof(uint32)) == B_OK
2970 				&& link.Read(ptList, ptCount * sizeof(BPoint)) == B_OK
2971 				&& link.ReadGradient(&gradient) == B_OK) {
2972 
2973 				// this might seem a bit weird, but under R5, the shapes
2974 				// are always offset by the current pen location
2975 				BPoint screenOffset
2976 					= fCurrentView->CurrentState()->PenLocation();
2977 				shapeFrame.OffsetBy(screenOffset);
2978 
2979 				const SimpleTransform transform =
2980 					fCurrentView->PenToScreenTransform();
2981 				transform.Apply(&screenOffset);
2982 				transform.Apply(&shapeFrame);
2983 				transform.Apply(gradient);
2984 				drawingEngine->FillShape(shapeFrame, opCount, opList,
2985 					ptCount, ptList, *gradient, screenOffset,
2986 					fCurrentView->Scale());
2987 				delete gradient;
2988 			}
2989 
2990 			delete[] opList;
2991 			delete[] ptList;
2992 			break;
2993 		}
2994 		case AS_FILL_REGION:
2995 		{
2996 			DTRACE(("ServerWindow %s: Message AS_FILL_REGION\n", Title()));
2997 
2998 			BRegion region;
2999 			if (link.ReadRegion(&region) < B_OK)
3000 				break;
3001 
3002 			fCurrentView->PenToScreenTransform().Apply(&region);
3003 			drawingEngine->FillRegion(region);
3004 
3005 			break;
3006 		}
3007 		case AS_FILL_REGION_GRADIENT:
3008 		{
3009 			DTRACE(("ServerWindow %s: Message AS_FILL_REGION_GRADIENT\n",
3010 				Title()));
3011 
3012 			BRegion region;
3013 			link.ReadRegion(&region);
3014 
3015 			BGradient* gradient;
3016 			if (link.ReadGradient(&gradient) != B_OK)
3017 				break;
3018 
3019 			const SimpleTransform transform =
3020 				fCurrentView->PenToScreenTransform();
3021 			transform.Apply(&region);
3022 			transform.Apply(gradient);
3023 			drawingEngine->FillRegion(region, *gradient);
3024 			delete gradient;
3025 			break;
3026 		}
3027 		case AS_STROKE_LINEARRAY:
3028 		{
3029 			DTRACE(("ServerWindow %s: Message AS_STROKE_LINEARRAY\n",
3030 				Title()));
3031 
3032 			// Attached Data:
3033 			// 1) int32 Number of lines in the array
3034 			// 2) LineArrayData
3035 
3036 			int32 lineCount;
3037 			if (link.Read<int32>(&lineCount) != B_OK || lineCount <= 0)
3038 				break;
3039 
3040 			// To speed things up, try to use a stack allocation and only
3041 			// fall back to the heap if there are enough lines...
3042 			ViewLineArrayInfo* lineData;
3043 			const int32 kStackBufferLineDataCount = 64;
3044 			ViewLineArrayInfo lineDataStackBuffer[kStackBufferLineDataCount];
3045 			if (lineCount > kStackBufferLineDataCount) {
3046 				lineData = new(std::nothrow) ViewLineArrayInfo[lineCount];
3047 				if (lineData == NULL)
3048 					break;
3049 			} else
3050 				lineData = lineDataStackBuffer;
3051 
3052 			// Read them all in one go
3053 			size_t dataSize = lineCount * sizeof(ViewLineArrayInfo);
3054 			if (link.Read(lineData, dataSize) != B_OK) {
3055 				if (lineData != lineDataStackBuffer)
3056 					delete[] lineData;
3057 				break;
3058 			}
3059 
3060 			// Convert to screen coords and draw
3061 			const SimpleTransform transform =
3062 				fCurrentView->PenToScreenTransform();
3063 			for (int32 i = 0; i < lineCount; i++) {
3064 				transform.Apply(&lineData[i].startPoint);
3065 				transform.Apply(&lineData[i].endPoint);
3066 			}
3067 			drawingEngine->StrokeLineArray(lineCount, lineData);
3068 
3069 			if (lineData != lineDataStackBuffer)
3070 				delete[] lineData;
3071 			break;
3072 		}
3073 		case AS_DRAW_STRING:
3074 		case AS_DRAW_STRING_WITH_DELTA:
3075 		{
3076 			ViewDrawStringInfo info;
3077 			if (link.Read<ViewDrawStringInfo>(&info) != B_OK
3078 				|| info.stringLength <= 0) {
3079 				break;
3080 			}
3081 
3082 			// NOTE: Careful, the + 1 is for termination!
3083 			BStackOrHeapArray<char, 4096> string(
3084 				(info.stringLength + 1 + 63) / 64 * 64);
3085 			if (!string.IsValid())
3086 				break;
3087 
3088 			escapement_delta* delta = NULL;
3089 			if (code == AS_DRAW_STRING_WITH_DELTA) {
3090 				// In this case, info.delta will contain valid values.
3091 				delta = &info.delta;
3092 			}
3093 
3094 			if (link.Read(string, info.stringLength) != B_OK)
3095 				break;
3096 
3097 			// Terminate the string, if nothing else, it's important
3098 			// for the DTRACE call below...
3099 			string[info.stringLength] = '\0';
3100 
3101 			DTRACE(("ServerWindow %s: Message AS_DRAW_STRING, View: %s "
3102 				"-> %s\n", Title(), fCurrentView->Name(), string));
3103 
3104 			fCurrentView->PenToScreenTransform().Apply(&info.location);
3105 			BPoint penLocation = drawingEngine->DrawString(string,
3106 				info.stringLength, info.location, delta);
3107 
3108 			fCurrentView->ScreenToPenTransform().Apply(&penLocation);
3109 			fCurrentView->CurrentState()->SetPenLocation(penLocation);
3110 
3111 			break;
3112 		}
3113 		case AS_DRAW_STRING_WITH_OFFSETS:
3114 		{
3115 			int32 stringLength;
3116 			if (link.Read<int32>(&stringLength) != B_OK || stringLength <= 0)
3117 				break;
3118 
3119 			int32 glyphCount;
3120 			if (link.Read<int32>(&glyphCount) != B_OK || glyphCount <= 0)
3121 				break;
3122 
3123 			// NOTE: Careful, the + 1 is for termination!
3124 			BStackOrHeapArray<char, 512> string(
3125 				(stringLength + 1 + 63) / 64 * 64);
3126 			BStackOrHeapArray<BPoint, 512> locations(glyphCount);
3127 			if (!string.IsValid() || !locations.IsValid())
3128 				break;
3129 
3130 			if (link.Read(string, stringLength) != B_OK)
3131 				break;
3132 			// Count UTF8 glyphs and make sure we have enough locations
3133 			if ((int32)UTF8CountChars(string, stringLength) > glyphCount)
3134 				break;
3135 			if (link.Read(locations, glyphCount * sizeof(BPoint)) != B_OK)
3136 				break;
3137 			// Terminate the string, if nothing else, it's important
3138 			// for the DTRACE call below...
3139 			string[stringLength] = '\0';
3140 
3141 			DTRACE(("ServerWindow %s: Message AS_DRAW_STRING_WITH_OFFSETS, View: %s "
3142 				"-> %s\n", Title(), fCurrentView->Name(), string));
3143 
3144 			const SimpleTransform transform =
3145 				fCurrentView->PenToScreenTransform();
3146 			for (int32 i = 0; i < glyphCount; i++)
3147 				transform.Apply(&locations[i]);
3148 
3149 			BPoint penLocation = drawingEngine->DrawString(string,
3150 				stringLength, locations);
3151 
3152 			fCurrentView->ScreenToPenTransform().Apply(&penLocation);
3153 			fCurrentView->CurrentState()->SetPenLocation(penLocation);
3154 
3155 			break;
3156 		}
3157 
3158 		case AS_VIEW_DRAW_PICTURE:
3159 		{
3160 			int32 token;
3161 			link.Read<int32>(&token);
3162 
3163 			BPoint where;
3164 			if (link.Read<BPoint>(&where) == B_OK) {
3165 				ServerPicture* picture = App()->GetPicture(token);
3166 				if (picture != NULL) {
3167 					// Setting the drawing origin outside of the
3168 					// state makes sure that everything the picture
3169 					// does is relative to the global picture offset.
3170 					fCurrentView->PushState();
3171 					fCurrentView->SetDrawingOrigin(where);
3172 
3173 					fCurrentView->PushState();
3174 					picture->Play(fCurrentView);
3175 					fCurrentView->PopState();
3176 
3177 					fCurrentView->PopState();
3178 
3179 					picture->ReleaseReference();
3180 				}
3181 			}
3182 			break;
3183 		}
3184 
3185 		case AS_VIEW_END_LAYER:
3186 		{
3187 			DTRACE(("ServerWindow %s: Message AS_VIEW_END_LAYER\n",
3188 				Title()));
3189 
3190 			fCurrentView->BlendAllLayers();
3191 			fCurrentView->SetPicture(NULL);
3192 			fCurrentView->CurrentState()->SetDrawingModeLocked(false);
3193 			break;
3194 		}
3195 
3196 		default:
3197 			debug_printf("ServerWindow %s received unexpected code: %s\n",
3198 				Title(), string_for_message_code(code));
3199 
3200 			if (link.NeedsReply()) {
3201 				// the client is now blocking and waiting for a reply!
3202 				fLink.StartMessage(B_ERROR);
3203 				fLink.Flush();
3204 			}
3205 			break;
3206 	}
3207 
3208 	drawingEngine->UnlockParallelAccess();
3209 }
3210 
3211 
3212 bool
3213 ServerWindow::_DispatchPictureMessage(int32 code, BPrivate::LinkReceiver& link)
3214 {
3215 	ServerPicture* picture = fCurrentView->Picture();
3216 	if (picture == NULL)
3217 		return false;
3218 
3219 	switch (code) {
3220 		case AS_VIEW_SET_ORIGIN:
3221 		{
3222 			float x, y;
3223 			link.Read<float>(&x);
3224 			link.Read<float>(&y);
3225 
3226 			picture->WriteSetOrigin(BPoint(x, y));
3227 			break;
3228 		}
3229 
3230 		case AS_VIEW_INVERT_RECT:
3231 		{
3232 			BRect rect;
3233 			link.Read<BRect>(&rect);
3234 			picture->WriteInvertRect(rect);
3235 			break;
3236 		}
3237 
3238 		case AS_VIEW_PUSH_STATE:
3239 		{
3240 			picture->WritePushState();
3241 			break;
3242 		}
3243 
3244 		case AS_VIEW_POP_STATE:
3245 		{
3246 			picture->WritePopState();
3247 			break;
3248 		}
3249 
3250 		case AS_VIEW_SET_DRAWING_MODE:
3251 		{
3252 			int8 drawingMode;
3253 			link.Read<int8>(&drawingMode);
3254 
3255 			picture->WriteSetDrawingMode((drawing_mode)drawingMode);
3256 
3257 			fCurrentView->CurrentState()->SetDrawingMode(
3258 				(drawing_mode)drawingMode);
3259 			fWindow->GetDrawingEngine()->SetDrawingMode(
3260 				(drawing_mode)drawingMode);
3261 			break;
3262 		}
3263 
3264 		case AS_VIEW_SET_PEN_LOC:
3265 		{
3266 			BPoint location;
3267 			link.Read<BPoint>(&location);
3268 			picture->WriteSetPenLocation(location);
3269 
3270 			fCurrentView->CurrentState()->SetPenLocation(location);
3271 			break;
3272 		}
3273 
3274 		case AS_VIEW_SET_PEN_SIZE:
3275 		{
3276 			float penSize;
3277 			link.Read<float>(&penSize);
3278 			picture->WriteSetPenSize(penSize);
3279 
3280 			fCurrentView->CurrentState()->SetPenSize(penSize);
3281 			fWindow->GetDrawingEngine()->SetPenSize(
3282 				fCurrentView->CurrentState()->PenSize());
3283 			break;
3284 		}
3285 
3286 		case AS_VIEW_SET_LINE_MODE:
3287 		{
3288 
3289 			ViewSetLineModeInfo info;
3290 			link.Read<ViewSetLineModeInfo>(&info);
3291 
3292 			picture->WriteSetLineMode(info.lineCap, info.lineJoin,
3293 				info.miterLimit);
3294 
3295 			fCurrentView->CurrentState()->SetLineCapMode(info.lineCap);
3296 			fCurrentView->CurrentState()->SetLineJoinMode(info.lineJoin);
3297 			fCurrentView->CurrentState()->SetMiterLimit(info.miterLimit);
3298 
3299 			fWindow->GetDrawingEngine()->SetStrokeMode(info.lineCap,
3300 				info.lineJoin, info.miterLimit);
3301 			break;
3302 		}
3303 		case AS_VIEW_SET_SCALE:
3304 		{
3305 			float scale;
3306 			if (link.Read<float>(&scale) != B_OK)
3307 				break;
3308 
3309 			picture->WriteSetScale(scale);
3310 
3311 			fCurrentView->SetScale(scale);
3312 			_UpdateDrawState(fCurrentView);
3313 			break;
3314 		}
3315 		case AS_VIEW_SET_TRANSFORM:
3316 		{
3317 			BAffineTransform transform;
3318 			if (link.Read<BAffineTransform>(&transform) != B_OK)
3319 				break;
3320 
3321 			picture->WriteSetTransform(transform);
3322 
3323 			fCurrentView->CurrentState()->SetTransform(transform);
3324 			_UpdateDrawState(fCurrentView);
3325 			break;
3326 		}
3327 
3328 		case AS_VIEW_AFFINE_TRANSLATE:
3329 		{
3330 			double x, y;
3331 			link.Read<double>(&x);
3332 			link.Read<double>(&y);
3333 
3334 			picture->WriteTranslateBy(x, y);
3335 
3336 			BAffineTransform current =
3337 				fCurrentView->CurrentState()->Transform();
3338 			current.PreTranslateBy(x, y);
3339 			fCurrentView->CurrentState()->SetTransform(current);
3340 			_UpdateDrawState(fCurrentView);
3341 			break;
3342 		}
3343 
3344 		case AS_VIEW_AFFINE_SCALE:
3345 		{
3346 			double x, y;
3347 			link.Read<double>(&x);
3348 			link.Read<double>(&y);
3349 
3350 			picture->WriteScaleBy(x, y);
3351 
3352 			BAffineTransform current =
3353 				fCurrentView->CurrentState()->Transform();
3354 			current.PreScaleBy(x, y);
3355 			fCurrentView->CurrentState()->SetTransform(current);
3356 			_UpdateDrawState(fCurrentView);
3357 			break;
3358 		}
3359 
3360 		case AS_VIEW_AFFINE_ROTATE:
3361 		{
3362 			double angleRadians;
3363 			link.Read<double>(&angleRadians);
3364 
3365 			picture->WriteRotateBy(angleRadians);
3366 
3367 			BAffineTransform current =
3368 				fCurrentView->CurrentState()->Transform();
3369 			current.PreRotateBy(angleRadians);
3370 			fCurrentView->CurrentState()->SetTransform(current);
3371 			_UpdateDrawState(fCurrentView);
3372 			break;
3373 		}
3374 
3375 
3376 		case AS_VIEW_SET_PATTERN:
3377 		{
3378 			pattern pat;
3379 			link.Read(&pat, sizeof(pattern));
3380 			picture->WriteSetPattern(pat);
3381 			break;
3382 		}
3383 
3384 		case AS_VIEW_SET_FONT_STATE:
3385 		{
3386 			uint16 mask = fCurrentView->CurrentState()->ReadFontFromLink(link);
3387 			fWindow->GetDrawingEngine()->SetFont(
3388 				fCurrentView->CurrentState());
3389 
3390 			picture->WriteFontState(fCurrentView->CurrentState()->Font(), mask);
3391 			break;
3392 		}
3393 
3394 		case AS_FILL_RECT:
3395 		case AS_STROKE_RECT:
3396 		{
3397 			BRect rect;
3398 			link.Read<BRect>(&rect);
3399 
3400 			picture->WriteDrawRect(rect, code == AS_FILL_RECT);
3401 			break;
3402 		}
3403 
3404 		case AS_FILL_REGION:
3405 		{
3406 			// There is no B_PIC_FILL_REGION op, we have to
3407 			// implement it using B_PIC_FILL_RECT
3408 			BRegion region;
3409 			if (link.ReadRegion(&region) < B_OK)
3410 				break;
3411 			for (int32 i = 0; i < region.CountRects(); i++)
3412 				picture->WriteDrawRect(region.RectAt(i), true);
3413 			break;
3414 		}
3415 
3416 		case AS_STROKE_ROUNDRECT:
3417 		case AS_FILL_ROUNDRECT:
3418 		{
3419 			BRect rect;
3420 			link.Read<BRect>(&rect);
3421 
3422 			BPoint radii;
3423 			link.Read<float>(&radii.x);
3424 			link.Read<float>(&radii.y);
3425 
3426 			picture->WriteDrawRoundRect(rect, radii, code == AS_FILL_ROUNDRECT);
3427 			break;
3428 		}
3429 
3430 		case AS_STROKE_ELLIPSE:
3431 		case AS_FILL_ELLIPSE:
3432 		{
3433 			BRect rect;
3434 			link.Read<BRect>(&rect);
3435 			picture->WriteDrawEllipse(rect, code == AS_FILL_ELLIPSE);
3436 			break;
3437 		}
3438 
3439 		case AS_STROKE_ARC:
3440 		case AS_FILL_ARC:
3441 		{
3442 			BRect rect;
3443 			link.Read<BRect>(&rect);
3444 			float startTheta, arcTheta;
3445 			link.Read<float>(&startTheta);
3446 			link.Read<float>(&arcTheta);
3447 
3448 			BPoint radii((rect.Width() + 1) / 2, (rect.Height() + 1) / 2);
3449 			BPoint center = rect.LeftTop() + radii;
3450 
3451 			picture->WriteDrawArc(center, radii, startTheta, arcTheta,
3452 				code == AS_FILL_ARC);
3453 			break;
3454 		}
3455 
3456 		case AS_STROKE_TRIANGLE:
3457 		case AS_FILL_TRIANGLE:
3458 		{
3459 			// There is no B_PIC_FILL/STROKE_TRIANGLE op,
3460 			// we implement it using B_PIC_FILL/STROKE_POLYGON
3461 			BPoint points[3];
3462 
3463 			for (int32 i = 0; i < 3; i++) {
3464 				link.Read<BPoint>(&(points[i]));
3465 			}
3466 
3467 			BRect rect;
3468 			link.Read<BRect>(&rect);
3469 
3470 			picture->WriteDrawPolygon(3, points,
3471 					true, code == AS_FILL_TRIANGLE);
3472 			break;
3473 		}
3474 		case AS_STROKE_POLYGON:
3475 		case AS_FILL_POLYGON:
3476 		{
3477 			BRect polyFrame;
3478 			bool isClosed = true;
3479 			int32 pointCount;
3480 			const bool fill = (code == AS_FILL_POLYGON);
3481 
3482 			link.Read<BRect>(&polyFrame);
3483 			if (code == AS_STROKE_POLYGON)
3484 				link.Read<bool>(&isClosed);
3485 			link.Read<int32>(&pointCount);
3486 
3487 			BPoint* pointList = new(nothrow) BPoint[pointCount];
3488 			if (link.Read(pointList, pointCount * sizeof(BPoint)) >= B_OK) {
3489 				picture->WriteDrawPolygon(pointCount, pointList,
3490 					isClosed && pointCount > 2, fill);
3491 			}
3492 			delete[] pointList;
3493 			break;
3494 		}
3495 
3496 		case AS_STROKE_BEZIER:
3497 		case AS_FILL_BEZIER:
3498 		{
3499 			BPoint points[4];
3500 			for (int32 i = 0; i < 4; i++) {
3501 				link.Read<BPoint>(&(points[i]));
3502 			}
3503 			picture->WriteDrawBezier(points, code == AS_FILL_BEZIER);
3504 			break;
3505 		}
3506 
3507 		case AS_STROKE_LINE:
3508 		{
3509 			ViewStrokeLineInfo info;
3510 			link.Read<ViewStrokeLineInfo>(&info);
3511 
3512 			picture->WriteStrokeLine(info.startPoint, info.endPoint);
3513 
3514 			BPoint penPos = info.endPoint;
3515 			const SimpleTransform transform =
3516 				fCurrentView->PenToScreenTransform();
3517 			transform.Apply(&info.endPoint);
3518 			fCurrentView->CurrentState()->SetPenLocation(penPos);
3519 			break;
3520 		}
3521 
3522 		case AS_STROKE_LINEARRAY:
3523 		{
3524 			int32 lineCount;
3525 			if (link.Read<int32>(&lineCount) != B_OK || lineCount <= 0)
3526 				break;
3527 
3528 			// To speed things up, try to use a stack allocation and only
3529 			// fall back to the heap if there are enough lines...
3530 			ViewLineArrayInfo* lineData;
3531 			const int32 kStackBufferLineDataCount = 64;
3532 			ViewLineArrayInfo lineDataStackBuffer[kStackBufferLineDataCount];
3533 			if (lineCount > kStackBufferLineDataCount) {
3534 				lineData = new(std::nothrow) ViewLineArrayInfo[lineCount];
3535 				if (lineData == NULL)
3536 					break;
3537 			} else
3538 				lineData = lineDataStackBuffer;
3539 
3540 			// Read them all in one go
3541 			size_t dataSize = lineCount * sizeof(ViewLineArrayInfo);
3542 			if (link.Read(lineData, dataSize) != B_OK) {
3543 				if (lineData != lineDataStackBuffer)
3544 					delete[] lineData;
3545 				break;
3546 			}
3547 
3548 			picture->WritePushState();
3549 
3550 			for (int32 i = 0; i < lineCount; i++) {
3551 				picture->WriteSetHighColor(lineData[i].color);
3552 				picture->WriteStrokeLine(lineData[i].startPoint,
3553 					lineData[i].endPoint);
3554 			}
3555 
3556 			picture->WritePopState();
3557 
3558 			if (lineData != lineDataStackBuffer)
3559 				delete[] lineData;
3560 			break;
3561 		}
3562 
3563 		case AS_VIEW_SET_LOW_COLOR:
3564 		case AS_VIEW_SET_HIGH_COLOR:
3565 		{
3566 			rgb_color color;
3567 			link.Read(&color, sizeof(rgb_color));
3568 
3569 			if (code == AS_VIEW_SET_HIGH_COLOR) {
3570 				picture->WriteSetHighColor(color);
3571 				fCurrentView->CurrentState()->SetHighColor(color);
3572 				fWindow->GetDrawingEngine()->SetHighColor(color);
3573 			} else {
3574 				picture->WriteSetLowColor(color);
3575 				fCurrentView->CurrentState()->SetLowColor(color);
3576 				fWindow->GetDrawingEngine()->SetLowColor(color);
3577 			}
3578 		}	break;
3579 
3580 		case AS_DRAW_STRING:
3581 		case AS_DRAW_STRING_WITH_DELTA:
3582 		{
3583 			ViewDrawStringInfo info;
3584 			if (link.Read<ViewDrawStringInfo>(&info) != B_OK)
3585 				break;
3586 
3587 			char* string = (char*)malloc(info.stringLength + 1);
3588 			if (string == NULL)
3589 				break;
3590 
3591 			if (code != AS_DRAW_STRING_WITH_DELTA) {
3592 				// In this case, info.delta will NOT contain valid values.
3593 				info.delta = (escapement_delta){ 0, 0 };
3594 			}
3595 
3596 			if (link.Read(string, info.stringLength) != B_OK) {
3597 				free(string);
3598 				break;
3599 			}
3600 			// Terminate the string
3601 			string[info.stringLength] = '\0';
3602 
3603 			picture->WriteDrawString(info.location, string, info.stringLength,
3604 				info.delta);
3605 
3606 			// We need to update the pen location
3607 			fCurrentView->PenToScreenTransform().Apply(&info.location);
3608 			BPoint penLocation = fWindow->GetDrawingEngine()->DrawStringDry(
3609 				string, info.stringLength, info.location, &info.delta);
3610 
3611 			fCurrentView->ScreenToPenTransform().Apply(&penLocation);
3612 			fCurrentView->CurrentState()->SetPenLocation(penLocation);
3613 
3614 			free(string);
3615 			break;
3616 		}
3617 
3618 		case AS_DRAW_STRING_WITH_OFFSETS:
3619 		{
3620 			int32 stringLength;
3621 			if (link.Read<int32>(&stringLength) != B_OK || stringLength <= 0)
3622 				break;
3623 
3624 			int32 glyphCount;
3625 			if (link.Read<int32>(&glyphCount) != B_OK || glyphCount <= 0)
3626 				break;
3627 
3628 			// NOTE: Careful, the + 1 is for termination!
3629 			BStackOrHeapArray<char, 512> string(
3630 				(stringLength + 1 + 63) / 64 * 64);
3631 			BStackOrHeapArray<BPoint, 512> locations(glyphCount);
3632 			if (!string.IsValid() || !locations.IsValid())
3633 				break;
3634 
3635 			if (link.Read(string, stringLength) != B_OK)
3636 				break;
3637 			// Count UTF8 glyphs and make sure we have enough locations
3638 			if ((int32)UTF8CountChars(string, stringLength) > glyphCount)
3639 				break;
3640 			if (link.Read(locations, glyphCount * sizeof(BPoint)) != B_OK)
3641 				break;
3642 			// Terminate the string
3643 			string[stringLength] = '\0';
3644 
3645 			const SimpleTransform transform =
3646 				fCurrentView->PenToScreenTransform();
3647 			for (int32 i = 0; i < glyphCount; i++)
3648 				transform.Apply(&locations[i]);
3649 
3650 			picture->WriteDrawString(string, stringLength, locations,
3651 				glyphCount);
3652 
3653 			// Update pen location
3654 			BPoint penLocation = fWindow->GetDrawingEngine()->DrawStringDry(
3655 				string, stringLength, locations);
3656 
3657 			fCurrentView->ScreenToPenTransform().Apply(&penLocation);
3658 			fCurrentView->CurrentState()->SetPenLocation(penLocation);
3659 
3660 			break;
3661 		}
3662 
3663 		case AS_STROKE_SHAPE:
3664 		case AS_FILL_SHAPE:
3665 		{
3666 			BRect shapeFrame;
3667 			int32 opCount;
3668 			int32 ptCount;
3669 
3670 			link.Read<BRect>(&shapeFrame);
3671 			link.Read<int32>(&opCount);
3672 			link.Read<int32>(&ptCount);
3673 
3674 			BStackOrHeapArray<uint32, 512> opList(opCount);
3675 			BStackOrHeapArray<BPoint, 512> ptList(ptCount);
3676 			if (!opList.IsValid() || !ptList.IsValid()
3677 				|| link.Read(opList, opCount * sizeof(uint32)) < B_OK
3678 				|| link.Read(ptList, ptCount * sizeof(BPoint)) < B_OK) {
3679 				break;
3680 			}
3681 			picture->WriteDrawShape(opCount, opList, ptCount,
3682 				ptList, code == AS_FILL_SHAPE);
3683 
3684 			break;
3685 		}
3686 
3687 		case AS_VIEW_DRAW_BITMAP:
3688 		{
3689 			ViewDrawBitmapInfo info;
3690 			link.Read<ViewDrawBitmapInfo>(&info);
3691 
3692 			ServerBitmap* bitmap = App()->GetBitmap(info.bitmapToken);
3693 			if (bitmap == NULL)
3694 				break;
3695 
3696 			picture->WriteDrawBitmap(info.bitmapRect, info.viewRect,
3697 				bitmap->Width(), bitmap->Height(), bitmap->BytesPerRow(),
3698 				bitmap->ColorSpace(), info.options, bitmap->Bits(),
3699 				bitmap->BitsLength());
3700 
3701 			bitmap->ReleaseReference();
3702 			break;
3703 		}
3704 
3705 		case AS_VIEW_DRAW_PICTURE:
3706 		{
3707 			int32 token;
3708 			link.Read<int32>(&token);
3709 
3710 			BPoint where;
3711 			if (link.Read<BPoint>(&where) == B_OK) {
3712 				ServerPicture* pictureToDraw = App()->GetPicture(token);
3713 				if (pictureToDraw != NULL) {
3714 					// We need to make a copy of the picture, since it can
3715 					// change after it has been drawn
3716 					ServerPicture* copy = App()->CreatePicture(pictureToDraw);
3717 					picture->NestPicture(copy);
3718 					picture->WriteDrawPicture(where, copy->Token());
3719 
3720 					pictureToDraw->ReleaseReference();
3721 				}
3722 			}
3723 			break;
3724 		}
3725 
3726 		case AS_VIEW_SET_CLIP_REGION:
3727 		{
3728 			int32 rectCount;
3729 			status_t status = link.Read<int32>(&rectCount);
3730 				// a negative count means no
3731 				// region for the current draw state,
3732 				// but an *empty* region is actually valid!
3733 				// even if it means no drawing is allowed
3734 
3735 			if (status < B_OK)
3736 				break;
3737 
3738 			if (rectCount >= 0) {
3739 				// we are supposed to set the clipping region
3740 				BRegion region;
3741 				if (rectCount > 0 && link.ReadRegion(&region) < B_OK)
3742 					break;
3743 				picture->WriteSetClipping(region);
3744 			} else {
3745 				// we are supposed to clear the clipping region
3746 				picture->WriteClearClipping();
3747 			}
3748 			break;
3749 		}
3750 
3751 		case AS_VIEW_CLIP_TO_PICTURE:
3752 		{
3753 			int32 pictureToken;
3754 			BPoint where;
3755 			bool inverse = false;
3756 
3757 			link.Read<int32>(&pictureToken);
3758 			if (pictureToken < 0)
3759 				break;
3760 
3761 			link.Read<BPoint>(&where);
3762 			if (link.Read<bool>(&inverse) != B_OK)
3763 				break;
3764 
3765 			ServerPicture* pictureToClip = fServerApp->GetPicture(pictureToken);
3766 			if (pictureToClip != NULL) {
3767 				// We need to make a copy of the picture, since it can
3768 				// change after it has been drawn
3769 				ServerPicture* copy = App()->CreatePicture(pictureToClip);
3770 				picture->NestPicture(copy);
3771 				picture->WriteClipToPicture(copy->Token(), where, inverse);
3772 
3773 				pictureToClip->ReleaseReference();
3774 			}
3775 			break;
3776 		}
3777 
3778 		case AS_VIEW_CLIP_TO_RECT:
3779 		{
3780 			bool inverse;
3781 			BRect rect;
3782 			link.Read<bool>(&inverse);
3783 			link.Read<BRect>(&rect);
3784 			picture->WriteClipToRect(rect, inverse);
3785 
3786 			break;
3787 		}
3788 
3789 		case AS_VIEW_CLIP_TO_SHAPE:
3790 		{
3791 			bool inverse;
3792 			link.Read<bool>(&inverse);
3793 
3794 			shape_data shape;
3795 			link.Read<int32>(&shape.opCount);
3796 			link.Read<int32>(&shape.ptCount);
3797 			shape.opSize = shape.opCount * sizeof(uint32);
3798 			shape.ptSize = shape.ptCount * sizeof(BPoint);
3799 			shape.opList = new(nothrow) uint32[shape.opCount];
3800 			shape.ptList = new(nothrow) BPoint[shape.ptCount];
3801 			if (link.Read(shape.opList, shape.opSize) >= B_OK
3802 				&& link.Read(shape.ptList, shape.ptSize) >= B_OK) {
3803 				picture->WriteClipToShape(shape.opCount, shape.opList,
3804 					shape.ptCount, shape.ptList, inverse);
3805 			}
3806 
3807 			delete[] shape.opList;
3808 			delete[] shape.ptList;
3809 			break;
3810 		}
3811 
3812 		case AS_VIEW_BEGIN_PICTURE:
3813 		{
3814 			ServerPicture* newPicture = App()->CreatePicture();
3815 			if (newPicture != NULL) {
3816 				newPicture->PushPicture(picture);
3817 				newPicture->SyncState(fCurrentView);
3818 				fCurrentView->SetPicture(newPicture);
3819 			}
3820 			break;
3821 		}
3822 
3823 		case AS_VIEW_APPEND_TO_PICTURE:
3824 		{
3825 			int32 token;
3826 			link.Read<int32>(&token);
3827 
3828 			ServerPicture* appendPicture = App()->GetPicture(token);
3829 			if (appendPicture != NULL) {
3830 				//picture->SyncState(fCurrentView);
3831 				appendPicture->AppendPicture(picture);
3832 			}
3833 
3834 			fCurrentView->SetPicture(appendPicture);
3835 
3836 			if (appendPicture != NULL)
3837 				appendPicture->ReleaseReference();
3838 			break;
3839 		}
3840 
3841 		case AS_VIEW_END_PICTURE:
3842 		{
3843 			ServerPicture* poppedPicture = picture->PopPicture();
3844 			fCurrentView->SetPicture(poppedPicture);
3845 			if (poppedPicture != NULL)
3846 				poppedPicture->ReleaseReference();
3847 
3848 			fLink.StartMessage(B_OK);
3849 			fLink.Attach<int32>(picture->Token());
3850 			fLink.Flush();
3851 			return true;
3852 		}
3853 
3854 		case AS_VIEW_BEGIN_LAYER:
3855 		{
3856 			uint8 opacity;
3857 			link.Read<uint8>(&opacity);
3858 
3859 			Layer* layer = dynamic_cast<Layer*>(picture);
3860 			if (layer == NULL)
3861 				break;
3862 
3863 			Layer* nextLayer = new(std::nothrow) Layer(opacity);
3864 			if (nextLayer == NULL)
3865 				break;
3866 
3867 			if (opacity != 255) {
3868 				fCurrentView->CurrentState()->SetDrawingMode(B_OP_ALPHA);
3869 				fCurrentView->CurrentState()->SetBlendingMode(B_PIXEL_ALPHA,
3870 					B_ALPHA_COMPOSITE);
3871 				fCurrentView->CurrentState()->SetDrawingModeLocked(true);
3872 			}
3873 
3874 			nextLayer->PushLayer(layer);
3875 			fCurrentView->SetPicture(nextLayer);
3876 			break;
3877 		}
3878 
3879 		case AS_VIEW_END_LAYER:
3880 		{
3881 			Layer* layer = dynamic_cast<Layer*>(picture);
3882 			if (layer == NULL)
3883 				break;
3884 
3885 			Layer* previousLayer = layer->PopLayer();
3886 			if (previousLayer == NULL) {
3887 				// End last layer
3888 				return false;
3889 			}
3890 			fCurrentView->SetPicture(previousLayer);
3891 
3892 			previousLayer->WriteBlendLayer(layer);
3893 			break;
3894 		}
3895 
3896 /*
3897 		case AS_VIEW_SET_BLENDING_MODE:
3898 		{
3899 			ViewBlendingModeInfo info;
3900 			link.Read<ViewBlendingModeInfo>(&info);
3901 
3902 			picture->BeginOp(B_PIC_SET_BLENDING_MODE);
3903 			picture->AddInt16((int16)info.sourceAlpha);
3904 			picture->AddInt16((int16)info.alphaFunction);
3905 			picture->EndOp();
3906 
3907 			fCurrentView->CurrentState()->SetBlendingMode(info.sourceAlpha,
3908 				info.alphaFunction);
3909 			fWindow->GetDrawingEngine()->SetBlendingMode(info.sourceAlpha,
3910 				info.alphaFunction);
3911 			break;
3912 		}*/
3913 		default:
3914 			return false;
3915 	}
3916 
3917 	if (link.NeedsReply()) {
3918 		fLink.StartMessage(B_ERROR);
3919 		fLink.Flush();
3920 	}
3921 	return true;
3922 }
3923 
3924 
3925 /*!	\brief Message-dispatching loop for the ServerWindow
3926 
3927 	Watches the ServerWindow's message port and dispatches as necessary
3928 */
3929 void
3930 ServerWindow::_MessageLooper()
3931 {
3932 	// Send a reply to our window - it is expecting fMessagePort
3933 	// port and some other info.
3934 
3935 	fLink.StartMessage(B_OK);
3936 	fLink.Attach<port_id>(fMessagePort);
3937 
3938 	int32 minWidth, maxWidth, minHeight, maxHeight;
3939 	fWindow->GetSizeLimits(&minWidth, &maxWidth, &minHeight, &maxHeight);
3940 
3941 	fLink.Attach<BRect>(fWindow->Frame());
3942 	fLink.Attach<float>((float)minWidth);
3943 	fLink.Attach<float>((float)maxWidth);
3944 	fLink.Attach<float>((float)minHeight);
3945 	fLink.Attach<float>((float)maxHeight);
3946 	fLink.Flush();
3947 
3948 	BPrivate::LinkReceiver& receiver = fLink.Receiver();
3949 	bool quitLoop = false;
3950 
3951 	while (!quitLoop) {
3952 		//STRACE(("info: ServerWindow::MonitorWin listening on port %ld.\n",
3953 		//	fMessagePort));
3954 
3955 		int32 code;
3956 		status_t status = receiver.GetNextMessage(code);
3957 		if (status != B_OK) {
3958 			// that shouldn't happen, it's our port
3959 			printf("Someone deleted our message port!\n");
3960 
3961 			// try to let our client die happily
3962 			NotifyQuitRequested();
3963 			break;
3964 		}
3965 
3966 #ifdef PROFILE_MESSAGE_LOOP
3967 		bigtime_t start = system_time();
3968 #endif
3969 
3970 		Lock();
3971 
3972 #ifdef PROFILE_MESSAGE_LOOP
3973 		bigtime_t diff = system_time() - start;
3974 		if (diff > 10000) {
3975 			printf("ServerWindow %s: lock acquisition took %" B_PRId64 " usecs\n",
3976 				Title(), diff);
3977 		}
3978 #endif
3979 
3980 		int32 messagesProcessed = 0;
3981 		bigtime_t processingStart = system_time();
3982 		bool lockedDesktopSingleWindow = false;
3983 
3984 		while (true) {
3985 			if (code == AS_DELETE_WINDOW || code == kMsgQuitLooper) {
3986 				// this means the client has been killed
3987 				DTRACE(("ServerWindow %s received 'AS_DELETE_WINDOW' message "
3988 					"code\n", Title()));
3989 
3990 				if (code == AS_DELETE_WINDOW) {
3991 					fLink.StartMessage(B_OK);
3992 					fLink.Flush();
3993 				}
3994 
3995 				if (lockedDesktopSingleWindow)
3996 					fDesktop->UnlockSingleWindow();
3997 
3998 				quitLoop = true;
3999 
4000 				// ServerWindow's destructor takes care of pulling this object
4001 				// off the desktop.
4002 				ASSERT(fWindow->IsHidden());
4003 				break;
4004 			}
4005 
4006 			// Acquire the appropriate lock
4007 			bool needsAllWindowsLocked = _MessageNeedsAllWindowsLocked(code);
4008 			if (needsAllWindowsLocked) {
4009 				// We may already still hold the read-lock from the previous
4010 				// inner-loop iteration.
4011 				if (lockedDesktopSingleWindow) {
4012 					fDesktop->UnlockSingleWindow();
4013 					lockedDesktopSingleWindow = false;
4014 				}
4015 				fDesktop->LockAllWindows();
4016 			} else {
4017 				// We never keep the write-lock across inner-loop iterations,
4018 				// so there is nothing else to do besides read-locking unless
4019 				// we already have the read-lock from the previous iteration.
4020 				if (!lockedDesktopSingleWindow) {
4021 					fDesktop->LockSingleWindow();
4022 					lockedDesktopSingleWindow = true;
4023 				}
4024 			}
4025 
4026 			if (atomic_and(&fRedrawRequested, 0) != 0) {
4027 #ifdef PROFILE_MESSAGE_LOOP
4028 				bigtime_t redrawStart = system_time();
4029 #endif
4030 				fWindow->RedrawDirtyRegion();
4031 #ifdef PROFILE_MESSAGE_LOOP
4032 				diff = system_time() - redrawStart;
4033 				atomic_add(&sRedrawProcessingTime.count, 1);
4034 # ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
4035 				atomic_add64(&sRedrawProcessingTime.time, diff);
4036 # else
4037 				sRedrawProcessingTime.time += diff;
4038 # endif
4039 #endif
4040 			}
4041 
4042 #ifdef PROFILE_MESSAGE_LOOP
4043 			bigtime_t dispatchStart = system_time();
4044 #endif
4045 			_DispatchMessage(code, receiver);
4046 
4047 #ifdef PROFILE_MESSAGE_LOOP
4048 			if (code >= 0 && code < AS_LAST_CODE) {
4049 				diff = system_time() - dispatchStart;
4050 				atomic_add(&sMessageProfile[code].count, 1);
4051 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
4052 				atomic_add64(&sMessageProfile[code].time, diff);
4053 #else
4054 				sMessageProfile[code].time += diff;
4055 #endif
4056 				if (diff > 10000) {
4057 					printf("ServerWindow %s: message %" B_PRId32 " took %"
4058 						B_PRId64 " usecs\n", Title(), code, diff);
4059 				}
4060 			}
4061 #endif
4062 
4063 			if (needsAllWindowsLocked)
4064 				fDesktop->UnlockAllWindows();
4065 
4066 			// Only process up to 70 waiting messages at once (we have the
4067 			// Desktop locked), but don't hold the lock longer than 10 ms
4068 			if (!receiver.HasMessages() || ++messagesProcessed > 70
4069 				|| system_time() - processingStart > 10000) {
4070 				if (lockedDesktopSingleWindow)
4071 					fDesktop->UnlockSingleWindow();
4072 				break;
4073 			}
4074 
4075 			// next message
4076 			status_t status = receiver.GetNextMessage(code);
4077 			if (status != B_OK) {
4078 				// that shouldn't happen, it's our port
4079 				printf("Someone deleted our message port!\n");
4080 				if (lockedDesktopSingleWindow)
4081 					fDesktop->UnlockSingleWindow();
4082 
4083 				// try to let our client die happily
4084 				NotifyQuitRequested();
4085 				break;
4086 			}
4087 		}
4088 
4089 		Unlock();
4090 	}
4091 
4092 	// We were asked to quit the message loop - either on request or because of
4093 	// an error.
4094 	Quit();
4095 		// does not return
4096 }
4097 
4098 
4099 void
4100 ServerWindow::ScreenChanged(const BMessage* message)
4101 {
4102 	SendMessageToClient(message);
4103 
4104 	if (fDirectWindowInfo != NULL && fDirectWindowInfo->IsFullScreen())
4105 		_ResizeToFullScreen();
4106 }
4107 
4108 
4109 status_t
4110 ServerWindow::SendMessageToClient(const BMessage* msg, int32 target) const
4111 {
4112 	if (target == B_NULL_TOKEN)
4113 		target = fClientToken;
4114 
4115 	BMessenger reply;
4116 	BMessage::Private messagePrivate((BMessage*)msg);
4117 	return messagePrivate.SendMessage(fClientLooperPort, fClientTeam, target,
4118 		0, false, reply);
4119 }
4120 
4121 
4122 Window*
4123 ServerWindow::MakeWindow(BRect frame, const char* name,
4124 	window_look look, window_feel feel, uint32 flags, uint32 workspace)
4125 {
4126 	// The non-offscreen ServerWindow uses the DrawingEngine instance from
4127 	// the desktop.
4128 	return new(std::nothrow) ::Window(frame, name, look, feel, flags,
4129 		workspace, this, fDesktop->HWInterface()->CreateDrawingEngine());
4130 }
4131 
4132 
4133 void
4134 ServerWindow::HandleDirectConnection(int32 bufferState, int32 driverState)
4135 {
4136 	ASSERT_MULTI_LOCKED(fDesktop->WindowLocker());
4137 
4138 	if (fDirectWindowInfo == NULL)
4139 		return;
4140 
4141 	STRACE(("HandleDirectConnection(bufferState = %" B_PRId32 ", driverState = "
4142 		"%" B_PRId32 ")\n", bufferState, driverState));
4143 
4144 	status_t status = fDirectWindowInfo->SetState(
4145 		(direct_buffer_state)bufferState, (direct_driver_state)driverState,
4146 		fDesktop->HWInterface()->FrontBuffer(), fWindow->Frame(),
4147 		fWindow->VisibleContentRegion());
4148 
4149 	if (status != B_OK) {
4150 		char errorString[256];
4151 		snprintf(errorString, sizeof(errorString),
4152 			"%s killed for a problem in DirectConnected(): %s",
4153 			App()->Signature(), strerror(status));
4154 		syslog(LOG_ERR, errorString);
4155 
4156 		// The client application didn't release the semaphore
4157 		// within the given timeout. Or something else went wrong.
4158 		// Deleting this member should make it crash.
4159 		delete fDirectWindowInfo;
4160 		fDirectWindowInfo = NULL;
4161 	} else if ((bufferState & B_DIRECT_MODE_MASK) == B_DIRECT_START)
4162 		fIsDirectlyAccessing = true;
4163 	else if ((bufferState & B_DIRECT_MODE_MASK) == B_DIRECT_STOP)
4164 		fIsDirectlyAccessing = false;
4165 }
4166 
4167 
4168 void
4169 ServerWindow::_SetCurrentView(View* view)
4170 {
4171 	if (fCurrentView == view)
4172 		return;
4173 
4174 	fCurrentView = view;
4175 	fCurrentDrawingRegionValid = false;
4176 	_UpdateDrawState(fCurrentView);
4177 
4178 #if 0
4179 #if DELAYED_BACKGROUND_CLEARING
4180 	if (fCurrentView && fCurrentView->IsBackgroundDirty()
4181 		&& fWindow->InUpdate()) {
4182 		DrawingEngine* drawingEngine = fWindow->GetDrawingEngine();
4183 		if (drawingEngine->LockParallelAccess()) {
4184 			fWindow->GetEffectiveDrawingRegion(fCurrentView,
4185 				fCurrentDrawingRegion);
4186 			fCurrentDrawingRegionValid = true;
4187 			BRegion dirty(fCurrentDrawingRegion);
4188 
4189 			BRegion content;
4190 			fWindow->GetContentRegion(&content);
4191 
4192 			fCurrentView->Draw(drawingEngine, &dirty, &content, false);
4193 
4194 			drawingEngine->UnlockParallelAccess();
4195 		}
4196 	}
4197 #endif
4198 #endif // 0
4199 }
4200 
4201 
4202 void
4203 ServerWindow::_UpdateDrawState(View* view)
4204 {
4205 	// switch the drawing state
4206 	// TODO: is it possible to scroll a view while it
4207 	// is being drawn? probably not... otherwise the
4208 	// "offsets" passed below would need to be updated again
4209 	DrawingEngine* drawingEngine = fWindow->GetDrawingEngine();
4210 	if (view != NULL && drawingEngine != NULL) {
4211 		BPoint leftTop(0, 0);
4212 		if (view->GetAlphaMask() != NULL) {
4213 			view->LocalToScreenTransform().Apply(&leftTop);
4214 			view->GetAlphaMask()->SetCanvasGeometry(leftTop, view->Bounds());
4215 			leftTop = BPoint(0, 0);
4216 		}
4217 		view->PenToScreenTransform().Apply(&leftTop);
4218 		drawingEngine->SetDrawState(view->CurrentState(), leftTop.x, leftTop.y);
4219 	}
4220 }
4221 
4222 
4223 void
4224 ServerWindow::_UpdateCurrentDrawingRegion()
4225 {
4226 	if (!fCurrentDrawingRegionValid
4227 		|| fWindow->DrawingRegionChanged(fCurrentView)) {
4228 		fWindow->GetEffectiveDrawingRegion(fCurrentView, fCurrentDrawingRegion);
4229 		fCurrentDrawingRegionValid = true;
4230 	}
4231 }
4232 
4233 
4234 bool
4235 ServerWindow::_MessageNeedsAllWindowsLocked(uint32 code) const
4236 {
4237 	switch (code) {
4238 		case AS_SET_WINDOW_TITLE:
4239 		case AS_ADD_TO_SUBSET:
4240 		case AS_REMOVE_FROM_SUBSET:
4241 		case AS_VIEW_CREATE_ROOT:
4242 		case AS_VIEW_CREATE:
4243 		case AS_SEND_BEHIND:
4244 		case AS_SET_LOOK:
4245 		case AS_SET_FEEL:
4246 		case AS_SET_FLAGS:
4247 		case AS_SET_WORKSPACES:
4248 		case AS_WINDOW_MOVE:
4249 		case AS_WINDOW_RESIZE:
4250 		case AS_SET_SIZE_LIMITS:
4251 		case AS_SYSTEM_FONT_CHANGED:
4252 		case AS_SET_DECORATOR_SETTINGS:
4253 		case AS_GET_MOUSE:
4254 		case AS_DIRECT_WINDOW_SET_FULLSCREEN:
4255 //		case AS_VIEW_SET_EVENT_MASK:
4256 //		case AS_VIEW_SET_MOUSE_EVENT_MASK:
4257 		case AS_TALK_TO_DESKTOP_LISTENER:
4258 			return true;
4259 		default:
4260 			return false;
4261 	}
4262 }
4263 
4264 
4265 void
4266 ServerWindow::_ResizeToFullScreen()
4267 {
4268 	BRect screenFrame;
4269 
4270 	{
4271 		AutoReadLocker _(fDesktop->ScreenLocker());
4272 		const Screen* screen = fWindow->Screen();
4273 		if (screen == NULL)
4274 			return;
4275 
4276 		screenFrame = fWindow->Screen()->Frame();
4277 	}
4278 
4279 	fDesktop->MoveWindowBy(fWindow,
4280 		screenFrame.left - fWindow->Frame().left,
4281 		screenFrame.top - fWindow->Frame().top);
4282 	fDesktop->ResizeWindowBy(fWindow,
4283 		screenFrame.Width() - fWindow->Frame().Width(),
4284 		screenFrame.Height() - fWindow->Frame().Height());
4285 }
4286 
4287 
4288 status_t
4289 ServerWindow::_EnableDirectWindowMode()
4290 {
4291 	if (fDirectWindowInfo != NULL) {
4292 		// already in direct window mode
4293 		return B_ERROR;
4294 	}
4295 
4296 	if (fDesktop->HWInterface()->FrontBuffer() == NULL) {
4297 		// direct window mode not supported
4298 		return B_UNSUPPORTED;
4299 	}
4300 
4301 	fDirectWindowInfo = new(std::nothrow) DirectWindowInfo;
4302 	if (fDirectWindowInfo == NULL)
4303 		return B_NO_MEMORY;
4304 
4305 	status_t status = fDirectWindowInfo->InitCheck();
4306 	if (status != B_OK) {
4307 		delete fDirectWindowInfo;
4308 		fDirectWindowInfo = NULL;
4309 
4310 		return status;
4311 	}
4312 
4313 	return B_OK;
4314 }
4315 
4316 
4317 void
4318 ServerWindow::_DirectWindowSetFullScreen(bool enable)
4319 {
4320 	window_feel feel = kWindowScreenFeel;
4321 
4322 	if (enable) {
4323 		fDesktop->HWInterface()->SetCursorVisible(false);
4324 
4325 		fDirectWindowInfo->EnableFullScreen(fWindow->Frame(), fWindow->Feel());
4326 		_ResizeToFullScreen();
4327 	} else {
4328 		const BRect& originalFrame = fDirectWindowInfo->OriginalFrame();
4329 
4330 		fDirectWindowInfo->DisableFullScreen();
4331 
4332 		// Resize window back to its original size
4333 		fDesktop->MoveWindowBy(fWindow,
4334 			originalFrame.left - fWindow->Frame().left,
4335 			originalFrame.top - fWindow->Frame().top);
4336 		fDesktop->ResizeWindowBy(fWindow,
4337 			originalFrame.Width() - fWindow->Frame().Width(),
4338 			originalFrame.Height() - fWindow->Frame().Height());
4339 
4340 		fDesktop->HWInterface()->SetCursorVisible(true);
4341 	}
4342 
4343 	fDesktop->SetWindowFeel(fWindow, feel);
4344 }
4345