xref: /haiku/src/servers/app/ServerWindow.cpp (revision 85892ec52f476b254d75e2bb2e6560e72faa567c)
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: %" B_PRId32 "\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 
1269 					if (fCurrentView == view || fCurrentView->HasParent(view))
1270 						_SetCurrentView(parent);
1271 
1272 					delete view;
1273 				} // else we don't delete the root view
1274 			}
1275 			break;
1276 		}
1277 		case AS_VIEW_SET_STATE:
1278 		{
1279 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_STATE: "
1280 				"View name: %s\n", fTitle, fCurrentView->Name()));
1281 
1282 			fCurrentView->CurrentState()->ReadFromLink(link);
1283 			// TODO: When is this used?!?
1284 			fCurrentView->RebuildClipping(true);
1285 			_UpdateDrawState(fCurrentView);
1286 
1287 			break;
1288 		}
1289 		case AS_VIEW_SET_FONT_STATE:
1290 		{
1291 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_FONT_STATE: "
1292 				"View name: %s\n", fTitle, fCurrentView->Name()));
1293 
1294 			fCurrentView->CurrentState()->ReadFontFromLink(link);
1295 			fWindow->GetDrawingEngine()->SetFont(
1296 				fCurrentView->CurrentState());
1297 			break;
1298 		}
1299 		case AS_VIEW_GET_STATE:
1300 		{
1301 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_STATE: "
1302 				"View name: %s\n", fTitle, fCurrentView->Name()));
1303 
1304 			fLink.StartMessage(B_OK);
1305 
1306 			// attach state data
1307 			fCurrentView->CurrentState()->WriteToLink(fLink.Sender());
1308 			fLink.Flush();
1309 			break;
1310 		}
1311 		case AS_VIEW_SET_EVENT_MASK:
1312 		{
1313 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_EVENT_MASK: "
1314 				"View name: %s\n", fTitle, fCurrentView->Name()));
1315 			uint32 eventMask, options;
1316 
1317 			link.Read<uint32>(&eventMask);
1318 			if (link.Read<uint32>(&options) == B_OK) {
1319 				fCurrentView->SetEventMask(eventMask, options);
1320 
1321 fDesktop->UnlockSingleWindow();
1322 				// TODO: possible deadlock!
1323 				if (eventMask != 0 || options != 0) {
1324 					fDesktop->EventDispatcher().AddListener(EventTarget(),
1325 						fCurrentView->Token(), eventMask, options);
1326 				} else {
1327 					fDesktop->EventDispatcher().RemoveListener(EventTarget(),
1328 						fCurrentView->Token());
1329 				}
1330 fDesktop->LockSingleWindow();
1331 			}
1332 			break;
1333 		}
1334 		case AS_VIEW_SET_MOUSE_EVENT_MASK:
1335 		{
1336 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_MOUSE_EVENT_MASK: "
1337 				"View name: %s\n", fTitle, fCurrentView->Name()));
1338 			uint32 eventMask, options;
1339 
1340 			link.Read<uint32>(&eventMask);
1341 			if (link.Read<uint32>(&options) == B_OK) {
1342 fDesktop->UnlockSingleWindow();
1343 				// TODO: possible deadlock
1344 				if (eventMask != 0 || options != 0) {
1345 					if (options & B_LOCK_WINDOW_FOCUS)
1346 						fDesktop->SetFocusLocked(fWindow);
1347 					fDesktop->EventDispatcher().AddTemporaryListener(EventTarget(),
1348 						fCurrentView->Token(), eventMask, options);
1349 				} else {
1350 					fDesktop->EventDispatcher().RemoveTemporaryListener(EventTarget(),
1351 						fCurrentView->Token());
1352 				}
1353 fDesktop->LockSingleWindow();
1354 			}
1355 
1356 			// TODO: support B_LOCK_WINDOW_FOCUS option in Desktop
1357 			break;
1358 		}
1359 		case AS_VIEW_MOVE_TO:
1360 		{
1361 			float x, y;
1362 			link.Read<float>(&x);
1363 			if (link.Read<float>(&y) != B_OK)
1364 				break;
1365 
1366 			DTRACE(("ServerWindow %s: Message AS_VIEW_MOVE_TO: View name: "
1367 				"%s, x: %.1f, y: %.1f\n", fTitle, fCurrentView->Name(), x, y));
1368 
1369 			float offsetX = x - fCurrentView->Frame().left;
1370 			float offsetY = y - fCurrentView->Frame().top;
1371 
1372 			BRegion dirty;
1373 			fCurrentView->MoveBy(offsetX, offsetY, &dirty);
1374 
1375 			// TODO: think about how to avoid this hack:
1376 			// the parent clipping needs to be updated, it is not
1377 			// done in MoveBy() since it would cause
1378 			// too much computations when children are resized because
1379 			// follow modes
1380 			if (View* parent = fCurrentView->Parent())
1381 				parent->RebuildClipping(false);
1382 
1383 			fWindow->MarkContentDirty(dirty);
1384 			break;
1385 		}
1386 		case AS_VIEW_RESIZE_TO:
1387 		{
1388 			float newWidth, newHeight;
1389 			link.Read<float>(&newWidth);
1390 			if (link.Read<float>(&newHeight) != B_OK)
1391 				break;
1392 
1393 			DTRACE(("ServerWindow %s: Message AS_VIEW_RESIZE_TO: View name: "
1394 				"%s, width: %.1f, height: %.1f\n", fTitle,
1395 				fCurrentView->Name(), newWidth, newHeight));
1396 
1397 			float deltaWidth = newWidth - fCurrentView->Frame().Width();
1398 			float deltaHeight = newHeight - fCurrentView->Frame().Height();
1399 
1400 			BRegion dirty;
1401 			fCurrentView->ResizeBy(deltaWidth, deltaHeight, &dirty);
1402 
1403 			// TODO: see above
1404 			if (View* parent = fCurrentView->Parent())
1405 				parent->RebuildClipping(false);
1406 
1407 			fWindow->MarkContentDirty(dirty);
1408 			break;
1409 		}
1410 		case AS_VIEW_GET_COORD:
1411 		{
1412 			// our offset in the parent -> will be originX and originY
1413 			// in BView
1414 			BPoint parentOffset = fCurrentView->Frame().LeftTop();
1415 
1416 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_COORD: "
1417 				"View: %s -> x: %.1f, y: %.1f\n", Title(),
1418 				fCurrentView->Name(), parentOffset.x, parentOffset.y));
1419 
1420 			fLink.StartMessage(B_OK);
1421 			fLink.Attach<BPoint>(parentOffset);
1422 			fLink.Attach<BRect>(fCurrentView->Bounds());
1423 			fLink.Flush();
1424 			break;
1425 		}
1426 		case AS_VIEW_SET_ORIGIN:
1427 		{
1428 			float x, y;
1429 			link.Read<float>(&x);
1430 			if (link.Read<float>(&y) != B_OK)
1431 				break;
1432 
1433 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_ORIGIN: "
1434 				"View: %s -> x: %.1f, y: %.1f\n", Title(),
1435 				fCurrentView->Name(), x, y));
1436 
1437 			fCurrentView->SetDrawingOrigin(BPoint(x, y));
1438 			_UpdateDrawState(fCurrentView);
1439 			break;
1440 		}
1441 		case AS_VIEW_GET_ORIGIN:
1442 		{
1443 			BPoint drawingOrigin = fCurrentView->DrawingOrigin();
1444 
1445 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_ORIGIN: "
1446 				"View: %s -> x: %.1f, y: %.1f\n", Title(),
1447 				fCurrentView->Name(), drawingOrigin.x, drawingOrigin.y));
1448 
1449 			fLink.StartMessage(B_OK);
1450 			fLink.Attach<BPoint>(drawingOrigin);
1451 			fLink.Flush();
1452 			break;
1453 		}
1454 		case AS_VIEW_RESIZE_MODE:
1455 		{
1456 			uint32 resizeMode;
1457 			if (link.Read<uint32>(&resizeMode) != B_OK)
1458 				break;
1459 
1460 			DTRACE(("ServerWindow %s: Message AS_VIEW_RESIZE_MODE: "
1461 				"View: %s -> %" B_PRId32 "\n", Title(), fCurrentView->Name(),
1462 				resizeMode));
1463 
1464 			fCurrentView->SetResizeMode(resizeMode);
1465 			break;
1466 		}
1467 		case AS_VIEW_SET_FLAGS:
1468 		{
1469 			uint32 flags;
1470 			link.Read<uint32>(&flags);
1471 
1472 			// The views clipping changes when the B_DRAW_ON_CHILDREN flag is
1473 			// toggled.
1474 			bool updateClipping = (flags & B_DRAW_ON_CHILDREN)
1475 				^ (fCurrentView->Flags() & B_DRAW_ON_CHILDREN);
1476 
1477 			fCurrentView->SetFlags(flags);
1478 			_UpdateDrawState(fCurrentView);
1479 
1480 			if (updateClipping) {
1481 				fCurrentView->RebuildClipping(false);
1482 				fCurrentDrawingRegionValid = false;
1483 			}
1484 
1485 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_FLAGS: "
1486 				"View: %s -> flags: %" B_PRIu32 "\n", Title(),
1487 				fCurrentView->Name(), flags));
1488 			break;
1489 		}
1490 		case AS_VIEW_HIDE:
1491 			DTRACE(("ServerWindow %s: Message AS_VIEW_HIDE: View: %s\n",
1492 				Title(), fCurrentView->Name()));
1493 			fCurrentView->SetHidden(true);
1494 			break;
1495 
1496 		case AS_VIEW_SHOW:
1497 			DTRACE(("ServerWindow %s: Message AS_VIEW_SHOW: View: %s\n",
1498 				Title(), fCurrentView->Name()));
1499 			fCurrentView->SetHidden(false);
1500 			break;
1501 
1502 		case AS_VIEW_SET_LINE_MODE:
1503 		{
1504 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_LINE_MODE: "
1505 				"View: %s\n", Title(), fCurrentView->Name()));
1506 			ViewSetLineModeInfo info;
1507 			if (link.Read<ViewSetLineModeInfo>(&info) != B_OK)
1508 				break;
1509 
1510 			fCurrentView->CurrentState()->SetLineCapMode(info.lineCap);
1511 			fCurrentView->CurrentState()->SetLineJoinMode(info.lineJoin);
1512 			fCurrentView->CurrentState()->SetMiterLimit(info.miterLimit);
1513 
1514 			fWindow->GetDrawingEngine()->SetStrokeMode(info.lineCap,
1515 				info.lineJoin, info.miterLimit);
1516 
1517 			break;
1518 		}
1519 		case AS_VIEW_GET_LINE_MODE:
1520 		{
1521 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_LINE_MODE: "
1522 				"View: %s\n", Title(), fCurrentView->Name()));
1523 			ViewSetLineModeInfo info;
1524 			info.lineJoin = fCurrentView->CurrentState()->LineJoinMode();
1525 			info.lineCap = fCurrentView->CurrentState()->LineCapMode();
1526 			info.miterLimit = fCurrentView->CurrentState()->MiterLimit();
1527 
1528 			fLink.StartMessage(B_OK);
1529 			fLink.Attach<ViewSetLineModeInfo>(info);
1530 			fLink.Flush();
1531 
1532 			break;
1533 		}
1534 		case AS_VIEW_SET_FILL_RULE:
1535 		{
1536 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_FILL_RULE: "
1537 				"View: %s\n", Title(), fCurrentView->Name()));
1538 			int32 fillRule;
1539 			if (link.Read<int32>(&fillRule) != B_OK)
1540 				break;
1541 
1542 			fCurrentView->CurrentState()->SetFillRule(fillRule);
1543 			fWindow->GetDrawingEngine()->SetFillRule(fillRule);
1544 
1545 			break;
1546 		}
1547 		case AS_VIEW_GET_FILL_RULE:
1548 		{
1549 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_FILL_RULE: "
1550 				"View: %s\n", Title(), fCurrentView->Name()));
1551 			int32 fillRule = fCurrentView->CurrentState()->FillRule();
1552 
1553 			fLink.StartMessage(B_OK);
1554 			fLink.Attach<int32>(fillRule);
1555 			fLink.Flush();
1556 
1557 			break;
1558 		}
1559 		case AS_VIEW_PUSH_STATE:
1560 		{
1561 			DTRACE(("ServerWindow %s: Message AS_VIEW_PUSH_STATE: View: "
1562 				"%s\n", Title(), fCurrentView->Name()));
1563 
1564 			fCurrentView->PushState();
1565 			// TODO: is this necessary?
1566 //			_UpdateDrawState(fCurrentView);
1567 			break;
1568 		}
1569 		case AS_VIEW_POP_STATE:
1570 		{
1571 			DTRACE(("ServerWindow %s: Message AS_VIEW_POP_STATE: View: %s\n",
1572 				Title(), fCurrentView->Name()));
1573 
1574 			fCurrentView->PopState();
1575 			_UpdateDrawState(fCurrentView);
1576 			break;
1577 		}
1578 		case AS_VIEW_SET_SCALE:
1579 		{
1580 			float scale;
1581 			if (link.Read<float>(&scale) != B_OK)
1582 				break;
1583 
1584 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_SCALE: "
1585 				"View: %s -> scale: %.2f\n", Title(), fCurrentView->Name(),
1586 				scale));
1587 
1588 			fCurrentView->SetScale(scale);
1589 			_UpdateDrawState(fCurrentView);
1590 			break;
1591 		}
1592 		case AS_VIEW_GET_SCALE:
1593 		{
1594 			float scale = fCurrentView->CurrentState()->Scale();
1595 
1596 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_SCALE: "
1597 				"View: %s -> scale: %.2f\n",
1598 				Title(), fCurrentView->Name(), scale));
1599 
1600 			fLink.StartMessage(B_OK);
1601 			fLink.Attach<float>(scale);
1602 			fLink.Flush();
1603 			break;
1604 		}
1605 		case AS_VIEW_SET_TRANSFORM:
1606 		{
1607 			BAffineTransform transform;
1608 			if (link.Read<BAffineTransform>(&transform) != B_OK)
1609 				break;
1610 
1611 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_TRANSFORM: "
1612 				"View: %s -> transform: %.2f, %.2f, %.2f, %.2f, %.2f, %.2f\n",
1613 				Title(), fCurrentView->Name(), transform.sx, transform.shy,
1614 				transform.shx, transform.sy, transform.tx, transform.ty));
1615 
1616 			fCurrentView->CurrentState()->SetTransform(transform);
1617 			_UpdateDrawState(fCurrentView);
1618 			break;
1619 		}
1620 		case AS_VIEW_GET_TRANSFORM:
1621 		{
1622 			BAffineTransform transform
1623 				= fCurrentView->CurrentState()->Transform();
1624 
1625 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_TRANSFORM: "
1626 				"View: %s -> transform: %.2f, %.2f, %.2f, %.2f, %.2f, %.2f\n",
1627 				Title(), fCurrentView->Name(), transform.sx, transform.shy,
1628 				transform.shx, transform.sy, transform.tx, transform.ty));
1629 
1630 			fLink.StartMessage(B_OK);
1631 			fLink.Attach<BAffineTransform>(transform);
1632 			fLink.Flush();
1633 			break;
1634 		}
1635 		case AS_VIEW_SET_PEN_LOC:
1636 		{
1637 			BPoint location;
1638 			if (link.Read<BPoint>(&location) != B_OK)
1639 				break;
1640 
1641 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_PEN_LOC: "
1642 				"View: %s -> BPoint(%.1f, %.1f)\n", Title(),
1643 				fCurrentView->Name(), location.x, location.y));
1644 
1645 			fCurrentView->CurrentState()->SetPenLocation(location);
1646 			break;
1647 		}
1648 		case AS_VIEW_GET_PEN_LOC:
1649 		{
1650 			BPoint location = fCurrentView->CurrentState()->PenLocation();
1651 
1652 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_PEN_LOC: "
1653 				"View: %s -> BPoint(%.1f, %.1f)\n", Title(),
1654 				fCurrentView->Name(), location.x, location.y));
1655 
1656 			fLink.StartMessage(B_OK);
1657 			fLink.Attach<BPoint>(location);
1658 			fLink.Flush();
1659 
1660 			break;
1661 		}
1662 		case AS_VIEW_SET_PEN_SIZE:
1663 		{
1664 			float penSize;
1665 			if (link.Read<float>(&penSize) != B_OK)
1666 				break;
1667 
1668 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_PEN_SIZE: "
1669 				"View: %s -> %.1f\n", Title(), fCurrentView->Name(), penSize));
1670 
1671 			fCurrentView->CurrentState()->SetPenSize(penSize);
1672 			fWindow->GetDrawingEngine()->SetPenSize(
1673 				fCurrentView->CurrentState()->PenSize());
1674 			break;
1675 		}
1676 		case AS_VIEW_GET_PEN_SIZE:
1677 		{
1678 			float penSize = fCurrentView->CurrentState()->UnscaledPenSize();
1679 
1680 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_PEN_SIZE: "
1681 				"View: %s -> %.1f\n", Title(), fCurrentView->Name(), penSize));
1682 
1683 			fLink.StartMessage(B_OK);
1684 			fLink.Attach<float>(penSize);
1685 			fLink.Flush();
1686 
1687 			break;
1688 		}
1689 		case AS_VIEW_SET_VIEW_COLOR:
1690 		{
1691 			rgb_color color;
1692 			if (link.Read(&color, sizeof(rgb_color)) != B_OK)
1693 				break;
1694 
1695 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_VIEW_COLOR: "
1696 				"View: %s -> rgb_color(%d, %d, %d, %d)\n", Title(),
1697 				fCurrentView->Name(), color.red, color.green, color.blue,
1698 				color.alpha));
1699 
1700 			fCurrentView->SetViewColor(color);
1701 			break;
1702 		}
1703 		case AS_VIEW_GET_VIEW_COLOR:
1704 		{
1705 			rgb_color color = fCurrentView->ViewColor();
1706 
1707 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_VIEW_COLOR: "
1708 				"View: %s -> rgb_color(%d, %d, %d, %d)\n",
1709 				Title(), fCurrentView->Name(), color.red, color.green,
1710 				color.blue, color.alpha));
1711 
1712 			fLink.StartMessage(B_OK);
1713 			fLink.Attach<rgb_color>(color);
1714 			fLink.Flush();
1715 			break;
1716 		}
1717 		case AS_VIEW_SET_HIGH_COLOR:
1718 		{
1719 			rgb_color color;
1720 			if (link.Read(&color, sizeof(rgb_color)) != B_OK)
1721 				break;
1722 
1723 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_HIGH_COLOR: "
1724 				"View: %s -> rgb_color(%d, %d, %d, %d)\n",
1725 				Title(), fCurrentView->Name(), color.red, color.green,
1726 				color.blue, color.alpha));
1727 
1728 			fCurrentView->CurrentState()->SetHighColor(color);
1729 			fWindow->GetDrawingEngine()->SetHighColor(color);
1730 			break;
1731 		}
1732 		case AS_VIEW_GET_HIGH_COLOR:
1733 		{
1734 			rgb_color color = fCurrentView->CurrentState()->HighColor();
1735 
1736 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_HIGH_COLOR: "
1737 				"View: %s -> rgb_color(%d, %d, %d, %d)\n",
1738 				Title(), fCurrentView->Name(), color.red, color.green,
1739 				color.blue, color.alpha));
1740 
1741 			fLink.StartMessage(B_OK);
1742 			fLink.Attach<rgb_color>(color);
1743 			fLink.Flush();
1744 			break;
1745 		}
1746 		case AS_VIEW_SET_LOW_COLOR:
1747 		{
1748 			rgb_color color;
1749 			if (link.Read(&color, sizeof(rgb_color)) != B_OK)
1750 				break;
1751 
1752 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_LOW_COLOR: "
1753 				"View: %s -> rgb_color(%d, %d, %d, %d)\n",
1754 				Title(), fCurrentView->Name(), color.red, color.green,
1755 				color.blue, color.alpha));
1756 
1757 			fCurrentView->CurrentState()->SetLowColor(color);
1758 			fWindow->GetDrawingEngine()->SetLowColor(color);
1759 			break;
1760 		}
1761 		case AS_VIEW_GET_LOW_COLOR:
1762 		{
1763 			rgb_color color = fCurrentView->CurrentState()->LowColor();
1764 
1765 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_LOW_COLOR: "
1766 				"View: %s -> rgb_color(%d, %d, %d, %d)\n",
1767 				Title(), fCurrentView->Name(), color.red, color.green,
1768 				color.blue, color.alpha));
1769 
1770 			fLink.StartMessage(B_OK);
1771 			fLink.Attach<rgb_color>(color);
1772 			fLink.Flush();
1773 			break;
1774 		}
1775 		case AS_VIEW_SET_PATTERN:
1776 		{
1777 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_PATTERN: "
1778 				"View: %s\n", fTitle, fCurrentView->Name()));
1779 
1780 			pattern pat;
1781 			if (link.Read(&pat, sizeof(pattern)) != B_OK)
1782 				break;
1783 
1784 			fCurrentView->CurrentState()->SetPattern(Pattern(pat));
1785 			fWindow->GetDrawingEngine()->SetPattern(pat);
1786 			break;
1787 		}
1788 
1789 		case AS_VIEW_SET_BLENDING_MODE:
1790 		{
1791 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_BLEND_MODE: "
1792 				"View: %s\n", Title(), fCurrentView->Name()));
1793 
1794 			ViewBlendingModeInfo info;
1795 			if (link.Read<ViewBlendingModeInfo>(&info) != B_OK)
1796 				break;
1797 
1798 			fCurrentView->CurrentState()->SetBlendingMode(
1799 				info.sourceAlpha, info.alphaFunction);
1800 			fWindow->GetDrawingEngine()->SetBlendingMode(
1801 				info.sourceAlpha, info.alphaFunction);
1802 			break;
1803 		}
1804 		case AS_VIEW_GET_BLENDING_MODE:
1805 		{
1806 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_BLEND_MODE: "
1807 				"View: %s\n", Title(), fCurrentView->Name()));
1808 
1809 			ViewBlendingModeInfo info;
1810 			info.sourceAlpha = fCurrentView->CurrentState()->AlphaSrcMode();
1811 			info.alphaFunction = fCurrentView->CurrentState()->AlphaFncMode();
1812 
1813 			fLink.StartMessage(B_OK);
1814 			fLink.Attach<ViewBlendingModeInfo>(info);
1815 			fLink.Flush();
1816 
1817 			break;
1818 		}
1819 		case AS_VIEW_SET_DRAWING_MODE:
1820 		{
1821 			int8 drawingMode;
1822 			if (link.Read<int8>(&drawingMode) != B_OK)
1823 				break;
1824 
1825 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_DRAW_MODE: "
1826 				"View: %s -> %s\n", Title(), fCurrentView->Name(),
1827 				kDrawingModeMap[drawingMode]));
1828 
1829 			fCurrentView->CurrentState()->SetDrawingMode(
1830 				(drawing_mode)drawingMode);
1831 			fWindow->GetDrawingEngine()->SetDrawingMode(
1832 				(drawing_mode)drawingMode);
1833 			break;
1834 		}
1835 		case AS_VIEW_GET_DRAWING_MODE:
1836 		{
1837 			int8 drawingMode
1838 				= (int8)(fCurrentView->CurrentState()->GetDrawingMode());
1839 
1840 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_DRAW_MODE: "
1841 				"View: %s -> %s\n", Title(), fCurrentView->Name(),
1842 				kDrawingModeMap[drawingMode]));
1843 
1844 			fLink.StartMessage(B_OK);
1845 			fLink.Attach<int8>(drawingMode);
1846 			fLink.Flush();
1847 
1848 			break;
1849 		}
1850 		case AS_VIEW_SET_VIEW_BITMAP:
1851 		{
1852 			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_VIEW_BITMAP: "
1853 				"View: %s\n", Title(), fCurrentView->Name()));
1854 
1855 			int32 bitmapToken, resizingMode, options;
1856 			BRect srcRect, dstRect;
1857 
1858 			link.Read<int32>(&bitmapToken);
1859 			link.Read<BRect>(&srcRect);
1860 			link.Read<BRect>(&dstRect);
1861 			link.Read<int32>(&resizingMode);
1862 			status_t status = link.Read<int32>(&options);
1863 
1864 			rgb_color colorKey = {0};
1865 
1866 			if (status == B_OK) {
1867 				ServerBitmap* bitmap = fServerApp->GetBitmap(bitmapToken);
1868 				if (bitmapToken == -1 || bitmap != NULL) {
1869 					bool wasOverlay = fCurrentView->ViewBitmap() != NULL
1870 						&& fCurrentView->ViewBitmap()->Overlay() != NULL;
1871 
1872 					fCurrentView->SetViewBitmap(bitmap, srcRect, dstRect,
1873 						resizingMode, options);
1874 
1875 					// TODO: if we revert the view color overlay handling
1876 					//	in View::Draw() to the BeOS version, we never
1877 					//	need to invalidate the view for overlays.
1878 
1879 					// Invalidate view - but only if this is a non-overlay
1880 					// switch
1881 					if (bitmap == NULL || bitmap->Overlay() == NULL
1882 						|| !wasOverlay) {
1883 						BRegion dirty((BRect)fCurrentView->Bounds());
1884 						fWindow->InvalidateView(fCurrentView, dirty);
1885 					}
1886 
1887 					if (bitmap != NULL && bitmap->Overlay() != NULL) {
1888 						bitmap->Overlay()->SetFlags(options);
1889 						colorKey = bitmap->Overlay()->Color();
1890 					}
1891 
1892 					if (bitmap != NULL)
1893 						bitmap->ReleaseReference();
1894 				} else
1895 					status = B_BAD_VALUE;
1896 			}
1897 
1898 			fLink.StartMessage(status);
1899 			if (status == B_OK && (options & AS_REQUEST_COLOR_KEY) != 0) {
1900 				// Attach color key for the overlay bitmap
1901 				fLink.Attach<rgb_color>(colorKey);
1902 			}
1903 
1904 			fLink.Flush();
1905 			break;
1906 		}
1907 		case AS_VIEW_PRINT_ALIASING:
1908 		{
1909 			DTRACE(("ServerWindow %s: Message AS_VIEW_PRINT_ALIASING: "
1910 				"View: %s\n", Title(), fCurrentView->Name()));
1911 
1912 			bool fontAliasing;
1913 			if (link.Read<bool>(&fontAliasing) == B_OK) {
1914 				fCurrentView->CurrentState()->SetForceFontAliasing(fontAliasing);
1915 				_UpdateDrawState(fCurrentView);
1916 			}
1917 			break;
1918 		}
1919 		case AS_VIEW_CLIP_TO_PICTURE:
1920 		{
1921 			DTRACE(("ServerWindow %s: Message AS_VIEW_CLIP_TO_PICTURE: "
1922 				"View: %s\n", Title(), fCurrentView->Name()));
1923 
1924 			int32 pictureToken;
1925 			BPoint where;
1926 			bool inverse = false;
1927 
1928 			link.Read<int32>(&pictureToken);
1929 			if (pictureToken < 0) {
1930 				fCurrentView->SetAlphaMask(NULL);
1931 				_UpdateDrawState(fCurrentView);
1932 				break;
1933 			}
1934 
1935 			link.Read<BPoint>(&where);
1936 			if (link.Read<bool>(&inverse) != B_OK)
1937 				break;
1938 
1939 			ServerPicture* picture = fServerApp->GetPicture(pictureToken);
1940 			if (picture == NULL)
1941 				break;
1942 
1943 			AlphaMask* mask = new(std::nothrow) AlphaMask(
1944 				picture, inverse, where, *fCurrentView->CurrentState());
1945 			fCurrentView->SetAlphaMask(mask);
1946 			if (mask != NULL)
1947 				mask->ReleaseReference();
1948 			_UpdateDrawState(fCurrentView);
1949 
1950 			picture->ReleaseReference();
1951 			break;
1952 		}
1953 
1954 		case AS_VIEW_GET_CLIP_REGION:
1955 		{
1956 			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_CLIP_REGION: "
1957 				"View: %s\n", Title(), fCurrentView->Name()));
1958 
1959 			// if this view is hidden, it has no visible region
1960 			fLink.StartMessage(B_OK);
1961 			if (!fWindow->IsVisible() || !fCurrentView->IsVisible()) {
1962 				BRegion empty;
1963 				fLink.AttachRegion(empty);
1964 			} else {
1965 				_UpdateCurrentDrawingRegion();
1966 				BRegion region(fCurrentDrawingRegion);
1967 				fCurrentView->ConvertFromScreen(&region);
1968 				fLink.AttachRegion(region);
1969 			}
1970 			fLink.Flush();
1971 
1972 			break;
1973 		}
1974 		case AS_VIEW_SET_CLIP_REGION:
1975 		{
1976 			int32 rectCount;
1977 			status_t status = link.Read<int32>(&rectCount);
1978 				// a negative count means no
1979 				// region for the current draw state,
1980 				// but an *empty* region is actually valid!
1981 				// even if it means no drawing is allowed
1982 
1983 			if (status < B_OK)
1984 				break;
1985 
1986 			if (rectCount >= 0) {
1987 				// we are supposed to set the clipping region
1988 				BRegion region;
1989 				if (rectCount > 0 && link.ReadRegion(&region) < B_OK)
1990 					break;
1991 
1992 				DTRACE(("ServerWindow %s: Message AS_VIEW_SET_CLIP_REGION: "
1993 					"View: %s -> rect count: %" B_PRId32 ", frame = "
1994 					"BRect(%.1f, %.1f, %.1f, %.1f)\n",
1995 					Title(), fCurrentView->Name(), rectCount,
1996 					region.Frame().left, region.Frame().top,
1997 					region.Frame().right, region.Frame().bottom));
1998 
1999 				fCurrentView->SetUserClipping(&region);
2000 			} else {
2001 				// we are supposed to unset the clipping region
2002 				// passing NULL sets this states region to that
2003 				// of the previous state
2004 
2005 				DTRACE(("ServerWindow %s: Message AS_VIEW_SET_CLIP_REGION: "
2006 					"View: %s -> unset\n", Title(), fCurrentView->Name()));
2007 
2008 				fCurrentView->SetUserClipping(NULL);
2009 			}
2010 			fCurrentDrawingRegionValid = false;
2011 
2012 			break;
2013 		}
2014 
2015 		case AS_VIEW_INVALIDATE_RECT:
2016 		{
2017 			// NOTE: looks like this call is NOT affected by origin and scale
2018 			// on R5 so this implementation is "correct"
2019 			BRect invalidRect;
2020 			if (link.Read<BRect>(&invalidRect) == B_OK) {
2021 				DTRACE(("ServerWindow %s: Message AS_VIEW_INVALIDATE_RECT: "
2022 					"View: %s -> BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(),
2023 					fCurrentView->Name(), invalidRect.left, invalidRect.top,
2024 					invalidRect.right, invalidRect.bottom));
2025 
2026 				BRegion dirty(invalidRect);
2027 				fWindow->InvalidateView(fCurrentView, dirty);
2028 			}
2029 			break;
2030 		}
2031 		case AS_VIEW_INVALIDATE_REGION:
2032 		{
2033 			// NOTE: looks like this call is NOT affected by origin and scale
2034 			// on R5 so this implementation is "correct"
2035 			BRegion region;
2036 			if (link.ReadRegion(&region) < B_OK)
2037 				break;
2038 
2039 			DTRACE(("ServerWindow %s: Message AS_VIEW_INVALIDATE_REGION: "
2040 					"View: %s -> rect count: %" B_PRId32 ", frame: BRect(%.1f, "
2041 					"%.1f, %.1f, %.1f)\n", Title(),
2042 					fCurrentView->Name(), region.CountRects(),
2043 					region.Frame().left, region.Frame().top,
2044 					region.Frame().right, region.Frame().bottom));
2045 
2046 			fWindow->InvalidateView(fCurrentView, region);
2047 			break;
2048 		}
2049 
2050 		case AS_VIEW_DRAG_IMAGE:
2051 		{
2052 			// TODO: flesh out AS_VIEW_DRAG_IMAGE
2053 			DTRACE(("ServerWindow %s: Message AS_DRAG_IMAGE\n", Title()));
2054 
2055 			int32 bitmapToken;
2056 			drawing_mode dragMode;
2057 			BPoint offset;
2058 			int32 bufferSize;
2059 
2060 			link.Read<int32>(&bitmapToken);
2061 			link.Read<int32>((int32*)&dragMode);
2062 			link.Read<BPoint>(&offset);
2063 			link.Read<int32>(&bufferSize);
2064 
2065 			if (bufferSize > 0) {
2066 				char* buffer = new (nothrow) char[bufferSize];
2067 				BMessage dragMessage;
2068 				if (link.Read(buffer, bufferSize) == B_OK
2069 					&& dragMessage.Unflatten(buffer) == B_OK) {
2070 						ServerBitmap* bitmap
2071 							= fServerApp->GetBitmap(bitmapToken);
2072 						// TODO: possible deadlock
2073 fDesktop->UnlockSingleWindow();
2074 						fDesktop->EventDispatcher().SetDragMessage(dragMessage,
2075 							bitmap, offset);
2076 fDesktop->LockSingleWindow();
2077 						bitmap->ReleaseReference();
2078 				}
2079 				delete[] buffer;
2080 			}
2081 			// sync the client (it can now delete the bitmap)
2082 			fLink.StartMessage(B_OK);
2083 			fLink.Flush();
2084 
2085 			break;
2086 		}
2087 		case AS_VIEW_DRAG_RECT:
2088 		{
2089 			// TODO: flesh out AS_VIEW_DRAG_RECT
2090 			DTRACE(("ServerWindow %s: Message AS_DRAG_RECT\n", Title()));
2091 
2092 			BRect dragRect;
2093 			BPoint offset;
2094 			int32 bufferSize;
2095 
2096 			link.Read<BRect>(&dragRect);
2097 			link.Read<BPoint>(&offset);
2098 			link.Read<int32>(&bufferSize);
2099 
2100 			if (bufferSize > 0) {
2101 				char* buffer = new (nothrow) char[bufferSize];
2102 				BMessage dragMessage;
2103 				if (link.Read(buffer, bufferSize) == B_OK
2104 					&& dragMessage.Unflatten(buffer) == B_OK) {
2105 						// TODO: possible deadlock
2106 fDesktop->UnlockSingleWindow();
2107 						fDesktop->EventDispatcher().SetDragMessage(dragMessage,
2108 							NULL /* should be dragRect */, offset);
2109 fDesktop->LockSingleWindow();
2110 				}
2111 				delete[] buffer;
2112 			}
2113 			break;
2114 		}
2115 
2116 		case AS_VIEW_BEGIN_RECT_TRACK:
2117 		{
2118 			DTRACE(("ServerWindow %s: Message AS_VIEW_BEGIN_RECT_TRACK\n",
2119 				Title()));
2120 			BRect dragRect;
2121 			uint32 style;
2122 
2123 			link.Read<BRect>(&dragRect);
2124 			link.Read<uint32>(&style);
2125 
2126 			// TODO: implement rect tracking (used sometimes for selecting
2127 			// a group of things, also sometimes used to appear to drag
2128 			// something, but without real drag message)
2129 			break;
2130 		}
2131 		case AS_VIEW_END_RECT_TRACK:
2132 		{
2133 			DTRACE(("ServerWindow %s: Message AS_VIEW_END_RECT_TRACK\n",
2134 				Title()));
2135 			// TODO: implement rect tracking
2136 			break;
2137 		}
2138 
2139 		case AS_VIEW_BEGIN_PICTURE:
2140 		{
2141 			DTRACE(("ServerWindow %s: Message AS_VIEW_BEGIN_PICTURE\n",
2142 				Title()));
2143 			ServerPicture* picture = App()->CreatePicture();
2144 			if (picture != NULL) {
2145 				picture->SyncState(fCurrentView);
2146 				fCurrentView->SetPicture(picture);
2147 			}
2148 			break;
2149 		}
2150 
2151 		case AS_VIEW_APPEND_TO_PICTURE:
2152 		{
2153 			DTRACE(("ServerWindow %s: Message AS_VIEW_APPEND_TO_PICTURE\n",
2154 				Title()));
2155 
2156 			int32 token;
2157 			link.Read<int32>(&token);
2158 
2159 			ServerPicture* picture = App()->GetPicture(token);
2160 			if (picture != NULL)
2161 				picture->SyncState(fCurrentView);
2162 
2163 			fCurrentView->SetPicture(picture);
2164 
2165 			if (picture != NULL)
2166 				picture->ReleaseReference();
2167 			break;
2168 		}
2169 
2170 		case AS_VIEW_END_PICTURE:
2171 		{
2172 			DTRACE(("ServerWindow %s: Message AS_VIEW_END_PICTURE\n",
2173 				Title()));
2174 
2175 			ServerPicture* picture = fCurrentView->Picture();
2176 			if (picture != NULL) {
2177 				fCurrentView->SetPicture(NULL);
2178 				fLink.StartMessage(B_OK);
2179 				fLink.Attach<int32>(picture->Token());
2180 			} else
2181 				fLink.StartMessage(B_ERROR);
2182 
2183 			fLink.Flush();
2184 			break;
2185 		}
2186 
2187 		default:
2188 			_DispatchViewDrawingMessage(code, link);
2189 			break;
2190 	}
2191 }
2192 
2193 
2194 /*!	Dispatches all view drawing messages.
2195 	The desktop clipping must be read locked when entering this method.
2196 	Requires a valid fCurrentView.
2197 */
2198 void
2199 ServerWindow::_DispatchViewDrawingMessage(int32 code,
2200 	BPrivate::LinkReceiver &link)
2201 {
2202 	if (!fCurrentView->IsVisible() || !fWindow->IsVisible()) {
2203 		if (link.NeedsReply()) {
2204 			debug_printf("ServerWindow::DispatchViewDrawingMessage() got "
2205 				"message %" B_PRId32 " that needs a reply!\n", code);
2206 			// the client is now blocking and waiting for a reply!
2207 			fLink.StartMessage(B_ERROR);
2208 			fLink.Flush();
2209 		}
2210 		return;
2211 	}
2212 
2213 	DrawingEngine* drawingEngine = fWindow->GetDrawingEngine();
2214 	if (!drawingEngine) {
2215 		// ?!?
2216 		debug_printf("ServerWindow %s: no drawing engine!!\n", Title());
2217 		if (link.NeedsReply()) {
2218 			// the client is now blocking and waiting for a reply!
2219 			fLink.StartMessage(B_ERROR);
2220 			fLink.Flush();
2221 		}
2222 		return;
2223 	}
2224 
2225 	_UpdateCurrentDrawingRegion();
2226 	if (fCurrentDrawingRegion.CountRects() <= 0) {
2227 		DTRACE(("ServerWindow %s: _DispatchViewDrawingMessage(): View: %s, "
2228 			"INVALID CLIPPING!\n", Title(), fCurrentView->Name()));
2229 		if (link.NeedsReply()) {
2230 			// the client is now blocking and waiting for a reply!
2231 			fLink.StartMessage(B_ERROR);
2232 			fLink.Flush();
2233 		}
2234 		return;
2235 	}
2236 
2237 	drawingEngine->LockParallelAccess();
2238 	// NOTE: the region is not copied, Painter keeps a pointer,
2239 	// that's why you need to use the clipping only for as long
2240 	// as you have it locked
2241 	drawingEngine->ConstrainClippingRegion(&fCurrentDrawingRegion);
2242 
2243 	switch (code) {
2244 		case AS_STROKE_LINE:
2245 		{
2246 			ViewStrokeLineInfo info;
2247 			if (link.Read<ViewStrokeLineInfo>(&info) != B_OK)
2248 				break;
2249 
2250 			DTRACE(("ServerWindow %s: Message AS_STROKE_LINE: View: %s -> "
2251 				"BPoint(%.1f, %.1f) - BPoint(%.1f, %.1f)\n", Title(),
2252 					fCurrentView->Name(),
2253 					info.startPoint.x, info.startPoint.y,
2254 					info.endPoint.x, info.endPoint.y));
2255 
2256 			BPoint penPos = info.endPoint;
2257 			fCurrentView->ConvertToScreenForDrawing(&info.startPoint);
2258 			fCurrentView->ConvertToScreenForDrawing(&info.endPoint);
2259 			drawingEngine->StrokeLine(info.startPoint, info.endPoint);
2260 
2261 			// We update the pen here because many DrawingEngine calls which
2262 			// do not update the pen position actually call StrokeLine
2263 
2264 			// TODO: Decide where to put this, for example, it cannot be done
2265 			// for DrawString(), also there needs to be a decision, if the pen
2266 			// location is in View coordinates (I think it should be) or in
2267 			// screen coordinates.
2268 			fCurrentView->CurrentState()->SetPenLocation(penPos);
2269 			break;
2270 		}
2271 		case AS_VIEW_INVERT_RECT:
2272 		{
2273 			BRect rect;
2274 			if (link.Read<BRect>(&rect) != B_OK)
2275 				break;
2276 
2277 			DTRACE(("ServerWindow %s: Message AS_INVERT_RECT: View: %s -> "
2278 				"BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(),
2279 				fCurrentView->Name(), rect.left, rect.top, rect.right,
2280 				rect.bottom));
2281 
2282 			fCurrentView->ConvertToScreenForDrawing(&rect);
2283 			drawingEngine->InvertRect(rect);
2284 			break;
2285 		}
2286 		case AS_STROKE_RECT:
2287 		{
2288 			BRect rect;
2289 			if (link.Read<BRect>(&rect) != B_OK)
2290 				break;
2291 
2292 			DTRACE(("ServerWindow %s: Message AS_STROKE_RECT: View: %s -> "
2293 				"BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(),
2294 				fCurrentView->Name(), rect.left, rect.top, rect.right,
2295 				rect.bottom));
2296 
2297 			fCurrentView->ConvertToScreenForDrawing(&rect);
2298 			drawingEngine->StrokeRect(rect);
2299 			break;
2300 		}
2301 		case AS_FILL_RECT:
2302 		{
2303 			BRect rect;
2304 			if (link.Read<BRect>(&rect) != B_OK)
2305 				break;
2306 
2307 			DTRACE(("ServerWindow %s: Message AS_FILL_RECT: View: %s -> "
2308 				"BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(),
2309 				fCurrentView->Name(), rect.left, rect.top, rect.right,
2310 				rect.bottom));
2311 
2312 			fCurrentView->ConvertToScreenForDrawing(&rect);
2313 			drawingEngine->FillRect(rect);
2314 			break;
2315 		}
2316 		case AS_FILL_RECT_GRADIENT:
2317 		{
2318 			BRect rect;
2319 			link.Read<BRect>(&rect);
2320 			BGradient* gradient;
2321 			if (link.ReadGradient(&gradient) != B_OK)
2322 				break;
2323 
2324 			GTRACE(("ServerWindow %s: Message AS_FILL_RECT_GRADIENT: View: %s "
2325 				"-> BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(),
2326 				fCurrentView->Name(), rect.left, rect.top, rect.right,
2327 				rect.bottom));
2328 
2329 			fCurrentView->ConvertToScreenForDrawing(&rect);
2330 			fCurrentView->ConvertToScreenForDrawing(gradient);
2331 			drawingEngine->FillRect(rect, *gradient);
2332 			delete gradient;
2333 			break;
2334 		}
2335 		case AS_VIEW_DRAW_BITMAP:
2336 		{
2337 			ViewDrawBitmapInfo info;
2338 			if (link.Read<ViewDrawBitmapInfo>(&info) != B_OK)
2339 				break;
2340 
2341 #if 0
2342 			if (strcmp(fServerApp->SignatureLeaf(), "x-vnd.videolan-vlc") == 0)
2343 				info.options |= B_FILTER_BITMAP_BILINEAR;
2344 #endif
2345 
2346 			ServerBitmap* bitmap = fServerApp->GetBitmap(info.bitmapToken);
2347 			if (bitmap != NULL) {
2348 				DTRACE(("ServerWindow %s: Message AS_VIEW_DRAW_BITMAP: "
2349 					"View: %s, bitmap: %" B_PRId32 " (size %" B_PRId32 " x "
2350 					"%" B_PRId32 "), BRect(%.1f, %.1f, %.1f, %.1f) -> "
2351 					"BRect(%.1f, %.1f, %.1f, %.1f)\n",
2352 					fTitle, fCurrentView->Name(), info.bitmapToken,
2353 					bitmap->Width(), bitmap->Height(),
2354 					info.bitmapRect.left, info.bitmapRect.top,
2355 					info.bitmapRect.right, info.bitmapRect.bottom,
2356 					info.viewRect.left, info.viewRect.top,
2357 					info.viewRect.right, info.viewRect.bottom));
2358 
2359 				fCurrentView->ConvertToScreenForDrawing(&info.viewRect);
2360 
2361 // TODO: Unbreak...
2362 //				if ((info.options & B_WAIT_FOR_RETRACE) != 0)
2363 //					fDesktop->HWInterface()->WaitForRetrace(20000);
2364 
2365 				drawingEngine->DrawBitmap(bitmap, info.bitmapRect,
2366 					info.viewRect, info.options);
2367 
2368 				bitmap->ReleaseReference();
2369 			}
2370 			break;
2371 		}
2372 		case AS_STROKE_ARC:
2373 		case AS_FILL_ARC:
2374 		{
2375 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ARC\n", Title()));
2376 
2377 			float angle, span;
2378 			BRect r;
2379 
2380 			link.Read<BRect>(&r);
2381 			link.Read<float>(&angle);
2382 			if (link.Read<float>(&span) != B_OK)
2383 				break;
2384 
2385 			fCurrentView->ConvertToScreenForDrawing(&r);
2386 			drawingEngine->DrawArc(r, angle, span, code == AS_FILL_ARC);
2387 			break;
2388 		}
2389 		case AS_FILL_ARC_GRADIENT:
2390 		{
2391 			GTRACE(("ServerWindow %s: Message AS_FILL_ARC_GRADIENT\n",
2392 				Title()));
2393 
2394 			float angle, span;
2395 			BRect r;
2396 			link.Read<BRect>(&r);
2397 			link.Read<float>(&angle);
2398 			link.Read<float>(&span);
2399 			BGradient* gradient;
2400 			if (link.ReadGradient(&gradient) != B_OK)
2401 				break;
2402 			fCurrentView->ConvertToScreenForDrawing(&r);
2403 			fCurrentView->ConvertToScreenForDrawing(gradient);
2404 			drawingEngine->FillArc(r, angle, span, *gradient);
2405 			delete gradient;
2406 			break;
2407 		}
2408 		case AS_STROKE_BEZIER:
2409 		case AS_FILL_BEZIER:
2410 		{
2411 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_BEZIER\n",
2412 				Title()));
2413 
2414 			BPoint pts[4];
2415 			status_t status;
2416 			for (int32 i = 0; i < 4; i++) {
2417 				status = link.Read<BPoint>(&(pts[i]));
2418 				fCurrentView->ConvertToScreenForDrawing(&pts[i]);
2419 			}
2420 			if (status != B_OK)
2421 				break;
2422 
2423 			drawingEngine->DrawBezier(pts, code == AS_FILL_BEZIER);
2424 			break;
2425 		}
2426 		case AS_FILL_BEZIER_GRADIENT:
2427 		{
2428 			GTRACE(("ServerWindow %s: Message AS_FILL_BEZIER_GRADIENT\n",
2429 				Title()));
2430 
2431 			BPoint pts[4];
2432 			for (int32 i = 0; i < 4; i++) {
2433 				link.Read<BPoint>(&(pts[i]));
2434 				fCurrentView->ConvertToScreenForDrawing(&pts[i]);
2435 			}
2436 			BGradient* gradient;
2437 			if (link.ReadGradient(&gradient) != B_OK)
2438 				break;
2439 			fCurrentView->ConvertToScreenForDrawing(gradient);
2440 			drawingEngine->FillBezier(pts, *gradient);
2441 			delete gradient;
2442 			break;
2443 		}
2444 		case AS_STROKE_ELLIPSE:
2445 		case AS_FILL_ELLIPSE:
2446 		{
2447 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ELLIPSE\n",
2448 				Title()));
2449 
2450 			BRect rect;
2451 			if (link.Read<BRect>(&rect) != B_OK)
2452 				break;
2453 
2454 			fCurrentView->ConvertToScreenForDrawing(&rect);
2455 			drawingEngine->DrawEllipse(rect, code == AS_FILL_ELLIPSE);
2456 			break;
2457 		}
2458 		case AS_FILL_ELLIPSE_GRADIENT:
2459 		{
2460 			GTRACE(("ServerWindow %s: Message AS_FILL_ELLIPSE_GRADIENT\n",
2461 				Title()));
2462 
2463 			BRect rect;
2464 			link.Read<BRect>(&rect);
2465 			BGradient* gradient;
2466 			if (link.ReadGradient(&gradient) != B_OK)
2467 				break;
2468 			fCurrentView->ConvertToScreenForDrawing(&rect);
2469 			fCurrentView->ConvertToScreenForDrawing(gradient);
2470 			drawingEngine->FillEllipse(rect, *gradient);
2471 			delete gradient;
2472 			break;
2473 		}
2474 		case AS_STROKE_ROUNDRECT:
2475 		case AS_FILL_ROUNDRECT:
2476 		{
2477 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ROUNDRECT\n",
2478 				Title()));
2479 
2480 			BRect rect;
2481 			float xRadius;
2482 			float yRadius;
2483 			link.Read<BRect>(&rect);
2484 			link.Read<float>(&xRadius);
2485 			if (link.Read<float>(&yRadius) != B_OK)
2486 				break;
2487 
2488 			fCurrentView->ConvertToScreenForDrawing(&rect);
2489 			float scale = fCurrentView->CurrentState()->CombinedScale();
2490 			drawingEngine->DrawRoundRect(rect, xRadius * scale, yRadius * scale,
2491 				code == AS_FILL_ROUNDRECT);
2492 			break;
2493 		}
2494 		case AS_FILL_ROUNDRECT_GRADIENT:
2495 		{
2496 			GTRACE(("ServerWindow %s: Message AS_FILL_ROUNDRECT_GRADIENT\n",
2497 				Title()));
2498 
2499 			BRect rect;
2500 			float xrad,yrad;
2501 			link.Read<BRect>(&rect);
2502 			link.Read<float>(&xrad);
2503 			link.Read<float>(&yrad);
2504 			BGradient* gradient;
2505 			if (link.ReadGradient(&gradient) != B_OK)
2506 				break;
2507 			fCurrentView->ConvertToScreenForDrawing(&rect);
2508 			fCurrentView->ConvertToScreenForDrawing(gradient);
2509 			drawingEngine->FillRoundRect(rect, xrad, yrad, *gradient);
2510 			delete gradient;
2511 			break;
2512 		}
2513 		case AS_STROKE_TRIANGLE:
2514 		case AS_FILL_TRIANGLE:
2515 		{
2516 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_TRIANGLE\n",
2517 				Title()));
2518 
2519 			BPoint pts[3];
2520 			BRect rect;
2521 
2522 			for (int32 i = 0; i < 3; i++) {
2523 				link.Read<BPoint>(&(pts[i]));
2524 				fCurrentView->ConvertToScreenForDrawing(&pts[i]);
2525 			}
2526 
2527 			if (link.Read<BRect>(&rect) != B_OK)
2528 				break;
2529 
2530 			fCurrentView->ConvertToScreenForDrawing(&rect);
2531 			drawingEngine->DrawTriangle(pts, rect, code == AS_FILL_TRIANGLE);
2532 			break;
2533 		}
2534 		case AS_FILL_TRIANGLE_GRADIENT:
2535 		{
2536 			DTRACE(("ServerWindow %s: Message AS_FILL_TRIANGLE_GRADIENT\n",
2537 				Title()));
2538 
2539 			BPoint pts[3];
2540 			BRect rect;
2541 			for (int32 i = 0; i < 3; i++) {
2542 				link.Read<BPoint>(&(pts[i]));
2543 				fCurrentView->ConvertToScreenForDrawing(&pts[i]);
2544 			}
2545 			link.Read<BRect>(&rect);
2546 			BGradient* gradient;
2547 			if (link.ReadGradient(&gradient) != B_OK)
2548 				break;
2549 			fCurrentView->ConvertToScreenForDrawing(&rect);
2550 			fCurrentView->ConvertToScreenForDrawing(gradient);
2551 			drawingEngine->FillTriangle(pts, rect, *gradient);
2552 			delete gradient;
2553 			break;
2554 		}
2555 		case AS_STROKE_POLYGON:
2556 		case AS_FILL_POLYGON:
2557 		{
2558 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_POLYGON\n",
2559 				Title()));
2560 
2561 			BRect polyFrame;
2562 			bool isClosed = true;
2563 			int32 pointCount;
2564 
2565 			link.Read<BRect>(&polyFrame);
2566 			if (code == AS_STROKE_POLYGON)
2567 				link.Read<bool>(&isClosed);
2568 			link.Read<int32>(&pointCount);
2569 
2570 			BPoint* pointList = new(nothrow) BPoint[pointCount];
2571 			if (link.Read(pointList, pointCount * sizeof(BPoint)) >= B_OK) {
2572 				for (int32 i = 0; i < pointCount; i++)
2573 					fCurrentView->ConvertToScreenForDrawing(&pointList[i]);
2574 				fCurrentView->ConvertToScreenForDrawing(&polyFrame);
2575 
2576 				drawingEngine->DrawPolygon(pointList, pointCount, polyFrame,
2577 					code == AS_FILL_POLYGON, isClosed && pointCount > 2);
2578 			}
2579 			delete[] pointList;
2580 			break;
2581 		}
2582 		case AS_FILL_POLYGON_GRADIENT:
2583 		{
2584 			DTRACE(("ServerWindow %s: Message AS_FILL_POLYGON_GRADIENT\n",
2585 				Title()));
2586 
2587 			BRect polyFrame;
2588 			bool isClosed = true;
2589 			int32 pointCount;
2590 			link.Read<BRect>(&polyFrame);
2591 			link.Read<int32>(&pointCount);
2592 
2593 			BPoint* pointList = new(nothrow) BPoint[pointCount];
2594 			BGradient* gradient;
2595 			if (link.Read(pointList, pointCount * sizeof(BPoint)) == B_OK
2596 				&& link.ReadGradient(&gradient) == B_OK) {
2597 				for (int32 i = 0; i < pointCount; i++)
2598 					fCurrentView->ConvertToScreenForDrawing(&pointList[i]);
2599 				fCurrentView->ConvertToScreenForDrawing(&polyFrame);
2600 				fCurrentView->ConvertToScreenForDrawing(gradient);
2601 
2602 				drawingEngine->FillPolygon(pointList, pointCount,
2603 					polyFrame, *gradient, isClosed && pointCount > 2);
2604 				delete gradient;
2605 			}
2606 			delete[] pointList;
2607 			break;
2608 		}
2609 		case AS_STROKE_SHAPE:
2610 		case AS_FILL_SHAPE:
2611 		{
2612 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_SHAPE\n",
2613 				Title()));
2614 
2615 			BRect shapeFrame;
2616 			int32 opCount;
2617 			int32 ptCount;
2618 
2619 			link.Read<BRect>(&shapeFrame);
2620 			link.Read<int32>(&opCount);
2621 			link.Read<int32>(&ptCount);
2622 
2623 			uint32* opList = new(nothrow) uint32[opCount];
2624 			BPoint* ptList = new(nothrow) BPoint[ptCount];
2625 			if (link.Read(opList, opCount * sizeof(uint32)) >= B_OK &&
2626 				link.Read(ptList, ptCount * sizeof(BPoint)) >= B_OK) {
2627 
2628 				// this might seem a bit weird, but under R5, the shapes
2629 				// are always offset by the current pen location
2630 				BPoint screenOffset
2631 					= fCurrentView->CurrentState()->PenLocation();
2632 				shapeFrame.OffsetBy(screenOffset);
2633 
2634 				fCurrentView->ConvertToScreenForDrawing(&screenOffset);
2635 				fCurrentView->ConvertToScreenForDrawing(&shapeFrame);
2636 
2637 				drawingEngine->DrawShape(shapeFrame, opCount, opList, ptCount,
2638 					ptList, code == AS_FILL_SHAPE, screenOffset,
2639 					fCurrentView->Scale());
2640 			}
2641 
2642 			delete[] opList;
2643 			delete[] ptList;
2644 			break;
2645 		}
2646 		case AS_FILL_SHAPE_GRADIENT:
2647 		{
2648 			DTRACE(("ServerWindow %s: Message AS_FILL_SHAPE_GRADIENT\n",
2649 				Title()));
2650 
2651 			BRect shapeFrame;
2652 			int32 opCount;
2653 			int32 ptCount;
2654 
2655 			link.Read<BRect>(&shapeFrame);
2656 			link.Read<int32>(&opCount);
2657 			link.Read<int32>(&ptCount);
2658 
2659 			uint32* opList = new(nothrow) uint32[opCount];
2660 			BPoint* ptList = new(nothrow) BPoint[ptCount];
2661 			BGradient* gradient;
2662 			if (link.Read(opList, opCount * sizeof(uint32)) == B_OK
2663 				&& link.Read(ptList, ptCount * sizeof(BPoint)) == B_OK
2664 				&& link.ReadGradient(&gradient) == B_OK) {
2665 
2666 				// this might seem a bit weird, but under R5, the shapes
2667 				// are always offset by the current pen location
2668 				BPoint screenOffset
2669 					= fCurrentView->CurrentState()->PenLocation();
2670 				shapeFrame.OffsetBy(screenOffset);
2671 
2672 				fCurrentView->ConvertToScreenForDrawing(&screenOffset);
2673 				fCurrentView->ConvertToScreenForDrawing(&shapeFrame);
2674 				fCurrentView->ConvertToScreenForDrawing(gradient);
2675 				drawingEngine->FillShape(shapeFrame, opCount, opList,
2676 					ptCount, ptList, *gradient, screenOffset,
2677 					fCurrentView->Scale());
2678 				delete gradient;
2679 			}
2680 
2681 			delete[] opList;
2682 			delete[] ptList;
2683 			break;
2684 		}
2685 		case AS_FILL_REGION:
2686 		{
2687 			DTRACE(("ServerWindow %s: Message AS_FILL_REGION\n", Title()));
2688 
2689 			BRegion region;
2690 			if (link.ReadRegion(&region) < B_OK)
2691 				break;
2692 
2693 			fCurrentView->ConvertToScreenForDrawing(&region);
2694 			drawingEngine->FillRegion(region);
2695 
2696 			break;
2697 		}
2698 		case AS_FILL_REGION_GRADIENT:
2699 		{
2700 			DTRACE(("ServerWindow %s: Message AS_FILL_REGION_GRADIENT\n",
2701 				Title()));
2702 
2703 			BRegion region;
2704 			link.ReadRegion(&region);
2705 
2706 			BGradient* gradient;
2707 			if (link.ReadGradient(&gradient) != B_OK)
2708 				break;
2709 
2710 			fCurrentView->ConvertToScreenForDrawing(&region);
2711 			fCurrentView->ConvertToScreenForDrawing(gradient);
2712 			drawingEngine->FillRegion(region, *gradient);
2713 			delete gradient;
2714 			break;
2715 		}
2716 		case AS_STROKE_LINEARRAY:
2717 		{
2718 			DTRACE(("ServerWindow %s: Message AS_STROKE_LINEARRAY\n",
2719 				Title()));
2720 
2721 			// Attached Data:
2722 			// 1) int32 Number of lines in the array
2723 			// 2) LineArrayData
2724 
2725 			int32 lineCount;
2726 			if (link.Read<int32>(&lineCount) != B_OK || lineCount <= 0)
2727 				break;
2728 
2729 			// To speed things up, try to use a stack allocation and only
2730 			// fall back to the heap if there are enough lines...
2731 			ViewLineArrayInfo* lineData;
2732 			const int32 kStackBufferLineDataCount = 64;
2733 			ViewLineArrayInfo lineDataStackBuffer[kStackBufferLineDataCount];
2734 			if (lineCount > kStackBufferLineDataCount) {
2735 				lineData = new(std::nothrow) ViewLineArrayInfo[lineCount];
2736 				if (lineData == NULL)
2737 					break;
2738 			} else
2739 				lineData = lineDataStackBuffer;
2740 
2741 			// Read them all in one go
2742 			size_t dataSize = lineCount * sizeof(ViewLineArrayInfo);
2743 			if (link.Read(lineData, dataSize) != B_OK) {
2744 				if (lineData != lineDataStackBuffer)
2745 					delete[] lineData;
2746 				break;
2747 			}
2748 
2749 			// Convert to screen coords and draw
2750 			for (int32 i = 0; i < lineCount; i++) {
2751 				fCurrentView->ConvertToScreenForDrawing(
2752 					&lineData[i].startPoint);
2753 				fCurrentView->ConvertToScreenForDrawing(
2754 					&lineData[i].endPoint);
2755 			}
2756 			drawingEngine->StrokeLineArray(lineCount, lineData);
2757 
2758 			if (lineData != lineDataStackBuffer)
2759 				delete[] lineData;
2760 			break;
2761 		}
2762 		case AS_DRAW_STRING:
2763 		case AS_DRAW_STRING_WITH_DELTA:
2764 		{
2765 			ViewDrawStringInfo info;
2766 			if (link.Read<ViewDrawStringInfo>(&info) != B_OK
2767 				|| info.stringLength <= 0) {
2768 				break;
2769 			}
2770 
2771 			const ssize_t kMaxStackStringSize = 4096;
2772 			char stackString[kMaxStackStringSize];
2773 			char* string = stackString;
2774 			if (info.stringLength >= kMaxStackStringSize) {
2775 				// NOTE: Careful, the + 1 is for termination!
2776 				string = (char*)malloc((info.stringLength + 1 + 63) / 64 * 64);
2777 				if (string == NULL)
2778 					break;
2779 			}
2780 
2781 			escapement_delta* delta = NULL;
2782 			if (code == AS_DRAW_STRING_WITH_DELTA) {
2783 				// In this case, info.delta will contain valid values.
2784 				delta = &info.delta;
2785 			}
2786 
2787 			if (link.Read(string, info.stringLength) != B_OK) {
2788 				if (string != stackString)
2789 					free(string);
2790 				break;
2791 			}
2792 			// Terminate the string, if nothing else, it's important
2793 			// for the DTRACE call below...
2794 			string[info.stringLength] = '\0';
2795 
2796 			DTRACE(("ServerWindow %s: Message AS_DRAW_STRING, View: %s "
2797 				"-> %s\n", Title(), fCurrentView->Name(), string));
2798 
2799 			fCurrentView->ConvertToScreenForDrawing(&info.location);
2800 			BPoint penLocation = drawingEngine->DrawString(string,
2801 				info.stringLength, info.location, delta);
2802 
2803 			fCurrentView->ConvertFromScreenForDrawing(&penLocation);
2804 			fCurrentView->CurrentState()->SetPenLocation(penLocation);
2805 
2806 			if (string != stackString)
2807 				free(string);
2808 			break;
2809 		}
2810 		case AS_DRAW_STRING_WITH_OFFSETS:
2811 		{
2812 			int32 stringLength;
2813 			if (link.Read<int32>(&stringLength) != B_OK || stringLength <= 0)
2814 				break;
2815 
2816 			int32 glyphCount;
2817 			if (link.Read<int32>(&glyphCount) != B_OK || glyphCount <= 0)
2818 				break;
2819 
2820 			const ssize_t kMaxStackStringSize = 512;
2821 			char stackString[kMaxStackStringSize];
2822 			char* string = stackString;
2823 			BPoint stackLocations[kMaxStackStringSize];
2824 			BPoint* locations = stackLocations;
2825 			MemoryDeleter stringDeleter;
2826 			MemoryDeleter locationsDeleter;
2827 			if (stringLength >= kMaxStackStringSize) {
2828 				// NOTE: Careful, the + 1 is for termination!
2829 				string = (char*)malloc((stringLength + 1 + 63) / 64 * 64);
2830 				if (string == NULL)
2831 					break;
2832 				stringDeleter.SetTo(string);
2833 			}
2834 			if (glyphCount > kMaxStackStringSize) {
2835 				locations = (BPoint*)malloc(
2836 					((glyphCount * sizeof(BPoint)) + 63) / 64 * 64);
2837 				if (locations == NULL)
2838 					break;
2839 				locationsDeleter.SetTo(locations);
2840 			}
2841 
2842 			if (link.Read(string, stringLength) != B_OK)
2843 				break;
2844 			// Count UTF8 glyphs and make sure we have enough locations
2845 			if ((int32)UTF8CountChars(string, stringLength) > glyphCount)
2846 				break;
2847 			if (link.Read(locations, glyphCount * sizeof(BPoint)) != B_OK)
2848 				break;
2849 			// Terminate the string, if nothing else, it's important
2850 			// for the DTRACE call below...
2851 			string[stringLength] = '\0';
2852 
2853 			DTRACE(("ServerWindow %s: Message AS_DRAW_STRING_WITH_OFFSETS, View: %s "
2854 				"-> %s\n", Title(), fCurrentView->Name(), string));
2855 
2856 			for (int32 i = 0; i < glyphCount; i++)
2857 				fCurrentView->ConvertToScreenForDrawing(&locations[i]);
2858 
2859 			BPoint penLocation = drawingEngine->DrawString(string,
2860 				stringLength, locations);
2861 
2862 			fCurrentView->ConvertFromScreenForDrawing(&penLocation);
2863 			fCurrentView->CurrentState()->SetPenLocation(penLocation);
2864 
2865 			break;
2866 		}
2867 
2868 		case AS_VIEW_DRAW_PICTURE:
2869 		{
2870 			int32 token;
2871 			link.Read<int32>(&token);
2872 
2873 			BPoint where;
2874 			if (link.Read<BPoint>(&where) == B_OK) {
2875 				ServerPicture* picture = App()->GetPicture(token);
2876 				if (picture != NULL) {
2877 					// Setting the drawing origin outside of the
2878 					// state makes sure that everything the picture
2879 					// does is relative to the global picture offset.
2880 					fCurrentView->PushState();
2881 					fCurrentView->SetDrawingOrigin(where);
2882 
2883 					fCurrentView->PushState();
2884 					picture->Play(fCurrentView);
2885 					fCurrentView->PopState();
2886 
2887 					fCurrentView->PopState();
2888 
2889 					picture->ReleaseReference();
2890 				}
2891 			}
2892 			break;
2893 		}
2894 
2895 		default:
2896 			BString codeString;
2897 			string_for_message_code(code, codeString);
2898 			debug_printf("ServerWindow %s received unexpected code: %s\n",
2899 				Title(), codeString.String());
2900 
2901 			if (link.NeedsReply()) {
2902 				// the client is now blocking and waiting for a reply!
2903 				fLink.StartMessage(B_ERROR);
2904 				fLink.Flush();
2905 			}
2906 			break;
2907 	}
2908 
2909 	drawingEngine->UnlockParallelAccess();
2910 }
2911 
2912 
2913 bool
2914 ServerWindow::_DispatchPictureMessage(int32 code, BPrivate::LinkReceiver& link)
2915 {
2916 	ServerPicture* picture = fCurrentView->Picture();
2917 	if (picture == NULL)
2918 		return false;
2919 
2920 	switch (code) {
2921 		case AS_VIEW_SET_ORIGIN:
2922 		{
2923 			float x, y;
2924 			link.Read<float>(&x);
2925 			link.Read<float>(&y);
2926 
2927 			picture->WriteSetOrigin(BPoint(x, y));
2928 			break;
2929 		}
2930 
2931 		case AS_VIEW_INVERT_RECT:
2932 		{
2933 			BRect rect;
2934 			link.Read<BRect>(&rect);
2935 			picture->WriteInvertRect(rect);
2936 			break;
2937 		}
2938 
2939 		case AS_VIEW_PUSH_STATE:
2940 		{
2941 			picture->WritePushState();
2942 			break;
2943 		}
2944 
2945 		case AS_VIEW_POP_STATE:
2946 		{
2947 			picture->WritePopState();
2948 			break;
2949 		}
2950 
2951 		case AS_VIEW_SET_DRAWING_MODE:
2952 		{
2953 			int8 drawingMode;
2954 			link.Read<int8>(&drawingMode);
2955 
2956 			picture->WriteSetDrawingMode((drawing_mode)drawingMode);
2957 
2958 			fCurrentView->CurrentState()->SetDrawingMode(
2959 				(drawing_mode)drawingMode);
2960 			fWindow->GetDrawingEngine()->SetDrawingMode(
2961 				(drawing_mode)drawingMode);
2962 			break;
2963 		}
2964 
2965 		case AS_VIEW_SET_PEN_LOC:
2966 		{
2967 			BPoint location;
2968 			link.Read<BPoint>(&location);
2969 			picture->WriteSetPenLocation(location);
2970 
2971 			fCurrentView->CurrentState()->SetPenLocation(location);
2972 			break;
2973 		}
2974 		case AS_VIEW_SET_PEN_SIZE:
2975 		{
2976 			float penSize;
2977 			link.Read<float>(&penSize);
2978 			picture->WriteSetPenSize(penSize);
2979 
2980 			fCurrentView->CurrentState()->SetPenSize(penSize);
2981 			fWindow->GetDrawingEngine()->SetPenSize(
2982 				fCurrentView->CurrentState()->PenSize());
2983 			break;
2984 		}
2985 
2986 		case AS_VIEW_SET_LINE_MODE:
2987 		{
2988 
2989 			ViewSetLineModeInfo info;
2990 			link.Read<ViewSetLineModeInfo>(&info);
2991 
2992 			picture->WriteSetLineMode(info.lineCap, info.lineJoin,
2993 				info.miterLimit);
2994 
2995 			fCurrentView->CurrentState()->SetLineCapMode(info.lineCap);
2996 			fCurrentView->CurrentState()->SetLineJoinMode(info.lineJoin);
2997 			fCurrentView->CurrentState()->SetMiterLimit(info.miterLimit);
2998 
2999 			fWindow->GetDrawingEngine()->SetStrokeMode(info.lineCap,
3000 				info.lineJoin, info.miterLimit);
3001 			break;
3002 		}
3003 		case AS_VIEW_SET_SCALE:
3004 		{
3005 			float scale;
3006 			if (link.Read<float>(&scale) != B_OK)
3007 				break;
3008 
3009 			picture->WriteSetScale(scale);
3010 
3011 			fCurrentView->SetScale(scale);
3012 			_UpdateDrawState(fCurrentView);
3013 			break;
3014 		}
3015 		case AS_VIEW_SET_TRANSFORM:
3016 		{
3017 			BAffineTransform transform;
3018 			if (link.Read<BAffineTransform>(&transform) != B_OK)
3019 				break;
3020 
3021 			picture->WriteSetTransform(transform);
3022 
3023 			fCurrentView->CurrentState()->SetTransform(transform);
3024 			_UpdateDrawState(fCurrentView);
3025 			break;
3026 		}
3027 
3028 		case AS_VIEW_SET_PATTERN:
3029 		{
3030 			pattern pat;
3031 			link.Read(&pat, sizeof(pattern));
3032 			picture->WriteSetPattern(pat);
3033 			break;
3034 		}
3035 
3036 		case AS_VIEW_SET_FONT_STATE:
3037 		{
3038 			picture->SetFontFromLink(link);
3039 			break;
3040 		}
3041 
3042 		case AS_FILL_RECT:
3043 		case AS_STROKE_RECT:
3044 		{
3045 			BRect rect;
3046 			link.Read<BRect>(&rect);
3047 
3048 			picture->WriteDrawRect(rect, code == AS_FILL_RECT);
3049 			break;
3050 		}
3051 
3052 		case AS_FILL_REGION:
3053 		{
3054 			// There is no B_PIC_FILL_REGION op, we have to
3055 			// implement it using B_PIC_FILL_RECT
3056 			BRegion region;
3057 			if (link.ReadRegion(&region) < B_OK)
3058 				break;
3059 			for (int32 i = 0; i < region.CountRects(); i++)
3060 				picture->WriteDrawRect(region.RectAt(i), true);
3061 			break;
3062 		}
3063 
3064 		case AS_STROKE_ROUNDRECT:
3065 		case AS_FILL_ROUNDRECT:
3066 		{
3067 			BRect rect;
3068 			link.Read<BRect>(&rect);
3069 
3070 			BPoint radii;
3071 			link.Read<float>(&radii.x);
3072 			link.Read<float>(&radii.y);
3073 
3074 			picture->WriteDrawRoundRect(rect, radii, code == AS_FILL_ROUNDRECT);
3075 			break;
3076 		}
3077 
3078 		case AS_STROKE_ELLIPSE:
3079 		case AS_FILL_ELLIPSE:
3080 		{
3081 			BRect rect;
3082 			link.Read<BRect>(&rect);
3083 			picture->WriteDrawEllipse(rect, code == AS_FILL_ELLIPSE);
3084 			break;
3085 		}
3086 
3087 		case AS_STROKE_ARC:
3088 		case AS_FILL_ARC:
3089 		{
3090 			BRect rect;
3091 			link.Read<BRect>(&rect);
3092 			float startTheta, arcTheta;
3093 			link.Read<float>(&startTheta);
3094 			link.Read<float>(&arcTheta);
3095 
3096 			BPoint radii((rect.Width() + 1) / 2, (rect.Height() + 1) / 2);
3097 			BPoint center = rect.LeftTop() + radii;
3098 
3099 			picture->WriteDrawArc(center, radii, startTheta, arcTheta,
3100 				code == AS_FILL_ARC);
3101 			break;
3102 		}
3103 
3104 		case AS_STROKE_TRIANGLE:
3105 		case AS_FILL_TRIANGLE:
3106 		{
3107 			// There is no B_PIC_FILL/STROKE_TRIANGLE op,
3108 			// we implement it using B_PIC_FILL/STROKE_POLYGON
3109 			BPoint points[3];
3110 
3111 			for (int32 i = 0; i < 3; i++) {
3112 				link.Read<BPoint>(&(points[i]));
3113 			}
3114 
3115 			BRect rect;
3116 			link.Read<BRect>(&rect);
3117 
3118 			picture->WriteDrawPolygon(3, points,
3119 					true, code == AS_FILL_TRIANGLE);
3120 			break;
3121 		}
3122 		case AS_STROKE_POLYGON:
3123 		case AS_FILL_POLYGON:
3124 		{
3125 			BRect polyFrame;
3126 			bool isClosed = true;
3127 			int32 pointCount;
3128 			const bool fill = (code == AS_FILL_POLYGON);
3129 
3130 			link.Read<BRect>(&polyFrame);
3131 			if (code == AS_STROKE_POLYGON)
3132 				link.Read<bool>(&isClosed);
3133 			link.Read<int32>(&pointCount);
3134 
3135 			BPoint* pointList = new(nothrow) BPoint[pointCount];
3136 			if (link.Read(pointList, pointCount * sizeof(BPoint)) >= B_OK) {
3137 				picture->WriteDrawPolygon(pointCount, pointList,
3138 					isClosed && pointCount > 2, fill);
3139 			}
3140 			delete[] pointList;
3141 			break;
3142 		}
3143 
3144 		case AS_STROKE_BEZIER:
3145 		case AS_FILL_BEZIER:
3146 		{
3147 			BPoint points[4];
3148 			for (int32 i = 0; i < 4; i++) {
3149 				link.Read<BPoint>(&(points[i]));
3150 			}
3151 			picture->WriteDrawBezier(points, code == AS_FILL_BEZIER);
3152 			break;
3153 		}
3154 
3155 		case AS_STROKE_LINE:
3156 		{
3157 			ViewStrokeLineInfo info;
3158 			link.Read<ViewStrokeLineInfo>(&info);
3159 
3160 			picture->WriteStrokeLine(info.startPoint, info.endPoint);
3161 			break;
3162 		}
3163 
3164 		case AS_STROKE_LINEARRAY:
3165 		{
3166 			int32 lineCount;
3167 			if (link.Read<int32>(&lineCount) != B_OK || lineCount <= 0)
3168 				break;
3169 
3170 			// To speed things up, try to use a stack allocation and only
3171 			// fall back to the heap if there are enough lines...
3172 			ViewLineArrayInfo* lineData;
3173 			const int32 kStackBufferLineDataCount = 64;
3174 			ViewLineArrayInfo lineDataStackBuffer[kStackBufferLineDataCount];
3175 			if (lineCount > kStackBufferLineDataCount) {
3176 				lineData = new(std::nothrow) ViewLineArrayInfo[lineCount];
3177 				if (lineData == NULL)
3178 					break;
3179 			} else
3180 				lineData = lineDataStackBuffer;
3181 
3182 			// Read them all in one go
3183 			size_t dataSize = lineCount * sizeof(ViewLineArrayInfo);
3184 			if (link.Read(lineData, dataSize) != B_OK) {
3185 				if (lineData != lineDataStackBuffer)
3186 					delete[] lineData;
3187 				break;
3188 			}
3189 
3190 			picture->WritePushState();
3191 
3192 			for (int32 i = 0; i < lineCount; i++) {
3193 				picture->WriteSetHighColor(lineData[i].color);
3194 				picture->WriteStrokeLine(lineData[i].startPoint,
3195 					lineData[i].endPoint);
3196 			}
3197 
3198 			picture->WritePopState();
3199 
3200 			if (lineData != lineDataStackBuffer)
3201 				delete[] lineData;
3202 			break;
3203 		}
3204 
3205 		case AS_VIEW_SET_LOW_COLOR:
3206 		case AS_VIEW_SET_HIGH_COLOR:
3207 		{
3208 			rgb_color color;
3209 			link.Read(&color, sizeof(rgb_color));
3210 
3211 			if (code == AS_VIEW_SET_HIGH_COLOR) {
3212 				picture->WriteSetHighColor(color);
3213 				fCurrentView->CurrentState()->SetHighColor(color);
3214 				fWindow->GetDrawingEngine()->SetHighColor(color);
3215 			} else {
3216 				picture->WriteSetLowColor(color);
3217 				fCurrentView->CurrentState()->SetLowColor(color);
3218 				fWindow->GetDrawingEngine()->SetLowColor(color);
3219 			}
3220 		}	break;
3221 
3222 		case AS_DRAW_STRING:
3223 		case AS_DRAW_STRING_WITH_DELTA:
3224 		{
3225 			ViewDrawStringInfo info;
3226 			if (link.Read<ViewDrawStringInfo>(&info) != B_OK)
3227 				break;
3228 
3229 			char* string = (char*)malloc(info.stringLength + 1);
3230 			if (string == NULL)
3231 				break;
3232 
3233 			if (code != AS_DRAW_STRING_WITH_DELTA) {
3234 				// In this case, info.delta will NOT contain valid values.
3235 				info.delta = (escapement_delta){ 0, 0 };
3236 			}
3237 
3238 			if (link.Read(string, info.stringLength) != B_OK) {
3239 				free(string);
3240 				break;
3241 			}
3242 			// Terminate the string
3243 			string[info.stringLength] = '\0';
3244 
3245 			picture->WriteDrawString(info.location, string, info.stringLength,
3246 				info.delta);
3247 
3248 			free(string);
3249 			break;
3250 		}
3251 
3252 		case AS_STROKE_SHAPE:
3253 		case AS_FILL_SHAPE:
3254 		{
3255 			BRect shapeFrame;
3256 			int32 opCount;
3257 			int32 ptCount;
3258 
3259 			link.Read<BRect>(&shapeFrame);
3260 			link.Read<int32>(&opCount);
3261 			link.Read<int32>(&ptCount);
3262 
3263 			uint32* opList = new(std::nothrow) uint32[opCount];
3264 			BPoint* ptList = new(std::nothrow) BPoint[ptCount];
3265 			if (opList != NULL && ptList != NULL
3266 				&& link.Read(opList, opCount * sizeof(uint32)) >= B_OK
3267 				&& link.Read(ptList, ptCount * sizeof(BPoint)) >= B_OK) {
3268 				// This might seem a bit weird, but under BeOS, the shapes
3269 				// are always offset by the current pen location
3270 				BPoint penLocation
3271 					= fCurrentView->CurrentState()->PenLocation();
3272 				for (int32 i = 0; i < ptCount; i++) {
3273 					ptList[i] += penLocation;
3274 				}
3275 				const bool fill = (code == AS_FILL_SHAPE);
3276 				picture->WriteDrawShape(opCount, opList, ptCount, ptList, fill);
3277 			}
3278 
3279 			delete[] opList;
3280 			delete[] ptList;
3281 			break;
3282 		}
3283 
3284 		case AS_VIEW_DRAW_BITMAP:
3285 		{
3286 			ViewDrawBitmapInfo info;
3287 			link.Read<ViewDrawBitmapInfo>(&info);
3288 
3289 			ServerBitmap* bitmap = App()->GetBitmap(info.bitmapToken);
3290 			if (bitmap == NULL)
3291 				break;
3292 
3293 			picture->WriteDrawBitmap(info.bitmapRect, info.viewRect,
3294 				bitmap->Width(), bitmap->Height(), bitmap->BytesPerRow(),
3295 				bitmap->ColorSpace(), info.options, bitmap->Bits(),
3296 				bitmap->BitsLength());
3297 
3298 			bitmap->ReleaseReference();
3299 			break;
3300 		}
3301 
3302 		case AS_VIEW_DRAW_PICTURE:
3303 		{
3304 			int32 token;
3305 			link.Read<int32>(&token);
3306 
3307 			BPoint where;
3308 			if (link.Read<BPoint>(&where) == B_OK) {
3309 				ServerPicture* pictureToDraw = App()->GetPicture(token);
3310 				if (pictureToDraw != NULL) {
3311 					// We need to make a copy of the picture, since it can
3312 					// change after it has been drawn
3313 					ServerPicture* copy = App()->CreatePicture(pictureToDraw);
3314 					picture->NestPicture(copy);
3315 					picture->WriteDrawPicture(where, copy->Token());
3316 
3317 					pictureToDraw->ReleaseReference();
3318 				}
3319 			}
3320 			break;
3321 		}
3322 
3323 		case AS_VIEW_SET_CLIP_REGION:
3324 		{
3325 			int32 rectCount;
3326 			status_t status = link.Read<int32>(&rectCount);
3327 				// a negative count means no
3328 				// region for the current draw state,
3329 				// but an *empty* region is actually valid!
3330 				// even if it means no drawing is allowed
3331 
3332 			if (status < B_OK)
3333 				break;
3334 
3335 			if (rectCount >= 0) {
3336 				// we are supposed to set the clipping region
3337 				BRegion region;
3338 				if (rectCount > 0 && link.ReadRegion(&region) < B_OK)
3339 					break;
3340 				picture->WriteSetClipping(region);
3341 			} else {
3342 				// we are supposed to clear the clipping region
3343 				picture->WriteClearClipping();
3344 			}
3345 			break;
3346 		}
3347 
3348 		case AS_VIEW_BEGIN_PICTURE:
3349 		{
3350 			ServerPicture* newPicture = App()->CreatePicture();
3351 			if (newPicture != NULL) {
3352 				newPicture->PushPicture(picture);
3353 				newPicture->SyncState(fCurrentView);
3354 				fCurrentView->SetPicture(newPicture);
3355 			}
3356 			break;
3357 		}
3358 
3359 		case AS_VIEW_APPEND_TO_PICTURE:
3360 		{
3361 			int32 token;
3362 			link.Read<int32>(&token);
3363 
3364 			ServerPicture* appendPicture = App()->GetPicture(token);
3365 			if (appendPicture != NULL) {
3366 				//picture->SyncState(fCurrentView);
3367 				appendPicture->AppendPicture(picture);
3368 			}
3369 
3370 			fCurrentView->SetPicture(appendPicture);
3371 
3372 			if (appendPicture != NULL)
3373 				appendPicture->ReleaseReference();
3374 			break;
3375 		}
3376 
3377 		case AS_VIEW_END_PICTURE:
3378 		{
3379 			ServerPicture* poppedPicture = picture->PopPicture();
3380 			fCurrentView->SetPicture(poppedPicture);
3381 			if (poppedPicture != NULL)
3382 				poppedPicture->ReleaseReference();
3383 
3384 			fLink.StartMessage(B_OK);
3385 			fLink.Attach<int32>(picture->Token());
3386 			fLink.Flush();
3387 			return true;
3388 		}
3389 /*
3390 		case AS_VIEW_SET_BLENDING_MODE:
3391 		{
3392 			ViewBlendingModeInfo info;
3393 			link.Read<ViewBlendingModeInfo>(&info);
3394 
3395 			picture->BeginOp(B_PIC_SET_BLENDING_MODE);
3396 			picture->AddInt16((int16)info.sourceAlpha);
3397 			picture->AddInt16((int16)info.alphaFunction);
3398 			picture->EndOp();
3399 
3400 			fCurrentView->CurrentState()->SetBlendingMode(info.sourceAlpha,
3401 				info.alphaFunction);
3402 			fWindow->GetDrawingEngine()->SetBlendingMode(info.sourceAlpha,
3403 				info.alphaFunction);
3404 			break;
3405 		}*/
3406 		default:
3407 			return false;
3408 	}
3409 
3410 	if (link.NeedsReply()) {
3411 		fLink.StartMessage(B_ERROR);
3412 		fLink.Flush();
3413 	}
3414 	return true;
3415 }
3416 
3417 
3418 /*!	\brief Message-dispatching loop for the ServerWindow
3419 
3420 	Watches the ServerWindow's message port and dispatches as necessary
3421 */
3422 void
3423 ServerWindow::_MessageLooper()
3424 {
3425 	// Send a reply to our window - it is expecting fMessagePort
3426 	// port and some other info.
3427 
3428 	fLink.StartMessage(B_OK);
3429 	fLink.Attach<port_id>(fMessagePort);
3430 
3431 	int32 minWidth, maxWidth, minHeight, maxHeight;
3432 	fWindow->GetSizeLimits(&minWidth, &maxWidth, &minHeight, &maxHeight);
3433 
3434 	fLink.Attach<BRect>(fWindow->Frame());
3435 	fLink.Attach<float>((float)minWidth);
3436 	fLink.Attach<float>((float)maxWidth);
3437 	fLink.Attach<float>((float)minHeight);
3438 	fLink.Attach<float>((float)maxHeight);
3439 	fLink.Flush();
3440 
3441 	BPrivate::LinkReceiver& receiver = fLink.Receiver();
3442 	bool quitLoop = false;
3443 
3444 	while (!quitLoop) {
3445 		//STRACE(("info: ServerWindow::MonitorWin listening on port %ld.\n",
3446 		//	fMessagePort));
3447 
3448 		int32 code;
3449 		status_t status = receiver.GetNextMessage(code);
3450 		if (status != B_OK) {
3451 			// that shouldn't happen, it's our port
3452 			printf("Someone deleted our message port!\n");
3453 
3454 			// try to let our client die happily
3455 			NotifyQuitRequested();
3456 			break;
3457 		}
3458 
3459 #ifdef PROFILE_MESSAGE_LOOP
3460 		bigtime_t start = system_time();
3461 #endif
3462 
3463 		Lock();
3464 
3465 #ifdef PROFILE_MESSAGE_LOOP
3466 		bigtime_t diff = system_time() - start;
3467 		if (diff > 10000) {
3468 			printf("ServerWindow %s: lock acquisition took %" B_PRId64 " usecs\n",
3469 				Title(), diff);
3470 		}
3471 #endif
3472 
3473 		int32 messagesProcessed = 0;
3474 		bigtime_t processingStart = system_time();
3475 		bool lockedDesktopSingleWindow = false;
3476 
3477 		while (true) {
3478 			if (code == AS_DELETE_WINDOW || code == kMsgQuitLooper) {
3479 				// this means the client has been killed
3480 				DTRACE(("ServerWindow %s received 'AS_DELETE_WINDOW' message "
3481 					"code\n", Title()));
3482 
3483 				if (code == AS_DELETE_WINDOW) {
3484 					fLink.StartMessage(B_OK);
3485 					fLink.Flush();
3486 				}
3487 
3488 				if (lockedDesktopSingleWindow)
3489 					fDesktop->UnlockSingleWindow();
3490 
3491 				quitLoop = true;
3492 
3493 				// ServerWindow's destructor takes care of pulling this object
3494 				// off the desktop.
3495 				ASSERT(fWindow->IsHidden());
3496 				break;
3497 			}
3498 
3499 			// Acquire the appropriate lock
3500 			bool needsAllWindowsLocked = _MessageNeedsAllWindowsLocked(code);
3501 			if (needsAllWindowsLocked) {
3502 				// We may already still hold the read-lock from the previous
3503 				// inner-loop iteration.
3504 				if (lockedDesktopSingleWindow) {
3505 					fDesktop->UnlockSingleWindow();
3506 					lockedDesktopSingleWindow = false;
3507 				}
3508 				fDesktop->LockAllWindows();
3509 			} else {
3510 				// We never keep the write-lock across inner-loop iterations,
3511 				// so there is nothing else to do besides read-locking unless
3512 				// we already have the read-lock from the previous iteration.
3513 				if (!lockedDesktopSingleWindow) {
3514 					fDesktop->LockSingleWindow();
3515 					lockedDesktopSingleWindow = true;
3516 				}
3517 			}
3518 
3519 			if (atomic_and(&fRedrawRequested, 0) != 0) {
3520 #ifdef PROFILE_MESSAGE_LOOP
3521 				bigtime_t redrawStart = system_time();
3522 #endif
3523 				fWindow->RedrawDirtyRegion();
3524 #ifdef PROFILE_MESSAGE_LOOP
3525 				diff = system_time() - redrawStart;
3526 				atomic_add(&sRedrawProcessingTime.count, 1);
3527 # ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
3528 				atomic_add64(&sRedrawProcessingTime.time, diff);
3529 # else
3530 				sRedrawProcessingTime.time += diff;
3531 # endif
3532 #endif
3533 			}
3534 
3535 #ifdef PROFILE_MESSAGE_LOOP
3536 			bigtime_t dispatchStart = system_time();
3537 #endif
3538 			_DispatchMessage(code, receiver);
3539 
3540 #ifdef PROFILE_MESSAGE_LOOP
3541 			if (code >= 0 && code < AS_LAST_CODE) {
3542 				diff = system_time() - dispatchStart;
3543 				atomic_add(&sMessageProfile[code].count, 1);
3544 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
3545 				atomic_add64(&sMessageProfile[code].time, diff);
3546 #else
3547 				sMessageProfile[code].time += diff;
3548 #endif
3549 				if (diff > 10000) {
3550 					printf("ServerWindow %s: message %" B_PRId32 " took %"
3551 						B_PRId64 " usecs\n", Title(), code, diff);
3552 				}
3553 			}
3554 #endif
3555 
3556 			if (needsAllWindowsLocked)
3557 				fDesktop->UnlockAllWindows();
3558 
3559 			// Only process up to 70 waiting messages at once (we have the
3560 			// Desktop locked), but don't hold the lock longer than 10 ms
3561 			if (!receiver.HasMessages() || ++messagesProcessed > 70
3562 				|| system_time() - processingStart > 10000) {
3563 				if (lockedDesktopSingleWindow)
3564 					fDesktop->UnlockSingleWindow();
3565 				break;
3566 			}
3567 
3568 			// next message
3569 			status_t status = receiver.GetNextMessage(code);
3570 			if (status != B_OK) {
3571 				// that shouldn't happen, it's our port
3572 				printf("Someone deleted our message port!\n");
3573 				if (lockedDesktopSingleWindow)
3574 					fDesktop->UnlockSingleWindow();
3575 
3576 				// try to let our client die happily
3577 				NotifyQuitRequested();
3578 				break;
3579 			}
3580 		}
3581 
3582 		Unlock();
3583 	}
3584 
3585 	// We were asked to quit the message loop - either on request or because of
3586 	// an error.
3587 	Quit();
3588 		// does not return
3589 }
3590 
3591 
3592 void
3593 ServerWindow::ScreenChanged(const BMessage* message)
3594 {
3595 	SendMessageToClient(message);
3596 
3597 	if (fDirectWindowInfo != NULL && fDirectWindowInfo->IsFullScreen())
3598 		_ResizeToFullScreen();
3599 }
3600 
3601 
3602 status_t
3603 ServerWindow::SendMessageToClient(const BMessage* msg, int32 target) const
3604 {
3605 	if (target == B_NULL_TOKEN)
3606 		target = fClientToken;
3607 
3608 	BMessenger reply;
3609 	BMessage::Private messagePrivate((BMessage*)msg);
3610 	return messagePrivate.SendMessage(fClientLooperPort, fClientTeam, target,
3611 		0, false, reply);
3612 }
3613 
3614 
3615 Window*
3616 ServerWindow::MakeWindow(BRect frame, const char* name,
3617 	window_look look, window_feel feel, uint32 flags, uint32 workspace)
3618 {
3619 	// The non-offscreen ServerWindow uses the DrawingEngine instance from
3620 	// the desktop.
3621 	return new(std::nothrow) ::Window(frame, name, look, feel, flags,
3622 		workspace, this, fDesktop->HWInterface()->CreateDrawingEngine());
3623 }
3624 
3625 
3626 void
3627 ServerWindow::HandleDirectConnection(int32 bufferState, int32 driverState)
3628 {
3629 	ASSERT_MULTI_LOCKED(fDesktop->WindowLocker());
3630 
3631 	if (fDirectWindowInfo == NULL)
3632 		return;
3633 
3634 	STRACE(("HandleDirectConnection(bufferState = %" B_PRId32 ", driverState = "
3635 		"%" B_PRId32 ")\n", bufferState, driverState));
3636 
3637 	status_t status = fDirectWindowInfo->SetState(
3638 		(direct_buffer_state)bufferState, (direct_driver_state)driverState,
3639 		fDesktop->HWInterface()->FrontBuffer(), fWindow->Frame(),
3640 		fWindow->VisibleContentRegion());
3641 
3642 	if (status != B_OK) {
3643 		char errorString[256];
3644 		snprintf(errorString, sizeof(errorString),
3645 			"%s killed for a problem in DirectConnected(): %s",
3646 			App()->Signature(), strerror(status));
3647 		syslog(LOG_ERR, errorString);
3648 
3649 		// The client application didn't release the semaphore
3650 		// within the given timeout. Or something else went wrong.
3651 		// Deleting this member should make it crash.
3652 		delete fDirectWindowInfo;
3653 		fDirectWindowInfo = NULL;
3654 	} else if ((bufferState & B_DIRECT_MODE_MASK) == B_DIRECT_START)
3655 		fIsDirectlyAccessing = true;
3656 	else if ((bufferState & B_DIRECT_MODE_MASK) == B_DIRECT_STOP)
3657 		fIsDirectlyAccessing = false;
3658 }
3659 
3660 
3661 void
3662 ServerWindow::_SetCurrentView(View* view)
3663 {
3664 	if (fCurrentView == view)
3665 		return;
3666 
3667 	fCurrentView = view;
3668 	fCurrentDrawingRegionValid = false;
3669 	_UpdateDrawState(fCurrentView);
3670 
3671 #if 0
3672 #if DELAYED_BACKGROUND_CLEARING
3673 	if (fCurrentView && fCurrentView->IsBackgroundDirty()
3674 		&& fWindow->InUpdate()) {
3675 		DrawingEngine* drawingEngine = fWindow->GetDrawingEngine();
3676 		if (drawingEngine->LockParallelAccess()) {
3677 			fWindow->GetEffectiveDrawingRegion(fCurrentView,
3678 				fCurrentDrawingRegion);
3679 			fCurrentDrawingRegionValid = true;
3680 			BRegion dirty(fCurrentDrawingRegion);
3681 
3682 			BRegion content;
3683 			fWindow->GetContentRegion(&content);
3684 
3685 			fCurrentView->Draw(drawingEngine, &dirty, &content, false);
3686 
3687 			drawingEngine->UnlockParallelAccess();
3688 		}
3689 	}
3690 #endif
3691 #endif // 0
3692 }
3693 
3694 
3695 void
3696 ServerWindow::_UpdateDrawState(View* view)
3697 {
3698 	// switch the drawing state
3699 	// TODO: is it possible to scroll a view while it
3700 	// is being drawn? probably not... otherwise the
3701 	// "offsets" passed below would need to be updated again
3702 	DrawingEngine* drawingEngine = fWindow->GetDrawingEngine();
3703 	if (view != NULL && drawingEngine != NULL) {
3704 		BPoint leftTop(0, 0);
3705 		if (view->GetAlphaMask() != NULL) {
3706 			view->ConvertToScreen(&leftTop);
3707  			view->GetAlphaMask()->Update(view->Bounds(), leftTop);
3708 			leftTop = BPoint(0, 0);
3709 		}
3710 		view->ConvertToScreenForDrawing(&leftTop);
3711 		drawingEngine->SetDrawState(view->CurrentState(), leftTop.x, leftTop.y);
3712 	}
3713 }
3714 
3715 
3716 void
3717 ServerWindow::_UpdateCurrentDrawingRegion()
3718 {
3719 	if (!fCurrentDrawingRegionValid
3720 		|| fWindow->DrawingRegionChanged(fCurrentView)) {
3721 		fWindow->GetEffectiveDrawingRegion(fCurrentView, fCurrentDrawingRegion);
3722 		fCurrentDrawingRegionValid = true;
3723 	}
3724 }
3725 
3726 
3727 bool
3728 ServerWindow::_MessageNeedsAllWindowsLocked(uint32 code) const
3729 {
3730 	switch (code) {
3731 		case AS_SET_WINDOW_TITLE:
3732 		case AS_ADD_TO_SUBSET:
3733 		case AS_REMOVE_FROM_SUBSET:
3734 		case AS_VIEW_CREATE_ROOT:
3735 		case AS_VIEW_CREATE:
3736 		case AS_SEND_BEHIND:
3737 		case AS_SET_LOOK:
3738 		case AS_SET_FEEL:
3739 		case AS_SET_FLAGS:
3740 		case AS_SET_WORKSPACES:
3741 		case AS_WINDOW_MOVE:
3742 		case AS_WINDOW_RESIZE:
3743 		case AS_SET_SIZE_LIMITS:
3744 		case AS_SYSTEM_FONT_CHANGED:
3745 		case AS_SET_DECORATOR_SETTINGS:
3746 		case AS_GET_MOUSE:
3747 		case AS_DIRECT_WINDOW_SET_FULLSCREEN:
3748 //		case AS_VIEW_SET_EVENT_MASK:
3749 //		case AS_VIEW_SET_MOUSE_EVENT_MASK:
3750 		case AS_TALK_TO_DESKTOP_LISTENER:
3751 			return true;
3752 		default:
3753 			return false;
3754 	}
3755 }
3756 
3757 
3758 void
3759 ServerWindow::_ResizeToFullScreen()
3760 {
3761 	BRect screenFrame;
3762 
3763 	{
3764 		AutoReadLocker _(fDesktop->ScreenLocker());
3765 		const Screen* screen = fWindow->Screen();
3766 		if (screen == NULL)
3767 			return;
3768 
3769 		screenFrame = fWindow->Screen()->Frame();
3770 	}
3771 
3772 	fDesktop->MoveWindowBy(fWindow,
3773 		screenFrame.left - fWindow->Frame().left,
3774 		screenFrame.top - fWindow->Frame().top);
3775 	fDesktop->ResizeWindowBy(fWindow,
3776 		screenFrame.Width() - fWindow->Frame().Width(),
3777 		screenFrame.Height() - fWindow->Frame().Height());
3778 }
3779 
3780 
3781 status_t
3782 ServerWindow::_EnableDirectWindowMode()
3783 {
3784 	if (fDirectWindowInfo != NULL) {
3785 		// already in direct window mode
3786 		return B_ERROR;
3787 	}
3788 
3789 	if (fDesktop->HWInterface()->FrontBuffer() == NULL) {
3790 		// direct window mode not supported
3791 		return B_UNSUPPORTED;
3792 	}
3793 
3794 	fDirectWindowInfo = new(std::nothrow) DirectWindowInfo;
3795 	if (fDirectWindowInfo == NULL)
3796 		return B_NO_MEMORY;
3797 
3798 	status_t status = fDirectWindowInfo->InitCheck();
3799 	if (status != B_OK) {
3800 		delete fDirectWindowInfo;
3801 		fDirectWindowInfo = NULL;
3802 
3803 		return status;
3804 	}
3805 
3806 	return B_OK;
3807 }
3808 
3809 
3810 void
3811 ServerWindow::_DirectWindowSetFullScreen(bool enable)
3812 {
3813 	window_feel feel = kWindowScreenFeel;
3814 
3815 	if (enable) {
3816 		fDesktop->HWInterface()->SetCursorVisible(false);
3817 
3818 		fDirectWindowInfo->EnableFullScreen(fWindow->Frame(), fWindow->Feel());
3819 		_ResizeToFullScreen();
3820 	} else {
3821 		const BRect& originalFrame = fDirectWindowInfo->OriginalFrame();
3822 
3823 		fDirectWindowInfo->DisableFullScreen();
3824 
3825 		// Resize window back to its original size
3826 		fDesktop->MoveWindowBy(fWindow,
3827 			originalFrame.left - fWindow->Frame().left,
3828 			originalFrame.top - fWindow->Frame().top);
3829 		fDesktop->ResizeWindowBy(fWindow,
3830 			originalFrame.Width() - fWindow->Frame().Width(),
3831 			originalFrame.Height() - fWindow->Frame().Height());
3832 
3833 		fDesktop->HWInterface()->SetCursorVisible(true);
3834 	}
3835 
3836 	fDesktop->SetWindowFeel(fWindow, feel);
3837 }
3838