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