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