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