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