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