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