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