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