1/*
2 * Copyright 2001-2019, 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 *		Julian Harnath <julian.harnath@rwth-aachen.de>
15 *		Joseph Groover <looncraz@looncraz.net>
16 */
17
18
19/*!	\class ServerWindow
20
21	The ServerWindow class handles all BWindow messaging; it forwards all
22	BWindow requests to the corresponding app_server classes, that is Desktop,
23	Window, and View.
24	Furthermore, it also sends app_server requests/notices to its BWindow. There
25	is one ServerWindow per BWindow.
26*/
27
28
29#include "ServerWindow.h"
30
31#include <syslog.h>
32#include <new>
33
34#include <AppDefs.h>
35#include <Autolock.h>
36#include <Debug.h>
37#include <DirectWindow.h>
38#include <TokenSpace.h>
39#include <View.h>
40#include <GradientLinear.h>
41#include <GradientRadial.h>
42#include <GradientRadialFocus.h>
43#include <GradientDiamond.h>
44#include <GradientConic.h>
45
46#include <MessagePrivate.h>
47#include <PortLink.h>
48#include <ShapePrivate.h>
49#include <ServerProtocolStructs.h>
50#include <StackOrHeapArray.h>
51#include <ViewPrivate.h>
52#include <WindowInfo.h>
53#include <WindowPrivate.h>
54
55#include "clipping.h"
56#include "utf8_functions.h"
57
58#include "AlphaMask.h"
59#include "AppServer.h"
60#include "AutoDeleter.h"
61#include "BBitmapBuffer.h"
62#include "BitmapManager.h"
63#include "Desktop.h"
64#include "DirectWindowInfo.h"
65#include "DrawingEngine.h"
66#include "DrawState.h"
67#include "HWInterface.h"
68#include "Layer.h"
69#include "Overlay.h"
70#include "ProfileMessageSupport.h"
71#include "RenderingBuffer.h"
72#include "ServerApp.h"
73#include "ServerBitmap.h"
74#include "ServerPicture.h"
75#include "ServerProtocol.h"
76#include "Window.h"
77#include "WorkspacesView.h"
78
79
80using std::nothrow;
81
82
83//#define TRACE_SERVER_WINDOW
84#ifdef TRACE_SERVER_WINDOW
85#	include <stdio.h>
86#	define STRACE(x) debug_printf x
87#else
88#	define STRACE(x) ;
89#endif
90
91//#define TRACE_SERVER_WINDOW_MESSAGES
92#ifdef TRACE_SERVER_WINDOW_MESSAGES
93#	include <stdio.h>
94static const char* kDrawingModeMap[] = {
95	"B_OP_COPY",
96	"B_OP_OVER",
97	"B_OP_ERASE",
98	"B_OP_INVERT",
99	"B_OP_ADD",
100	"B_OP_SUBTRACT",
101	"B_OP_BLEND",
102	"B_OP_MIN",
103	"B_OP_MAX",
104	"B_OP_SELECT",
105	"B_OP_ALPHA",
106
107	"fix kDrawingModeMap",
108	"fix kDrawingModeMap",
109	"fix kDrawingModeMap",
110	"fix kDrawingModeMap",
111	"fix kDrawingModeMap",
112};
113#	define DTRACE(x) debug_printf x
114#else
115#	define DTRACE(x) ;
116#endif
117
118//#define TRACE_SERVER_GRADIENTS
119#ifdef TRACE_SERVER_GRADIENTS
120#	include <OS.h>
121#	define GTRACE(x) debug_printf x
122#else
123#	define GTRACE(x) ;
124#endif
125
126//#define PROFILE_MESSAGE_LOOP
127#ifdef PROFILE_MESSAGE_LOOP
128struct profile { int32 code; int32 count; bigtime_t time; };
129static profile sMessageProfile[AS_LAST_CODE];
130static profile sRedrawProcessingTime;
131//static profile sNextMessageTime;
132#endif
133
134
135//	#pragma mark -
136
137
138#ifdef PROFILE_MESSAGE_LOOP
139static int
140compare_message_profiles(const void* _a, const void* _b)
141{
142	profile* a = (profile*)*(void**)_a;
143	profile* b = (profile*)*(void**)_b;
144	if (a->time < b->time)
145		return 1;
146	if (a->time > b->time)
147		return -1;
148	return 0;
149}
150#endif
151
152
153//	#pragma mark -
154
155
156/*!	Sets up the basic BWindow counterpart - you have to call Init() before
157	you can actually use it, though.
158*/
159ServerWindow::ServerWindow(const char* title, ServerApp* app,
160		port_id clientPort, port_id looperPort, int32 clientToken)
161	:
162	MessageLooper(title && *title ? title : "Unnamed Window"),
163	fTitle(NULL),
164	fDesktop(app->GetDesktop()),
165	fServerApp(app),
166	fWindowAddedToDesktop(false),
167
168	fClientTeam(app->ClientTeam()),
169
170	fMessagePort(-1),
171	fClientReplyPort(clientPort),
172	fClientLooperPort(looperPort),
173
174	fClientToken(clientToken),
175
176	fCurrentView(NULL),
177	fCurrentDrawingRegion(),
178	fCurrentDrawingRegionValid(false),
179
180	fIsDirectlyAccessing(false)
181{
182	STRACE(("ServerWindow(%s)::ServerWindow()\n", title));
183
184	SetTitle(title);
185	fServerToken = BPrivate::gDefaultTokens.NewToken(B_SERVER_TOKEN, this);
186
187	BMessenger::Private(fFocusMessenger).SetTo(fClientTeam,
188		looperPort, B_PREFERRED_TOKEN);
189	BMessenger::Private(fHandlerMessenger).SetTo(fClientTeam,
190		looperPort, clientToken);
191
192	fEventTarget.SetTo(fFocusMessenger);
193
194	fDeathSemaphore = create_sem(0, "window death");
195}
196
197
198/*! Tears down all connections the main app_server objects, and deletes some
199	internals.
200*/
201ServerWindow::~ServerWindow()
202{
203	STRACE(("ServerWindow(%s@%p):~ServerWindow()\n", fTitle, this));
204
205	if (!fWindow->IsOffscreenWindow()) {
206		fWindowAddedToDesktop = false;
207		fDesktop->RemoveWindow(fWindow.Get());
208	}
209
210	if (App() != NULL) {
211		App()->RemoveWindow(this);
212		fServerApp = NULL;
213	}
214
215	fWindow.Unset(); // TODO: is it really needed?
216
217	free(fTitle);
218	delete_port(fMessagePort);
219
220	BPrivate::gDefaultTokens.RemoveToken(fServerToken);
221
222	fDirectWindowInfo.Unset(); // TODO: is it really needed?
223	STRACE(("ServerWindow(%p) will exit NOW\n", this));
224
225	delete_sem(fDeathSemaphore);
226
227#ifdef PROFILE_MESSAGE_LOOP
228	BList profiles;
229	for (int32 i = 0; i < AS_LAST_CODE; i++) {
230		if (sMessageProfile[i].count == 0)
231			continue;
232		sMessageProfile[i].code = i;
233		profiles.AddItem(&sMessageProfile[i]);
234	}
235
236	profiles.SortItems(compare_message_profiles);
237
238	int32 count = profiles.CountItems();
239	for (int32 i = 0; i < count; i++) {
240		profile* p = (profile*)profiles.ItemAtFast(i);
241		printf("[%s] called %" B_PRId32 " times, %g secs (%" B_PRId64 " usecs "
242			"per call)\n", string_for_message_code(p->code), p->count, p->time / 1000000.0,
243			p->time / p->count);
244	}
245	if (sRedrawProcessingTime.count > 0) {
246		printf("average redraw processing time: %g secs, count: %" B_PRId32 " "
247			"(%" B_PRId64 " usecs per call)\n",
248			sRedrawProcessingTime.time / 1000000.0, sRedrawProcessingTime.count,
249			sRedrawProcessingTime.time / sRedrawProcessingTime.count);
250	}
251//	if (sNextMessageTime.count > 0) {
252//		printf("average NextMessage() time: %g secs, count: %ld (%lld usecs per call)\n",
253//			sNextMessageTime.time / 1000000.0, sNextMessageTime.count,
254//			sNextMessageTime.time / sNextMessageTime.count);
255//	}
256#endif
257}
258
259
260status_t
261ServerWindow::Init(BRect frame, window_look look, window_feel feel,
262	uint32 flags, uint32 workspace)
263{
264	if (!App()->AddWindow(this)) {
265		fServerApp = NULL;
266		return B_NO_MEMORY;
267	}
268
269	if (fTitle == NULL)
270		return B_NO_MEMORY;
271
272	// fMessagePort is the port to which the app sends messages for the server
273	fMessagePort = create_port(100, fTitle);
274	if (fMessagePort < B_OK)
275		return fMessagePort;
276
277	fLink.SetSenderPort(fClientReplyPort);
278	fLink.SetReceiverPort(fMessagePort);
279
280	// We cannot call MakeWindow in the constructor, since it
281	// is a virtual function!
282	fWindow.SetTo(MakeWindow(frame, fTitle, look, feel, flags, workspace));
283	if (!fWindow.IsSet() || fWindow->InitCheck() != B_OK) {
284		fWindow.Unset();
285		return B_NO_MEMORY;
286	}
287
288	if (!fWindow->IsOffscreenWindow()) {
289		fDesktop->AddWindow(fWindow.Get());
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*/
302Window*
303ServerWindow::Window() const
304{
305	if (!fWindowAddedToDesktop)
306		return NULL;
307
308	return fWindow.Get();
309}
310
311
312void
313ServerWindow::_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
325void
326ServerWindow::_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*/
338void
339ServerWindow::_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.Get());
352	if (fDirectWindowInfo.IsSet() && 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*/
362void
363ServerWindow::_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.Get());
372	fDesktop->LockSingleWindow();
373}
374
375
376void
377ServerWindow::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
388void
389ServerWindow::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.IsSet())
412		fDesktop->SetWindowTitle(fWindow.Get(), newTitle);
413}
414
415
416//! Requests that the ServerWindow's BWindow quit
417void
418ServerWindow::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
429void
430ServerWindow::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
446void
447ServerWindow::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
456void
457ServerWindow::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
492void
493ServerWindow::ResyncDrawState()
494{
495	_UpdateDrawState(fCurrentView);
496}
497
498
499View*
500ServerWindow::_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();
559fDesktop->UnlockAllWindows();
560		// TODO: possible deadlock
561		fDesktop->EventDispatcher().AddListener(EventTarget(),
562			newView->Token(), eventMask, eventOptions);
563fDesktop->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*/
596void
597ServerWindow::_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.Get(), 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.Get());
646			else
647				fDesktop->SendWindowBehind(fWindow.Get(), 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.Get(), 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.Get(), 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.Get(), 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.Get(), (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.Get(), (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.Get(), 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.Get();
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.Get(), 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.Get(),
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.Get(),
914					xMoveTo - fWindow->Frame().left,
915					yMoveTo - fWindow->Frame().top);
916				fLink.StartMessage(B_OK);
917			}
918			fLink.Flush();
919			break;
920		}
921		case AS_SET_SIZE_LIMITS:
922		{
923			// Has the all-window look
924
925			// Attached Data:
926			// 1) float minimum width
927			// 2) float maximum width
928			// 3) float minimum height
929			// 4) float maximum height
930
931			// TODO: for now, move the client to int32 as well!
932			int32 minWidth, maxWidth, minHeight, maxHeight;
933			float value;
934			link.Read<float>(&value);	minWidth = (int32)value;
935			link.Read<float>(&value);	maxWidth = (int32)value;
936			link.Read<float>(&value);	minHeight = (int32)value;
937			link.Read<float>(&value);	maxHeight = (int32)value;
938/*
939			link.Read<int32>(&minWidth);
940			link.Read<int32>(&maxWidth);
941			link.Read<int32>(&minHeight);
942			link.Read<int32>(&maxHeight);
943*/
944			DTRACE(("ServerWindow %s: Message AS_SET_SIZE_LIMITS: "
945				"x: %" B_PRId32 "-%" B_PRId32 ", y: %" B_PRId32 "-%" B_PRId32
946				"\n", Title(), minWidth, maxWidth, minHeight, maxHeight));
947
948			fWindow->SetSizeLimits(minWidth, maxWidth, minHeight, maxHeight);
949
950			// and now, sync the client to the limits that we were able to enforce
951			fWindow->GetSizeLimits(&minWidth, &maxWidth,
952				&minHeight, &maxHeight);
953
954			fLink.StartMessage(B_OK);
955			fLink.Attach<BRect>(fWindow->Frame());
956			fLink.Attach<float>((float)minWidth);
957			fLink.Attach<float>((float)maxWidth);
958			fLink.Attach<float>((float)minHeight);
959			fLink.Attach<float>((float)maxHeight);
960
961			fLink.Flush();
962
963			fDesktop->NotifySizeLimitsChanged(fWindow.Get(), minWidth, maxWidth,
964				minHeight, maxHeight);
965			break;
966		}
967
968		case AS_SET_DECORATOR_SETTINGS:
969		{
970			// Has the all-window look
971			DTRACE(("ServerWindow %s: Message AS_SET_DECORATOR_SETTINGS\n",
972				Title()));
973
974			int32 size;
975			if (fWindow.IsSet() && link.Read<int32>(&size) == B_OK) {
976				char buffer[size];
977				if (link.Read(buffer, size) == B_OK) {
978					BMessage settings;
979					if (settings.Unflatten(buffer) == B_OK)
980						fDesktop->SetWindowDecoratorSettings(
981							fWindow.Get(), settings);
982				}
983			}
984			break;
985		}
986
987		case AS_GET_DECORATOR_SETTINGS:
988		{
989			DTRACE(("ServerWindow %s: Message AS_GET_DECORATOR_SETTINGS\n",
990				Title()));
991
992			bool success = false;
993
994			BMessage settings;
995			if (fWindow->GetDecoratorSettings(&settings)) {
996				int32 size = settings.FlattenedSize();
997				char buffer[size];
998				if (settings.Flatten(buffer, size) == B_OK) {
999					success = true;
1000					fLink.StartMessage(B_OK);
1001					fLink.Attach<int32>(size);
1002					fLink.Attach(buffer, size);
1003				}
1004			}
1005
1006			if (!success)
1007				fLink.StartMessage(B_ERROR);
1008
1009			fLink.Flush();
1010			break;
1011		}
1012
1013		case AS_SYSTEM_FONT_CHANGED:
1014		{
1015			// Has the all-window look
1016			fDesktop->FontsChanged(fWindow.Get());
1017			break;
1018		}
1019
1020		// Forward to client
1021		case B_FONTS_UPDATED:
1022		{
1023			// TODO: would knowing which font was changed be useful?
1024			BMessage message(code);
1025			SendMessageToClient(&message);
1026			break;
1027		}
1028
1029		case AS_REDRAW:
1030			// Nothing to do here - the redraws are actually handled by looking
1031			// at the fRedrawRequested member variable in _MessageLooper().
1032			break;
1033
1034		case AS_SYNC:
1035			DTRACE(("ServerWindow %s: Message AS_SYNC\n", Title()));
1036			// the synchronisation works by the fact that the client
1037			// window is waiting for this reply, after having received it,
1038			// client and server queues are in sync (earlier, the client
1039			// may have pushed drawing commands at the server and now it
1040			// knows they have all been carried out)
1041			fLink.StartMessage(B_OK);
1042			fLink.Flush();
1043			break;
1044
1045		case AS_BEGIN_UPDATE:
1046			DTRACE(("ServerWindow %s: Message AS_BEGIN_UPDATE\n", Title()));
1047			fWindow->BeginUpdate(fLink);
1048			break;
1049
1050		case AS_END_UPDATE:
1051			DTRACE(("ServerWindow %s: Message AS_END_UPDATE\n", Title()));
1052			fWindow->EndUpdate();
1053			break;
1054
1055		case AS_GET_MOUSE:
1056		{
1057			// Has the all-window look
1058			DTRACE(("ServerWindow %s: Message AS_GET_MOUSE\n", fTitle));
1059
1060			// Returns
1061			// 1) BPoint mouse location
1062			// 2) int32 button state
1063
1064			BPoint where;
1065			int32 buttons;
1066			fDesktop->GetLastMouseState(&where, &buttons);
1067
1068			fLink.StartMessage(B_OK);
1069			fLink.Attach<BPoint>(where);
1070			fLink.Attach<int32>(buttons);
1071			fLink.Flush();
1072			break;
1073		}
1074
1075		// BDirectWindow communication
1076
1077		case AS_DIRECT_WINDOW_GET_SYNC_DATA:
1078		{
1079			status_t status = _EnableDirectWindowMode();
1080
1081			fLink.StartMessage(status);
1082			if (status == B_OK) {
1083				struct direct_window_sync_data syncData;
1084				fDirectWindowInfo->GetSyncData(syncData);
1085
1086				fLink.Attach(&syncData, sizeof(syncData));
1087			}
1088
1089			fLink.Flush();
1090			break;
1091		}
1092		case AS_DIRECT_WINDOW_SET_FULLSCREEN:
1093		{
1094			// Has the all-window look
1095			bool enable;
1096			link.Read<bool>(&enable);
1097
1098			status_t status = B_OK;
1099			if (fDirectWindowInfo.IsSet())
1100				_DirectWindowSetFullScreen(enable);
1101			else
1102				status = B_BAD_TYPE;
1103
1104			fLink.StartMessage(status);
1105			fLink.Flush();
1106			break;
1107		}
1108
1109		// View creation and destruction (don't need a valid fCurrentView)
1110
1111		case AS_SET_CURRENT_VIEW:
1112		{
1113			int32 token;
1114			if (link.Read<int32>(&token) != B_OK)
1115				break;
1116
1117			View *current;
1118			if (App()->ViewTokens().GetToken(token, B_HANDLER_TOKEN,
1119					(void**)&current) != B_OK
1120				|| current->Window()->ServerWindow() != this) {
1121				// TODO: if this happens, we probably want to kill the app and
1122				// clean up
1123				debug_printf("ServerWindow %s: Message "
1124					"\n\n\nAS_SET_CURRENT_VIEW: view not found, token %"
1125					B_PRId32 "\n", fTitle, token);
1126				current = NULL;
1127			} else {
1128				DTRACE(("\n\n\nServerWindow %s: Message AS_SET_CURRENT_VIEW: %s, "
1129					"token %" B_PRId32 "\n", fTitle, current->Name(), token));
1130				_SetCurrentView(current);
1131			}
1132			break;
1133		}
1134
1135		case AS_VIEW_CREATE_ROOT:
1136		{
1137			DTRACE(("ServerWindow %s: Message AS_VIEW_CREATE_ROOT\n", fTitle));
1138
1139			// Start receiving top_view data -- pass NULL as the parent view.
1140			// This should be the *only* place where this happens.
1141			if (fCurrentView != NULL) {
1142				debug_printf("ServerWindow %s: Message "
1143					"AS_VIEW_CREATE_ROOT: fCurrentView already set!!\n",
1144					fTitle);
1145				break;
1146			}
1147
1148			_SetCurrentView(_CreateView(link, NULL));
1149			fWindow->SetTopView(fCurrentView);
1150			break;
1151		}
1152
1153		case AS_VIEW_CREATE:
1154		{
1155			DTRACE(("ServerWindow %s: Message AS_VIEW_CREATE: View name: "
1156				"%s\n", fTitle, fCurrentView->Name()));
1157
1158			View* parent = NULL;
1159			View* newView = _CreateView(link, &parent);
1160			if (parent != NULL && newView != NULL)
1161				parent->AddChild(newView);
1162			else {
1163				delete newView;
1164				debug_printf("ServerWindow %s: Message AS_VIEW_CREATE: "
1165					"parent or newView NULL!!\n", fTitle);
1166			}
1167			break;
1168		}
1169
1170		case AS_TALK_TO_DESKTOP_LISTENER:
1171		{
1172			if (fDesktop->MessageForListener(fWindow.Get(), fLink.Receiver(),
1173				fLink.Sender()))
1174				break;
1175			// unhandled message at least send an error if needed
1176			if (link.NeedsReply()) {
1177				fLink.StartMessage(B_ERROR);
1178				fLink.Flush();
1179			}
1180			break;
1181		}
1182
1183		default:
1184			if (fCurrentView == NULL) {
1185				debug_printf("ServerWindow %s received unexpected code - "
1186					"message '%s' before top_view attached.\n",
1187					Title(), string_for_message_code(code));
1188				if (link.NeedsReply()) {
1189					fLink.StartMessage(B_ERROR);
1190					fLink.Flush();
1191				}
1192				return;
1193			}
1194
1195			_DispatchViewMessage(code, link);
1196			break;
1197	}
1198}
1199
1200
1201/*!
1202	Dispatches all view messages that need a valid fCurrentView.
1203*/
1204void
1205ServerWindow::_DispatchViewMessage(int32 code,
1206	BPrivate::LinkReceiver &link)
1207{
1208	if (_DispatchPictureMessage(code, link))
1209		return;
1210
1211	switch (code) {
1212		case AS_VIEW_SCROLL:
1213		{
1214			float dh;
1215			float dv;
1216			link.Read<float>(&dh);
1217			if (link.Read<float>(&dv) != B_OK)
1218				break;
1219
1220			DTRACE(("ServerWindow %s: Message AS_VIEW_SCROLL: View name: "
1221				"%s, %.1f x %.1f\n", fTitle, fCurrentView->Name(), dh, dv));
1222			fWindow->ScrollViewBy(fCurrentView, dh, dv);
1223			break;
1224		}
1225		case AS_VIEW_COPY_BITS:
1226		{
1227			BRect src;
1228			BRect dst;
1229
1230			link.Read<BRect>(&src);
1231			if (link.Read<BRect>(&dst) != B_OK)
1232				break;
1233
1234			DTRACE(("ServerWindow %s: Message AS_VIEW_COPY_BITS: View name: "
1235				"%s, BRect(%.1f, %.1f, %.1f, %.1f) -> "
1236				"BRect(%.1f, %.1f, %.1f, %.1f)\n", fTitle,
1237				fCurrentView->Name(), src.left, src.top, src.right, src.bottom,
1238				dst.left, dst.top, dst.right, dst.bottom));
1239
1240			BRegion contentRegion;
1241			// TODO: avoid copy operation maybe?
1242			fWindow->GetContentRegion(&contentRegion);
1243			fCurrentView->CopyBits(src, dst, contentRegion);
1244			break;
1245		}
1246		case AS_VIEW_DELETE:
1247		{
1248			// Received when a view is detached from a window
1249
1250			int32 token;
1251			if (link.Read<int32>(&token) != B_OK)
1252				break;
1253
1254			View *view;
1255			if (App()->ViewTokens().GetToken(token, B_HANDLER_TOKEN,
1256					(void**)&view) == B_OK
1257				&& view->Window()->ServerWindow() == this) {
1258				View* parent = view->Parent();
1259
1260				DTRACE(("ServerWindow %s: AS_VIEW_DELETE view: %p, "
1261					"parent: %p\n", fTitle, view, parent));
1262
1263				if (parent != NULL) {
1264					parent->RemoveChild(view);
1265
1266					if (view->EventMask() != 0) {
1267						// TODO: possible deadlock (event dispatcher already
1268						// locked itself, waits for Desktop write lock, but
1269						// we have it, now we are trying to lock the event
1270						// dispatcher -> deadlock)
1271fDesktop->UnlockSingleWindow();
1272						fDesktop->EventDispatcher().RemoveListener(
1273							EventTarget(), token);
1274fDesktop->LockSingleWindow();
1275					}
1276
1277					if (fCurrentView == view || fCurrentView->HasParent(view))
1278						_SetCurrentView(parent);
1279
1280					delete view;
1281				} // else we don't delete the root view
1282			}
1283			break;
1284		}
1285		case AS_VIEW_SET_STATE:
1286		{
1287			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_STATE: "
1288				"View name: %s\n", fTitle, fCurrentView->Name()));
1289
1290			fCurrentView->CurrentState()->ReadFromLink(link);
1291			// TODO: When is this used?!?
1292			fCurrentView->RebuildClipping(true);
1293			_UpdateDrawState(fCurrentView);
1294
1295			break;
1296		}
1297		case AS_VIEW_SET_FONT_STATE:
1298		{
1299			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_FONT_STATE: "
1300				"View name: %s\n", fTitle, fCurrentView->Name()));
1301
1302			fCurrentView->CurrentState()->ReadFontFromLink(link,
1303				fServerApp->FontManager());
1304			fWindow->GetDrawingEngine()->SetFont(
1305				fCurrentView->CurrentState());
1306			break;
1307		}
1308		case AS_VIEW_GET_STATE:
1309		{
1310			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_STATE: "
1311				"View name: %s\n", fTitle, fCurrentView->Name()));
1312
1313			fLink.StartMessage(B_OK);
1314
1315			// attach state data
1316			fCurrentView->CurrentState()->WriteToLink(fLink.Sender());
1317			fLink.Flush();
1318			break;
1319		}
1320		case AS_VIEW_SET_EVENT_MASK:
1321		{
1322			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_EVENT_MASK: "
1323				"View name: %s\n", fTitle, fCurrentView->Name()));
1324			uint32 eventMask, options;
1325
1326			link.Read<uint32>(&eventMask);
1327			if (link.Read<uint32>(&options) == B_OK) {
1328				fCurrentView->SetEventMask(eventMask, options);
1329
1330fDesktop->UnlockSingleWindow();
1331				// TODO: possible deadlock!
1332				if (eventMask != 0 || options != 0) {
1333					fDesktop->EventDispatcher().AddListener(EventTarget(),
1334						fCurrentView->Token(), eventMask, options);
1335				} else {
1336					fDesktop->EventDispatcher().RemoveListener(EventTarget(),
1337						fCurrentView->Token());
1338				}
1339fDesktop->LockSingleWindow();
1340			}
1341			break;
1342		}
1343		case AS_VIEW_SET_MOUSE_EVENT_MASK:
1344		{
1345			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_MOUSE_EVENT_MASK: "
1346				"View name: %s\n", fTitle, fCurrentView->Name()));
1347			uint32 eventMask, options;
1348
1349			link.Read<uint32>(&eventMask);
1350			if (link.Read<uint32>(&options) == B_OK) {
1351fDesktop->UnlockSingleWindow();
1352				// TODO: possible deadlock
1353				if (eventMask != 0 || options != 0) {
1354					if (options & B_LOCK_WINDOW_FOCUS)
1355						fDesktop->SetFocusLocked(fWindow.Get());
1356					fDesktop->EventDispatcher().AddTemporaryListener(EventTarget(),
1357						fCurrentView->Token(), eventMask, options);
1358				} else {
1359					fDesktop->EventDispatcher().RemoveTemporaryListener(EventTarget(),
1360						fCurrentView->Token());
1361				}
1362fDesktop->LockSingleWindow();
1363			}
1364
1365			// TODO: support B_LOCK_WINDOW_FOCUS option in Desktop
1366			break;
1367		}
1368		case AS_VIEW_MOVE_TO:
1369		{
1370			float x, y;
1371			link.Read<float>(&x);
1372			if (link.Read<float>(&y) != B_OK)
1373				break;
1374
1375			DTRACE(("ServerWindow %s: Message AS_VIEW_MOVE_TO: View name: "
1376				"%s, x: %.1f, y: %.1f\n", fTitle, fCurrentView->Name(), x, y));
1377
1378			float offsetX = x - fCurrentView->Frame().left;
1379			float offsetY = y - fCurrentView->Frame().top;
1380
1381			BRegion dirty, expose;
1382			fCurrentView->MoveBy(offsetX, offsetY, &dirty);
1383
1384			// TODO: think about how to avoid this hack:
1385			// the parent clipping needs to be updated, it is not
1386			// done in MoveBy() since it would cause
1387			// too much computations when children are resized because
1388			// follow modes
1389			if (View* parent = fCurrentView->Parent())
1390				parent->RebuildClipping(false);
1391
1392			fWindow->MarkContentDirty(dirty, expose);
1393			break;
1394		}
1395		case AS_VIEW_RESIZE_TO:
1396		{
1397			float newWidth, newHeight;
1398			link.Read<float>(&newWidth);
1399			if (link.Read<float>(&newHeight) != B_OK)
1400				break;
1401
1402			DTRACE(("ServerWindow %s: Message AS_VIEW_RESIZE_TO: View name: "
1403				"%s, width: %.1f, height: %.1f\n", fTitle,
1404				fCurrentView->Name(), newWidth, newHeight));
1405
1406			float deltaWidth = newWidth - fCurrentView->Frame().Width();
1407			float deltaHeight = newHeight - fCurrentView->Frame().Height();
1408
1409			BRegion dirty, expose;
1410			fCurrentView->ResizeBy(deltaWidth, deltaHeight, &dirty);
1411
1412			// TODO: see above
1413			if (View* parent = fCurrentView->Parent())
1414				parent->RebuildClipping(false);
1415
1416			fWindow->MarkContentDirty(dirty, expose);
1417			break;
1418		}
1419		case AS_VIEW_GET_COORD:
1420		{
1421			// our offset in the parent -> will be originX and originY
1422			// in BView
1423			BPoint parentOffset = fCurrentView->Frame().LeftTop();
1424
1425			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_COORD: "
1426				"View: %s -> x: %.1f, y: %.1f\n", Title(),
1427				fCurrentView->Name(), parentOffset.x, parentOffset.y));
1428
1429			fLink.StartMessage(B_OK);
1430			fLink.Attach<BPoint>(parentOffset);
1431			fLink.Attach<BRect>(fCurrentView->Bounds());
1432			fLink.Flush();
1433			break;
1434		}
1435		case AS_VIEW_SET_ORIGIN:
1436		{
1437			float x, y;
1438			link.Read<float>(&x);
1439			if (link.Read<float>(&y) != B_OK)
1440				break;
1441
1442			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_ORIGIN: "
1443				"View: %s -> x: %.1f, y: %.1f\n", Title(),
1444				fCurrentView->Name(), x, y));
1445
1446			fCurrentView->SetDrawingOrigin(BPoint(x, y));
1447			_UpdateDrawState(fCurrentView);
1448			break;
1449		}
1450		case AS_VIEW_GET_ORIGIN:
1451		{
1452			BPoint drawingOrigin = fCurrentView->DrawingOrigin();
1453
1454			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_ORIGIN: "
1455				"View: %s -> x: %.1f, y: %.1f\n", Title(),
1456				fCurrentView->Name(), drawingOrigin.x, drawingOrigin.y));
1457
1458			fLink.StartMessage(B_OK);
1459			fLink.Attach<BPoint>(drawingOrigin);
1460			fLink.Flush();
1461			break;
1462		}
1463		case AS_VIEW_RESIZE_MODE:
1464		{
1465			uint32 resizeMode;
1466			if (link.Read<uint32>(&resizeMode) != B_OK)
1467				break;
1468
1469			DTRACE(("ServerWindow %s: Message AS_VIEW_RESIZE_MODE: "
1470				"View: %s -> %" B_PRId32 "\n", Title(), fCurrentView->Name(),
1471				resizeMode));
1472
1473			fCurrentView->SetResizeMode(resizeMode);
1474			break;
1475		}
1476		case AS_VIEW_SET_FLAGS:
1477		{
1478			uint32 flags;
1479			link.Read<uint32>(&flags);
1480
1481			// The views clipping changes when the B_DRAW_ON_CHILDREN flag is
1482			// toggled.
1483			bool updateClipping = (flags & B_DRAW_ON_CHILDREN)
1484				^ (fCurrentView->Flags() & B_DRAW_ON_CHILDREN);
1485
1486			fCurrentView->SetFlags(flags);
1487			_UpdateDrawState(fCurrentView);
1488
1489			if (updateClipping) {
1490				fCurrentView->RebuildClipping(false);
1491				fCurrentDrawingRegionValid = false;
1492			}
1493
1494			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_FLAGS: "
1495				"View: %s -> flags: %" B_PRIu32 "\n", Title(),
1496				fCurrentView->Name(), flags));
1497			break;
1498		}
1499		case AS_VIEW_HIDE:
1500			DTRACE(("ServerWindow %s: Message AS_VIEW_HIDE: View: %s\n",
1501				Title(), fCurrentView->Name()));
1502			fCurrentView->SetHidden(true);
1503			break;
1504
1505		case AS_VIEW_SHOW:
1506			DTRACE(("ServerWindow %s: Message AS_VIEW_SHOW: View: %s\n",
1507				Title(), fCurrentView->Name()));
1508			fCurrentView->SetHidden(false);
1509			break;
1510
1511		case AS_VIEW_SET_LINE_MODE:
1512		{
1513			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_LINE_MODE: "
1514				"View: %s\n", Title(), fCurrentView->Name()));
1515			ViewSetLineModeInfo info;
1516			if (link.Read<ViewSetLineModeInfo>(&info) != B_OK)
1517				break;
1518
1519			fCurrentView->CurrentState()->SetLineCapMode(info.lineCap);
1520			fCurrentView->CurrentState()->SetLineJoinMode(info.lineJoin);
1521			fCurrentView->CurrentState()->SetMiterLimit(info.miterLimit);
1522
1523			fWindow->GetDrawingEngine()->SetStrokeMode(info.lineCap,
1524				info.lineJoin, info.miterLimit);
1525
1526			break;
1527		}
1528		case AS_VIEW_GET_LINE_MODE:
1529		{
1530			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_LINE_MODE: "
1531				"View: %s\n", Title(), fCurrentView->Name()));
1532			ViewSetLineModeInfo info;
1533			info.lineJoin = fCurrentView->CurrentState()->LineJoinMode();
1534			info.lineCap = fCurrentView->CurrentState()->LineCapMode();
1535			info.miterLimit = fCurrentView->CurrentState()->MiterLimit();
1536
1537			fLink.StartMessage(B_OK);
1538			fLink.Attach<ViewSetLineModeInfo>(info);
1539			fLink.Flush();
1540
1541			break;
1542		}
1543		case AS_VIEW_SET_FILL_RULE:
1544		{
1545			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_FILL_RULE: "
1546				"View: %s\n", Title(), fCurrentView->Name()));
1547			int32 fillRule;
1548			if (link.Read<int32>(&fillRule) != B_OK)
1549				break;
1550
1551			fCurrentView->CurrentState()->SetFillRule(fillRule);
1552			fWindow->GetDrawingEngine()->SetFillRule(fillRule);
1553
1554			break;
1555		}
1556		case AS_VIEW_GET_FILL_RULE:
1557		{
1558			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_FILL_RULE: "
1559				"View: %s\n", Title(), fCurrentView->Name()));
1560			int32 fillRule = fCurrentView->CurrentState()->FillRule();
1561
1562			fLink.StartMessage(B_OK);
1563			fLink.Attach<int32>(fillRule);
1564			fLink.Flush();
1565
1566			break;
1567		}
1568		case AS_VIEW_PUSH_STATE:
1569		{
1570			DTRACE(("ServerWindow %s: Message AS_VIEW_PUSH_STATE: View: "
1571				"%s\n", Title(), fCurrentView->Name()));
1572
1573			fCurrentView->PushState();
1574			// TODO: is this necessary?
1575//			_UpdateDrawState(fCurrentView);
1576			break;
1577		}
1578		case AS_VIEW_POP_STATE:
1579		{
1580			DTRACE(("ServerWindow %s: Message AS_VIEW_POP_STATE: View: %s\n",
1581				Title(), fCurrentView->Name()));
1582
1583			fCurrentView->PopState();
1584			_UpdateDrawState(fCurrentView);
1585			break;
1586		}
1587		case AS_VIEW_SET_SCALE:
1588		{
1589			float scale;
1590			if (link.Read<float>(&scale) != B_OK)
1591				break;
1592
1593			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_SCALE: "
1594				"View: %s -> scale: %.2f\n", Title(), fCurrentView->Name(),
1595				scale));
1596
1597			fCurrentView->SetScale(scale);
1598			_UpdateDrawState(fCurrentView);
1599			break;
1600		}
1601		case AS_VIEW_GET_SCALE:
1602		{
1603			float scale = fCurrentView->CurrentState()->Scale();
1604
1605			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_SCALE: "
1606				"View: %s -> scale: %.2f\n",
1607				Title(), fCurrentView->Name(), scale));
1608
1609			fLink.StartMessage(B_OK);
1610			fLink.Attach<float>(scale);
1611			fLink.Flush();
1612			break;
1613		}
1614		case AS_VIEW_SET_TRANSFORM:
1615		{
1616			BAffineTransform transform;
1617			if (link.Read<BAffineTransform>(&transform) != B_OK)
1618				break;
1619
1620			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_TRANSFORM: "
1621				"View: %s -> transform: %.2f, %.2f, %.2f, %.2f, %.2f, %.2f\n",
1622				Title(), fCurrentView->Name(), transform.sx, transform.shy,
1623				transform.shx, transform.sy, transform.tx, transform.ty));
1624
1625			fCurrentView->CurrentState()->SetTransform(transform);
1626			_UpdateDrawState(fCurrentView);
1627			break;
1628		}
1629		case AS_VIEW_GET_TRANSFORM:
1630		{
1631			BAffineTransform transform
1632				= fCurrentView->CurrentState()->Transform();
1633
1634			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_TRANSFORM: "
1635				"View: %s -> transform: %.2f, %.2f, %.2f, %.2f, %.2f, %.2f\n",
1636				Title(), fCurrentView->Name(), transform.sx, transform.shy,
1637				transform.shx, transform.sy, transform.tx, transform.ty));
1638
1639			fLink.StartMessage(B_OK);
1640			fLink.Attach<BAffineTransform>(transform);
1641			fLink.Flush();
1642			break;
1643		}
1644		case AS_VIEW_GET_PARENT_COMPOSITE:
1645		{
1646			DrawState* state = fCurrentView->CurrentState()->PreviousState();
1647
1648			fLink.StartMessage(B_OK);
1649			if (state != NULL) {
1650				fLink.Attach<BAffineTransform>(state->CombinedTransform());
1651				fLink.Attach<float>(state->CombinedScale());
1652				fLink.Attach<BPoint>(state->CombinedOrigin());
1653			} else {
1654				fLink.Attach<BAffineTransform>(BAffineTransform());
1655				fLink.Attach<float>(1.0f);
1656				fLink.Attach<BPoint>(B_ORIGIN);
1657			}
1658			fLink.Flush();
1659			break;
1660		}
1661		case AS_VIEW_AFFINE_TRANSLATE:
1662		{
1663			double x, y;
1664			link.Read<double>(&x);
1665			link.Read<double>(&y);
1666			BAffineTransform current =
1667				fCurrentView->CurrentState()->Transform();
1668			current.PreTranslateBy(x, y);
1669			fCurrentView->CurrentState()->SetTransform(current);
1670			_UpdateDrawState(fCurrentView);
1671			break;
1672		}
1673
1674		case AS_VIEW_AFFINE_SCALE:
1675		{
1676			double x, y;
1677			link.Read<double>(&x);
1678			link.Read<double>(&y);
1679			BAffineTransform current =
1680				fCurrentView->CurrentState()->Transform();
1681			current.PreScaleBy(x, y);
1682			fCurrentView->CurrentState()->SetTransform(current);
1683			_UpdateDrawState(fCurrentView);
1684			break;
1685		}
1686
1687		case AS_VIEW_AFFINE_ROTATE:
1688		{
1689			double angleRadians;
1690			link.Read<double>(&angleRadians);
1691			BAffineTransform current =
1692				fCurrentView->CurrentState()->Transform();
1693			current.PreRotateBy(angleRadians);
1694			fCurrentView->CurrentState()->SetTransform(current);
1695			_UpdateDrawState(fCurrentView);
1696			break;
1697		}
1698
1699		case AS_VIEW_SET_PEN_LOC:
1700		{
1701			BPoint location;
1702			if (link.Read<BPoint>(&location) != B_OK)
1703				break;
1704
1705			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_PEN_LOC: "
1706				"View: %s -> BPoint(%.1f, %.1f)\n", Title(),
1707				fCurrentView->Name(), location.x, location.y));
1708
1709			fCurrentView->CurrentState()->SetPenLocation(location);
1710			break;
1711		}
1712		case AS_VIEW_GET_PEN_LOC:
1713		{
1714			BPoint location = fCurrentView->CurrentState()->PenLocation();
1715
1716			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_PEN_LOC: "
1717				"View: %s -> BPoint(%.1f, %.1f)\n", Title(),
1718				fCurrentView->Name(), location.x, location.y));
1719
1720			fLink.StartMessage(B_OK);
1721			fLink.Attach<BPoint>(location);
1722			fLink.Flush();
1723
1724			break;
1725		}
1726		case AS_VIEW_SET_PEN_SIZE:
1727		{
1728			float penSize;
1729			if (link.Read<float>(&penSize) != B_OK)
1730				break;
1731
1732			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_PEN_SIZE: "
1733				"View: %s -> %.1f\n", Title(), fCurrentView->Name(), penSize));
1734
1735			fCurrentView->CurrentState()->SetPenSize(penSize);
1736			fWindow->GetDrawingEngine()->SetPenSize(
1737				fCurrentView->CurrentState()->PenSize());
1738			break;
1739		}
1740		case AS_VIEW_GET_PEN_SIZE:
1741		{
1742			float penSize = fCurrentView->CurrentState()->UnscaledPenSize();
1743
1744			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_PEN_SIZE: "
1745				"View: %s -> %.1f\n", Title(), fCurrentView->Name(), penSize));
1746
1747			fLink.StartMessage(B_OK);
1748			fLink.Attach<float>(penSize);
1749			fLink.Flush();
1750
1751			break;
1752		}
1753		case AS_VIEW_SET_VIEW_COLOR:
1754		{
1755			rgb_color color;
1756			if (link.Read(&color, sizeof(rgb_color)) != B_OK)
1757				break;
1758
1759			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_VIEW_COLOR: "
1760				"View: %s -> rgb_color(%d, %d, %d, %d)\n", Title(),
1761				fCurrentView->Name(), color.red, color.green, color.blue,
1762				color.alpha));
1763
1764			fCurrentView->SetViewColor(color);
1765			break;
1766		}
1767		case AS_VIEW_GET_VIEW_COLOR:
1768		{
1769			rgb_color color = fCurrentView->ViewColor();
1770
1771			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_VIEW_COLOR: "
1772				"View: %s -> rgb_color(%d, %d, %d, %d)\n",
1773				Title(), fCurrentView->Name(), color.red, color.green,
1774				color.blue, color.alpha));
1775
1776			fLink.StartMessage(B_OK);
1777			fLink.Attach<rgb_color>(color);
1778			fLink.Flush();
1779			break;
1780		}
1781		case AS_VIEW_SET_HIGH_COLOR:
1782		{
1783			rgb_color color;
1784			if (link.Read(&color, sizeof(rgb_color)) != B_OK)
1785				break;
1786
1787			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_HIGH_COLOR: "
1788				"View: %s -> rgb_color(%d, %d, %d, %d)\n",
1789				Title(), fCurrentView->Name(), color.red, color.green,
1790				color.blue, color.alpha));
1791
1792			fCurrentView->CurrentState()->SetHighColor(color);
1793			fWindow->GetDrawingEngine()->SetHighColor(color);
1794			break;
1795		}
1796
1797		case AS_VIEW_SET_HIGH_UI_COLOR:
1798		{
1799			color_which which = B_NO_COLOR;
1800			float tint = B_NO_TINT;
1801
1802			if (link.Read<color_which>(&which) != B_OK
1803				|| link.Read<float>(&tint) != B_OK )
1804				break;
1805
1806			fCurrentView->CurrentState()->SetHighUIColor(which, tint);
1807
1808			// TODO: should we do more color_which validity checking?
1809			if (which != B_NO_COLOR) {
1810				DesktopSettings settings(fDesktop);
1811				rgb_color color = tint_color(settings.UIColor(which), tint);
1812
1813				fCurrentView->CurrentState()->SetHighColor(color);
1814				fWindow->GetDrawingEngine()->SetHighColor(color);
1815			}
1816			break;
1817		}
1818		case AS_VIEW_SET_LOW_UI_COLOR:
1819		{
1820			color_which which = B_NO_COLOR;
1821			float tint = B_NO_TINT;
1822
1823			if (link.Read<color_which>(&which) != B_OK
1824				|| link.Read<float>(&tint) != B_OK )
1825				break;
1826
1827			fCurrentView->CurrentState()->SetLowUIColor(which, tint);
1828
1829			// TODO: should we do more color_which validity checking?
1830			if (which != B_NO_COLOR) {
1831				DesktopSettings settings(fDesktop);
1832				rgb_color color = tint_color(settings.UIColor(which), tint);
1833
1834				fCurrentView->CurrentState()->SetLowColor(color);
1835				fWindow->GetDrawingEngine()->SetLowColor(color);
1836			}
1837			break;
1838		}
1839		case AS_VIEW_SET_VIEW_UI_COLOR:
1840		{
1841			color_which which = B_NO_COLOR;
1842			float tint = B_NO_TINT;
1843
1844			if (link.Read<color_which>(&which) != B_OK
1845				|| link.Read<float>(&tint) != B_OK )
1846				break;
1847
1848			// TODO: should we do more color_which validity checking?
1849			fCurrentView->SetViewUIColor(which, tint);
1850			break;
1851		}
1852		case AS_VIEW_GET_HIGH_UI_COLOR:
1853		{
1854			float tint;
1855			color_which which = fCurrentView->CurrentState()->HighUIColor(&tint);
1856			rgb_color color = fCurrentView->CurrentState()->HighColor();
1857
1858			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_HIGH_UI_COLOR: "
1859				"View: %s -> color_which(%i) tint(%.3f) - rgb_color(%i, %i,"
1860				" %i, %i)\n", Title(), fCurrentView->Name(), which, tint,
1861				color.red, color.green, color.blue, color.alpha));
1862
1863			fLink.StartMessage(B_OK);
1864			fLink.Attach<color_which>(which);
1865			fLink.Attach<float>(tint);
1866			fLink.Attach<rgb_color>(color);
1867			fLink.Flush();
1868			break;
1869		}
1870		case AS_VIEW_GET_LOW_UI_COLOR:
1871		{
1872			float tint;
1873			color_which which = fCurrentView->CurrentState()->LowUIColor(&tint);
1874			rgb_color color = fCurrentView->CurrentState()->LowColor();
1875
1876			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_LOW_UI_COLOR: "
1877				"View: %s -> color_which(%i) tint(%.3f) - rgb_color(%i, %i,"
1878				" %i, %i)\n", Title(), fCurrentView->Name(), which, tint,
1879				color.red, color.green, color.blue, color.alpha));
1880
1881			fLink.StartMessage(B_OK);
1882			fLink.Attach<color_which>(which);
1883			fLink.Attach<float>(tint);
1884			fLink.Attach<rgb_color>(color);
1885			fLink.Flush();
1886			break;
1887		}
1888		case AS_VIEW_GET_VIEW_UI_COLOR:
1889		{
1890			float tint;
1891			color_which which = fCurrentView->ViewUIColor(&tint);
1892			rgb_color color = fCurrentView->ViewColor();
1893
1894			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_VIEW_UI_COLOR: "
1895				"View: %s -> color_which(%i) tint(%.3f) - rgb_color(%i, %i,"
1896				" %i, %i)\n", Title(), fCurrentView->Name(), which, tint,
1897				color.red, color.green, color.blue, color.alpha));
1898
1899			fLink.StartMessage(B_OK);
1900			fLink.Attach<color_which>(which);
1901			fLink.Attach<float>(tint);
1902			fLink.Attach<rgb_color>(color);
1903			fLink.Flush();
1904			break;
1905		}
1906		case AS_VIEW_GET_HIGH_COLOR:
1907		{
1908			rgb_color color = fCurrentView->CurrentState()->HighColor();
1909
1910			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_HIGH_COLOR: "
1911				"View: %s -> rgb_color(%d, %d, %d, %d)\n",
1912				Title(), fCurrentView->Name(), color.red, color.green,
1913				color.blue, color.alpha));
1914
1915			fLink.StartMessage(B_OK);
1916			fLink.Attach<rgb_color>(color);
1917			fLink.Flush();
1918			break;
1919		}
1920		case AS_VIEW_SET_LOW_COLOR:
1921		{
1922			rgb_color color;
1923			if (link.Read(&color, sizeof(rgb_color)) != B_OK)
1924				break;
1925
1926			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_LOW_COLOR: "
1927				"View: %s -> rgb_color(%d, %d, %d, %d)\n",
1928				Title(), fCurrentView->Name(), color.red, color.green,
1929				color.blue, color.alpha));
1930
1931			fCurrentView->CurrentState()->SetLowColor(color);
1932			fWindow->GetDrawingEngine()->SetLowColor(color);
1933			break;
1934		}
1935		case AS_VIEW_GET_LOW_COLOR:
1936		{
1937			rgb_color color = fCurrentView->CurrentState()->LowColor();
1938
1939			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_LOW_COLOR: "
1940				"View: %s -> rgb_color(%d, %d, %d, %d)\n",
1941				Title(), fCurrentView->Name(), color.red, color.green,
1942				color.blue, color.alpha));
1943
1944			fLink.StartMessage(B_OK);
1945			fLink.Attach<rgb_color>(color);
1946			fLink.Flush();
1947			break;
1948		}
1949		case AS_VIEW_SET_PATTERN:
1950		{
1951			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_PATTERN: "
1952				"View: %s\n", fTitle, fCurrentView->Name()));
1953
1954			pattern pat;
1955			if (link.Read(&pat, sizeof(pattern)) != B_OK)
1956				break;
1957
1958			fCurrentView->CurrentState()->SetPattern(Pattern(pat));
1959			fWindow->GetDrawingEngine()->SetPattern(pat);
1960			break;
1961		}
1962
1963		case AS_VIEW_SET_BLENDING_MODE:
1964		{
1965			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_BLEND_MODE: "
1966				"View: %s\n", Title(), fCurrentView->Name()));
1967
1968			ViewBlendingModeInfo info;
1969			if (link.Read<ViewBlendingModeInfo>(&info) != B_OK)
1970				break;
1971
1972			fCurrentView->CurrentState()->SetBlendingMode(
1973				info.sourceAlpha, info.alphaFunction);
1974			fWindow->GetDrawingEngine()->SetBlendingMode(
1975				info.sourceAlpha, info.alphaFunction);
1976			break;
1977		}
1978		case AS_VIEW_GET_BLENDING_MODE:
1979		{
1980			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_BLEND_MODE: "
1981				"View: %s\n", Title(), fCurrentView->Name()));
1982
1983			ViewBlendingModeInfo info;
1984			info.sourceAlpha = fCurrentView->CurrentState()->AlphaSrcMode();
1985			info.alphaFunction = fCurrentView->CurrentState()->AlphaFncMode();
1986
1987			fLink.StartMessage(B_OK);
1988			fLink.Attach<ViewBlendingModeInfo>(info);
1989			fLink.Flush();
1990
1991			break;
1992		}
1993		case AS_VIEW_SET_DRAWING_MODE:
1994		{
1995			int8 drawingMode;
1996			if (link.Read<int8>(&drawingMode) != B_OK)
1997				break;
1998
1999			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_DRAW_MODE: "
2000				"View: %s -> %s\n", Title(), fCurrentView->Name(),
2001				kDrawingModeMap[drawingMode]));
2002
2003			fCurrentView->CurrentState()->SetDrawingMode(
2004				(drawing_mode)drawingMode);
2005			fWindow->GetDrawingEngine()->SetDrawingMode(
2006				(drawing_mode)drawingMode);
2007			break;
2008		}
2009		case AS_VIEW_GET_DRAWING_MODE:
2010		{
2011			int8 drawingMode
2012				= (int8)(fCurrentView->CurrentState()->GetDrawingMode());
2013
2014			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_DRAW_MODE: "
2015				"View: %s -> %s\n", Title(), fCurrentView->Name(),
2016				kDrawingModeMap[drawingMode]));
2017
2018			fLink.StartMessage(B_OK);
2019			fLink.Attach<int8>(drawingMode);
2020			fLink.Flush();
2021
2022			break;
2023		}
2024		case AS_VIEW_SET_VIEW_BITMAP:
2025		{
2026			DTRACE(("ServerWindow %s: Message AS_VIEW_SET_VIEW_BITMAP: "
2027				"View: %s\n", Title(), fCurrentView->Name()));
2028
2029			int32 bitmapToken, resizingMode, options;
2030			BRect srcRect, dstRect;
2031
2032			link.Read<int32>(&bitmapToken);
2033			link.Read<BRect>(&srcRect);
2034			link.Read<BRect>(&dstRect);
2035			link.Read<int32>(&resizingMode);
2036			status_t status = link.Read<int32>(&options);
2037
2038			rgb_color colorKey = {0};
2039
2040			if (status == B_OK) {
2041				BReference<ServerBitmap> bitmap(fServerApp->GetBitmap(bitmapToken), true);
2042				if (bitmapToken == -1 || bitmap != NULL) {
2043					bool wasOverlay = fCurrentView->ViewBitmap() != NULL
2044						&& fCurrentView->ViewBitmap()->Overlay() != NULL;
2045
2046					fCurrentView->SetViewBitmap(bitmap, srcRect, dstRect,
2047						resizingMode, options);
2048
2049					// TODO: if we revert the view color overlay handling
2050					//	in View::Draw() to the BeOS version, we never
2051					//	need to invalidate the view for overlays.
2052
2053					// Invalidate view - but only if this is a non-overlay
2054					// switch
2055					if (bitmap == NULL || bitmap->Overlay() == NULL
2056						|| !wasOverlay) {
2057						BRegion dirty((BRect)fCurrentView->Bounds());
2058						fWindow->InvalidateView(fCurrentView, dirty);
2059					}
2060
2061					if (bitmap != NULL && bitmap->Overlay() != NULL) {
2062						bitmap->Overlay()->SetFlags(options);
2063						colorKey = bitmap->Overlay()->Color();
2064					}
2065				} else
2066					status = B_BAD_VALUE;
2067			}
2068
2069			fLink.StartMessage(status);
2070			if (status == B_OK && (options & AS_REQUEST_COLOR_KEY) != 0) {
2071				// Attach color key for the overlay bitmap
2072				fLink.Attach<rgb_color>(colorKey);
2073			}
2074
2075			fLink.Flush();
2076			break;
2077		}
2078		case AS_VIEW_PRINT_ALIASING:
2079		{
2080			DTRACE(("ServerWindow %s: Message AS_VIEW_PRINT_ALIASING: "
2081				"View: %s\n", Title(), fCurrentView->Name()));
2082
2083			bool fontAliasing;
2084			if (link.Read<bool>(&fontAliasing) == B_OK) {
2085				fCurrentView->CurrentState()->SetForceFontAliasing(fontAliasing);
2086				_UpdateDrawState(fCurrentView);
2087			}
2088			break;
2089		}
2090		case AS_VIEW_CLIP_TO_PICTURE:
2091		{
2092			DTRACE(("ServerWindow %s: Message AS_VIEW_CLIP_TO_PICTURE: "
2093				"View: %s\n", Title(), fCurrentView->Name()));
2094
2095			int32 pictureToken;
2096			BPoint where;
2097			bool inverse = false;
2098
2099			link.Read<int32>(&pictureToken);
2100			if (pictureToken < 0) {
2101				fCurrentView->SetAlphaMask(NULL);
2102				_UpdateDrawState(fCurrentView);
2103				break;
2104			}
2105
2106			link.Read<BPoint>(&where);
2107			if (link.Read<bool>(&inverse) != B_OK)
2108				break;
2109
2110			BReference<ServerPicture> picture(fServerApp->GetPicture(pictureToken), true);
2111			if (picture == NULL)
2112				break;
2113
2114			BReference<AlphaMask> const mask(new(std::nothrow) PictureAlphaMask(
2115				fCurrentView->GetAlphaMask(), picture,
2116				*fCurrentView->CurrentState(), where, inverse), true);
2117			fCurrentView->SetAlphaMask(mask);
2118
2119			_UpdateDrawState(fCurrentView);
2120			break;
2121		}
2122
2123		case AS_VIEW_GET_CLIP_REGION:
2124		{
2125			DTRACE(("ServerWindow %s: Message AS_VIEW_GET_CLIP_REGION: "
2126				"View: %s\n", Title(), fCurrentView->Name()));
2127
2128			// if this view is hidden, it has no visible region
2129			fLink.StartMessage(B_OK);
2130			if (!fWindow->IsVisible() || !fCurrentView->IsVisible()) {
2131				BRegion empty;
2132				fLink.AttachRegion(empty);
2133			} else {
2134				_UpdateCurrentDrawingRegion();
2135				BRegion region(fCurrentDrawingRegion);
2136				fCurrentView->ScreenToLocalTransform().Apply(&region);
2137				fLink.AttachRegion(region);
2138			}
2139			fLink.Flush();
2140
2141			break;
2142		}
2143		case AS_VIEW_SET_CLIP_REGION:
2144		{
2145			int32 rectCount;
2146			status_t status = link.Read<int32>(&rectCount);
2147				// a negative count means no
2148				// region for the current draw state,
2149				// but an *empty* region is actually valid!
2150				// even if it means no drawing is allowed
2151
2152			if (status < B_OK)
2153				break;
2154
2155			if (rectCount >= 0) {
2156				// we are supposed to set the clipping region
2157				BRegion region;
2158				if (rectCount > 0 && link.ReadRegion(&region) < B_OK)
2159					break;
2160
2161				DTRACE(("ServerWindow %s: Message AS_VIEW_SET_CLIP_REGION: "
2162					"View: %s -> rect count: %" B_PRId32 ", frame = "
2163					"BRect(%.1f, %.1f, %.1f, %.1f)\n",
2164					Title(), fCurrentView->Name(), rectCount,
2165					region.Frame().left, region.Frame().top,
2166					region.Frame().right, region.Frame().bottom));
2167
2168				fCurrentView->SetUserClipping(&region);
2169			} else {
2170				// we are supposed to unset the clipping region
2171				// passing NULL sets this states region to that
2172				// of the previous state
2173
2174				DTRACE(("ServerWindow %s: Message AS_VIEW_SET_CLIP_REGION: "
2175					"View: %s -> unset\n", Title(), fCurrentView->Name()));
2176
2177				fCurrentView->SetUserClipping(NULL);
2178			}
2179			fCurrentDrawingRegionValid = false;
2180
2181			break;
2182		}
2183
2184		case AS_VIEW_CLIP_TO_RECT:
2185		{
2186			bool inverse;
2187			BRect rect;
2188
2189			link.Read<bool>(&inverse);
2190			link.Read<BRect>(&rect);
2191
2192			bool needDrawStateUpdate = fCurrentView->ClipToRect(
2193				rect, inverse);
2194			fCurrentDrawingRegionValid = false;
2195
2196			if (needDrawStateUpdate)
2197				_UpdateDrawState(fCurrentView);
2198
2199			_UpdateCurrentDrawingRegion();
2200
2201			BRegion region(fCurrentDrawingRegion);
2202			fCurrentView->ScreenToLocalTransform().Apply(&region);
2203
2204			break;
2205		}
2206
2207		case AS_VIEW_CLIP_TO_SHAPE:
2208		{
2209			bool inverse;
2210			link.Read<bool>(&inverse);
2211
2212			shape_data shape;
2213			link.Read<int32>(&shape.opCount);
2214			link.Read<int32>(&shape.ptCount);
2215			shape.opSize = shape.opCount * sizeof(uint32);
2216			shape.ptSize = shape.ptCount * sizeof(BPoint);
2217			shape.opList = new(nothrow) uint32[shape.opCount];
2218			shape.ptList = new(nothrow) BPoint[shape.ptCount];
2219			if (link.Read(shape.opList, shape.opSize) >= B_OK
2220				&& link.Read(shape.ptList, shape.ptSize) >= B_OK) {
2221				fCurrentView->ClipToShape(&shape, inverse);
2222				_UpdateDrawState(fCurrentView);
2223			}
2224
2225			delete[] shape.opList;
2226			delete[] shape.ptList;
2227			break;
2228		}
2229
2230		case AS_VIEW_INVALIDATE_RECT:
2231		{
2232			// NOTE: looks like this call is NOT affected by origin and scale
2233			// on R5 so this implementation is "correct"
2234			BRect invalidRect;
2235			if (link.Read<BRect>(&invalidRect) == B_OK) {
2236				DTRACE(("ServerWindow %s: Message AS_VIEW_INVALIDATE_RECT: "
2237					"View: %s -> BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(),
2238					fCurrentView->Name(), invalidRect.left, invalidRect.top,
2239					invalidRect.right, invalidRect.bottom));
2240
2241				View* view = NULL;
2242				if (link.Read<View*>(&view) != B_OK)
2243					view = fCurrentView;
2244
2245				// make sure the view is still available!
2246				if (view != fCurrentView
2247					&& !fWindow->TopView()->HasView(view))
2248					break;
2249
2250				BRegion dirty(invalidRect);
2251				fWindow->InvalidateView(view, dirty);
2252			}
2253			break;
2254		}
2255
2256		case AS_VIEW_DELAYED_INVALIDATE_RECT:
2257		{
2258			bigtime_t time = 0;
2259			BRect invalidRect;
2260			if (link.Read<bigtime_t>(&time) == B_OK
2261				&& link.Read<BRect>(&invalidRect) == B_OK) {
2262				DTRACE(("ServerWindow %s: Message "
2263					"AS_VIEW_DELAYED_INVALIDATE_RECT: "
2264					"View: %s -> BRect(%.1f, %.1f, %.1f, %.1f) at time %llu\n",
2265					Title(), fCurrentView->Name(), invalidRect.left,
2266					invalidRect.top, invalidRect.right, invalidRect.bottom,
2267					time));
2268
2269				DelayedMessage delayed(AS_VIEW_INVALIDATE_RECT, time, true);
2270				delayed.AddTarget(MessagePort());
2271				delayed.SetMerge(DM_MERGE_DUPLICATES);
2272
2273				if (delayed.Attach<BRect>(invalidRect) == B_OK
2274						&& delayed.Attach<View*>(fCurrentView) == B_OK)
2275					delayed.Flush();
2276			}
2277			break;
2278		}
2279
2280		case AS_VIEW_INVALIDATE_REGION:
2281		{
2282			// NOTE: looks like this call is NOT affected by origin and scale
2283			// on R5 so this implementation is "correct"
2284			BRegion region;
2285			if (link.ReadRegion(&region) < B_OK)
2286				break;
2287
2288			DTRACE(("ServerWindow %s: Message AS_VIEW_INVALIDATE_REGION: "
2289					"View: %s -> rect count: %" B_PRId32 ", frame: BRect(%.1f, "
2290					"%.1f, %.1f, %.1f)\n", Title(),
2291					fCurrentView->Name(), region.CountRects(),
2292					region.Frame().left, region.Frame().top,
2293					region.Frame().right, region.Frame().bottom));
2294
2295			fWindow->InvalidateView(fCurrentView, region);
2296			break;
2297		}
2298
2299		case AS_VIEW_DRAG_IMAGE:
2300		{
2301			// TODO: flesh out AS_VIEW_DRAG_IMAGE
2302			DTRACE(("ServerWindow %s: Message AS_DRAG_IMAGE\n", Title()));
2303
2304			int32 bitmapToken;
2305			drawing_mode dragMode;
2306			BPoint offset;
2307			int32 bufferSize;
2308
2309			link.Read<int32>(&bitmapToken);
2310			link.Read<int32>((int32*)&dragMode);
2311			link.Read<BPoint>(&offset);
2312			link.Read<int32>(&bufferSize);
2313
2314			if (bufferSize > 0) {
2315				char* buffer = new (nothrow) char[bufferSize];
2316				BMessage dragMessage;
2317				if (link.Read(buffer, bufferSize) == B_OK
2318					&& dragMessage.Unflatten(buffer) == B_OK) {
2319						BReference<ServerBitmap> bitmap(
2320							fServerApp->GetBitmap(bitmapToken), true);
2321						// TODO: possible deadlock
2322fDesktop->UnlockSingleWindow();
2323						fDesktop->EventDispatcher().SetDragMessage(dragMessage,
2324							bitmap, offset);
2325fDesktop->LockSingleWindow();
2326				}
2327				delete[] buffer;
2328			}
2329			// sync the client (it can now delete the bitmap)
2330			fLink.StartMessage(B_OK);
2331			fLink.Flush();
2332
2333			break;
2334		}
2335		case AS_VIEW_DRAG_RECT:
2336		{
2337			// TODO: flesh out AS_VIEW_DRAG_RECT
2338			DTRACE(("ServerWindow %s: Message AS_DRAG_RECT\n", Title()));
2339
2340			BRect dragRect;
2341			BPoint offset;
2342			int32 bufferSize;
2343
2344			link.Read<BRect>(&dragRect);
2345			link.Read<BPoint>(&offset);
2346			link.Read<int32>(&bufferSize);
2347
2348			if (bufferSize > 0) {
2349				char* buffer = new (nothrow) char[bufferSize];
2350				BMessage dragMessage;
2351				if (link.Read(buffer, bufferSize) == B_OK
2352					&& dragMessage.Unflatten(buffer) == B_OK) {
2353						// TODO: possible deadlock
2354fDesktop->UnlockSingleWindow();
2355						fDesktop->EventDispatcher().SetDragMessage(dragMessage,
2356							NULL /* should be dragRect */, offset);
2357fDesktop->LockSingleWindow();
2358				}
2359				delete[] buffer;
2360			}
2361			break;
2362		}
2363
2364		case AS_VIEW_BEGIN_RECT_TRACK:
2365		{
2366			DTRACE(("ServerWindow %s: Message AS_VIEW_BEGIN_RECT_TRACK\n",
2367				Title()));
2368			BRect dragRect;
2369			uint32 style;
2370
2371			link.Read<BRect>(&dragRect);
2372			link.Read<uint32>(&style);
2373
2374			// TODO: implement rect tracking (used sometimes for selecting
2375			// a group of things, also sometimes used to appear to drag
2376			// something, but without real drag message)
2377			break;
2378		}
2379		case AS_VIEW_END_RECT_TRACK:
2380		{
2381			DTRACE(("ServerWindow %s: Message AS_VIEW_END_RECT_TRACK\n",
2382				Title()));
2383			// TODO: implement rect tracking
2384			break;
2385		}
2386
2387		case AS_VIEW_BEGIN_PICTURE:
2388		{
2389			DTRACE(("ServerWindow %s: Message AS_VIEW_BEGIN_PICTURE\n",
2390				Title()));
2391			BReference<ServerPicture> picture(App()->CreatePicture(), true);
2392			if (picture != NULL) {
2393				picture->SyncState(fCurrentView);
2394				fCurrentView->SetPicture(picture);
2395			}
2396			break;
2397		}
2398
2399		case AS_VIEW_APPEND_TO_PICTURE:
2400		{
2401			DTRACE(("ServerWindow %s: Message AS_VIEW_APPEND_TO_PICTURE\n",
2402				Title()));
2403
2404			int32 token;
2405			link.Read<int32>(&token);
2406
2407			BReference<ServerPicture> picture(App()->GetPicture(token), true);
2408			if (picture != NULL)
2409				picture->SyncState(fCurrentView);
2410
2411			fCurrentView->SetPicture(picture);
2412
2413			break;
2414		}
2415
2416		case AS_VIEW_END_PICTURE:
2417		{
2418			DTRACE(("ServerWindow %s: Message AS_VIEW_END_PICTURE\n",
2419				Title()));
2420
2421			ServerPicture* picture = fCurrentView->Picture();
2422			if (picture != NULL) {
2423				fCurrentView->SetPicture(NULL);
2424				fLink.StartMessage(B_OK);
2425				fLink.Attach<int32>(picture->Token());
2426			} else
2427				fLink.StartMessage(B_ERROR);
2428
2429			fLink.Flush();
2430			break;
2431		}
2432
2433		case AS_VIEW_BEGIN_LAYER:
2434		{
2435			DTRACE(("ServerWindow %s: Message AS_VIEW_BEGIN_LAYER\n",
2436				Title()));
2437
2438			uint8 opacity;
2439			link.Read<uint8>(&opacity);
2440
2441			Layer* layer = new(std::nothrow) Layer(opacity);
2442			if (layer == NULL)
2443				break;
2444
2445			if (opacity != 255) {
2446				fCurrentView->CurrentState()->SetDrawingMode(B_OP_ALPHA);
2447				fCurrentView->CurrentState()->SetBlendingMode(B_PIXEL_ALPHA,
2448					B_ALPHA_COMPOSITE);
2449				fCurrentView->CurrentState()->SetDrawingModeLocked(true);
2450			}
2451
2452			fCurrentView->SetPicture(layer);
2453			break;
2454		}
2455
2456		default:
2457			// The drawing code handles allocation failures using exceptions;
2458			// so we need to account for that here.
2459			try {
2460				_DispatchViewDrawingMessage(code, link);
2461			} catch (std::bad_alloc&) {
2462				// Cancel any message we were in the middle of sending.
2463				fLink.CancelMessage();
2464
2465				if (link.NeedsReply()) {
2466					// As done in _DispatchViewDrawingMessage, send just a
2467					// single status_t as the reply.
2468					fLink.StartMessage(B_NO_MEMORY);
2469					fLink.Flush();
2470				}
2471			}
2472			break;
2473	}
2474}
2475
2476
2477/*!	Dispatches all view drawing messages.
2478	The desktop clipping must be read locked when entering this method.
2479	Requires a valid fCurrentView.
2480*/
2481void
2482ServerWindow::_DispatchViewDrawingMessage(int32 code,
2483	BPrivate::LinkReceiver &link)
2484{
2485	if (!fCurrentView->IsVisible() || !fWindow->IsVisible()) {
2486		if (link.NeedsReply()) {
2487			debug_printf("ServerWindow::DispatchViewDrawingMessage() got "
2488				"message %" B_PRId32 " that needs a reply!\n", code);
2489			// the client is now blocking and waiting for a reply!
2490			fLink.StartMessage(B_ERROR);
2491			fLink.Flush();
2492		}
2493		return;
2494	}
2495
2496	DrawingEngine* drawingEngine = fWindow->GetDrawingEngine();
2497	if (!drawingEngine) {
2498		// ?!?
2499		debug_printf("ServerWindow %s: no drawing engine!!\n", Title());
2500		if (link.NeedsReply()) {
2501			// the client is now blocking and waiting for a reply!
2502			fLink.StartMessage(B_ERROR);
2503			fLink.Flush();
2504		}
2505		return;
2506	}
2507
2508	_UpdateCurrentDrawingRegion();
2509	if (fCurrentDrawingRegion.CountRects() <= 0 && code != AS_VIEW_END_LAYER) {
2510			// If the command is AS_VIEW_END_LAYER, then we continue even if
2511			// the clipping region is empty. The layer itself might set a valid
2512			// clipping while its contents are drawn, and even if it doesn't,
2513			// we must still play back its picture so that we don't leak
2514			// nested layer instances.
2515
2516		DTRACE(("ServerWindow %s: _DispatchViewDrawingMessage(): View: %s, "
2517			"INVALID CLIPPING!\n", Title(), fCurrentView->Name()));
2518		if (link.NeedsReply()) {
2519			// the client is now blocking and waiting for a reply!
2520			fLink.StartMessage(B_ERROR);
2521			fLink.Flush();
2522		}
2523		return;
2524	}
2525
2526	drawingEngine->LockParallelAccess();
2527	// NOTE: the region is not copied, Painter keeps a pointer,
2528	// that's why you need to use the clipping only for as long
2529	// as you have it locked
2530	drawingEngine->ConstrainClippingRegion(&fCurrentDrawingRegion);
2531
2532	switch (code) {
2533		case AS_STROKE_LINE:
2534		{
2535			ViewStrokeLineInfo info;
2536			if (link.Read<ViewStrokeLineInfo>(&info) != B_OK)
2537				break;
2538
2539			DTRACE(("ServerWindow %s: Message AS_STROKE_LINE: View: %s -> "
2540				"BPoint(%.1f, %.1f) - BPoint(%.1f, %.1f)\n", Title(),
2541					fCurrentView->Name(),
2542					info.startPoint.x, info.startPoint.y,
2543					info.endPoint.x, info.endPoint.y));
2544
2545			BPoint penPos = info.endPoint;
2546			const SimpleTransform transform =
2547				fCurrentView->PenToScreenTransform();
2548			transform.Apply(&info.startPoint);
2549			transform.Apply(&info.endPoint);
2550			drawingEngine->StrokeLine(info.startPoint, info.endPoint);
2551
2552			// We update the pen here because many DrawingEngine calls which
2553			// do not update the pen position actually call StrokeLine
2554
2555			// TODO: Decide where to put this, for example, it cannot be done
2556			// for DrawString(), also there needs to be a decision, if the pen
2557			// location is in View coordinates (I think it should be) or in
2558			// screen coordinates.
2559			fCurrentView->CurrentState()->SetPenLocation(penPos);
2560			break;
2561		}
2562		case AS_VIEW_INVERT_RECT:
2563		{
2564			BRect rect;
2565			if (link.Read<BRect>(&rect) != B_OK)
2566				break;
2567
2568			DTRACE(("ServerWindow %s: Message AS_INVERT_RECT: View: %s -> "
2569				"BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(),
2570				fCurrentView->Name(), rect.left, rect.top, rect.right,
2571				rect.bottom));
2572
2573			fCurrentView->PenToScreenTransform().Apply(&rect);
2574			drawingEngine->InvertRect(rect);
2575			break;
2576		}
2577		case AS_STROKE_RECT:
2578		{
2579			BRect rect;
2580			if (link.Read<BRect>(&rect) != B_OK)
2581				break;
2582
2583			DTRACE(("ServerWindow %s: Message AS_STROKE_RECT: View: %s -> "
2584				"BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(),
2585				fCurrentView->Name(), rect.left, rect.top, rect.right,
2586				rect.bottom));
2587
2588			fCurrentView->PenToScreenTransform().Apply(&rect);
2589			drawingEngine->StrokeRect(rect);
2590			break;
2591		}
2592		case AS_FILL_RECT:
2593		{
2594			BRect rect;
2595			if (link.Read<BRect>(&rect) != B_OK)
2596				break;
2597
2598			DTRACE(("ServerWindow %s: Message AS_FILL_RECT: View: %s -> "
2599				"BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(),
2600				fCurrentView->Name(), rect.left, rect.top, rect.right,
2601				rect.bottom));
2602
2603			fCurrentView->PenToScreenTransform().Apply(&rect);
2604			drawingEngine->FillRect(rect);
2605			break;
2606		}
2607		case AS_FILL_RECT_GRADIENT:
2608		{
2609			BRect rect;
2610			link.Read<BRect>(&rect);
2611			BGradient* gradient;
2612			if (link.ReadGradient(&gradient) != B_OK)
2613				break;
2614
2615			GTRACE(("ServerWindow %s: Message AS_FILL_RECT_GRADIENT: View: %s "
2616				"-> BRect(%.1f, %.1f, %.1f, %.1f)\n", Title(),
2617				fCurrentView->Name(), rect.left, rect.top, rect.right,
2618				rect.bottom));
2619
2620			const SimpleTransform transform =
2621				fCurrentView->PenToScreenTransform();
2622			transform.Apply(&rect);
2623			transform.Apply(gradient);
2624			drawingEngine->FillRect(rect, *gradient);
2625			delete gradient;
2626			break;
2627		}
2628		case AS_VIEW_DRAW_BITMAP:
2629		{
2630			ViewDrawBitmapInfo info;
2631			if (link.Read<ViewDrawBitmapInfo>(&info) != B_OK)
2632				break;
2633
2634#if 0
2635			if (strcmp(fServerApp->SignatureLeaf(), "x-vnd.videolan-vlc") == 0)
2636				info.options |= B_FILTER_BITMAP_BILINEAR;
2637#endif
2638
2639			BReference<ServerBitmap> bitmap(fServerApp->GetBitmap(info.bitmapToken), true);
2640			if (bitmap != NULL) {
2641				DTRACE(("ServerWindow %s: Message AS_VIEW_DRAW_BITMAP: "
2642					"View: %s, bitmap: %" B_PRId32 " (size %" B_PRId32 " x "
2643					"%" B_PRId32 "), BRect(%.1f, %.1f, %.1f, %.1f) -> "
2644					"BRect(%.1f, %.1f, %.1f, %.1f)\n",
2645					fTitle, fCurrentView->Name(), info.bitmapToken,
2646					bitmap->Width(), bitmap->Height(),
2647					info.bitmapRect.left, info.bitmapRect.top,
2648					info.bitmapRect.right, info.bitmapRect.bottom,
2649					info.viewRect.left, info.viewRect.top,
2650					info.viewRect.right, info.viewRect.bottom));
2651
2652				fCurrentView->PenToScreenTransform().Apply(&info.viewRect);
2653
2654// TODO: Unbreak...
2655//				if ((info.options & B_WAIT_FOR_RETRACE) != 0)
2656//					fDesktop->HWInterface()->WaitForRetrace(20000);
2657
2658				drawingEngine->DrawBitmap(bitmap, info.bitmapRect,
2659					info.viewRect, info.options);
2660			}
2661			break;
2662		}
2663		case AS_STROKE_ARC:
2664		case AS_FILL_ARC:
2665		{
2666			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ARC\n", Title()));
2667
2668			float angle, span;
2669			BRect r;
2670
2671			link.Read<BRect>(&r);
2672			link.Read<float>(&angle);
2673			if (link.Read<float>(&span) != B_OK)
2674				break;
2675
2676			fCurrentView->PenToScreenTransform().Apply(&r);
2677			drawingEngine->DrawArc(r, angle, span, code == AS_FILL_ARC);
2678			break;
2679		}
2680		case AS_FILL_ARC_GRADIENT:
2681		{
2682			GTRACE(("ServerWindow %s: Message AS_FILL_ARC_GRADIENT\n",
2683				Title()));
2684
2685			float angle, span;
2686			BRect r;
2687			link.Read<BRect>(&r);
2688			link.Read<float>(&angle);
2689			link.Read<float>(&span);
2690			BGradient* gradient;
2691			if (link.ReadGradient(&gradient) != B_OK)
2692				break;
2693			const SimpleTransform transform =
2694				fCurrentView->PenToScreenTransform();
2695			transform.Apply(&r);
2696			transform.Apply(gradient);
2697			drawingEngine->FillArc(r, angle, span, *gradient);
2698			delete gradient;
2699			break;
2700		}
2701		case AS_STROKE_BEZIER:
2702		case AS_FILL_BEZIER:
2703		{
2704			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_BEZIER\n",
2705				Title()));
2706
2707			const SimpleTransform transform =
2708				fCurrentView->PenToScreenTransform();
2709			BPoint pts[4];
2710			status_t status;
2711			for (int32 i = 0; i < 4; i++) {
2712				status = link.Read<BPoint>(&(pts[i]));
2713				transform.Apply(&pts[i]);
2714			}
2715			if (status != B_OK)
2716				break;
2717
2718			drawingEngine->DrawBezier(pts, code == AS_FILL_BEZIER);
2719			break;
2720		}
2721		case AS_FILL_BEZIER_GRADIENT:
2722		{
2723			GTRACE(("ServerWindow %s: Message AS_FILL_BEZIER_GRADIENT\n",
2724				Title()));
2725
2726			const SimpleTransform transform =
2727				fCurrentView->PenToScreenTransform();
2728			BPoint pts[4];
2729			for (int32 i = 0; i < 4; i++) {
2730				link.Read<BPoint>(&(pts[i]));
2731				transform.Apply(&pts[i]);
2732			}
2733			BGradient* gradient;
2734			if (link.ReadGradient(&gradient) != B_OK)
2735				break;
2736			transform.Apply(gradient);
2737			drawingEngine->FillBezier(pts, *gradient);
2738			delete gradient;
2739			break;
2740		}
2741		case AS_STROKE_ELLIPSE:
2742		case AS_FILL_ELLIPSE:
2743		{
2744			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ELLIPSE\n",
2745				Title()));
2746
2747			BRect rect;
2748			if (link.Read<BRect>(&rect) != B_OK)
2749				break;
2750
2751			fCurrentView->PenToScreenTransform().Apply(&rect);
2752			drawingEngine->DrawEllipse(rect, code == AS_FILL_ELLIPSE);
2753			break;
2754		}
2755		case AS_FILL_ELLIPSE_GRADIENT:
2756		{
2757			GTRACE(("ServerWindow %s: Message AS_FILL_ELLIPSE_GRADIENT\n",
2758				Title()));
2759
2760			BRect rect;
2761			link.Read<BRect>(&rect);
2762			BGradient* gradient;
2763			if (link.ReadGradient(&gradient) != B_OK)
2764				break;
2765			const SimpleTransform transform =
2766				fCurrentView->PenToScreenTransform();
2767			transform.Apply(&rect);
2768			transform.Apply(gradient);
2769			drawingEngine->FillEllipse(rect, *gradient);
2770			delete gradient;
2771			break;
2772		}
2773		case AS_STROKE_ROUNDRECT:
2774		case AS_FILL_ROUNDRECT:
2775		{
2776			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ROUNDRECT\n",
2777				Title()));
2778
2779			BRect rect;
2780			float xRadius;
2781			float yRadius;
2782			link.Read<BRect>(&rect);
2783			link.Read<float>(&xRadius);
2784			if (link.Read<float>(&yRadius) != B_OK)
2785				break;
2786
2787			fCurrentView->PenToScreenTransform().Apply(&rect);
2788			float scale = fCurrentView->CurrentState()->CombinedScale();
2789			drawingEngine->DrawRoundRect(rect, xRadius * scale, yRadius * scale,
2790				code == AS_FILL_ROUNDRECT);
2791			break;
2792		}
2793		case AS_FILL_ROUNDRECT_GRADIENT:
2794		{
2795			GTRACE(("ServerWindow %s: Message AS_FILL_ROUNDRECT_GRADIENT\n",
2796				Title()));
2797
2798			BRect rect;
2799			float xrad,yrad;
2800			link.Read<BRect>(&rect);
2801			link.Read<float>(&xrad);
2802			link.Read<float>(&yrad);
2803			BGradient* gradient;
2804			if (link.ReadGradient(&gradient) != B_OK)
2805				break;
2806			const SimpleTransform transform =
2807				fCurrentView->PenToScreenTransform();
2808			transform.Apply(&rect);
2809			transform.Apply(gradient);
2810			drawingEngine->FillRoundRect(rect, xrad, yrad, *gradient);
2811			delete gradient;
2812			break;
2813		}
2814		case AS_STROKE_TRIANGLE:
2815		case AS_FILL_TRIANGLE:
2816		{
2817			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_TRIANGLE\n",
2818				Title()));
2819
2820			const SimpleTransform transform =
2821				fCurrentView->PenToScreenTransform();
2822			BPoint pts[3];
2823			BRect rect;
2824
2825			for (int32 i = 0; i < 3; i++) {
2826				link.Read<BPoint>(&(pts[i]));
2827				transform.Apply(&pts[i]);
2828			}
2829
2830			if (link.Read<BRect>(&rect) != B_OK)
2831				break;
2832
2833			transform.Apply(&rect);
2834			drawingEngine->DrawTriangle(pts, rect, code == AS_FILL_TRIANGLE);
2835			break;
2836		}
2837		case AS_FILL_TRIANGLE_GRADIENT:
2838		{
2839			DTRACE(("ServerWindow %s: Message AS_FILL_TRIANGLE_GRADIENT\n",
2840				Title()));
2841
2842			const SimpleTransform transform =
2843				fCurrentView->PenToScreenTransform();
2844			BPoint pts[3];
2845			BRect rect;
2846			for (int32 i = 0; i < 3; i++) {
2847				link.Read<BPoint>(&(pts[i]));
2848				transform.Apply(&pts[i]);
2849			}
2850			link.Read<BRect>(&rect);
2851			BGradient* gradient;
2852			if (link.ReadGradient(&gradient) != B_OK)
2853				break;
2854			transform.Apply(&rect);
2855			transform.Apply(gradient);
2856			drawingEngine->FillTriangle(pts, rect, *gradient);
2857			delete gradient;
2858			break;
2859		}
2860		case AS_STROKE_POLYGON:
2861		case AS_FILL_POLYGON:
2862		{
2863			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_POLYGON\n",
2864				Title()));
2865
2866			BRect polyFrame;
2867			bool isClosed = true;
2868			int32 pointCount;
2869
2870			link.Read<BRect>(&polyFrame);
2871			if (code == AS_STROKE_POLYGON)
2872				link.Read<bool>(&isClosed);
2873			link.Read<int32>(&pointCount);
2874
2875			const SimpleTransform transform =
2876				fCurrentView->PenToScreenTransform();
2877			BPoint* pointList = new(nothrow) BPoint[pointCount];
2878			if (link.Read(pointList, pointCount * sizeof(BPoint)) >= B_OK) {
2879				for (int32 i = 0; i < pointCount; i++)
2880					transform.Apply(&pointList[i]);
2881				transform.Apply(&polyFrame);
2882
2883				drawingEngine->DrawPolygon(pointList, pointCount, polyFrame,
2884					code == AS_FILL_POLYGON, isClosed && pointCount > 2);
2885			}
2886			delete[] pointList;
2887			break;
2888		}
2889		case AS_FILL_POLYGON_GRADIENT:
2890		{
2891			DTRACE(("ServerWindow %s: Message AS_FILL_POLYGON_GRADIENT\n",
2892				Title()));
2893
2894			BRect polyFrame;
2895			bool isClosed = true;
2896			int32 pointCount;
2897			link.Read<BRect>(&polyFrame);
2898			link.Read<int32>(&pointCount);
2899
2900			const SimpleTransform transform =
2901				fCurrentView->PenToScreenTransform();
2902			BPoint* pointList = new(nothrow) BPoint[pointCount];
2903			BGradient* gradient;
2904			if (link.Read(pointList, pointCount * sizeof(BPoint)) == B_OK
2905				&& link.ReadGradient(&gradient) == B_OK) {
2906				for (int32 i = 0; i < pointCount; i++)
2907					transform.Apply(&pointList[i]);
2908				transform.Apply(&polyFrame);
2909				transform.Apply(gradient);
2910
2911				drawingEngine->FillPolygon(pointList, pointCount,
2912					polyFrame, *gradient, isClosed && pointCount > 2);
2913				delete gradient;
2914			}
2915			delete[] pointList;
2916			break;
2917		}
2918		case AS_STROKE_SHAPE:
2919		case AS_FILL_SHAPE:
2920		{
2921			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_SHAPE\n",
2922				Title()));
2923
2924			BRect shapeFrame;
2925			int32 opCount;
2926			int32 ptCount;
2927
2928			link.Read<BRect>(&shapeFrame);
2929			link.Read<int32>(&opCount);
2930			link.Read<int32>(&ptCount);
2931
2932			uint32* opList = new(nothrow) uint32[opCount];
2933			BPoint* ptList = new(nothrow) BPoint[ptCount];
2934			if (link.Read(opList, opCount * sizeof(uint32)) >= B_OK &&
2935				link.Read(ptList, ptCount * sizeof(BPoint)) >= B_OK) {
2936
2937				// this might seem a bit weird, but under R5, the shapes
2938				// are always offset by the current pen location
2939				BPoint screenOffset
2940					= fCurrentView->CurrentState()->PenLocation();
2941				shapeFrame.OffsetBy(screenOffset);
2942
2943				const SimpleTransform transform =
2944					fCurrentView->PenToScreenTransform();
2945				transform.Apply(&screenOffset);
2946				transform.Apply(&shapeFrame);
2947
2948				drawingEngine->DrawShape(shapeFrame, opCount, opList, ptCount,
2949					ptList, code == AS_FILL_SHAPE, screenOffset,
2950					fCurrentView->Scale());
2951			}
2952
2953			delete[] opList;
2954			delete[] ptList;
2955			break;
2956		}
2957		case AS_FILL_SHAPE_GRADIENT:
2958		{
2959			DTRACE(("ServerWindow %s: Message AS_FILL_SHAPE_GRADIENT\n",
2960				Title()));
2961
2962			BRect shapeFrame;
2963			int32 opCount;
2964			int32 ptCount;
2965
2966			link.Read<BRect>(&shapeFrame);
2967			link.Read<int32>(&opCount);
2968			link.Read<int32>(&ptCount);
2969
2970			uint32* opList = new(nothrow) uint32[opCount];
2971			BPoint* ptList = new(nothrow) BPoint[ptCount];
2972			BGradient* gradient;
2973			if (link.Read(opList, opCount * sizeof(uint32)) == B_OK
2974				&& link.Read(ptList, ptCount * sizeof(BPoint)) == B_OK
2975				&& link.ReadGradient(&gradient) == B_OK) {
2976
2977				// this might seem a bit weird, but under R5, the shapes
2978				// are always offset by the current pen location
2979				BPoint screenOffset
2980					= fCurrentView->CurrentState()->PenLocation();
2981				shapeFrame.OffsetBy(screenOffset);
2982
2983				const SimpleTransform transform =
2984					fCurrentView->PenToScreenTransform();
2985				transform.Apply(&screenOffset);
2986				transform.Apply(&shapeFrame);
2987				transform.Apply(gradient);
2988				drawingEngine->FillShape(shapeFrame, opCount, opList,
2989					ptCount, ptList, *gradient, screenOffset,
2990					fCurrentView->Scale());
2991				delete gradient;
2992			}
2993
2994			delete[] opList;
2995			delete[] ptList;
2996			break;
2997		}
2998		case AS_FILL_REGION:
2999		{
3000			DTRACE(("ServerWindow %s: Message AS_FILL_REGION\n", Title()));
3001
3002			BRegion region;
3003			if (link.ReadRegion(&region) < B_OK)
3004				break;
3005
3006			fCurrentView->PenToScreenTransform().Apply(&region);
3007			drawingEngine->FillRegion(region);
3008
3009			break;
3010		}
3011		case AS_FILL_REGION_GRADIENT:
3012		{
3013			DTRACE(("ServerWindow %s: Message AS_FILL_REGION_GRADIENT\n",
3014				Title()));
3015
3016			BRegion region;
3017			link.ReadRegion(&region);
3018
3019			BGradient* gradient;
3020			if (link.ReadGradient(&gradient) != B_OK)
3021				break;
3022
3023			const SimpleTransform transform =
3024				fCurrentView->PenToScreenTransform();
3025			transform.Apply(&region);
3026			transform.Apply(gradient);
3027			drawingEngine->FillRegion(region, *gradient);
3028			delete gradient;
3029			break;
3030		}
3031		case AS_STROKE_LINEARRAY:
3032		{
3033			DTRACE(("ServerWindow %s: Message AS_STROKE_LINEARRAY\n",
3034				Title()));
3035
3036			// Attached Data:
3037			// 1) int32 Number of lines in the array
3038			// 2) LineArrayData
3039
3040			int32 lineCount;
3041			if (link.Read<int32>(&lineCount) != B_OK || lineCount <= 0)
3042				break;
3043
3044			// To speed things up, try to use a stack allocation and only
3045			// fall back to the heap if there are enough lines...
3046			ViewLineArrayInfo* lineData;
3047			const int32 kStackBufferLineDataCount = 64;
3048			ViewLineArrayInfo lineDataStackBuffer[kStackBufferLineDataCount];
3049			if (lineCount > kStackBufferLineDataCount) {
3050				lineData = new(std::nothrow) ViewLineArrayInfo[lineCount];
3051				if (lineData == NULL)
3052					break;
3053			} else
3054				lineData = lineDataStackBuffer;
3055
3056			// Read them all in one go
3057			size_t dataSize = lineCount * sizeof(ViewLineArrayInfo);
3058			if (link.Read(lineData, dataSize) != B_OK) {
3059				if (lineData != lineDataStackBuffer)
3060					delete[] lineData;
3061				break;
3062			}
3063
3064			// Convert to screen coords and draw
3065			const SimpleTransform transform =
3066				fCurrentView->PenToScreenTransform();
3067			for (int32 i = 0; i < lineCount; i++) {
3068				transform.Apply(&lineData[i].startPoint);
3069				transform.Apply(&lineData[i].endPoint);
3070			}
3071			drawingEngine->StrokeLineArray(lineCount, lineData);
3072
3073			if (lineData != lineDataStackBuffer)
3074				delete[] lineData;
3075			break;
3076		}
3077		case AS_DRAW_STRING:
3078		case AS_DRAW_STRING_WITH_DELTA:
3079		{
3080			ViewDrawStringInfo info;
3081			if (link.Read<ViewDrawStringInfo>(&info) != B_OK
3082				|| info.stringLength <= 0) {
3083				break;
3084			}
3085
3086			// NOTE: Careful, the + 1 is for termination!
3087			BStackOrHeapArray<char, 4096> string(
3088				(info.stringLength + 1 + 63) / 64 * 64);
3089			if (!string.IsValid())
3090				break;
3091
3092			escapement_delta* delta = NULL;
3093			if (code == AS_DRAW_STRING_WITH_DELTA) {
3094				// In this case, info.delta will contain valid values.
3095				delta = &info.delta;
3096			}
3097
3098			if (link.Read(string, info.stringLength) != B_OK)
3099				break;
3100
3101			// Terminate the string, if nothing else, it's important
3102			// for the DTRACE call below...
3103			string[info.stringLength] = '\0';
3104
3105			DTRACE(("ServerWindow %s: Message AS_DRAW_STRING, View: %s "
3106				"-> %s\n", Title(), fCurrentView->Name(), string));
3107
3108			fCurrentView->PenToScreenTransform().Apply(&info.location);
3109			BPoint penLocation = drawingEngine->DrawString(string,
3110				info.stringLength, info.location, delta);
3111
3112			fCurrentView->ScreenToPenTransform().Apply(&penLocation);
3113			fCurrentView->CurrentState()->SetPenLocation(penLocation);
3114
3115			break;
3116		}
3117		case AS_DRAW_STRING_WITH_OFFSETS:
3118		{
3119			int32 stringLength;
3120			if (link.Read<int32>(&stringLength) != B_OK || stringLength <= 0)
3121				break;
3122
3123			int32 glyphCount;
3124			if (link.Read<int32>(&glyphCount) != B_OK || glyphCount <= 0)
3125				break;
3126
3127			// NOTE: Careful, the + 1 is for termination!
3128			BStackOrHeapArray<char, 512> string(
3129				(stringLength + 1 + 63) / 64 * 64);
3130			BStackOrHeapArray<BPoint, 512> locations(glyphCount);
3131			if (!string.IsValid() || !locations.IsValid())
3132				break;
3133
3134			if (link.Read(string, stringLength) != B_OK)
3135				break;
3136			// Count UTF8 glyphs and make sure we have enough locations
3137			if ((int32)UTF8CountChars(string, stringLength) > glyphCount)
3138				break;
3139			if (link.Read(locations, glyphCount * sizeof(BPoint)) != B_OK)
3140				break;
3141			// Terminate the string, if nothing else, it's important
3142			// for the DTRACE call below...
3143			string[stringLength] = '\0';
3144
3145			DTRACE(("ServerWindow %s: Message AS_DRAW_STRING_WITH_OFFSETS, View: %s "
3146				"-> %s\n", Title(), fCurrentView->Name(), string));
3147
3148			const SimpleTransform transform =
3149				fCurrentView->PenToScreenTransform();
3150			for (int32 i = 0; i < glyphCount; i++)
3151				transform.Apply(&locations[i]);
3152
3153			BPoint penLocation = drawingEngine->DrawString(string,
3154				stringLength, locations);
3155
3156			fCurrentView->ScreenToPenTransform().Apply(&penLocation);
3157			fCurrentView->CurrentState()->SetPenLocation(penLocation);
3158
3159			break;
3160		}
3161
3162		case AS_VIEW_DRAW_PICTURE:
3163		{
3164			int32 token;
3165			link.Read<int32>(&token);
3166
3167			BPoint where;
3168			if (link.Read<BPoint>(&where) == B_OK) {
3169				BReference<ServerPicture> picture(App()->GetPicture(token), true);
3170				if (picture != NULL) {
3171					// Setting the drawing origin outside of the
3172					// state makes sure that everything the picture
3173					// does is relative to the global picture offset.
3174					fCurrentView->PushState();
3175					fCurrentView->SetDrawingOrigin(where);
3176
3177					fCurrentView->PushState();
3178					picture->Play(fCurrentView);
3179					fCurrentView->PopState();
3180
3181					fCurrentView->PopState();
3182				}
3183			}
3184			break;
3185		}
3186
3187		case AS_VIEW_END_LAYER:
3188		{
3189			DTRACE(("ServerWindow %s: Message AS_VIEW_END_LAYER\n",
3190				Title()));
3191
3192			fCurrentView->BlendAllLayers();
3193			fCurrentView->SetPicture(NULL);
3194			fCurrentView->CurrentState()->SetDrawingModeLocked(false);
3195			break;
3196		}
3197
3198		default:
3199			debug_printf("ServerWindow %s received unexpected code: %s\n",
3200				Title(), string_for_message_code(code));
3201
3202			if (link.NeedsReply()) {
3203				// the client is now blocking and waiting for a reply!
3204				fLink.StartMessage(B_ERROR);
3205				fLink.Flush();
3206			}
3207			break;
3208	}
3209
3210	drawingEngine->UnlockParallelAccess();
3211}
3212
3213
3214bool
3215ServerWindow::_DispatchPictureMessage(int32 code, BPrivate::LinkReceiver& link)
3216{
3217	ServerPicture* picture = fCurrentView->Picture();
3218	if (picture == NULL)
3219		return false;
3220
3221	switch (code) {
3222		case AS_VIEW_SET_ORIGIN:
3223		{
3224			float x, y;
3225			link.Read<float>(&x);
3226			link.Read<float>(&y);
3227
3228			fCurrentView->SetDrawingOrigin(BPoint(x, y));
3229			picture->WriteSetOrigin(BPoint(x, y));
3230			break;
3231		}
3232
3233		case AS_VIEW_INVERT_RECT:
3234		{
3235			BRect rect;
3236			link.Read<BRect>(&rect);
3237			picture->WriteInvertRect(rect);
3238			break;
3239		}
3240
3241		case AS_VIEW_PUSH_STATE:
3242		{
3243			fCurrentView->PushState();
3244			picture->WritePushState();
3245			break;
3246		}
3247
3248		case AS_VIEW_POP_STATE:
3249		{
3250			fCurrentView->PopState();
3251			picture->WritePopState();
3252			break;
3253		}
3254
3255		case AS_VIEW_SET_DRAWING_MODE:
3256		{
3257			int8 drawingMode;
3258			link.Read<int8>(&drawingMode);
3259
3260			picture->WriteSetDrawingMode((drawing_mode)drawingMode);
3261
3262			fCurrentView->CurrentState()->SetDrawingMode(
3263				(drawing_mode)drawingMode);
3264			fWindow->GetDrawingEngine()->SetDrawingMode(
3265				(drawing_mode)drawingMode);
3266			break;
3267		}
3268
3269		case AS_VIEW_SET_PEN_LOC:
3270		{
3271			BPoint location;
3272			link.Read<BPoint>(&location);
3273			picture->WriteSetPenLocation(location);
3274
3275			fCurrentView->CurrentState()->SetPenLocation(location);
3276			break;
3277		}
3278
3279		case AS_VIEW_SET_PEN_SIZE:
3280		{
3281			float penSize;
3282			link.Read<float>(&penSize);
3283			picture->WriteSetPenSize(penSize);
3284
3285			fCurrentView->CurrentState()->SetPenSize(penSize);
3286			fWindow->GetDrawingEngine()->SetPenSize(
3287				fCurrentView->CurrentState()->PenSize());
3288			break;
3289		}
3290
3291		case AS_VIEW_SET_LINE_MODE:
3292		{
3293
3294			ViewSetLineModeInfo info;
3295			link.Read<ViewSetLineModeInfo>(&info);
3296
3297			picture->WriteSetLineMode(info.lineCap, info.lineJoin,
3298				info.miterLimit);
3299
3300			fCurrentView->CurrentState()->SetLineCapMode(info.lineCap);
3301			fCurrentView->CurrentState()->SetLineJoinMode(info.lineJoin);
3302			fCurrentView->CurrentState()->SetMiterLimit(info.miterLimit);
3303
3304			fWindow->GetDrawingEngine()->SetStrokeMode(info.lineCap,
3305				info.lineJoin, info.miterLimit);
3306			break;
3307		}
3308		case AS_VIEW_SET_FILL_RULE:
3309		{
3310			int32 fillRule;
3311			if (link.Read<int32>(&fillRule) != B_OK)
3312				break;
3313
3314			picture->WriteSetFillRule(fillRule);
3315
3316			fCurrentView->CurrentState()->SetFillRule(fillRule);
3317			fWindow->GetDrawingEngine()->SetFillRule(fillRule);
3318
3319			break;
3320		}
3321		case AS_VIEW_SET_SCALE:
3322		{
3323			float scale;
3324			if (link.Read<float>(&scale) != B_OK)
3325				break;
3326
3327			picture->WriteSetScale(scale);
3328
3329			fCurrentView->SetScale(scale);
3330			_UpdateDrawState(fCurrentView);
3331			break;
3332		}
3333		case AS_VIEW_SET_TRANSFORM:
3334		{
3335			BAffineTransform transform;
3336			if (link.Read<BAffineTransform>(&transform) != B_OK)
3337				break;
3338
3339			picture->WriteSetTransform(transform);
3340
3341			fCurrentView->CurrentState()->SetTransform(transform);
3342			_UpdateDrawState(fCurrentView);
3343			break;
3344		}
3345
3346		case AS_VIEW_AFFINE_TRANSLATE:
3347		{
3348			double x, y;
3349			link.Read<double>(&x);
3350			link.Read<double>(&y);
3351
3352			picture->WriteTranslateBy(x, y);
3353
3354			BAffineTransform current =
3355				fCurrentView->CurrentState()->Transform();
3356			current.PreTranslateBy(x, y);
3357			fCurrentView->CurrentState()->SetTransform(current);
3358			_UpdateDrawState(fCurrentView);
3359			break;
3360		}
3361
3362		case AS_VIEW_AFFINE_SCALE:
3363		{
3364			double x, y;
3365			link.Read<double>(&x);
3366			link.Read<double>(&y);
3367
3368			picture->WriteScaleBy(x, y);
3369
3370			BAffineTransform current =
3371				fCurrentView->CurrentState()->Transform();
3372			current.PreScaleBy(x, y);
3373			fCurrentView->CurrentState()->SetTransform(current);
3374			_UpdateDrawState(fCurrentView);
3375			break;
3376		}
3377
3378		case AS_VIEW_AFFINE_ROTATE:
3379		{
3380			double angleRadians;
3381			link.Read<double>(&angleRadians);
3382
3383			picture->WriteRotateBy(angleRadians);
3384
3385			BAffineTransform current =
3386				fCurrentView->CurrentState()->Transform();
3387			current.PreRotateBy(angleRadians);
3388			fCurrentView->CurrentState()->SetTransform(current);
3389			_UpdateDrawState(fCurrentView);
3390			break;
3391		}
3392
3393
3394		case AS_VIEW_SET_PATTERN:
3395		{
3396			pattern pat;
3397			link.Read(&pat, sizeof(pattern));
3398			picture->WriteSetPattern(pat);
3399			break;
3400		}
3401
3402		case AS_VIEW_SET_FONT_STATE:
3403		{
3404			uint16 mask = fCurrentView->CurrentState()->ReadFontFromLink(link);
3405			fWindow->GetDrawingEngine()->SetFont(
3406				fCurrentView->CurrentState());
3407
3408			picture->WriteFontState(fCurrentView->CurrentState()->Font(), mask);
3409			break;
3410		}
3411
3412		case AS_FILL_RECT:
3413		case AS_STROKE_RECT:
3414		{
3415			BRect rect;
3416			link.Read<BRect>(&rect);
3417
3418			picture->WriteDrawRect(rect, code == AS_FILL_RECT);
3419			break;
3420		}
3421
3422		case AS_FILL_REGION:
3423		{
3424			// There is no B_PIC_FILL_REGION op, we have to
3425			// implement it using B_PIC_FILL_RECT
3426			BRegion region;
3427			if (link.ReadRegion(&region) < B_OK)
3428				break;
3429			for (int32 i = 0; i < region.CountRects(); i++)
3430				picture->WriteDrawRect(region.RectAt(i), true);
3431			break;
3432		}
3433
3434		case AS_STROKE_ROUNDRECT:
3435		case AS_FILL_ROUNDRECT:
3436		{
3437			BRect rect;
3438			link.Read<BRect>(&rect);
3439
3440			BPoint radii;
3441			link.Read<float>(&radii.x);
3442			link.Read<float>(&radii.y);
3443
3444			picture->WriteDrawRoundRect(rect, radii, code == AS_FILL_ROUNDRECT);
3445			break;
3446		}
3447
3448		case AS_STROKE_ELLIPSE:
3449		case AS_FILL_ELLIPSE:
3450		{
3451			BRect rect;
3452			link.Read<BRect>(&rect);
3453			picture->WriteDrawEllipse(rect, code == AS_FILL_ELLIPSE);
3454			break;
3455		}
3456
3457		case AS_STROKE_ARC:
3458		case AS_FILL_ARC:
3459		{
3460			BRect rect;
3461			link.Read<BRect>(&rect);
3462			float startTheta, arcTheta;
3463			link.Read<float>(&startTheta);
3464			link.Read<float>(&arcTheta);
3465
3466			BPoint radii((rect.Width() + 1) / 2, (rect.Height() + 1) / 2);
3467			BPoint center = rect.LeftTop() + radii;
3468
3469			picture->WriteDrawArc(center, radii, startTheta, arcTheta,
3470				code == AS_FILL_ARC);
3471			break;
3472		}
3473
3474		case AS_STROKE_TRIANGLE:
3475		case AS_FILL_TRIANGLE:
3476		{
3477			// There is no B_PIC_FILL/STROKE_TRIANGLE op,
3478			// we implement it using B_PIC_FILL/STROKE_POLYGON
3479			BPoint points[3];
3480
3481			for (int32 i = 0; i < 3; i++) {
3482				link.Read<BPoint>(&(points[i]));
3483			}
3484
3485			BRect rect;
3486			link.Read<BRect>(&rect);
3487
3488			picture->WriteDrawPolygon(3, points,
3489					true, code == AS_FILL_TRIANGLE);
3490			break;
3491		}
3492		case AS_STROKE_POLYGON:
3493		case AS_FILL_POLYGON:
3494		{
3495			BRect polyFrame;
3496			bool isClosed = true;
3497			int32 pointCount;
3498			const bool fill = (code == AS_FILL_POLYGON);
3499
3500			link.Read<BRect>(&polyFrame);
3501			if (code == AS_STROKE_POLYGON)
3502				link.Read<bool>(&isClosed);
3503			link.Read<int32>(&pointCount);
3504
3505			BPoint* pointList = new(nothrow) BPoint[pointCount];
3506			if (link.Read(pointList, pointCount * sizeof(BPoint)) >= B_OK) {
3507				picture->WriteDrawPolygon(pointCount, pointList,
3508					isClosed && pointCount > 2, fill);
3509			}
3510			delete[] pointList;
3511			break;
3512		}
3513
3514		case AS_STROKE_BEZIER:
3515		case AS_FILL_BEZIER:
3516		{
3517			BPoint points[4];
3518			for (int32 i = 0; i < 4; i++) {
3519				link.Read<BPoint>(&(points[i]));
3520			}
3521			picture->WriteDrawBezier(points, code == AS_FILL_BEZIER);
3522			break;
3523		}
3524
3525		//case AS_STROKE_RECT_GRADIENT:
3526		case AS_FILL_RECT_GRADIENT:
3527		{
3528			BRect rect;
3529			link.Read<BRect>(&rect);
3530			BGradient* gradient;
3531			if (link.ReadGradient(&gradient) != B_OK)
3532				break;
3533			ObjectDeleter<BGradient> gradientDeleter(gradient);
3534
3535			picture->WriteDrawRectGradient(rect, *gradient, code == AS_FILL_RECT_GRADIENT);
3536			break;
3537		}
3538
3539		//case AS_STROKE_ARC_GRADIENT:
3540		case AS_FILL_ARC_GRADIENT:
3541		{
3542			BRect rect;
3543			link.Read<BRect>(&rect);
3544			float startTheta, arcTheta;
3545			link.Read<float>(&startTheta);
3546			link.Read<float>(&arcTheta);
3547			BGradient* gradient;
3548			if (link.ReadGradient(&gradient) != B_OK)
3549				break;
3550			ObjectDeleter<BGradient> gradientDeleter(gradient);
3551
3552			BPoint radii((rect.Width() + 1) / 2, (rect.Height() + 1) / 2);
3553			BPoint center = rect.LeftTop() + radii;
3554
3555			picture->WriteDrawArcGradient(center, radii, startTheta, arcTheta, *gradient,
3556				code == AS_FILL_ARC_GRADIENT);
3557			break;
3558		}
3559
3560		//case AS_STROKE_BEZIER_GRADIENT:
3561		case AS_FILL_BEZIER_GRADIENT:
3562		{
3563			BPoint points[4];
3564			for (int32 i = 0; i < 4; i++) {
3565				link.Read<BPoint>(&(points[i]));
3566			}
3567			BGradient* gradient;
3568			if (link.ReadGradient(&gradient) != B_OK)
3569				break;
3570			ObjectDeleter<BGradient> gradientDeleter(gradient);
3571
3572			picture->WriteDrawBezierGradient(points, *gradient, code == AS_FILL_BEZIER_GRADIENT);
3573			break;
3574		}
3575
3576		//case AS_STROKE_ELLIPSE_GRADIENT:
3577		case AS_FILL_ELLIPSE_GRADIENT:
3578		{
3579			BRect rect;
3580			link.Read<BRect>(&rect);
3581			BGradient* gradient;
3582			if (link.ReadGradient(&gradient) != B_OK)
3583				break;
3584			ObjectDeleter<BGradient> gradientDeleter(gradient);
3585
3586			picture->WriteDrawEllipseGradient(rect, *gradient, code == AS_FILL_ELLIPSE_GRADIENT);
3587			break;
3588		}
3589
3590		//case AS_STROKE_ROUNDRECT_GRADIENT:
3591		case AS_FILL_ROUNDRECT_GRADIENT:
3592		{
3593			BRect rect;
3594			link.Read<BRect>(&rect);
3595
3596			BPoint radii;
3597			link.Read<float>(&radii.x);
3598			link.Read<float>(&radii.y);
3599			BGradient* gradient;
3600			if (link.ReadGradient(&gradient) != B_OK)
3601				break;
3602			ObjectDeleter<BGradient> gradientDeleter(gradient);
3603
3604			picture->WriteDrawRoundRectGradient(rect, radii, *gradient, code == AS_FILL_ROUNDRECT_GRADIENT);
3605			break;
3606		}
3607
3608		//case AS_STROKE_TRIANGLE_GRADIENT:
3609		case AS_FILL_TRIANGLE_GRADIENT:
3610		{
3611			// There is no B_PIC_FILL/STROKE_TRIANGLE op,
3612			// we implement it using B_PIC_FILL/STROKE_POLYGON
3613			BPoint points[3];
3614
3615			for (int32 i = 0; i < 3; i++) {
3616				link.Read<BPoint>(&(points[i]));
3617			}
3618
3619			BRect rect;
3620			link.Read<BRect>(&rect);
3621			BGradient* gradient;
3622			if (link.ReadGradient(&gradient) != B_OK)
3623				break;
3624			ObjectDeleter<BGradient> gradientDeleter(gradient);
3625
3626			picture->WriteDrawPolygonGradient(3, points,
3627					true, *gradient, code == AS_FILL_TRIANGLE_GRADIENT);
3628			break;
3629		}
3630
3631		//case AS_STROKE_POLYGON_GRADIENT:
3632		case AS_FILL_POLYGON_GRADIENT:
3633		{
3634			BRect polyFrame;
3635			bool isClosed = true;
3636			int32 pointCount;
3637			const bool fill = (code == AS_FILL_POLYGON_GRADIENT);
3638
3639			link.Read<BRect>(&polyFrame);
3640			if (code == AS_STROKE_POLYGON)
3641				link.Read<bool>(&isClosed);
3642			link.Read<int32>(&pointCount);
3643
3644			ArrayDeleter<BPoint> pointList(new(nothrow) BPoint[pointCount]);
3645			if (link.Read(pointList.Get(), pointCount * sizeof(BPoint)) != B_OK)
3646				break;
3647
3648			BGradient* gradient;
3649			if (link.ReadGradient(&gradient) != B_OK)
3650				break;
3651			ObjectDeleter<BGradient> gradientDeleter(gradient);
3652
3653			picture->WriteDrawPolygonGradient(pointCount, pointList.Get(),
3654				isClosed && pointCount > 2, *gradient, fill);
3655			break;
3656		}
3657
3658		//case AS_STROKE_SHAPE_GRADIENT:
3659		case AS_FILL_SHAPE_GRADIENT:
3660		{
3661			BRect shapeFrame;
3662			int32 opCount;
3663			int32 ptCount;
3664
3665			link.Read<BRect>(&shapeFrame);
3666			link.Read<int32>(&opCount);
3667			link.Read<int32>(&ptCount);
3668
3669			ArrayDeleter<uint32> opList(new(std::nothrow) uint32[opCount]);
3670			ArrayDeleter<BPoint> ptList(new(std::nothrow) BPoint[ptCount]);
3671			if (!opList.IsSet() || !ptList.IsSet()
3672				|| link.Read(opList.Get(), opCount * sizeof(uint32)) != B_OK
3673				|| link.Read(ptList.Get(), ptCount * sizeof(BPoint)) != B_OK)
3674				break;
3675
3676			BGradient* gradient;
3677			if (link.ReadGradient(&gradient) != B_OK)
3678				break;
3679			ObjectDeleter<BGradient> gradientDeleter(gradient);
3680
3681			// This might seem a bit weird, but under BeOS, the shapes
3682			// are always offset by the current pen location
3683			BPoint penLocation
3684				= fCurrentView->CurrentState()->PenLocation();
3685			for (int32 i = 0; i < ptCount; i++) {
3686				ptList.Get()[i] += penLocation;
3687			}
3688			const bool fill = (code == AS_FILL_SHAPE_GRADIENT);
3689			picture->WriteDrawShapeGradient(opCount, opList.Get(), ptCount, ptList.Get(), *gradient, fill);
3690
3691			break;
3692		}
3693
3694		case AS_FILL_REGION_GRADIENT:
3695		{
3696			// There is no B_PIC_FILL_REGION op, we have to
3697			// implement it using B_PIC_FILL_RECT
3698			BRegion region;
3699			if (link.ReadRegion(&region) < B_OK)
3700				break;
3701
3702			BGradient* gradient;
3703			if (link.ReadGradient(&gradient) != B_OK)
3704				break;
3705			ObjectDeleter<BGradient> gradientDeleter(gradient);
3706
3707			for (int32 i = 0; i < region.CountRects(); i++)
3708				picture->WriteDrawRectGradient(region.RectAt(i), *gradient, true);
3709			break;
3710		}
3711
3712		case AS_STROKE_LINE:
3713		{
3714			ViewStrokeLineInfo info;
3715			link.Read<ViewStrokeLineInfo>(&info);
3716
3717			picture->WriteStrokeLine(info.startPoint, info.endPoint);
3718
3719			BPoint penPos = info.endPoint;
3720			const SimpleTransform transform =
3721				fCurrentView->PenToScreenTransform();
3722			transform.Apply(&info.endPoint);
3723			fCurrentView->CurrentState()->SetPenLocation(penPos);
3724			break;
3725		}
3726
3727		case AS_STROKE_LINEARRAY:
3728		{
3729			int32 lineCount;
3730			if (link.Read<int32>(&lineCount) != B_OK || lineCount <= 0)
3731				break;
3732
3733			// To speed things up, try to use a stack allocation and only
3734			// fall back to the heap if there are enough lines...
3735			ViewLineArrayInfo* lineData;
3736			const int32 kStackBufferLineDataCount = 64;
3737			ViewLineArrayInfo lineDataStackBuffer[kStackBufferLineDataCount];
3738			if (lineCount > kStackBufferLineDataCount) {
3739				lineData = new(std::nothrow) ViewLineArrayInfo[lineCount];
3740				if (lineData == NULL)
3741					break;
3742			} else
3743				lineData = lineDataStackBuffer;
3744
3745			// Read them all in one go
3746			size_t dataSize = lineCount * sizeof(ViewLineArrayInfo);
3747			if (link.Read(lineData, dataSize) != B_OK) {
3748				if (lineData != lineDataStackBuffer)
3749					delete[] lineData;
3750				break;
3751			}
3752
3753			picture->WritePushState();
3754
3755			for (int32 i = 0; i < lineCount; i++) {
3756				picture->WriteSetHighColor(lineData[i].color);
3757				picture->WriteStrokeLine(lineData[i].startPoint,
3758					lineData[i].endPoint);
3759			}
3760
3761			picture->WritePopState();
3762
3763			if (lineData != lineDataStackBuffer)
3764				delete[] lineData;
3765			break;
3766		}
3767
3768		case AS_VIEW_SET_LOW_COLOR:
3769		case AS_VIEW_SET_HIGH_COLOR:
3770		{
3771			rgb_color color;
3772			link.Read(&color, sizeof(rgb_color));
3773
3774			if (code == AS_VIEW_SET_HIGH_COLOR) {
3775				picture->WriteSetHighColor(color);
3776				fCurrentView->CurrentState()->SetHighColor(color);
3777				fWindow->GetDrawingEngine()->SetHighColor(color);
3778			} else {
3779				picture->WriteSetLowColor(color);
3780				fCurrentView->CurrentState()->SetLowColor(color);
3781				fWindow->GetDrawingEngine()->SetLowColor(color);
3782			}
3783		}	break;
3784
3785		case AS_DRAW_STRING:
3786		case AS_DRAW_STRING_WITH_DELTA:
3787		{
3788			ViewDrawStringInfo info;
3789			if (link.Read<ViewDrawStringInfo>(&info) != B_OK)
3790				break;
3791
3792			char* string = (char*)malloc(info.stringLength + 1);
3793			if (string == NULL)
3794				break;
3795
3796			if (code != AS_DRAW_STRING_WITH_DELTA) {
3797				// In this case, info.delta will NOT contain valid values.
3798				info.delta = (escapement_delta){ 0, 0 };
3799			}
3800
3801			if (link.Read(string, info.stringLength) != B_OK) {
3802				free(string);
3803				break;
3804			}
3805			// Terminate the string
3806			string[info.stringLength] = '\0';
3807
3808			picture->WriteDrawString(info.location, string, info.stringLength,
3809				info.delta);
3810
3811			// We need to update the pen location
3812			fCurrentView->PenToScreenTransform().Apply(&info.location);
3813			DrawingEngine* drawingEngine = fWindow->GetDrawingEngine();
3814			if (drawingEngine->LockParallelAccess()) {
3815				BPoint penLocation = drawingEngine->DrawStringDry(
3816					string, info.stringLength, info.location, &info.delta);
3817
3818				fCurrentView->ScreenToPenTransform().Apply(&penLocation);
3819				fCurrentView->CurrentState()->SetPenLocation(penLocation);
3820
3821				drawingEngine->UnlockParallelAccess();
3822			}
3823
3824			free(string);
3825			break;
3826		}
3827
3828		case AS_DRAW_STRING_WITH_OFFSETS:
3829		{
3830			int32 stringLength;
3831			if (link.Read<int32>(&stringLength) != B_OK || stringLength <= 0)
3832				break;
3833
3834			int32 glyphCount;
3835			if (link.Read<int32>(&glyphCount) != B_OK || glyphCount <= 0)
3836				break;
3837
3838			// NOTE: Careful, the + 1 is for termination!
3839			BStackOrHeapArray<char, 512> string(
3840				(stringLength + 1 + 63) / 64 * 64);
3841			BStackOrHeapArray<BPoint, 512> locations(glyphCount);
3842			if (!string.IsValid() || !locations.IsValid())
3843				break;
3844
3845			if (link.Read(string, stringLength) != B_OK)
3846				break;
3847			// Count UTF8 glyphs and make sure we have enough locations
3848			if ((int32)UTF8CountChars(string, stringLength) > glyphCount)
3849				break;
3850			if (link.Read(locations, glyphCount * sizeof(BPoint)) != B_OK)
3851				break;
3852			// Terminate the string
3853			string[stringLength] = '\0';
3854
3855			const SimpleTransform transform =
3856				fCurrentView->PenToScreenTransform();
3857			for (int32 i = 0; i < glyphCount; i++)
3858				transform.Apply(&locations[i]);
3859
3860			picture->WriteDrawString(string, stringLength, locations,
3861				glyphCount);
3862
3863			DrawingEngine* drawingEngine = fWindow->GetDrawingEngine();
3864			if (drawingEngine->LockParallelAccess()) {
3865				// Update pen location
3866				BPoint penLocation = drawingEngine->DrawStringDry(
3867					string, stringLength, locations);
3868
3869				fCurrentView->ScreenToPenTransform().Apply(&penLocation);
3870				fCurrentView->CurrentState()->SetPenLocation(penLocation);
3871
3872				drawingEngine->UnlockParallelAccess();
3873			}
3874
3875			break;
3876		}
3877
3878		case AS_STROKE_SHAPE:
3879		case AS_FILL_SHAPE:
3880		{
3881			BRect shapeFrame;
3882			int32 opCount;
3883			int32 ptCount;
3884
3885			link.Read<BRect>(&shapeFrame);
3886			link.Read<int32>(&opCount);
3887			link.Read<int32>(&ptCount);
3888
3889			BStackOrHeapArray<uint32, 512> opList(opCount);
3890			BStackOrHeapArray<BPoint, 512> ptList(ptCount);
3891			if (!opList.IsValid() || !ptList.IsValid()
3892				|| link.Read(opList, opCount * sizeof(uint32)) < B_OK
3893				|| link.Read(ptList, ptCount * sizeof(BPoint)) < B_OK) {
3894				break;
3895			}
3896			picture->WriteDrawShape(opCount, opList, ptCount,
3897				ptList, code == AS_FILL_SHAPE);
3898
3899			break;
3900		}
3901
3902		case AS_VIEW_DRAW_BITMAP:
3903		{
3904			ViewDrawBitmapInfo info;
3905			link.Read<ViewDrawBitmapInfo>(&info);
3906
3907			BReference<ServerBitmap> bitmap(App()->GetBitmap(info.bitmapToken), true);
3908			if (bitmap == NULL)
3909				break;
3910
3911			picture->WriteDrawBitmap(info.bitmapRect, info.viewRect,
3912				bitmap->Width(), bitmap->Height(), bitmap->BytesPerRow(),
3913				bitmap->ColorSpace(), info.options, bitmap->Bits(),
3914				bitmap->BitsLength());
3915
3916			break;
3917		}
3918
3919		case AS_VIEW_DRAW_PICTURE:
3920		{
3921			int32 token;
3922			link.Read<int32>(&token);
3923
3924			BPoint where;
3925			if (link.Read<BPoint>(&where) == B_OK) {
3926				BReference<ServerPicture> pictureToDraw(App()->GetPicture(token), true);
3927				if (pictureToDraw != NULL) {
3928					// We need to make a copy of the picture, since it can
3929					// change after it has been drawn
3930					BReference<ServerPicture> copy(App()->CreatePicture(pictureToDraw), true);
3931					picture->NestPicture(copy);
3932					picture->WriteDrawPicture(where, copy->Token());
3933				}
3934			}
3935			break;
3936		}
3937
3938		case AS_VIEW_SET_CLIP_REGION:
3939		{
3940			int32 rectCount;
3941			status_t status = link.Read<int32>(&rectCount);
3942				// a negative count means no
3943				// region for the current draw state,
3944				// but an *empty* region is actually valid!
3945				// even if it means no drawing is allowed
3946
3947			if (status < B_OK)
3948				break;
3949
3950			if (rectCount >= 0) {
3951				// we are supposed to set the clipping region
3952				BRegion region;
3953				if (rectCount > 0 && link.ReadRegion(&region) < B_OK)
3954					break;
3955				picture->WriteSetClipping(region);
3956			} else {
3957				// we are supposed to clear the clipping region
3958				picture->WriteClearClipping();
3959			}
3960			break;
3961		}
3962
3963		case AS_VIEW_CLIP_TO_PICTURE:
3964		{
3965			int32 pictureToken;
3966			BPoint where;
3967			bool inverse = false;
3968
3969			link.Read<int32>(&pictureToken);
3970			if (pictureToken < 0)
3971				break;
3972
3973			link.Read<BPoint>(&where);
3974			if (link.Read<bool>(&inverse) != B_OK)
3975				break;
3976
3977			BReference<ServerPicture> pictureToClip(fServerApp->GetPicture(pictureToken), true);
3978			if (pictureToClip != NULL) {
3979				// We need to make a copy of the picture, since it can
3980				// change after it has been drawn
3981				BReference<ServerPicture> copy(App()->CreatePicture(pictureToClip), true);
3982				picture->NestPicture(copy);
3983				picture->WriteClipToPicture(copy->Token(), where, inverse);
3984			}
3985			break;
3986		}
3987
3988		case AS_VIEW_CLIP_TO_RECT:
3989		{
3990			bool inverse;
3991			BRect rect;
3992			link.Read<bool>(&inverse);
3993			link.Read<BRect>(&rect);
3994			picture->WriteClipToRect(rect, inverse);
3995
3996			break;
3997		}
3998
3999		case AS_VIEW_CLIP_TO_SHAPE:
4000		{
4001			bool inverse;
4002			link.Read<bool>(&inverse);
4003
4004			shape_data shape;
4005			link.Read<int32>(&shape.opCount);
4006			link.Read<int32>(&shape.ptCount);
4007			shape.opSize = shape.opCount * sizeof(uint32);
4008			shape.ptSize = shape.ptCount * sizeof(BPoint);
4009			shape.opList = new(nothrow) uint32[shape.opCount];
4010			shape.ptList = new(nothrow) BPoint[shape.ptCount];
4011			if (link.Read(shape.opList, shape.opSize) >= B_OK
4012				&& link.Read(shape.ptList, shape.ptSize) >= B_OK) {
4013				picture->WriteClipToShape(shape.opCount, shape.opList,
4014					shape.ptCount, shape.ptList, inverse);
4015			}
4016
4017			delete[] shape.opList;
4018			delete[] shape.ptList;
4019			break;
4020		}
4021
4022		case AS_VIEW_BEGIN_PICTURE:
4023		{
4024			BReference <ServerPicture> newPicture(App()->CreatePicture(), true);
4025			if (newPicture != NULL) {
4026				newPicture->PushPicture(picture);
4027				newPicture->SyncState(fCurrentView);
4028				fCurrentView->SetPicture(newPicture);
4029			}
4030			break;
4031		}
4032
4033		case AS_VIEW_APPEND_TO_PICTURE:
4034		{
4035			int32 token;
4036			link.Read<int32>(&token);
4037
4038			BReference<ServerPicture> appendPicture(App()->GetPicture(token), true);
4039			if (appendPicture != NULL) {
4040				//picture->SyncState(fCurrentView);
4041				appendPicture->AppendPicture(picture);
4042			}
4043
4044			fCurrentView->SetPicture(appendPicture);
4045
4046			break;
4047		}
4048
4049		case AS_VIEW_END_PICTURE:
4050		{
4051			BReference<ServerPicture> poppedPicture(picture->PopPicture(), true);
4052			fCurrentView->SetPicture(poppedPicture);
4053
4054			fLink.StartMessage(B_OK);
4055			fLink.Attach<int32>(picture->Token());
4056			fLink.Flush();
4057			return true;
4058		}
4059
4060		case AS_VIEW_BEGIN_LAYER:
4061		{
4062			uint8 opacity;
4063			link.Read<uint8>(&opacity);
4064
4065			Layer* layer = dynamic_cast<Layer*>(picture);
4066			if (layer == NULL)
4067				break;
4068
4069			Layer* nextLayer = new(std::nothrow) Layer(opacity);
4070			if (nextLayer == NULL)
4071				break;
4072
4073			if (opacity != 255) {
4074				fCurrentView->CurrentState()->SetDrawingMode(B_OP_ALPHA);
4075				fCurrentView->CurrentState()->SetBlendingMode(B_PIXEL_ALPHA,
4076					B_ALPHA_COMPOSITE);
4077				fCurrentView->CurrentState()->SetDrawingModeLocked(true);
4078			}
4079
4080			nextLayer->PushLayer(layer);
4081			fCurrentView->SetPicture(nextLayer);
4082			break;
4083		}
4084
4085		case AS_VIEW_END_LAYER:
4086		{
4087			Layer* layer = dynamic_cast<Layer*>(picture);
4088			if (layer == NULL)
4089				break;
4090
4091			BReference<Layer> previousLayer(layer->PopLayer(), true);
4092			if (previousLayer == NULL) {
4093				// End last layer
4094				return false;
4095			}
4096			fCurrentView->SetPicture(previousLayer);
4097
4098			previousLayer->WriteBlendLayer(layer);
4099			break;
4100		}
4101
4102/*
4103		case AS_VIEW_SET_BLENDING_MODE:
4104		{
4105			ViewBlendingModeInfo info;
4106			link.Read<ViewBlendingModeInfo>(&info);
4107
4108			picture->BeginOp(B_PIC_SET_BLENDING_MODE);
4109			picture->AddInt16((int16)info.sourceAlpha);
4110			picture->AddInt16((int16)info.alphaFunction);
4111			picture->EndOp();
4112
4113			fCurrentView->CurrentState()->SetBlendingMode(info.sourceAlpha,
4114				info.alphaFunction);
4115			fWindow->GetDrawingEngine()->SetBlendingMode(info.sourceAlpha,
4116				info.alphaFunction);
4117			break;
4118		}*/
4119		default:
4120			return false;
4121	}
4122
4123	if (link.NeedsReply()) {
4124		fLink.StartMessage(B_ERROR);
4125		fLink.Flush();
4126	}
4127	return true;
4128}
4129
4130
4131/*!	\brief Message-dispatching loop for the ServerWindow
4132
4133	Watches the ServerWindow's message port and dispatches as necessary
4134*/
4135void
4136ServerWindow::_MessageLooper()
4137{
4138	// Send a reply to our window - it is expecting fMessagePort
4139	// port and some other info.
4140
4141	fLink.StartMessage(B_OK);
4142	fLink.Attach<port_id>(fMessagePort);
4143
4144	int32 minWidth, maxWidth, minHeight, maxHeight;
4145	fWindow->GetSizeLimits(&minWidth, &maxWidth, &minHeight, &maxHeight);
4146
4147	fLink.Attach<BRect>(fWindow->Frame());
4148	fLink.Attach<float>((float)minWidth);
4149	fLink.Attach<float>((float)maxWidth);
4150	fLink.Attach<float>((float)minHeight);
4151	fLink.Attach<float>((float)maxHeight);
4152	fLink.Flush();
4153
4154	BPrivate::LinkReceiver& receiver = fLink.Receiver();
4155	bool quitLoop = false;
4156
4157	while (!quitLoop) {
4158		//STRACE(("info: ServerWindow::MonitorWin listening on port %ld.\n",
4159		//	fMessagePort));
4160
4161		int32 code;
4162		status_t status = receiver.GetNextMessage(code);
4163		if (status != B_OK) {
4164			// that shouldn't happen, it's our port
4165			printf("Someone deleted our message port!\n");
4166
4167			// try to let our client die happily
4168			NotifyQuitRequested();
4169			break;
4170		}
4171
4172#ifdef PROFILE_MESSAGE_LOOP
4173		bigtime_t start = system_time();
4174#endif
4175
4176		Lock();
4177
4178#ifdef PROFILE_MESSAGE_LOOP
4179		bigtime_t diff = system_time() - start;
4180		if (diff > 10000) {
4181			printf("ServerWindow %s: lock acquisition took %" B_PRId64 " usecs\n",
4182				Title(), diff);
4183		}
4184#endif
4185
4186		int32 messagesProcessed = 0;
4187		bigtime_t processingStart = system_time();
4188		bool lockedDesktopSingleWindow = false;
4189
4190		while (true) {
4191			if (code == AS_DELETE_WINDOW || code == kMsgQuitLooper) {
4192				// this means the client has been killed
4193				DTRACE(("ServerWindow %s received 'AS_DELETE_WINDOW' message "
4194					"code\n", Title()));
4195
4196				if (code == AS_DELETE_WINDOW) {
4197					fLink.StartMessage(B_OK);
4198					fLink.Flush();
4199				}
4200
4201				if (lockedDesktopSingleWindow)
4202					fDesktop->UnlockSingleWindow();
4203
4204				quitLoop = true;
4205
4206				// ServerWindow's destructor takes care of pulling this object
4207				// off the desktop.
4208				ASSERT(fWindow->IsHidden());
4209				break;
4210			}
4211
4212			// Acquire the appropriate lock
4213			bool needsAllWindowsLocked = _MessageNeedsAllWindowsLocked(code);
4214			if (needsAllWindowsLocked) {
4215				// We may already still hold the read-lock from the previous
4216				// inner-loop iteration.
4217				if (lockedDesktopSingleWindow) {
4218					fDesktop->UnlockSingleWindow();
4219					lockedDesktopSingleWindow = false;
4220				}
4221				fDesktop->LockAllWindows();
4222			} else {
4223				// We never keep the write-lock across inner-loop iterations,
4224				// so there is nothing else to do besides read-locking unless
4225				// we already have the read-lock from the previous iteration.
4226				if (!lockedDesktopSingleWindow) {
4227					fDesktop->LockSingleWindow();
4228					lockedDesktopSingleWindow = true;
4229				}
4230			}
4231
4232			if (atomic_and(&fRedrawRequested, 0) != 0) {
4233#ifdef PROFILE_MESSAGE_LOOP
4234				bigtime_t redrawStart = system_time();
4235#endif
4236				fWindow->RedrawDirtyRegion();
4237#ifdef PROFILE_MESSAGE_LOOP
4238				diff = system_time() - redrawStart;
4239				atomic_add(&sRedrawProcessingTime.count, 1);
4240# ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
4241				atomic_add64(&sRedrawProcessingTime.time, diff);
4242# else
4243				sRedrawProcessingTime.time += diff;
4244# endif
4245#endif
4246			}
4247
4248#ifdef PROFILE_MESSAGE_LOOP
4249			bigtime_t dispatchStart = system_time();
4250#endif
4251			_DispatchMessage(code, receiver);
4252
4253#ifdef PROFILE_MESSAGE_LOOP
4254			if (code >= 0 && code < AS_LAST_CODE) {
4255				diff = system_time() - dispatchStart;
4256				atomic_add(&sMessageProfile[code].count, 1);
4257#ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
4258				atomic_add64(&sMessageProfile[code].time, diff);
4259#else
4260				sMessageProfile[code].time += diff;
4261#endif
4262				if (diff > 10000) {
4263					printf("ServerWindow %s: message %" B_PRId32 " took %"
4264						B_PRId64 " usecs\n", Title(), code, diff);
4265				}
4266			}
4267#endif
4268
4269			if (needsAllWindowsLocked)
4270				fDesktop->UnlockAllWindows();
4271
4272			// Only process up to 70 waiting messages at once (we have the
4273			// Desktop locked), but don't hold the lock longer than 10 ms
4274			if (!receiver.HasMessages() || ++messagesProcessed > 70
4275				|| system_time() - processingStart > 10000) {
4276				if (lockedDesktopSingleWindow)
4277					fDesktop->UnlockSingleWindow();
4278				break;
4279			}
4280
4281			// next message
4282			status_t status = receiver.GetNextMessage(code);
4283			if (status != B_OK) {
4284				// that shouldn't happen, it's our port
4285				printf("Someone deleted our message port!\n");
4286				if (lockedDesktopSingleWindow)
4287					fDesktop->UnlockSingleWindow();
4288
4289				// try to let our client die happily
4290				NotifyQuitRequested();
4291				break;
4292			}
4293		}
4294
4295		Unlock();
4296	}
4297
4298	// We were asked to quit the message loop - either on request or because of
4299	// an error.
4300	Quit();
4301		// does not return
4302}
4303
4304
4305void
4306ServerWindow::ScreenChanged(const BMessage* message)
4307{
4308	SendMessageToClient(message);
4309
4310	if (fDirectWindowInfo.IsSet() && fDirectWindowInfo->IsFullScreen())
4311		_ResizeToFullScreen();
4312}
4313
4314
4315status_t
4316ServerWindow::SendMessageToClient(const BMessage* msg, int32 target) const
4317{
4318	if (target == B_NULL_TOKEN)
4319		target = fClientToken;
4320
4321	BMessenger reply;
4322	BMessage::Private messagePrivate((BMessage*)msg);
4323	return messagePrivate.SendMessage(fClientLooperPort, fClientTeam, target,
4324		0, false, reply);
4325}
4326
4327
4328Window*
4329ServerWindow::MakeWindow(BRect frame, const char* name,
4330	window_look look, window_feel feel, uint32 flags, uint32 workspace)
4331{
4332	// The non-offscreen ServerWindow uses the DrawingEngine instance from
4333	// the desktop.
4334	return new(std::nothrow) ::Window(frame, name, look, feel, flags,
4335		workspace, this, fDesktop->HWInterface()->CreateDrawingEngine());
4336}
4337
4338
4339void
4340ServerWindow::HandleDirectConnection(int32 bufferState, int32 driverState)
4341{
4342	ASSERT_MULTI_LOCKED(fDesktop->WindowLocker());
4343
4344	if (!fDirectWindowInfo.IsSet())
4345		return;
4346
4347	STRACE(("HandleDirectConnection(bufferState = %" B_PRId32 ", driverState = "
4348		"%" B_PRId32 ")\n", bufferState, driverState));
4349
4350	status_t status = fDirectWindowInfo->SetState(
4351		(direct_buffer_state)bufferState, (direct_driver_state)driverState,
4352		fDesktop->HWInterface()->FrontBuffer(), fWindow->Frame(),
4353		fWindow->VisibleContentRegion());
4354
4355	if (status != B_OK) {
4356		char errorString[256];
4357		snprintf(errorString, sizeof(errorString),
4358			"%s killed for a problem in DirectConnected(): %s",
4359			App()->Signature(), strerror(status));
4360		syslog(LOG_ERR, errorString);
4361
4362		// The client application didn't release the semaphore
4363		// within the given timeout. Or something else went wrong.
4364		// Deleting this member should make it crash.
4365		fDirectWindowInfo.Unset();
4366	} else if ((bufferState & B_DIRECT_MODE_MASK) == B_DIRECT_START)
4367		fIsDirectlyAccessing = true;
4368	else if ((bufferState & B_DIRECT_MODE_MASK) == B_DIRECT_STOP)
4369		fIsDirectlyAccessing = false;
4370}
4371
4372
4373void
4374ServerWindow::_SetCurrentView(View* view)
4375{
4376	if (fCurrentView == view)
4377		return;
4378
4379	fCurrentView = view;
4380	fCurrentDrawingRegionValid = false;
4381	_UpdateDrawState(fCurrentView);
4382
4383#if 0
4384#if DELAYED_BACKGROUND_CLEARING
4385	if (fCurrentView && fCurrentView->IsBackgroundDirty()
4386		&& fWindow->InUpdate()) {
4387		DrawingEngine* drawingEngine = fWindow->GetDrawingEngine();
4388		if (drawingEngine->LockParallelAccess()) {
4389			fWindow->GetEffectiveDrawingRegion(fCurrentView,
4390				fCurrentDrawingRegion);
4391			fCurrentDrawingRegionValid = true;
4392			BRegion dirty(fCurrentDrawingRegion);
4393
4394			BRegion content;
4395			fWindow->GetContentRegion(&content);
4396
4397			fCurrentView->Draw(drawingEngine, &dirty, &content, false);
4398
4399			drawingEngine->UnlockParallelAccess();
4400		}
4401	}
4402#endif
4403#endif // 0
4404}
4405
4406
4407void
4408ServerWindow::_UpdateDrawState(View* view)
4409{
4410	// switch the drawing state
4411	// TODO: is it possible to scroll a view while it
4412	// is being drawn? probably not... otherwise the
4413	// "offsets" passed below would need to be updated again
4414	DrawingEngine* drawingEngine = fWindow->GetDrawingEngine();
4415	if (view != NULL && drawingEngine != NULL) {
4416		BPoint leftTop(0, 0);
4417		if (view->GetAlphaMask() != NULL) {
4418			view->LocalToScreenTransform().Apply(&leftTop);
4419			view->GetAlphaMask()->SetCanvasGeometry(leftTop, view->Bounds());
4420			leftTop = BPoint(0, 0);
4421		}
4422		view->PenToScreenTransform().Apply(&leftTop);
4423		drawingEngine->SetDrawState(view->CurrentState(), leftTop.x, leftTop.y);
4424	}
4425}
4426
4427
4428void
4429ServerWindow::_UpdateCurrentDrawingRegion()
4430{
4431	if (!fCurrentDrawingRegionValid
4432		|| fWindow->DrawingRegionChanged(fCurrentView)) {
4433		fWindow->GetEffectiveDrawingRegion(fCurrentView, fCurrentDrawingRegion);
4434		fCurrentDrawingRegionValid = true;
4435	}
4436}
4437
4438
4439bool
4440ServerWindow::_MessageNeedsAllWindowsLocked(uint32 code) const
4441{
4442	switch (code) {
4443		case AS_SET_WINDOW_TITLE:
4444		case AS_ADD_TO_SUBSET:
4445		case AS_REMOVE_FROM_SUBSET:
4446		case AS_VIEW_CREATE_ROOT:
4447		case AS_VIEW_CREATE:
4448		case AS_SEND_BEHIND:
4449		case AS_SET_LOOK:
4450		case AS_SET_FEEL:
4451		case AS_SET_FLAGS:
4452		case AS_SET_WORKSPACES:
4453		case AS_WINDOW_MOVE:
4454		case AS_WINDOW_RESIZE:
4455		case AS_SET_SIZE_LIMITS:
4456		case AS_SYSTEM_FONT_CHANGED:
4457		case AS_SET_DECORATOR_SETTINGS:
4458		case AS_GET_MOUSE:
4459		case AS_DIRECT_WINDOW_SET_FULLSCREEN:
4460//		case AS_VIEW_SET_EVENT_MASK:
4461//		case AS_VIEW_SET_MOUSE_EVENT_MASK:
4462		case AS_TALK_TO_DESKTOP_LISTENER:
4463			return true;
4464		default:
4465			return false;
4466	}
4467}
4468
4469
4470void
4471ServerWindow::_ResizeToFullScreen()
4472{
4473	BRect screenFrame;
4474
4475	{
4476		AutoReadLocker _(fDesktop->ScreenLocker());
4477		const Screen* screen = fWindow->Screen();
4478		if (screen == NULL)
4479			return;
4480
4481		screenFrame = fWindow->Screen()->Frame();
4482	}
4483
4484	fDesktop->MoveWindowBy(fWindow.Get(),
4485		screenFrame.left - fWindow->Frame().left,
4486		screenFrame.top - fWindow->Frame().top);
4487	fDesktop->ResizeWindowBy(fWindow.Get(),
4488		screenFrame.Width() - fWindow->Frame().Width(),
4489		screenFrame.Height() - fWindow->Frame().Height());
4490}
4491
4492
4493status_t
4494ServerWindow::_EnableDirectWindowMode()
4495{
4496	if (fDirectWindowInfo.IsSet()) {
4497		// already in direct window mode
4498		return B_ERROR;
4499	}
4500
4501	if (fDesktop->HWInterface()->FrontBuffer() == NULL) {
4502		// direct window mode not supported
4503		return B_UNSUPPORTED;
4504	}
4505
4506	fDirectWindowInfo.SetTo(new(std::nothrow) DirectWindowInfo);
4507	if (!fDirectWindowInfo.IsSet())
4508		return B_NO_MEMORY;
4509
4510	status_t status = fDirectWindowInfo->InitCheck();
4511	if (status != B_OK) {
4512		fDirectWindowInfo.Unset();
4513
4514		return status;
4515	}
4516
4517	return B_OK;
4518}
4519
4520
4521void
4522ServerWindow::_DirectWindowSetFullScreen(bool enable)
4523{
4524	window_feel feel = kWindowScreenFeel;
4525
4526	if (enable) {
4527		fDesktop->HWInterface()->SetCursorVisible(false);
4528
4529		fDirectWindowInfo->EnableFullScreen(fWindow->Frame(), fWindow->Feel());
4530		_ResizeToFullScreen();
4531	} else {
4532		const BRect& originalFrame = fDirectWindowInfo->OriginalFrame();
4533
4534		fDirectWindowInfo->DisableFullScreen();
4535
4536		// Resize window back to its original size
4537		fDesktop->MoveWindowBy(fWindow.Get(),
4538			originalFrame.left - fWindow->Frame().left,
4539			originalFrame.top - fWindow->Frame().top);
4540		fDesktop->ResizeWindowBy(fWindow.Get(),
4541			originalFrame.Width() - fWindow->Frame().Width(),
4542			originalFrame.Height() - fWindow->Frame().Height());
4543
4544		fDesktop->HWInterface()->SetCursorVisible(true);
4545	}
4546
4547	fDesktop->SetWindowFeel(fWindow.Get(), feel);
4548}
4549