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