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