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