xref: /haiku/src/servers/app/ServerWindow.cpp (revision b028e77473189065f2baefc6f5e10d451cf591e2)
1 /*
2  * Copyright 2001-2007, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		DarkWyrm <bpmagic@columbus.rr.com>
7  *		Adrian Oanca <adioanca@gmail.com>
8  *		Stephan Aßmus <superstippi@gmx.de>
9  *		Stefano Ceccherini (burton666@libero.it)
10  *		Axel Dörfler, axeld@pinc-software.de
11  */
12 
13 /*!
14 	\class ServerWindow
15 	\brief Shadow BWindow class
16 
17 	A ServerWindow handles all the intraserver tasks required of it by its BWindow. There are
18 	too many tasks to list as being done by them, but they include handling View transactions,
19 	coordinating and linking a window's WindowLayer half with its messaging half, dispatching
20 	mouse and key events from the server to its window, and other such things.
21 */
22 
23 
24 #include "ServerWindow.h"
25 
26 #include "AppServer.h"
27 #include "DebugInfoManager.h"
28 #include "Desktop.h"
29 #include "DrawingEngine.h"
30 #include "HWInterface.h"
31 #include "Overlay.h"
32 #include "ProfileMessageSupport.h"
33 #include "RAMLinkMsgReader.h"
34 #include "RenderingBuffer.h"
35 #include "ServerApp.h"
36 #include "ServerBitmap.h"
37 #include "ServerPicture.h"
38 #include "ServerProtocol.h"
39 #include "WindowLayer.h"
40 #include "WorkspacesLayer.h"
41 
42 #include "clipping.h"
43 
44 #include <DirectWindowPrivate.h>
45 #include <MessagePrivate.h>
46 #include <PortLink.h>
47 #include <WindowInfo.h>
48 #include <WindowPrivate.h>
49 
50 #include <AppDefs.h>
51 #include <Autolock.h>
52 #include <DirectWindow.h>
53 #include <TokenSpace.h>
54 #include <View.h>
55 
56 #include <new>
57 
58 using std::nothrow;
59 
60 //#define TRACE_SERVER_WINDOW
61 //#define TRACE_SERVER_WINDOW_MESSAGES
62 //#define PROFILE_MESSAGE_LOOP
63 
64 
65 #ifdef TRACE_SERVER_WINDOW
66 #	include <stdio.h>
67 #	define STRACE(x) printf x
68 #else
69 #	define STRACE(x) ;
70 #endif
71 
72 #ifdef TRACE_SERVER_WINDOW_MESSAGES
73 #	include <stdio.h>
74 #	define DTRACE(x) printf x
75 #else
76 #	define DTRACE(x) ;
77 #endif
78 
79 #ifdef PROFILE_MESSAGE_LOOP
80 struct profile { int32 code; int32 count; bigtime_t time; };
81 static profile sMessageProfile[AS_LAST_CODE];
82 static profile sRedrawProcessingTime;
83 //static profile sNextMessageTime;
84 #endif
85 
86 
87 struct direct_window_data {
88 	direct_window_data();
89 	~direct_window_data();
90 
91 	status_t InitCheck() const;
92 
93 	sem_id	sem;
94 	sem_id	sem_ack;
95 	area_id	area;
96 	bool	started;
97 	int	next_buffer_state;
98 	direct_buffer_info *buffer_info;
99 };
100 
101 
102 direct_window_data::direct_window_data()
103 	:
104 	sem(-1),
105 	sem_ack(-1),
106 	area(-1),
107 	started(false),
108 	next_buffer_state(0),
109 	buffer_info(NULL)
110 {
111 	area = create_area("direct area", (void **)&buffer_info,
112 		B_ANY_ADDRESS, B_PAGE_SIZE, B_NO_LOCK, B_READ_WRITE);
113 
114 	sem = create_sem(0, "direct sem");
115 	sem_ack = create_sem(0, "direct sem ack");
116 }
117 
118 
119 direct_window_data::~direct_window_data()
120 {
121 	// this should make the client die in case it's still running
122 	buffer_info->bits = NULL;
123 	buffer_info->bytes_per_row = 0;
124 
125 	delete_area(area);
126 	delete_sem(sem);
127 	delete_sem(sem_ack);
128 }
129 
130 
131 status_t
132 direct_window_data::InitCheck() const
133 {
134 	if (area < B_OK)
135 		return area;
136 	if (sem < B_OK)
137 		return sem;
138 	if (sem_ack < B_OK)
139 		return sem_ack;
140 
141 	return B_OK;
142 }
143 
144 
145 //	#pragma mark -
146 
147 
148 /*!
149 	Sets up the basic BWindow counterpart - you have to call Init() before
150 	you can actually use it, though.
151 */
152 ServerWindow::ServerWindow(const char *title, ServerApp *app,
153 	port_id clientPort, port_id looperPort, int32 clientToken)
154 	: MessageLooper(title && *title ? title : "Unnamed Window"),
155 	fTitle(NULL),
156 	fDesktop(app->GetDesktop()),
157 	fServerApp(app),
158 	fWindowLayer(NULL),
159 	fWindowAddedToDesktop(false),
160 
161 	fClientTeam(app->ClientTeam()),
162 
163 	fMessagePort(-1),
164 	fClientReplyPort(clientPort),
165 	fClientLooperPort(looperPort),
166 
167 	fClientToken(clientToken),
168 
169 	fCurrentLayer(NULL),
170 	fCurrentDrawingRegion(),
171 	fCurrentDrawingRegionValid(false),
172 
173 	fDirectWindowData(NULL)
174 {
175 	STRACE(("ServerWindow(%s)::ServerWindow()\n", title));
176 
177 	SetTitle(title);
178 	fServerToken = BPrivate::gDefaultTokens.NewToken(B_SERVER_TOKEN, this);
179 
180 	BMessenger::Private(fFocusMessenger).SetTo(fClientTeam,
181 		looperPort, B_PREFERRED_TOKEN);
182 	BMessenger::Private(fHandlerMessenger).SetTo(fClientTeam,
183 		looperPort, clientToken);
184 
185 	fEventTarget.SetTo(fFocusMessenger);
186 
187 	fDeathSemaphore = create_sem(0, "window death");
188 }
189 
190 #ifdef PROFILE_MESSAGE_LOOP
191 static int
192 compare_message_profiles(const void* _a, const void* _b)
193 {
194 	profile* a = (profile*)*(void**)_a;
195 	profile* b = (profile*)*(void**)_b;
196 	if (a->time < b->time)
197 		return 1;
198 	if (a->time > b->time)
199 		return -1;
200 	return 0;
201 }
202 #endif
203 
204 
205 //! Tears down all connections the main app_server objects, and deletes some internals.
206 ServerWindow::~ServerWindow()
207 {
208 	STRACE(("ServerWindow(%s@%p):~ServerWindow()\n", fTitle, this));
209 
210 	if (!fWindowLayer->IsOffscreenWindow()) {
211 		fWindowAddedToDesktop = false;
212 		fDesktop->RemoveWindow(fWindowLayer);
213 	}
214 
215 	if (App() != NULL)
216 		App()->RemoveWindow(this);
217 
218 	delete fWindowLayer;
219 
220 	free(fTitle);
221 	delete_port(fMessagePort);
222 
223 	BPrivate::gDefaultTokens.RemoveToken(fServerToken);
224 
225 	delete fDirectWindowData;
226 	STRACE(("ServerWindow(%p) will exit NOW\n", this));
227 
228 	delete_sem(fDeathSemaphore);
229 
230 #ifdef PROFILE_MESSAGE_LOOP
231 	BList profiles;
232 	for (int32 i = 0; i < AS_LAST_CODE; i++) {
233 		if (sMessageProfile[i].count == 0)
234 			continue;
235 		sMessageProfile[i].code = i;
236 		profiles.AddItem(&sMessageProfile[i]);
237 	}
238 
239 	profiles.SortItems(compare_message_profiles);
240 
241 	BString codeName;
242 	int32 count = profiles.CountItems();
243 	for (int32 i = 0; i < count; i++) {
244 		profile* p = (profile*)profiles.ItemAtFast(i);
245 		string_for_message_code(p->code, codeName);
246 		printf("[%s] called %ld times, %g secs (%Ld usecs per call)\n",
247 			codeName.String(), p->count, p->time / 1000000.0,
248 			p->time / p->count);
249 	}
250 	if (sRedrawProcessingTime.count > 0) {
251 		printf("average redraw processing time: %g secs, count: %ld (%lld usecs per call)\n",
252 			sRedrawProcessingTime.time / 1000000.0, sRedrawProcessingTime.count,
253 			sRedrawProcessingTime.time / sRedrawProcessingTime.count);
254 	}
255 //	if (sNextMessageTime.count > 0) {
256 //		printf("average NextMessage() time: %g secs, count: %ld (%lld usecs per call)\n",
257 //			sNextMessageTime.time / 1000000.0, sNextMessageTime.count,
258 //			sNextMessageTime.time / sNextMessageTime.count);
259 //	}
260 #endif
261 }
262 
263 
264 status_t
265 ServerWindow::Init(BRect frame, window_look look, window_feel feel,
266 	uint32 flags, uint32 workspace)
267 {
268 	if (!App()->AddWindow(this)) {
269 		fServerApp = NULL;
270 		return B_NO_MEMORY;
271 	}
272 
273 	if (fTitle == NULL)
274 		return B_NO_MEMORY;
275 
276 	// fMessagePort is the port to which the app sends messages for the server
277 	fMessagePort = create_port(100, fTitle);
278 	if (fMessagePort < B_OK)
279 		return fMessagePort;
280 
281 	fLink.SetSenderPort(fClientReplyPort);
282 	fLink.SetReceiverPort(fMessagePort);
283 
284 	// We cannot call MakeWindowLayer in the constructor, since it
285 	// is a virtual function!
286 	fWindowLayer = MakeWindowLayer(frame, fTitle, look, feel, flags, workspace);
287 	if (!fWindowLayer)
288 		return B_NO_MEMORY;
289 
290 	if (!fWindowLayer->IsOffscreenWindow()) {
291 		fDesktop->AddWindow(fWindowLayer);
292 		fWindowAddedToDesktop = true;
293 	}
294 
295 	return B_OK;
296 }
297 
298 
299 bool
300 ServerWindow::Run()
301 {
302 	if (!MessageLooper::Run())
303 		return false;
304 
305 	// Send a reply to our window - it is expecting fMessagePort
306 	// port and some other info
307 
308 	fLink.StartMessage(B_OK);
309 	fLink.Attach<port_id>(fMessagePort);
310 
311 	int32 minWidth, maxWidth, minHeight, maxHeight;
312 	fWindowLayer->GetSizeLimits(&minWidth, &maxWidth, &minHeight, &maxHeight);
313 
314 	fLink.Attach<BRect>(fWindowLayer->Frame());
315 	fLink.Attach<float>((float)minWidth);
316 	fLink.Attach<float>((float)maxWidth);
317 	fLink.Attach<float>((float)minHeight);
318 	fLink.Attach<float>((float)maxHeight);
319 	fLink.Flush();
320 
321 	return true;
322 }
323 
324 
325 void
326 ServerWindow::_PrepareQuit()
327 {
328 	if (fThread == find_thread(NULL)) {
329 		// make sure we're hidden
330 		fDesktop->LockSingleWindow();
331 		_Hide();
332 		fDesktop->UnlockSingleWindow();
333 	} else if (fThread >= B_OK)
334 		PostMessage(AS_HIDE_WINDOW);
335 }
336 
337 
338 void
339 ServerWindow::_GetLooperName(char* name, size_t length)
340 {
341 	const char *title = Title();
342 	if (title == NULL || !title[0])
343 		title = "Unnamed Window";
344 
345 	snprintf(name, length, "w:%ld:%s", ClientTeam(), title);
346 }
347 
348 
349 //! Forces the window layer to update its decorator
350 void
351 ServerWindow::ReplaceDecorator()
352 {
353 	if (!IsLocked())
354 		debugger("you must lock a ServerWindow object before calling ::ReplaceDecorator()\n");
355 
356 	STRACE(("ServerWindow %s: Replace Decorator\n", fTitle));
357 	//fWindowLayer->UpdateDecorator();
358 }
359 
360 
361 //! Shows the window's WindowLayer
362 void
363 ServerWindow::_Show()
364 {
365 	// NOTE: if you do something else, other than sending a port message, PLEASE lock
366 	STRACE(("ServerWindow %s: _Show\n", Title()));
367 
368 	if (fQuitting || !fWindowLayer->IsHidden() || fWindowLayer->IsOffscreenWindow())
369 		return;
370 
371 // TODO: race condition? maybe we need to dispatch a message to the desktop to show/hide us
372 // instead of doing it from this thread.
373 fDesktop->UnlockSingleWindow();
374 	fDesktop->ShowWindow(fWindowLayer);
375 fDesktop->LockSingleWindow();
376 
377 	if (fDirectWindowData != NULL)
378 		HandleDirectConnection(B_DIRECT_START | B_BUFFER_RESET);
379 }
380 
381 
382 //! Hides the window's WindowLayer
383 void
384 ServerWindow::_Hide()
385 {
386 	// NOTE: if you do something else, other than sending a port message, PLEASE lock
387 	STRACE(("ServerWindow %s: _Hide\n", Title()));
388 
389 	if (fWindowLayer->IsHidden() || fWindowLayer->IsOffscreenWindow())
390 		return;
391 
392 	if (fDirectWindowData != NULL)
393 		HandleDirectConnection(B_DIRECT_STOP);
394 
395 // TODO: race condition? maybe we need to dispatch a message to the desktop to show/hide us
396 // instead of doing it from this thread.
397 fDesktop->UnlockSingleWindow();
398 	fDesktop->HideWindow(fWindowLayer);
399 fDesktop->LockSingleWindow();
400 }
401 
402 
403 void
404 ServerWindow::RequestRedraw()
405 {
406 	PostMessage(AS_REDRAW, 0);
407 		// we don't care if this fails - it's only a notification, and if
408 		// it fails, there are obviously enough messages in the queue
409 		// already
410 
411 	atomic_add(&fRedrawRequested, 1);
412 }
413 
414 
415 void
416 ServerWindow::SetTitle(const char* newTitle)
417 {
418 	char* oldTitle = fTitle;
419 
420 	if (newTitle == NULL)
421 		newTitle = "";
422 
423 	fTitle = strdup(newTitle);
424 	if (fTitle == NULL) {
425 		// out of memory condition
426 		fTitle = oldTitle;
427 		return;
428 	}
429 
430 	free(oldTitle);
431 
432 	if (Thread() >= B_OK) {
433 		char name[B_OS_NAME_LENGTH];
434 		_GetLooperName(name, sizeof(name));
435 		rename_thread(Thread(), name);
436 	}
437 
438 	if (fWindowLayer != NULL) {
439 fDesktop->UnlockSingleWindow();
440 		fDesktop->SetWindowTitle(fWindowLayer, newTitle);
441 fDesktop->LockSingleWindow();
442 	}
443 }
444 
445 
446 //! Requests that the ServerWindow's BWindow quit
447 void
448 ServerWindow::NotifyQuitRequested()
449 {
450 	// NOTE: if you do something else, other than sending a port message,
451 	// PLEASE lock
452 	STRACE(("ServerWindow %s: Quit\n", fTitle));
453 
454 	BMessage msg(B_QUIT_REQUESTED);
455 	SendMessageToClient(&msg);
456 }
457 
458 
459 void
460 ServerWindow::NotifyMinimize(bool minimize)
461 {
462 	if (fWindowLayer->Feel() != B_NORMAL_WINDOW_FEEL)
463 		return;
464 
465 	// The client is responsible for the actual minimization
466 
467 	BMessage msg(B_MINIMIZE);
468 	msg.AddInt64("when", real_time_clock_usecs());
469 	msg.AddBool("minimize", minimize);
470 
471 	SendMessageToClient(&msg);
472 }
473 
474 
475 //! Sends a message to the client to perform a Zoom
476 void
477 ServerWindow::NotifyZoom()
478 {
479 	// NOTE: if you do something else, other than sending a port message,
480 	// PLEASE lock
481 	BMessage msg(B_ZOOM);
482 	SendMessageToClient(&msg);
483 }
484 
485 
486 void
487 ServerWindow::GetInfo(window_info& info)
488 {
489 	info.team = ClientTeam();
490 	info.server_token = ServerToken();
491 
492 	info.thread = Thread();
493 	info.client_token = ClientToken();
494 	info.client_port = fClientLooperPort;
495 	info.workspaces = fWindowLayer->Workspaces();
496 
497 	info.layer = 0; // ToDo: what is this???
498 	info.feel = fWindowLayer->Feel();
499 	info.flags = fWindowLayer->Flags();
500 	info.window_left = (int)floor(fWindowLayer->Frame().left);
501 	info.window_top = (int)floor(fWindowLayer->Frame().top);
502 	info.window_right = (int)floor(fWindowLayer->Frame().right);
503 	info.window_bottom = (int)floor(fWindowLayer->Frame().bottom);
504 
505 	info.show_hide_level = fWindowLayer->IsHidden() ? 1 : 0; // ???
506 	info.is_mini = fWindowLayer->IsMinimized();
507 }
508 
509 
510 void
511 ServerWindow::ResyncDrawState()
512 {
513 	_UpdateDrawState(fCurrentLayer);
514 }
515 
516 
517 /*!
518 	Returns the ServerWindow's WindowLayer, if it exists and has been
519 	added to the Desktop already.
520 	In other words, you cannot assume this method will always give you
521 	a valid pointer.
522 */
523 WindowLayer*
524 ServerWindow::Window() const
525 {
526 	// TODO: ensure desktop is locked!
527 	if (!fWindowAddedToDesktop)
528 		return NULL;
529 
530 	return fWindowLayer;
531 }
532 
533 
534 ViewLayer*
535 ServerWindow::_CreateLayerTree(BPrivate::LinkReceiver &link, ViewLayer **_parent)
536 {
537 	// NOTE: no need to check for a lock. This is a private method.
538 
539 	int32 token;
540 	BRect frame;
541 	uint32 resizeMask;
542 	uint32 eventMask;
543 	uint32 eventOptions;
544 	uint32 flags;
545 	bool hidden;
546 	int32 parentToken;
547 	char* name = NULL;
548 	rgb_color viewColor;
549 	BPoint scrollingOffset;
550 
551 	link.Read<int32>(&token);
552 	link.ReadString(&name);
553 	link.Read<BRect>(&frame);
554 	link.Read<BPoint>(&scrollingOffset);
555 	link.Read<uint32>(&resizeMask);
556 	link.Read<uint32>(&eventMask);
557 	link.Read<uint32>(&eventOptions);
558 	link.Read<uint32>(&flags);
559 	link.Read<bool>(&hidden);
560 	link.Read<rgb_color>(&viewColor);
561 	link.Read<int32>(&parentToken);
562 
563 	STRACE(("ServerWindow(%s)::_CreateLayerTree()-> layer %s, token %ld\n",
564 		fTitle, name, token));
565 
566 	ViewLayer* newLayer;
567 
568 	if (link.Code() == AS_LAYER_CREATE_ROOT
569 		&& (fWindowLayer->Flags() & kWorkspacesWindowFlag) != 0) {
570 		// this is a workspaces window!
571 		newLayer = new (nothrow) WorkspacesLayer(frame, scrollingOffset, name,
572 			token, resizeMask, flags);
573 	} else {
574 		newLayer = new (nothrow) ViewLayer(frame, scrollingOffset, name, token,
575 			resizeMask, flags);
576 	}
577 
578 	free(name);
579 
580 	if (newLayer == NULL)
581 		return NULL;
582 
583 	// there is no way of setting this, other than manually :-)
584 	newLayer->SetViewColor(viewColor);
585 	newLayer->SetHidden(hidden);
586 	newLayer->SetEventMask(eventMask, eventOptions);
587 
588 	if (eventMask != 0 || eventOptions != 0) {
589 		fDesktop->UnlockSingleWindow();
590 		fDesktop->EventDispatcher().AddListener(EventTarget(),
591 			newLayer->Token(), eventMask, eventOptions);
592 		fDesktop->LockSingleWindow();
593 	}
594 
595 	DesktopSettings settings(fDesktop);
596 	ServerFont font;
597 	settings.GetDefaultPlainFont(font);
598 	newLayer->CurrentState()->SetFont(font);
599 
600 	if (_parent) {
601 		ViewLayer *parent;
602 		if (App()->ViewTokens().GetToken(parentToken, B_HANDLER_TOKEN,
603 				(void**)&parent) != B_OK
604 			|| parent->Window()->ServerWindow() != this) {
605 			CRITICAL("View token not found!\n");
606 			parent = NULL;
607 		}
608 
609 		*_parent = parent;
610 	}
611 
612 	return newLayer;
613 }
614 
615 
616 /*!
617 	Dispatches all window messages, and those view messages that
618 	don't need a valid fCurrentLayer (ie. layer creation).
619 */
620 void
621 ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
622 {
623 	switch (code) {
624 		case AS_SHOW_WINDOW:
625 			STRACE(("ServerWindow %s: Message AS_SHOW_WINDOW\n", Title()));
626 			_Show();
627 			break;
628 
629 		case AS_HIDE_WINDOW:
630 			STRACE(("ServerWindow %s: Message AS_HIDE_WINDOW\n", Title()));
631 			_Hide();
632 			break;
633 
634 		case AS_MINIMIZE_WINDOW:
635 		{
636 			DTRACE(("ServerWindow %s: Message AS_MINIMIZE_WINDOW\n", Title()));
637 			int32 showLevel;
638 			bool minimize;
639 
640 			link.Read<bool>(&minimize);
641 			if (link.Read<int32>(&showLevel) == B_OK) {
642 				if (showLevel <= 0) {
643 					// window is currently hidden - ignore the minimize request
644 					break;
645 				}
646 
647 				if (minimize && !fWindowLayer->IsHidden())
648 					_Hide();
649 				else if (!minimize && fWindowLayer->IsHidden())
650 					_Show();
651 
652 				fWindowLayer->SetMinimized(minimize);
653 			}
654 			break;
655 		}
656 
657 		case AS_ACTIVATE_WINDOW:
658 		{
659 			DTRACE(("ServerWindow %s: Message AS_ACTIVATE_WINDOW: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
660 			bool activate = true;
661 
662 			link.Read<bool>(&activate);
663 
664 fDesktop->UnlockSingleWindow();
665 			if (activate)
666 				fDesktop->ActivateWindow(fWindowLayer);
667 			else
668 				fDesktop->SendWindowBehind(fWindowLayer, NULL);
669 fDesktop->LockSingleWindow();
670 			break;
671 		}
672 		case AS_SEND_BEHIND:
673 		{
674 			STRACE(("ServerWindow %s: Message AS_SEND_BEHIND\n", Title()));
675 			int32 token;
676 			team_id teamID;
677 			status_t status;
678 
679 			link.Read<int32>(&token);
680 			link.Read<team_id>(&teamID);
681 
682 			WindowLayer *behindOf;
683 			if ((behindOf = fDesktop->FindWindowLayerByClientToken(token, teamID)) != NULL) {
684 fDesktop->UnlockSingleWindow();
685 // TODO: there is a big race condition when we unlock here (window could be gone by now)!
686 				fDesktop->SendWindowBehind(fWindowLayer, behindOf);
687 fDesktop->LockSingleWindow();
688 				status = B_OK;
689 			} else
690 				status = B_NAME_NOT_FOUND;
691 
692 			fLink.StartMessage(status);
693 			fLink.Flush();
694 			break;
695 		}
696 
697 		case B_QUIT_REQUESTED:
698 			STRACE(("ServerWindow %s received quit request\n", Title()));
699 			NotifyQuitRequested();
700 			break;
701 
702 		case AS_ENABLE_UPDATES:
703 		{
704 			STRACE(("ServerWindow %s: Message AS_ENABLE_UPDATES unimplemented\n",
705 				Title()));
706 // TODO: AS_ENABLE_UPDATES
707 			//fWindowLayer->EnableUpdateRequests();
708 			break;
709 		}
710 		case AS_DISABLE_UPDATES:
711 		{
712 			STRACE(("ServerWindow %s: Message AS_DISABLE_UPDATES unimplemented\n",
713 				Title()));
714 // TODO: AS_DISABLE_UPDATES
715 			//fWindowLayer->DisableUpdateRequests();
716 			break;
717 		}
718 		case AS_NEEDS_UPDATE:
719 		{
720 			STRACE(("ServerWindow %s: Message AS_NEEDS_UPDATE\n", Title()));
721 			if (fWindowLayer->NeedsUpdate())
722 				fLink.StartMessage(B_OK);
723 			else
724 				fLink.StartMessage(B_ERROR);
725 			fLink.Flush();
726 			break;
727 		}
728 		case AS_SET_WINDOW_TITLE:
729 		{
730 			char* newTitle;
731 			if (link.ReadString(&newTitle) == B_OK) {
732 				SetTitle(newTitle);
733 				free(newTitle);
734 			}
735 			break;
736 		}
737 
738 		case AS_ADD_TO_SUBSET:
739 		{
740 			STRACE(("ServerWindow %s: Message AS_ADD_TO_SUBSET\n", Title()));
741 			status_t status = B_ERROR;
742 
743 			int32 token;
744 			if (link.Read<int32>(&token) == B_OK) {
745 				WindowLayer* windowLayer = fDesktop->FindWindowLayerByClientToken(
746 					token, App()->ClientTeam());
747 				if (windowLayer == NULL
748 					|| windowLayer->Feel() != B_NORMAL_WINDOW_FEEL) {
749 					status = B_BAD_VALUE;
750 				} else {
751 fDesktop->UnlockSingleWindow();
752 // TODO: there is a big race condition when we unlock here (window could be gone by now)!
753 					status = fDesktop->AddWindowToSubset(fWindowLayer, windowLayer)
754 						? B_OK : B_NO_MEMORY;
755 fDesktop->LockSingleWindow();
756 				}
757 			}
758 
759 			fLink.StartMessage(status);
760 			fLink.Flush();
761 			break;
762 		}
763 		case AS_REMOVE_FROM_SUBSET:
764 		{
765 			STRACE(("ServerWindow %s: Message AS_REM_FROM_SUBSET\n", Title()));
766 			status_t status = B_ERROR;
767 
768 			int32 token;
769 			if (link.Read<int32>(&token) == B_OK) {
770 				WindowLayer* windowLayer = fDesktop->FindWindowLayerByClientToken(
771 					token, App()->ClientTeam());
772 				if (windowLayer != NULL) {
773 fDesktop->UnlockSingleWindow();
774 // TODO: there is a big race condition when we unlock here (window could be gone by now)!
775 					fDesktop->RemoveWindowFromSubset(fWindowLayer, windowLayer);
776 fDesktop->LockSingleWindow();
777 					status = B_OK;
778 				} else
779 					status = B_BAD_VALUE;
780 			}
781 
782 			fLink.StartMessage(status);
783 			fLink.Flush();
784 			break;
785 		}
786 
787 		case AS_SET_LOOK:
788 		{
789 			STRACE(("ServerWindow %s: Message AS_SET_LOOK\n", Title()));
790 
791 			status_t status = B_ERROR;
792 			int32 look;
793 			if (link.Read<int32>(&look) == B_OK) {
794 				// test if look is valid
795 				status = WindowLayer::IsValidLook((window_look)look)
796 					? B_OK : B_BAD_VALUE;
797 			}
798 
799 			if (status == B_OK && !fWindowLayer->IsOffscreenWindow()) {
800 fDesktop->UnlockSingleWindow();
801 				fDesktop->SetWindowLook(fWindowLayer, (window_look)look);
802 fDesktop->LockSingleWindow();
803 			}
804 
805 			fLink.StartMessage(status);
806 			fLink.Flush();
807 			break;
808 		}
809 		case AS_SET_FEEL:
810 		{
811 			STRACE(("ServerWindow %s: Message AS_SET_FEEL\n", Title()));
812 
813 			status_t status = B_ERROR;
814 			int32 feel;
815 			if (link.Read<int32>(&feel) == B_OK) {
816 				// test if feel is valid
817 				status = WindowLayer::IsValidFeel((window_feel)feel)
818 					? B_OK : B_BAD_VALUE;
819 			}
820 
821 			if (status == B_OK && !fWindowLayer->IsOffscreenWindow()) {
822 fDesktop->UnlockSingleWindow();
823 				fDesktop->SetWindowFeel(fWindowLayer, (window_feel)feel);
824 fDesktop->LockSingleWindow();
825 			}
826 
827 			fLink.StartMessage(status);
828 			fLink.Flush();
829 			break;
830 		}
831 		case AS_SET_FLAGS:
832 		{
833 			STRACE(("ServerWindow %s: Message AS_SET_FLAGS\n", Title()));
834 
835 			status_t status = B_ERROR;
836 			uint32 flags;
837 			if (link.Read<uint32>(&flags) == B_OK) {
838 				// test if flags are valid
839 				status = (flags & ~WindowLayer::ValidWindowFlags()) == 0
840 					? B_OK : B_BAD_VALUE;
841 			}
842 
843 			if (status == B_OK && !fWindowLayer->IsOffscreenWindow()) {
844 fDesktop->UnlockSingleWindow();
845 				fDesktop->SetWindowFlags(fWindowLayer, flags);
846 fDesktop->LockSingleWindow();
847 			}
848 
849 			fLink.StartMessage(status);
850 			fLink.Flush();
851 			break;
852 		}
853 #if 0
854 		case AS_SET_ALIGNMENT:
855 		{
856 			// TODO: Implement AS_SET_ALIGNMENT
857 			STRACE(("ServerWindow %s: Message Set_Alignment unimplemented\n", Title()));
858 			break;
859 		}
860 		case AS_GET_ALIGNMENT:
861 		{
862 			// TODO: Implement AS_GET_ALIGNMENT
863 			STRACE(("ServerWindow %s: Message Get_Alignment unimplemented\n", Title()));
864 			break;
865 		}
866 #endif
867 		case AS_IS_FRONT_WINDOW:
868 			fLink.StartMessage(fDesktop->FrontWindow() == fWindowLayer ? B_OK : B_ERROR);
869 			fLink.Flush();
870 			break;
871 
872 		case AS_GET_WORKSPACES:
873 		{
874 			STRACE(("ServerWindow %s: Message AS_GET_WORKSPACES\n", Title()));
875 			fLink.StartMessage(B_OK);
876 			fLink.Attach<uint32>(fWindowLayer->Workspaces());
877 			fLink.Flush();
878 			break;
879 		}
880 		case AS_SET_WORKSPACES:
881 		{
882 			uint32 newWorkspaces;
883 			if (link.Read<uint32>(&newWorkspaces) != B_OK)
884 				break;
885 
886 			STRACE(("ServerWindow %s: Message AS_SET_WORKSPACES %lx\n",
887 				Title(), newWorkspaces));
888 
889 fDesktop->UnlockSingleWindow();
890 			fDesktop->SetWindowWorkspaces(fWindowLayer, newWorkspaces);
891 fDesktop->LockSingleWindow();
892 			break;
893 		}
894 		case AS_WINDOW_RESIZE:
895 		{
896 			float xResizeBy;
897 			float yResizeBy;
898 			link.Read<float>(&xResizeBy);
899 			if (link.Read<float>(&yResizeBy) != B_OK)
900 				break;
901 
902 			STRACE(("ServerWindow %s: Message AS_WINDOW_RESIZE %.1f, %.1f\n",
903 				Title(), xResizeBy, yResizeBy));
904 
905 			if (fWindowLayer->IsResizing()) {
906 				// While the user resizes the window, we ignore
907 				// pragmatically set window bounds
908 				fLink.StartMessage(B_BUSY);
909 			} else {
910 fDesktop->UnlockSingleWindow();
911 				fDesktop->ResizeWindowBy(fWindowLayer, xResizeBy, yResizeBy);
912 fDesktop->LockSingleWindow();
913 				fLink.StartMessage(B_OK);
914 			}
915 			fLink.Flush();
916 			break;
917 		}
918 		case AS_WINDOW_MOVE:
919 		{
920 			float xMoveBy;
921 			float yMoveBy;
922 			link.Read<float>(&xMoveBy);
923 			if (link.Read<float>(&yMoveBy) != B_OK)
924 				break;
925 
926 			STRACE(("ServerWindow %s: Message AS_WINDOW_MOVE: %.1f, %.1f\n",
927 				Title(), xMoveBy, yMoveBy));
928 
929 			if (fWindowLayer->IsDragging()) {
930 				// While the user moves the window, we ignore
931 				// pragmatically set window positions
932 				fLink.StartMessage(B_BUSY);
933 			} else {
934 fDesktop->UnlockSingleWindow();
935 				fDesktop->MoveWindowBy(fWindowLayer, xMoveBy, yMoveBy);
936 fDesktop->LockSingleWindow();
937 				fLink.StartMessage(B_OK);
938 			}
939 			fLink.Flush();
940 			break;
941 		}
942 		case AS_SET_SIZE_LIMITS:
943 		{
944 			// Attached Data:
945 			// 1) float minimum width
946 			// 2) float maximum width
947 			// 3) float minimum height
948 			// 4) float maximum height
949 
950 			// TODO: for now, move the client to int32 as well!
951 			int32 minWidth, maxWidth, minHeight, maxHeight;
952 			float value;
953 			link.Read<float>(&value);	minWidth = (int32)value;
954 			link.Read<float>(&value);	maxWidth = (int32)value;
955 			link.Read<float>(&value);	minHeight = (int32)value;
956 			link.Read<float>(&value);	maxHeight = (int32)value;
957 /*
958 			link.Read<int32>(&minWidth);
959 			link.Read<int32>(&maxWidth);
960 			link.Read<int32>(&minHeight);
961 			link.Read<int32>(&maxHeight);
962 */
963 			fDesktop->UnlockSingleWindow();
964 
965 			if (fDesktop->LockAllWindows()) {
966 				fWindowLayer->SetSizeLimits(minWidth, maxWidth,
967 					minHeight, maxHeight);
968 				fDesktop->UnlockAllWindows();
969 			}
970 
971 			fDesktop->LockSingleWindow();
972 
973 			// and now, sync the client to the limits that we were able to enforce
974 			fWindowLayer->GetSizeLimits(&minWidth, &maxWidth,
975 				&minHeight, &maxHeight);
976 
977 			fLink.StartMessage(B_OK);
978 			fLink.Attach<BRect>(fWindowLayer->Frame());
979 			fLink.Attach<float>((float)minWidth);
980 			fLink.Attach<float>((float)maxWidth);
981 			fLink.Attach<float>((float)minHeight);
982 			fLink.Attach<float>((float)maxHeight);
983 
984 			fLink.Flush();
985 			break;
986 		}
987 
988 		case AS_SET_DECORATOR_SETTINGS:
989 		{
990 			STRACE(("ServerWindow %s: Message AS_SET_DECORATOR_SETTINGS\n"));
991 
992 			int32 size;
993 			if (fWindowLayer && link.Read<int32>(&size) == B_OK) {
994 				char buffer[size];
995 				if (link.Read(buffer, size) == B_OK) {
996 					BMessage settings;
997 					if (settings.Unflatten(buffer) == B_OK) {
998 fDesktop->UnlockSingleWindow();
999 						fDesktop->SetWindowDecoratorSettings(fWindowLayer, settings);
1000 fDesktop->LockSingleWindow();
1001 					}
1002 				}
1003 			}
1004 			break;
1005 		}
1006 
1007 		case AS_GET_DECORATOR_SETTINGS:
1008 		{
1009 			STRACE(("ServerWindow %s: Message AS_GET_DECORATOR_SETTINGS\n"));
1010 
1011 			bool success = false;
1012 
1013 			BMessage settings;
1014 			if (fWindowLayer->GetDecoratorSettings(&settings)) {
1015 				int32 size = settings.FlattenedSize();
1016 				char buffer[size];
1017 				if (settings.Flatten(buffer, size) == B_OK) {
1018 					success = true;
1019 					fLink.StartMessage(B_OK);
1020 					fLink.Attach<int32>(size);
1021 					fLink.Attach(buffer, size);
1022 				}
1023 			}
1024 
1025 			if (!success)
1026 				fLink.StartMessage(B_ERROR);
1027 
1028 			fLink.Flush();
1029 			break;
1030 		}
1031 
1032 		case AS_REDRAW:
1033 			// Nothing to do here - the redraws are actually handled by looking
1034 			// at the fRedrawRequested member variable in _MessageLooper().
1035 			break;
1036 
1037 		case AS_SYNC:
1038 			// the synchronisation works by the fact that the client
1039 			// window is waiting for this reply, after having received it,
1040 			// client and server queues are in sync (earlier, the client
1041 			// may have pushed drawing commands at the server and now it
1042 			// knows they have all been carried out)
1043 			fLink.StartMessage(B_OK);
1044 			fLink.Flush();
1045 			break;
1046 
1047 		case AS_BEGIN_UPDATE:
1048 			DTRACE(("ServerWindowo %s: AS_BEGIN_UPDATE\n", Title()));
1049 			fWindowLayer->BeginUpdate(fLink);
1050 			break;
1051 
1052 		case AS_END_UPDATE:
1053 			DTRACE(("ServerWindowo %s: AS_END_UPDATE\n", Title()));
1054 			fWindowLayer->EndUpdate();
1055 			break;
1056 
1057 		case AS_GET_MOUSE:
1058 		{
1059 			DTRACE(("ServerWindow %s: Message AS_GET_MOUSE\n", fTitle));
1060 
1061 			fDesktop->UnlockSingleWindow();
1062 			// Returns
1063 			// 1) BPoint mouse location
1064 			// 2) int32 button state
1065 
1066 			BPoint where;
1067 			int32 buttons;
1068 			fDesktop->EventDispatcher().GetMouse(where, buttons);
1069 			fDesktop->LockSingleWindow();
1070 
1071 			fLink.StartMessage(B_OK);
1072 			fLink.Attach<BPoint>(where);
1073 			fLink.Attach<int32>(buttons);
1074 			fLink.Flush();
1075 			break;
1076 		}
1077 
1078 		// BDirectWindow communication
1079 
1080 		case AS_DIRECT_WINDOW_GET_SYNC_DATA:
1081 		{
1082 			status_t status = _EnableDirectWindowMode();
1083 
1084 			fLink.StartMessage(status);
1085 			if (status == B_OK) {
1086 				struct direct_window_sync_data syncData = {
1087 					fDirectWindowData->area,
1088 					fDirectWindowData->sem,
1089 					fDirectWindowData->sem_ack
1090 				};
1091 
1092 				fLink.Attach(&syncData, sizeof(syncData));
1093 			}
1094 
1095 			fLink.Flush();
1096 			break;
1097 		}
1098 		case AS_DIRECT_WINDOW_SET_FULLSCREEN:
1099 		{
1100 			// TODO: maybe there is more to do than this?
1101 			bool enable;
1102 			link.Read<bool>(&enable);
1103 
1104 			status_t status = B_OK;
1105 			if (!fWindowLayer->IsOffscreenWindow()) {
1106 				fDesktop->UnlockSingleWindow();
1107 				fDesktop->SetWindowFeel(fWindowLayer,
1108 					enable ? kWindowScreenFeel : B_NORMAL_WINDOW_FEEL);
1109 				fDesktop->LockSingleWindow();
1110 			} else
1111 				status = B_BAD_TYPE;
1112 
1113 			fLink.StartMessage(status);
1114 			fLink.Flush();
1115 			break;
1116 		}
1117 
1118 		// View creation and destruction (don't need a valid fCurrentLayer)
1119 
1120 		case AS_SET_CURRENT_LAYER:
1121 		{
1122 			int32 token;
1123 			if (link.Read<int32>(&token) != B_OK)
1124 				break;
1125 
1126 			ViewLayer *current;
1127 			if (App()->ViewTokens().GetToken(token, B_HANDLER_TOKEN,
1128 					(void**)&current) != B_OK
1129 				|| current->Window()->ServerWindow() != this) {
1130 				// ToDo: if this happens, we probably want to kill the app and clean up
1131 				fprintf(stderr, "ServerWindow %s: Message AS_SET_CURRENT_LAYER: layer not found, token %ld\n", fTitle, token);
1132 				current = NULL;
1133 			} else {
1134 				DTRACE(("ServerWindow %s: Message AS_SET_CURRENT_LAYER: %s, token %ld\n", fTitle, current->Name(), token));
1135 				_SetCurrentLayer(current);
1136 			}
1137 			break;
1138 		}
1139 
1140 		case AS_LAYER_CREATE_ROOT:
1141 		{
1142 			STRACE(("ServerWindow %s: Message AS_LAYER_CREATE_ROOT\n", fTitle));
1143 
1144 			// Start receiving top_view data -- pass NULL as the parent view.
1145 			// This should be the *only* place where this happens.
1146 			if (fCurrentLayer != NULL) {
1147 				fprintf(stderr, "ServerWindow %s: Message AS_LAYER_CREATE_ROOT: fCurrentLayer already set!!\n", fTitle);
1148 				break;
1149 			}
1150 
1151 			_SetCurrentLayer(_CreateLayerTree(link, NULL));
1152 			fWindowLayer->SetTopLayer(fCurrentLayer);
1153 			break;
1154 		}
1155 
1156 		case AS_LAYER_CREATE:
1157 		{
1158 			STRACE(("ServerWindow %s: Message AS_LAYER_CREATE: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name()));
1159 
1160 			ViewLayer* parent = NULL;
1161 			ViewLayer* newLayer = _CreateLayerTree(link, &parent);
1162 			if (parent != NULL && newLayer != NULL)
1163 				parent->AddChild(newLayer);
1164 			else
1165 				fprintf(stderr, "ServerWindow %s: Message AS_LAYER_CREATE: parent or newLayer NULL!!\n", fTitle);
1166 			break;
1167 		}
1168 
1169 		default:
1170 			// TODO: when creating a ViewLayer, check for yet non-existing ViewLayer::InitCheck()
1171 			// and take appropriate actions, then checking for fCurrentLayer->CurrentState()
1172 			// is unnecessary
1173 			if (fCurrentLayer == NULL || fCurrentLayer->CurrentState() == NULL) {
1174 				BString codeName;
1175 				string_for_message_code(code, codeName);
1176 				printf("ServerWindow %s received unexpected code - "
1177 					"message '%s' before top_view attached.\n",
1178 					Title(), codeName.String());
1179 				if (link.NeedsReply()) {
1180 					fLink.StartMessage(B_ERROR);
1181 					fLink.Flush();
1182 				}
1183 				return;
1184 			}
1185 
1186 			_DispatchViewMessage(code, link);
1187 			break;
1188 	}
1189 }
1190 
1191 
1192 /*!
1193 	Dispatches all view messages that need a valid fCurrentLayer.
1194 */
1195 void
1196 ServerWindow::_DispatchViewMessage(int32 code,
1197 	BPrivate::LinkReceiver &link)
1198 {
1199 	if (_DispatchPictureMessage(code, link))
1200 		return;
1201 
1202 	switch (code) {
1203 		case AS_LAYER_SCROLL:
1204 		{
1205 			DTRACE(("ServerWindow %s: Message AS_LAYER_SCROLL: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name()));
1206 			float dh;
1207 			float dv;
1208 
1209 			link.Read<float>(&dh);
1210 			link.Read<float>(&dv);
1211 			fWindowLayer->ScrollViewBy(fCurrentLayer, dh, dv);
1212 			break;
1213 		}
1214 		case AS_LAYER_COPY_BITS:
1215 		{
1216 			BRect src;
1217 			BRect dst;
1218 
1219 			link.Read<BRect>(&src);
1220 			link.Read<BRect>(&dst);
1221 
1222 			BRegion contentRegion;
1223 			// TODO: avoid copy operation maybe?
1224 			fWindowLayer->GetContentRegion(&contentRegion);
1225 			fCurrentLayer->CopyBits(src, dst, contentRegion);
1226 			break;
1227 		}
1228 		case AS_LAYER_DELETE:
1229 		{
1230 			// Received when a view is detached from a window
1231 
1232 			int32 token;
1233 			if (link.Read<int32>(&token) != B_OK)
1234 				break;
1235 
1236 			ViewLayer *view;
1237 			if (App()->ViewTokens().GetToken(token, B_HANDLER_TOKEN,
1238 					(void**)&view) == B_OK
1239 				&& view->Window()->ServerWindow() == this) {
1240 				ViewLayer* parent = view->Parent();
1241 
1242 				STRACE(("ServerWindow %s: AS_LAYER_DELETE view: %p, parent: %p\n",
1243 					fTitle, view, parent));
1244 
1245 				if (parent != NULL) {
1246 					parent->RemoveChild(view);
1247 
1248 					if (view->EventMask() != 0) {
1249 						fDesktop->EventDispatcher().RemoveListener(EventTarget(),
1250 							token);
1251 					}
1252 					if (fCurrentLayer == view)
1253 						_SetCurrentLayer(parent);
1254 					delete view;
1255 				} // else we don't delete the root view
1256 			}
1257 			break;
1258 		}
1259 		case AS_LAYER_SET_STATE:
1260 		{
1261 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_STATE: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name()));
1262 
1263 			fCurrentLayer->CurrentState()->ReadFromLink(link);
1264 			// TODO: When is this used?!?
1265 			fCurrentLayer->RebuildClipping(true);
1266 			_UpdateDrawState(fCurrentLayer);
1267 
1268 			break;
1269 		}
1270 		case AS_LAYER_SET_FONT_STATE:
1271 		{
1272 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_FONT_STATE: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name()));
1273 			fCurrentLayer->CurrentState()->ReadFontFromLink(link);
1274 //			_UpdateDrawState(fCurrentLayer);
1275 			fWindowLayer->GetDrawingEngine()->SetFont(
1276 				fCurrentLayer->CurrentState()->Font());
1277 			break;
1278 		}
1279 		case AS_LAYER_GET_STATE:
1280 		{
1281 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_STATE: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name()));
1282 
1283 			fLink.StartMessage(B_OK);
1284 
1285 			// attach state data
1286 			fCurrentLayer->CurrentState()->WriteToLink(fLink.Sender());
1287 			fLink.Flush();
1288 			break;
1289 		}
1290 		case AS_LAYER_SET_EVENT_MASK:
1291 		{
1292 			STRACE(("ServerWindow %s: Message AS_LAYER_SET_MOUSE_EVENT_MASK: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name()));
1293 			uint32 eventMask, options;
1294 
1295 			link.Read<uint32>(&eventMask);
1296 			if (link.Read<uint32>(&options) == B_OK) {
1297 				fDesktop->UnlockSingleWindow();
1298 				fCurrentLayer->SetEventMask(eventMask, options);
1299 
1300 				if (eventMask != 0 || options != 0) {
1301 					fDesktop->EventDispatcher().AddListener(EventTarget(),
1302 						fCurrentLayer->Token(), eventMask, options);
1303 				} else {
1304 					fDesktop->EventDispatcher().RemoveListener(EventTarget(),
1305 						fCurrentLayer->Token());
1306 				}
1307 				fDesktop->LockSingleWindow();
1308 			}
1309 			break;
1310 		}
1311 		case AS_LAYER_SET_MOUSE_EVENT_MASK:
1312 		{
1313 			STRACE(("ServerWindow %s: Message AS_LAYER_SET_MOUSE_EVENT_MASK: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name()));
1314 			uint32 eventMask, options;
1315 
1316 			link.Read<uint32>(&eventMask);
1317 			if (link.Read<uint32>(&options) == B_OK) {
1318 				fDesktop->UnlockSingleWindow();
1319 				if (eventMask != 0 || options != 0) {
1320 					fDesktop->EventDispatcher().AddTemporaryListener(EventTarget(),
1321 						fCurrentLayer->Token(), eventMask, options);
1322 				} else {
1323 					fDesktop->EventDispatcher().RemoveTemporaryListener(EventTarget(),
1324 						fCurrentLayer->Token());
1325 				}
1326 				fDesktop->LockSingleWindow();
1327 			}
1328 
1329 			// TODO: support B_LOCK_WINDOW_FOCUS option in Desktop
1330 			break;
1331 		}
1332 		case AS_LAYER_MOVE_TO:
1333 		{
1334 			STRACE(("ServerWindow %s: Message AS_LAYER_MOVE_TO: ViewLayer name: %s\n",
1335 				fTitle, fCurrentLayer->Name()));
1336 
1337 			float x, y;
1338 			link.Read<float>(&x);
1339 			link.Read<float>(&y);
1340 
1341 			float offsetX = x - fCurrentLayer->Frame().left;
1342 			float offsetY = y - fCurrentLayer->Frame().top;
1343 
1344 			BRegion dirty;
1345 			fCurrentLayer->MoveBy(offsetX, offsetY, &dirty);
1346 
1347 			// TODO: think about how to avoid this hack:
1348 			// the parent clipping needs to be updated, it is not
1349 			// done in MoveBy() since it would need to avoid
1350 			// too much computations when children are resized because
1351 			// follow modes
1352 			if (ViewLayer* parent = fCurrentLayer->Parent())
1353 				parent->RebuildClipping(false);
1354 
1355 			fWindowLayer->MarkContentDirty(dirty);
1356 			break;
1357 		}
1358 		case AS_LAYER_RESIZE_TO:
1359 		{
1360 			STRACE(("ServerWindow %s: Message AS_LAYER_RESIZE_TO: ViewLayer name: %s\n",
1361 				fTitle, fCurrentLayer->Name()));
1362 
1363 			float newWidth, newHeight;
1364 			link.Read<float>(&newWidth);
1365 			link.Read<float>(&newHeight);
1366 
1367 			float deltaWidth = newWidth - fCurrentLayer->Frame().Width();
1368 			float deltaHeight = newHeight - fCurrentLayer->Frame().Height();
1369 
1370 			BRegion dirty;
1371 			fCurrentLayer->ResizeBy(deltaWidth, deltaHeight, &dirty);
1372 
1373 			// TODO: see above
1374 			if (ViewLayer* parent = fCurrentLayer->Parent())
1375 				parent->RebuildClipping(false);
1376 
1377 			fWindowLayer->MarkContentDirty(dirty);
1378 			break;
1379 		}
1380 		case AS_LAYER_GET_COORD:
1381 		{
1382 			STRACE(("ServerWindow %s: Message AS_LAYER_GET_COORD: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1383 			fLink.StartMessage(B_OK);
1384 			// our offset in the parent -> will be originX and originY in BView
1385 			fLink.Attach<float>(fCurrentLayer->Frame().left);
1386 			fLink.Attach<float>(fCurrentLayer->Frame().top);
1387 			fLink.Attach<BRect>(fCurrentLayer->Bounds());
1388 			fLink.Flush();
1389 			break;
1390 		}
1391 		case AS_LAYER_SET_ORIGIN:
1392 		{
1393 			STRACE(("ServerWindow %s: Message AS_LAYER_SET_ORIGIN: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1394 
1395 			float x, y;
1396 			link.Read<float>(&x);
1397 			link.Read<float>(&y);
1398 
1399 			fCurrentLayer->SetDrawingOrigin(BPoint(x, y));
1400 			_UpdateDrawState(fCurrentLayer);
1401 			break;
1402 		}
1403 		case AS_LAYER_GET_ORIGIN:
1404 		{
1405 			STRACE(("ServerWindow %s: Message AS_LAYER_GET_ORIGIN: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1406 			fLink.StartMessage(B_OK);
1407 			// TODO: rename this where it is used in the BView code!
1408 			// (it wants to know scrolling offset, not drawing origin)
1409 			fLink.Attach<BPoint>(fCurrentLayer->ScrollingOffset());
1410 			fLink.Flush();
1411 			break;
1412 		}
1413 		case AS_LAYER_RESIZE_MODE:
1414 		{
1415 			STRACE(("ServerWindow %s: Message AS_LAYER_RESIZE_MODE: ViewLayer: %s\n",
1416 				Title(), fCurrentLayer->Name()));
1417 
1418 			uint32 resizeMode;
1419 			if (link.Read<uint32>(&resizeMode) == B_OK)
1420 				fCurrentLayer->SetResizeMode(resizeMode);
1421 			break;
1422 		}
1423 		case AS_LAYER_SET_CURSOR:
1424 		{
1425 			DTRACE(("ServerWindow %s: Message AS_LAYER_CURSOR: ViewLayer: %s\n", Title(),
1426 				fCurrentLayer->Name()));
1427 
1428 			int32 token;
1429 			bool sync;
1430 			link.Read<int32>(&token);
1431 			if (link.Read<bool>(&sync) != B_OK)
1432 				break;
1433 
1434 			if (!fDesktop->GetCursorManager().Lock())
1435 				break;
1436 
1437 			ServerCursor* cursor = fDesktop->GetCursorManager().FindCursor(token);
1438 			fCurrentLayer->SetCursor(cursor);
1439 
1440 			fDesktop->GetCursorManager().Unlock();
1441 
1442 			if (fWindowLayer->IsFocus()) {
1443 				// The cursor might need to be updated now
1444 				if (fDesktop->ViewUnderMouse(fWindowLayer) == fCurrentLayer->Token())
1445 					fServerApp->SetCurrentCursor(cursor);
1446 			}
1447 			if (sync) {
1448 				// sync the client (it can now delete the cursor)
1449 				fLink.StartMessage(B_OK);
1450 				fLink.Flush();
1451 			}
1452 
1453 			break;
1454 		}
1455 		case AS_LAYER_SET_FLAGS:
1456 		{
1457 			uint32 flags;
1458 			link.Read<uint32>(&flags);
1459 			fCurrentLayer->SetFlags(flags);
1460 			_UpdateDrawState(fCurrentLayer);
1461 
1462 			STRACE(("ServerWindow %s: Message AS_LAYER_SET_FLAGS: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1463 			break;
1464 		}
1465 		case AS_LAYER_HIDE:
1466 		{
1467 			STRACE(("ServerWindow %s: Message AS_LAYER_HIDE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1468 			fCurrentLayer->SetHidden(true);
1469 			break;
1470 		}
1471 		case AS_LAYER_SHOW:
1472 		{
1473 			STRACE(("ServerWindow %s: Message AS_LAYER_SHOW: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1474 			fCurrentLayer->SetHidden(false);
1475 			break;
1476 		}
1477 		case AS_LAYER_SET_LINE_MODE:
1478 		{
1479 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_LINE_MODE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1480 			int8 lineCap, lineJoin;
1481 			float miterLimit;
1482 
1483 			link.Read<int8>(&lineCap);
1484 			link.Read<int8>(&lineJoin);
1485 			link.Read<float>(&miterLimit);
1486 
1487 			fCurrentLayer->CurrentState()->SetLineCapMode((cap_mode)lineCap);
1488 			fCurrentLayer->CurrentState()->SetLineJoinMode((join_mode)lineJoin);
1489 			fCurrentLayer->CurrentState()->SetMiterLimit(miterLimit);
1490 
1491 			fWindowLayer->GetDrawingEngine()->SetStrokeMode((cap_mode)lineCap,
1492 				(join_mode)lineJoin, miterLimit);
1493 //			_UpdateDrawState(fCurrentLayer);
1494 
1495 			break;
1496 		}
1497 		case AS_LAYER_GET_LINE_MODE:
1498 		{
1499 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_LINE_MODE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1500 			fLink.StartMessage(B_OK);
1501 			fLink.Attach<int8>((int8)(fCurrentLayer->CurrentState()->LineCapMode()));
1502 			fLink.Attach<int8>((int8)(fCurrentLayer->CurrentState()->LineJoinMode()));
1503 			fLink.Attach<float>(fCurrentLayer->CurrentState()->MiterLimit());
1504 			fLink.Flush();
1505 
1506 			break;
1507 		}
1508 		case AS_LAYER_PUSH_STATE:
1509 		{
1510 			DTRACE(("ServerWindow %s: Message AS_LAYER_PUSH_STATE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1511 
1512 			fCurrentLayer->PushState();
1513 			// TODO: is this necessary?
1514 			_UpdateDrawState(fCurrentLayer);
1515 			break;
1516 		}
1517 		case AS_LAYER_POP_STATE:
1518 		{
1519 			DTRACE(("ServerWindow %s: Message AS_LAYER_POP_STATE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1520 
1521 			fCurrentLayer->PopState();
1522 			_UpdateDrawState(fCurrentLayer);
1523 			break;
1524 		}
1525 		case AS_LAYER_SET_SCALE:
1526 		{
1527 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_SCALE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1528 			float scale;
1529 			link.Read<float>(&scale);
1530 
1531 			fCurrentLayer->SetScale(scale);
1532 			_UpdateDrawState(fCurrentLayer);
1533 			break;
1534 		}
1535 		case AS_LAYER_GET_SCALE:
1536 		{
1537 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_SCALE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1538 
1539 			fLink.StartMessage(B_OK);
1540 			fLink.Attach<float>(fCurrentLayer->CurrentState()->Scale());
1541 			fLink.Flush();
1542 			break;
1543 		}
1544 		case AS_LAYER_SET_PEN_LOC:
1545 		{
1546 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_PEN_LOC: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1547 			float x, y;
1548 
1549 			link.Read<float>(&x);
1550 			link.Read<float>(&y);
1551 
1552 			fCurrentLayer->CurrentState()->SetPenLocation(BPoint(x, y));
1553 			break;
1554 		}
1555 		case AS_LAYER_GET_PEN_LOC:
1556 		{
1557 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_PEN_LOC: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1558 			fLink.StartMessage(B_OK);
1559 			fLink.Attach<BPoint>(fCurrentLayer->CurrentState()->PenLocation());
1560 			fLink.Flush();
1561 
1562 			break;
1563 		}
1564 		case AS_LAYER_SET_PEN_SIZE:
1565 		{
1566 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_PEN_SIZE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1567 			float penSize;
1568 			link.Read<float>(&penSize);
1569 
1570 			fCurrentLayer->CurrentState()->SetPenSize(penSize);
1571 			fWindowLayer->GetDrawingEngine()->SetPenSize(
1572 				fCurrentLayer->CurrentState()->PenSize());
1573 			break;
1574 		}
1575 		case AS_LAYER_GET_PEN_SIZE:
1576 		{
1577 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_PEN_SIZE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1578 			fLink.StartMessage(B_OK);
1579 			fLink.Attach<float>(
1580 				fCurrentLayer->CurrentState()->UnscaledPenSize());
1581 			fLink.Flush();
1582 
1583 			break;
1584 		}
1585 		case AS_LAYER_SET_VIEW_COLOR:
1586 		{
1587 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_VIEW_COLOR: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1588 			rgb_color c;
1589 
1590 			link.Read(&c, sizeof(rgb_color));
1591 
1592 			fCurrentLayer->SetViewColor(RGBColor(c));
1593 			break;
1594 		}
1595 
1596 		case AS_LAYER_GET_HIGH_COLOR:
1597 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_HIGH_COLOR: ViewLayer: %s\n",
1598 				Title(), fCurrentLayer->Name()));
1599 
1600 			fLink.StartMessage(B_OK);
1601 			fLink.Attach<rgb_color>(fCurrentLayer->CurrentState()->HighColor().GetColor32());
1602 			fLink.Flush();
1603 			break;
1604 
1605 		case AS_LAYER_GET_LOW_COLOR:
1606 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_LOW_COLOR: ViewLayer: %s\n",
1607 				Title(), fCurrentLayer->Name()));
1608 
1609 			fLink.StartMessage(B_OK);
1610 			fLink.Attach<rgb_color>(fCurrentLayer->CurrentState()->LowColor().GetColor32());
1611 			fLink.Flush();
1612 			break;
1613 
1614 		case AS_LAYER_GET_VIEW_COLOR:
1615 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_VIEW_COLOR: ViewLayer: %s\n",
1616 				Title(), fCurrentLayer->Name()));
1617 
1618 			fLink.StartMessage(B_OK);
1619 			fLink.Attach<rgb_color>(fCurrentLayer->ViewColor().GetColor32());
1620 			fLink.Flush();
1621 			break;
1622 
1623 		case AS_LAYER_SET_BLENDING_MODE:
1624 		{
1625 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_BLEND_MODE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1626 			int8 srcAlpha, alphaFunc;
1627 
1628 			link.Read<int8>(&srcAlpha);
1629 			link.Read<int8>(&alphaFunc);
1630 
1631 			fCurrentLayer->CurrentState()->SetBlendingMode((source_alpha)srcAlpha,
1632 				(alpha_function)alphaFunc);
1633 			//_UpdateDrawState(fCurrentLayer);
1634 			fWindowLayer->GetDrawingEngine()->SetBlendingMode((source_alpha)srcAlpha,
1635 				(alpha_function)alphaFunc);
1636 			break;
1637 		}
1638 		case AS_LAYER_GET_BLENDING_MODE:
1639 		{
1640 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_BLEND_MODE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1641 			fLink.StartMessage(B_OK);
1642 			fLink.Attach<int8>((int8)(fCurrentLayer->CurrentState()->AlphaSrcMode()));
1643 			fLink.Attach<int8>((int8)(fCurrentLayer->CurrentState()->AlphaFncMode()));
1644 			fLink.Flush();
1645 
1646 			break;
1647 		}
1648 		case AS_LAYER_SET_DRAWING_MODE:
1649 		{
1650 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_DRAW_MODE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1651 			int8 drawingMode;
1652 
1653 			link.Read<int8>(&drawingMode);
1654 
1655 			fCurrentLayer->CurrentState()->SetDrawingMode((drawing_mode)drawingMode);
1656 			//_UpdateDrawState(fCurrentLayer);
1657 			fWindowLayer->GetDrawingEngine()->SetDrawingMode((drawing_mode)drawingMode);
1658 			break;
1659 		}
1660 		case AS_LAYER_GET_DRAWING_MODE:
1661 		{
1662 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_DRAW_MODE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1663 			fLink.StartMessage(B_OK);
1664 			fLink.Attach<int8>((int8)(fCurrentLayer->CurrentState()->GetDrawingMode()));
1665 			fLink.Flush();
1666 
1667 			break;
1668 		}
1669 		case AS_LAYER_SET_VIEW_BITMAP:
1670 		{
1671 			int32 bitmapToken, resizingMode, options;
1672 			BRect srcRect, dstRect;
1673 
1674 			link.Read<int32>(&bitmapToken);
1675 			link.Read<BRect>(&srcRect);
1676 			link.Read<BRect>(&dstRect);
1677 			link.Read<int32>(&resizingMode);
1678 			status_t status = link.Read<int32>(&options);
1679 
1680 			rgb_color colorKey = {0};
1681 
1682 			if (status == B_OK) {
1683 				ServerBitmap* bitmap = fServerApp->FindBitmap(bitmapToken);
1684 				if (bitmapToken == -1 || bitmap != NULL) {
1685 					bool wasOverlay = fCurrentLayer->ViewBitmap() != NULL
1686 						&& fCurrentLayer->ViewBitmap()->Overlay() != NULL;
1687 
1688 					// TODO: this is a race condition: the bitmap could have been
1689 					//	deleted in the mean time!!
1690 					fCurrentLayer->SetViewBitmap(bitmap, srcRect, dstRect,
1691 						resizingMode, options);
1692 
1693 					// TODO: if we revert the view color overlay handling
1694 					//	in ViewLayer::Draw() to the R5 version, we never
1695 					//	need to invalidate the view for overlays.
1696 
1697 					// invalidate view - but only if this is a non-overlay switch
1698 					if (bitmap == NULL || bitmap->Overlay() == NULL || !wasOverlay) {
1699 						BRegion dirty((BRect)fCurrentLayer->Bounds());
1700 						fWindowLayer->InvalidateView(fCurrentLayer, dirty);
1701 					}
1702 
1703 					if (bitmap != NULL && bitmap->Overlay() != NULL) {
1704 						bitmap->Overlay()->SetFlags(options);
1705 						colorKey = bitmap->Overlay()->Color().GetColor32();
1706 					}
1707 				} else
1708 					status = B_BAD_VALUE;
1709 			}
1710 
1711 			fLink.StartMessage(status);
1712 			if (status == B_OK && (options & AS_REQUEST_COLOR_KEY) != 0) {
1713 				// Attach color key for the overlay bitmap
1714 				fLink.Attach<rgb_color>(colorKey);
1715 			}
1716 
1717 			fLink.Flush();
1718 			break;
1719 		}
1720 		case AS_LAYER_PRINT_ALIASING:
1721 		{
1722 			DTRACE(("ServerWindow %s: Message AS_LAYER_PRINT_ALIASING: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1723 			bool fontAliasing;
1724 			if (link.Read<bool>(&fontAliasing) == B_OK) {
1725 				fCurrentLayer->CurrentState()->SetForceFontAliasing(fontAliasing);
1726 				_UpdateDrawState(fCurrentLayer);
1727 			}
1728 			break;
1729 		}
1730 		case AS_LAYER_CLIP_TO_PICTURE:
1731 		{
1732 			DTRACE(("ServerWindow %s: Message AS_LAYER_CLIP_TO_PICTURE: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1733 			// TODO: you are not allowed to use ViewLayer regions here!!!
1734 
1735 			int32 pictureToken;
1736 			BPoint where;
1737 			bool inverse = false;
1738 
1739 			link.Read<int32>(&pictureToken);
1740 			link.Read<BPoint>(&where);
1741 			link.Read<bool>(&inverse);
1742 
1743 			// search for a picture with the specified token.
1744 			ServerPicture *picture = fServerApp->FindPicture(pictureToken);
1745 			// TODO: Increase that picture's reference count.(~ allocate a picture)
1746 			if (picture == NULL)
1747 				break;
1748 
1749 			BRegion region;
1750 			// TODO: I think we also need the BView's token
1751 			// I think PictureToRegion would fit better into the ViewLayer class (?)
1752 			if (PictureToRegion(picture, region, inverse, where) < B_OK)
1753 				break;
1754 
1755 			fCurrentLayer->SetUserClipping(&region);
1756 
1757 // TODO: reenable AS_LAYER_CLIP_TO_PICTURE
1758 #if 0
1759 			if (rootLayer && !(fCurrentLayer->IsHidden()) && !fWindowLayer->InUpdate()) {
1760 				BRegion invalidRegion;
1761 				fCurrentLayer->GetOnScreenRegion(invalidRegion);
1762 
1763 				// TODO: this is broken! a smaller area may be invalidated!
1764 
1765 				fCurrentLayer->fParent->MarkForRebuild(invalidRegion);
1766 				fCurrentLayer->fParent->TriggerRebuild();
1767 				rootLayer->MarkForRedraw(invalidRegion);
1768 				rootLayer->TriggerRedraw();
1769 			}
1770 #endif
1771 			break;
1772 		}
1773 
1774 		case AS_LAYER_GET_CLIP_REGION:
1775 		{
1776 			DTRACE(("ServerWindow %s: Message AS_LAYER_GET_CLIP_REGION: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1777 
1778 			// if this ViewLayer is hidden, it is clear that its visible region is void.
1779 			fLink.StartMessage(B_OK);
1780 			if (fCurrentLayer->IsHidden()) {
1781 				BRegion empty;
1782 				fLink.AttachRegion(empty);
1783 			} else {
1784 				BRegion drawingRegion = fCurrentLayer->LocalClipping();
1785 				fLink.AttachRegion(drawingRegion);
1786 			}
1787 			fLink.Flush();
1788 
1789 			break;
1790 		}
1791 		case AS_LAYER_SET_CLIP_REGION:
1792 		{
1793 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_CLIP_REGION: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1794 
1795 			int32 rectCount;
1796 			status_t status = link.Read<int32>(&rectCount);
1797 				// a negative count means no
1798 				// region for the current draw state,
1799 				// but an *empty* region is actually valid!
1800 				// even if it means no drawing is allowed
1801 
1802 			if (status < B_OK)
1803 				break;
1804 
1805 			if (rectCount >= 0) {
1806 				// we are supposed to set the clipping region
1807 				BRegion region;
1808 				if (link.ReadRegion(&region) < B_OK)
1809 					break;
1810 				fCurrentLayer->SetUserClipping(&region);
1811 			} else {
1812 				// we are supposed to unset the clipping region
1813 				// passing NULL sets this states region to that
1814 				// of the previous state
1815 				fCurrentLayer->SetUserClipping(NULL);
1816 			}
1817 
1818 			break;
1819 		}
1820 
1821 		case AS_LAYER_INVALIDATE_RECT:
1822 		{
1823 			DTRACE(("ServerWindow %s: Message AS_LAYER_INVALIDATE_RECT: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1824 
1825 			// NOTE: looks like this call is NOT affected by origin and scale on R5
1826 			// so this implementation is "correct"
1827 			BRect invalidRect;
1828 			if (link.Read<BRect>(&invalidRect) == B_OK) {
1829 				BRegion dirty(invalidRect);
1830 				fWindowLayer->InvalidateView(fCurrentLayer, dirty);
1831 			}
1832 			break;
1833 		}
1834 		case AS_LAYER_INVALIDATE_REGION:
1835 		{
1836 			DTRACE(("ServerWindow %s: Message AS_LAYER_INVALIDATE_RECT: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1837 
1838 			// NOTE: looks like this call is NOT affected by origin and scale on R5
1839 			// so this implementation is "correct"
1840 			BRegion region;
1841 			if (link.ReadRegion(&region) < B_OK)
1842 				break;
1843 
1844 			fWindowLayer->InvalidateView(fCurrentLayer, region);
1845 			break;
1846 		}
1847 
1848 		case AS_LAYER_SET_HIGH_COLOR:
1849 		{
1850 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_HIGH_COLOR: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1851 
1852 			rgb_color c;
1853 			link.Read(&c, sizeof(rgb_color));
1854 
1855 			fCurrentLayer->CurrentState()->SetHighColor(RGBColor(c));
1856 			fWindowLayer->GetDrawingEngine()->SetHighColor(c);
1857 			break;
1858 		}
1859 		case AS_LAYER_SET_LOW_COLOR:
1860 		{
1861 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_LOW_COLOR: ViewLayer: %s\n", Title(), fCurrentLayer->Name()));
1862 
1863 			rgb_color c;
1864 			link.Read(&c, sizeof(rgb_color));
1865 
1866 			fCurrentLayer->CurrentState()->SetLowColor(RGBColor(c));
1867 			fWindowLayer->GetDrawingEngine()->SetLowColor(c);
1868 			break;
1869 		}
1870 		case AS_LAYER_SET_PATTERN:
1871 		{
1872 			DTRACE(("ServerWindow %s: Message AS_LAYER_SET_PATTERN: ViewLayer: %s\n", fTitle, fCurrentLayer->Name()));
1873 
1874 			pattern pat;
1875 			link.Read(&pat, sizeof(pattern));
1876 
1877 			fCurrentLayer->CurrentState()->SetPattern(Pattern(pat));
1878 			fWindowLayer->GetDrawingEngine()->SetPattern(pat);
1879 			break;
1880 		}
1881 		case AS_LAYER_DRAG_IMAGE:
1882 		{
1883 			// TODO: flesh out AS_LAYER_DRAG_IMAGE
1884 			STRACE(("ServerWindow %s: Message AS_DRAG_IMAGE\n", Title()));
1885 
1886 			int32 bitmapToken;
1887 			drawing_mode dragMode;
1888 			BPoint offset;
1889 			int32 bufferSize;
1890 
1891 			link.Read<int32>(&bitmapToken);
1892 			link.Read<int32>((int32*)&dragMode);
1893 			link.Read<BPoint>(&offset);
1894 			link.Read<int32>(&bufferSize);
1895 
1896 			if (bufferSize > 0) {
1897 				char* buffer = new (nothrow) char[bufferSize];
1898 				BMessage dragMessage;
1899 				if (link.Read(buffer, bufferSize) == B_OK
1900 					&& dragMessage.Unflatten(buffer) == B_OK) {
1901 						ServerBitmap* bitmap = fServerApp->FindBitmap(bitmapToken);
1902 						fDesktop->EventDispatcher().SetDragMessage(dragMessage,
1903 																   bitmap, offset);
1904 				}
1905 				delete[] buffer;
1906 			}
1907 			// sync the client (it can now delete the bitmap)
1908 			fLink.StartMessage(B_OK);
1909 			fLink.Flush();
1910 
1911 			break;
1912 		}
1913 		case AS_LAYER_DRAG_RECT:
1914 		{
1915 			// TODO: flesh out AS_LAYER_DRAG_RECT
1916 			STRACE(("ServerWindow %s: Message AS_DRAG_RECT\n", Title()));
1917 
1918 			BRect dragRect;
1919 			BPoint offset;
1920 			int32 bufferSize;
1921 
1922 			link.Read<BRect>(&dragRect);
1923 			link.Read<BPoint>(&offset);
1924 			link.Read<int32>(&bufferSize);
1925 
1926 			if (bufferSize > 0) {
1927 				char* buffer = new (nothrow) char[bufferSize];
1928 				BMessage dragMessage;
1929 				if (link.Read(buffer, bufferSize) == B_OK
1930 					&& dragMessage.Unflatten(buffer) == B_OK) {
1931 						fDesktop->EventDispatcher().SetDragMessage(dragMessage,
1932 							NULL /* should be dragRect */, offset);
1933 				}
1934 				delete[] buffer;
1935 			}
1936 
1937 			break;
1938 		}
1939 
1940 		case AS_LAYER_BEGIN_PICTURE:
1941 		{
1942 			DTRACE(("ServerWindow %s: Message AS_LAYER_BEGIN_PICTURE\n", Title()));
1943 			ServerPicture *picture = App()->CreatePicture();
1944 			picture->SyncState(fCurrentLayer);
1945 			fCurrentLayer->SetPicture(picture);
1946 			break;
1947 		}
1948 
1949 		case AS_LAYER_APPEND_TO_PICTURE:
1950 		{
1951 			DTRACE(("ServerWindow %s: Message AS_LAYER_APPEND_TO_PICTURE\n", Title()));
1952 
1953 			int32 pictureToken;
1954 			link.Read<int32>(&pictureToken);
1955 			ServerPicture *picture = App()->FindPicture(pictureToken);
1956 			if (picture)
1957 				picture->SyncState(fCurrentLayer);
1958 			fCurrentLayer->SetPicture(picture);
1959 				// we don't care if it's NULL
1960 			break;
1961 		}
1962 
1963 		case AS_LAYER_END_PICTURE:
1964 		{
1965 			DTRACE(("ServerWindow %s: Message AS_LAYER_END_PICTURE\n", Title()));
1966 
1967 			ServerPicture *picture = fCurrentLayer->Picture();
1968 			if (picture != NULL) {
1969 				fCurrentLayer->SetPicture(NULL);
1970 				fLink.StartMessage(B_OK);
1971 				fLink.Attach<int32>(picture->Token());
1972 			} else
1973 				fLink.StartMessage(B_ERROR);
1974 
1975 			fLink.Flush();
1976 			break;
1977 		}
1978 
1979 		default:
1980 			_DispatchViewDrawingMessage(code, link);
1981 			break;
1982 	}
1983 }
1984 
1985 
1986 /*!
1987 	Dispatches all view drawing messages.
1988 	The desktop clipping must be read locked when entering this method.
1989 	Requires a valid fCurrentLayer.
1990 */
1991 void
1992 ServerWindow::_DispatchViewDrawingMessage(int32 code, BPrivate::LinkReceiver &link)
1993 {
1994 	if (!fCurrentLayer->IsVisible() || !fWindowLayer->IsVisible()) {
1995 		if (link.NeedsReply()) {
1996 			printf("ServerWindow::DispatchViewDrawingMessage() got message %ld that needs a reply!\n", code);
1997 			// the client is now blocking and waiting for a reply!
1998 			fLink.StartMessage(B_ERROR);
1999 			fLink.Flush();
2000 		}
2001 		return;
2002 	}
2003 
2004 	DrawingEngine* drawingEngine = fWindowLayer->GetDrawingEngine();
2005 	if (!drawingEngine) {
2006 		// ?!?
2007 		DTRACE(("ServerWindow %s: no drawing engine!!\n", Title()));
2008 		if (link.NeedsReply()) {
2009 			// the client is now blocking and waiting for a reply!
2010 			fLink.StartMessage(B_ERROR);
2011 			fLink.Flush();
2012 		}
2013 		return;
2014 	}
2015 
2016 	if (!fCurrentDrawingRegionValid || fWindowLayer->DrawingRegionChanged(fCurrentLayer)) {
2017 		fWindowLayer->GetEffectiveDrawingRegion(fCurrentLayer, fCurrentDrawingRegion);
2018 		fCurrentDrawingRegionValid = true;
2019 	}
2020 
2021 	if (fCurrentDrawingRegion.CountRects() <= 0) {
2022 		if (link.NeedsReply()) {
2023 			// the client is now blocking and waiting for a reply!
2024 			fLink.StartMessage(B_ERROR);
2025 			fLink.Flush();
2026 		}
2027 		return;
2028 	}
2029 
2030 	drawingEngine->LockParallelAccess();
2031 	// NOTE: the region is not copied, Painter keeps a pointer,
2032 	// that's why you need to use the clipping only for as long
2033 	// as you have it locked
2034 	drawingEngine->ConstrainClippingRegion(&fCurrentDrawingRegion);
2035 
2036 	switch (code) {
2037 		case AS_STROKE_LINE:
2038 		{
2039 			DTRACE(("ServerWindow %s: Message AS_STROKE_LINE\n", Title()));
2040 
2041 			float x1, y1, x2, y2;
2042 
2043 			link.Read<float>(&x1);
2044 			link.Read<float>(&y1);
2045 			link.Read<float>(&x2);
2046 			link.Read<float>(&y2);
2047 
2048 			BPoint p1(x1, y1);
2049 			BPoint p2(x2, y2);
2050 			BPoint penPos = p2;
2051 			fCurrentLayer->ConvertToScreenForDrawing(&p1);
2052 			fCurrentLayer->ConvertToScreenForDrawing(&p2);
2053 			drawingEngine->StrokeLine(p1, p2);
2054 
2055 			// We update the pen here because many DrawingEngine calls which do not update the
2056 			// pen position actually call StrokeLine
2057 
2058 			// TODO: Decide where to put this, for example, it cannot be done
2059 			// for DrawString(), also there needs to be a decision, if penlocation
2060 			// is in View coordinates (I think it should be) or in screen coordinates.
2061 			fCurrentLayer->CurrentState()->SetPenLocation(penPos);
2062 			break;
2063 		}
2064 		case AS_LAYER_INVERT_RECT:
2065 		{
2066 			DTRACE(("ServerWindow %s: Message AS_INVERT_RECT\n", Title()));
2067 
2068 			BRect rect;
2069 			link.Read<BRect>(&rect);
2070 
2071 			fCurrentLayer->ConvertToScreenForDrawing(&rect);
2072 			drawingEngine->InvertRect(rect);
2073 			break;
2074 		}
2075 		case AS_STROKE_RECT:
2076 		{
2077 			DTRACE(("ServerWindow %s: Message AS_STROKE_RECT\n", Title()));
2078 
2079 			BRect rect;
2080 			link.Read<BRect>(&rect);
2081 
2082 			fCurrentLayer->ConvertToScreenForDrawing(&rect);
2083 			drawingEngine->StrokeRect(rect);
2084 			break;
2085 		}
2086 		case AS_FILL_RECT:
2087 		{
2088 			DTRACE(("ServerWindow %s: Message AS_FILL_RECT\n", Title()));
2089 
2090 			BRect rect;
2091 			link.Read<BRect>(&rect);
2092 
2093 			fCurrentLayer->ConvertToScreenForDrawing(&rect);
2094 			drawingEngine->FillRect(rect);
2095 			break;
2096 		}
2097 		case AS_LAYER_DRAW_BITMAP:
2098 		{
2099 			DTRACE(("ServerWindow %s: Message AS_LAYER_DRAW_BITMAP: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name()));
2100 			int32 bitmapToken;
2101 			BRect srcRect, dstRect;
2102 
2103 			link.Read<int32>(&bitmapToken);
2104 			link.Read<BRect>(&dstRect);
2105 			link.Read<BRect>(&srcRect);
2106 
2107 			ServerBitmap* bitmap = fServerApp->FindBitmap(bitmapToken);
2108 			if (bitmap) {
2109 				fCurrentLayer->ConvertToScreenForDrawing(&dstRect);
2110 
2111 				drawingEngine->DrawBitmap(bitmap, srcRect, dstRect);
2112 			}
2113 
2114 			break;
2115 		}
2116 		case AS_STROKE_ARC:
2117 		case AS_FILL_ARC:
2118 		{
2119 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ARC\n", Title()));
2120 
2121 			float angle, span;
2122 			BRect r;
2123 
2124 			link.Read<BRect>(&r);
2125 			link.Read<float>(&angle);
2126 			link.Read<float>(&span);
2127 
2128 			fCurrentLayer->ConvertToScreenForDrawing(&r);
2129 			drawingEngine->DrawArc(r, angle, span, code == AS_FILL_ARC);
2130 			break;
2131 		}
2132 		case AS_STROKE_BEZIER:
2133 		case AS_FILL_BEZIER:
2134 		{
2135 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_BEZIER\n", Title()));
2136 
2137 			BPoint pts[4];
2138 			for (int32 i = 0; i < 4; i++) {
2139 				link.Read<BPoint>(&(pts[i]));
2140 				fCurrentLayer->ConvertToScreenForDrawing(&pts[i]);
2141 			}
2142 
2143 			drawingEngine->DrawBezier(pts, code == AS_FILL_BEZIER);
2144 			break;
2145 		}
2146 		case AS_STROKE_ELLIPSE:
2147 		case AS_FILL_ELLIPSE:
2148 		{
2149 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ELLIPSE\n", Title()));
2150 
2151 			BRect rect;
2152 			link.Read<BRect>(&rect);
2153 
2154 			fCurrentLayer->ConvertToScreenForDrawing(&rect);
2155 			drawingEngine->DrawEllipse(rect, code == AS_FILL_ELLIPSE);
2156 			break;
2157 		}
2158 		case AS_STROKE_ROUNDRECT:
2159 		case AS_FILL_ROUNDRECT:
2160 		{
2161 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ROUNDRECT\n", Title()));
2162 
2163 			BRect rect;
2164 			float xrad,yrad;
2165 			link.Read<BRect>(&rect);
2166 			link.Read<float>(&xrad);
2167 			link.Read<float>(&yrad);
2168 
2169 			fCurrentLayer->ConvertToScreenForDrawing(&rect);
2170 			drawingEngine->DrawRoundRect(rect, xrad, yrad, code == AS_FILL_ROUNDRECT);
2171 			break;
2172 		}
2173 		case AS_STROKE_TRIANGLE:
2174 		case AS_FILL_TRIANGLE:
2175 		{
2176 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_TRIANGLE\n", Title()));
2177 
2178 			BPoint pts[3];
2179 			BRect rect;
2180 
2181 			for (int32 i = 0; i < 3; i++) {
2182 				link.Read<BPoint>(&(pts[i]));
2183 				fCurrentLayer->ConvertToScreenForDrawing(&pts[i]);
2184 			}
2185 
2186 			link.Read<BRect>(&rect);
2187 
2188 			fCurrentLayer->ConvertToScreenForDrawing(&rect);
2189 			drawingEngine->DrawTriangle(pts, rect, code == AS_FILL_TRIANGLE);
2190 			break;
2191 		}
2192 		case AS_STROKE_POLYGON:
2193 		case AS_FILL_POLYGON:
2194 		{
2195 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_POLYGON\n", Title()));
2196 
2197 			BRect polyFrame;
2198 			bool isClosed = true;
2199 			int32 pointCount;
2200 
2201 			link.Read<BRect>(&polyFrame);
2202 			if (code == AS_STROKE_POLYGON)
2203 				link.Read<bool>(&isClosed);
2204 			link.Read<int32>(&pointCount);
2205 
2206 			BPoint* pointList = new(nothrow) BPoint[pointCount];
2207 			if (link.Read(pointList, pointCount * sizeof(BPoint)) >= B_OK) {
2208 				for (int32 i = 0; i < pointCount; i++)
2209 					fCurrentLayer->ConvertToScreenForDrawing(&pointList[i]);
2210 				fCurrentLayer->ConvertToScreenForDrawing(&polyFrame);
2211 
2212 				drawingEngine->DrawPolygon(pointList, pointCount, polyFrame,
2213 					code == AS_FILL_POLYGON, isClosed && pointCount > 2);
2214 			}
2215 			delete[] pointList;
2216 			break;
2217 		}
2218 		case AS_STROKE_SHAPE:
2219 		case AS_FILL_SHAPE:
2220 		{
2221 			DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_SHAPE\n", Title()));
2222 
2223 			BRect shapeFrame;
2224 			int32 opCount;
2225 			int32 ptCount;
2226 
2227 			link.Read<BRect>(&shapeFrame);
2228 			link.Read<int32>(&opCount);
2229 			link.Read<int32>(&ptCount);
2230 
2231 			uint32* opList = new(nothrow) uint32[opCount];
2232 			BPoint* ptList = new(nothrow) BPoint[ptCount];
2233 			if (link.Read(opList, opCount * sizeof(uint32)) >= B_OK &&
2234 				link.Read(ptList, ptCount * sizeof(BPoint)) >= B_OK) {
2235 
2236 				// this might seem a bit weird, but under R5, the shapes
2237 				// are always offset by the current pen location
2238 				BPoint penLocation = fCurrentLayer->CurrentState()->PenLocation();
2239 				for (int32 i = 0; i < ptCount; i++) {
2240 					ptList[i] += penLocation;
2241 					fCurrentLayer->ConvertToScreenForDrawing(&ptList[i]);
2242 				}
2243 
2244 				drawingEngine->DrawShape(shapeFrame, opCount, opList, ptCount, ptList,
2245 					code == AS_FILL_SHAPE);
2246 			}
2247 
2248 			delete[] opList;
2249 			delete[] ptList;
2250 			break;
2251 		}
2252 		case AS_FILL_REGION:
2253 		{
2254 			DTRACE(("ServerWindow %s: Message AS_FILL_REGION\n", Title()));
2255 
2256 			BRegion region;
2257 			if (link.ReadRegion(&region) < B_OK)
2258 				break;
2259 
2260 			fCurrentLayer->ConvertToScreenForDrawing(&region);
2261 			drawingEngine->FillRegion(region);
2262 
2263 			break;
2264 		}
2265 		case AS_STROKE_LINEARRAY:
2266 		{
2267 			DTRACE(("ServerWindow %s: Message AS_STROKE_LINEARRAY\n", Title()));
2268 
2269 			// Attached Data:
2270 			// 1) int32 Number of lines in the array
2271 			// 2) LineArrayData
2272 
2273 			int32 lineCount;
2274 
2275 			link.Read<int32>(&lineCount);
2276 			if (lineCount > 0) {
2277 				LineArrayData lineData[lineCount];
2278 
2279 				for (int32 i = 0; i < lineCount; i++) {
2280 					LineArrayData* index = &lineData[i];
2281 
2282 					link.Read<float>(&(index->pt1.x));
2283 					link.Read<float>(&(index->pt1.y));
2284 					link.Read<float>(&(index->pt2.x));
2285 					link.Read<float>(&(index->pt2.y));
2286 					link.Read<rgb_color>(&(index->color));
2287 
2288 					fCurrentLayer->ConvertToScreenForDrawing(&index->pt1);
2289 					fCurrentLayer->ConvertToScreenForDrawing(&index->pt2);
2290 				}
2291 				drawingEngine->StrokeLineArray(lineCount, lineData);
2292 			}
2293 			break;
2294 		}
2295 		case AS_DRAW_STRING:
2296 		case AS_DRAW_STRING_WITH_DELTA:
2297 		{
2298 			DTRACE(("ServerWindow %s: Message AS_DRAW_STRING\n", Title()));
2299 			char* string;
2300 			int32 length;
2301 			BPoint location;
2302 			escapement_delta _delta;
2303 			escapement_delta* delta = NULL;
2304 
2305 			link.Read<int32>(&length);
2306 			link.Read<BPoint>(&location);
2307 			if (code == AS_DRAW_STRING_WITH_DELTA) {
2308 				link.Read<escapement_delta>(&_delta);
2309 				if (_delta.nonspace != 0.0 || _delta.space != 0.0)
2310 					delta = &_delta;
2311 			}
2312 			link.ReadString(&string);
2313 
2314 
2315 			fCurrentLayer->ConvertToScreenForDrawing(&location);
2316 			BPoint penLocation = drawingEngine->DrawString(string, length,
2317 				location, delta);
2318 
2319 			fCurrentLayer->ConvertFromScreenForDrawing(&penLocation);
2320 			fCurrentLayer->CurrentState()->SetPenLocation(penLocation);
2321 
2322 			free(string);
2323 			break;
2324 		}
2325 
2326 		case AS_LAYER_DRAW_PICTURE:
2327 		{
2328 			int32 token;
2329 			if (link.Read<int32>(&token) == B_OK) {
2330 				BPoint where;
2331 				link.Read<BPoint>(&where);
2332 
2333 				ServerPicture *picture = App()->FindPicture(token);
2334 				if (picture != NULL) {
2335 					fCurrentLayer->CurrentState()->SetOrigin(where);
2336 					picture->Play(fCurrentLayer);
2337 				}
2338 			}
2339 			break;
2340 		}
2341 
2342 		default:
2343 			printf("ServerWindow %s received unexpected code - message offset %ld\n",
2344 				Title(), code - B_OK);
2345 
2346 			if (link.NeedsReply()) {
2347 				// the client is now blocking and waiting for a reply!
2348 				fLink.StartMessage(B_ERROR);
2349 				fLink.Flush();
2350 			}
2351 			break;
2352 	}
2353 
2354 	drawingEngine->UnlockParallelAccess();
2355 }
2356 
2357 
2358 bool
2359 ServerWindow::_DispatchPictureMessage(int32 code, BPrivate::LinkReceiver &link)
2360 {
2361 	ServerPicture *picture = fCurrentLayer->Picture();
2362 	if (picture == NULL)
2363 		return false;
2364 
2365 	switch (code) {
2366 		case AS_LAYER_SET_ORIGIN:
2367 		{
2368 			float x, y;
2369 			link.Read<float>(&x);
2370 			link.Read<float>(&y);
2371 
2372 			picture->WriteSetOrigin(BPoint(x, y));
2373 			break;
2374 		}
2375 
2376 		case AS_LAYER_INVERT_RECT:
2377 		{
2378 			BRect rect;
2379 			link.Read<BRect>(&rect);
2380 			picture->WriteInvertRect(rect);
2381 
2382 			break;
2383 		}
2384 
2385 		case AS_LAYER_PUSH_STATE:
2386 		{
2387 			picture->WritePushState();
2388 			break;
2389 		}
2390 
2391 		case AS_LAYER_POP_STATE:
2392 		{
2393 			picture->WritePopState();
2394 			break;
2395 		}
2396 
2397 		case AS_LAYER_SET_DRAWING_MODE:
2398 		{
2399 			int8 drawingMode;
2400 			link.Read<int8>(&drawingMode);
2401 
2402 			picture->WriteSetDrawingMode((drawing_mode)drawingMode);
2403 			break;
2404 		}
2405 
2406 		case AS_LAYER_SET_PEN_SIZE:
2407 		{
2408 			float penSize;
2409 			link.Read<float>(&penSize);
2410 			picture->WriteSetPenSize(penSize);
2411 			break;
2412 		}
2413 
2414 		case AS_LAYER_SET_LINE_MODE:
2415 		{
2416 			int8 lineCap, lineJoin;
2417 			float miterLimit;
2418 
2419 			link.Read<int8>(&lineCap);
2420 			link.Read<int8>(&lineJoin);
2421 			link.Read<float>(&miterLimit);
2422 
2423 			picture->WriteSetLineMode((cap_mode)lineCap, (join_mode)lineJoin, miterLimit);
2424 
2425 			break;
2426 		}
2427 		case AS_LAYER_SET_SCALE:
2428 		{
2429 			float scale;
2430 			link.Read<float>(&scale);
2431 			picture->WriteSetScale(scale);
2432 			break;
2433 		}
2434 
2435 		case AS_FILL_RECT:
2436 		case AS_STROKE_RECT:
2437 		{
2438 			BRect rect;
2439 			link.Read<BRect>(&rect);
2440 
2441 			picture->WriteDrawRect(rect, code == AS_FILL_RECT);
2442 			break;
2443 		}
2444 
2445 		case AS_STROKE_ROUNDRECT:
2446 		case AS_FILL_ROUNDRECT:
2447 		{
2448 			BRect rect;
2449 			link.Read<BRect>(&rect);
2450 
2451 			BPoint radii;
2452 			link.Read<float>(&radii.x);
2453 			link.Read<float>(&radii.y);
2454 
2455 			picture->WriteDrawRoundRect(rect, radii, code == AS_FILL_ROUNDRECT);
2456 			break;
2457 		}
2458 
2459 		case AS_STROKE_ELLIPSE:
2460 		case AS_FILL_ELLIPSE:
2461 		{
2462 			BRect rect;
2463 			link.Read<BRect>(&rect);
2464 			picture->WriteDrawEllipse(rect, code == AS_FILL_ELLIPSE);
2465 			break;
2466 		}
2467 
2468 		case AS_STROKE_ARC:
2469 		case AS_FILL_ARC:
2470 		{
2471 			BRect rect;
2472 			link.Read<BRect>(&rect);
2473 			float startTheta, arcTheta;
2474 			link.Read<float>(&startTheta);
2475 			link.Read<float>(&arcTheta);
2476 
2477 			BPoint radii((rect.Width() + 1) / 2, (rect.Height() + 1) / 2);
2478 			BPoint center = rect.LeftTop() + radii;
2479 
2480 			picture->WriteDrawArc(center, radii, startTheta, arcTheta, code == AS_FILL_ARC);
2481 			break;
2482 		}
2483 
2484 		case AS_STROKE_LINE:
2485 		{
2486 			float x1, y1, x2, y2;
2487 
2488 			link.Read<float>(&x1);
2489 			link.Read<float>(&y1);
2490 			link.Read<float>(&x2);
2491 			link.Read<float>(&y2);
2492 
2493 			picture->WriteStrokeLine(BPoint(x1, y1), BPoint(x2, y2));
2494 			break;
2495 		}
2496 
2497 		case AS_STROKE_LINEARRAY:
2498 		{
2499 			int32 lineCount;
2500 			link.Read<int32>(&lineCount);
2501 			if (lineCount <= 0)
2502 				break;
2503 
2504 			picture->WritePushState();
2505 
2506 			for (int32 i = 0; i < lineCount; i++) {
2507 				float x1, y1, x2, y2;
2508 				link.Read<float>(&x1);
2509 				link.Read<float>(&y1);
2510 				link.Read<float>(&x2);
2511 				link.Read<float>(&y2);
2512 
2513 				rgb_color color;
2514 				link.Read<rgb_color>(&color);
2515 
2516 				picture->WriteSetHighColor(color);
2517 				picture->WriteStrokeLine(BPoint(x1, y1), BPoint(x2, y2));
2518 			}
2519 
2520 			picture->WritePopState();
2521 			break;
2522 		}
2523 
2524 		case AS_LAYER_SET_LOW_COLOR:
2525 		case AS_LAYER_SET_HIGH_COLOR:
2526 		{
2527 			rgb_color color;
2528 			link.Read(&color, sizeof(rgb_color));
2529 
2530 			if (code == AS_LAYER_SET_HIGH_COLOR)
2531 				picture->WriteSetHighColor(color);
2532 			else
2533 				picture->WriteSetLowColor(color);
2534 			break;
2535 		}
2536 
2537 		case AS_DRAW_STRING:
2538 		case AS_DRAW_STRING_WITH_DELTA:
2539 		{
2540 			char* string = NULL;
2541 			int32 length;
2542 			BPoint location;
2543 
2544 			link.Read<int32>(&length);
2545 			link.Read<BPoint>(&location);
2546 			escapement_delta delta = { 0, 0 };
2547 			if (code == AS_DRAW_STRING_WITH_DELTA)
2548 				link.Read<escapement_delta>(&delta);
2549 			link.ReadString(&string);
2550 
2551 			picture->WriteDrawString(location, string, length, delta);
2552 
2553 			free(string);
2554 			break;
2555 		}
2556 
2557 		case AS_STROKE_SHAPE:
2558 		case AS_FILL_SHAPE:
2559 		{
2560 			BRect shapeFrame;
2561 			int32 opCount;
2562 			int32 ptCount;
2563 
2564 			link.Read<BRect>(&shapeFrame);
2565 			link.Read<int32>(&opCount);
2566 			link.Read<int32>(&ptCount);
2567 
2568 			uint32 *opList = new(nothrow) uint32[opCount];
2569 			BPoint *ptList = new(nothrow) BPoint[ptCount];
2570 			if (opList != NULL && ptList != NULL
2571 				&& link.Read(opList, opCount * sizeof(uint32)) >= B_OK
2572 				&& link.Read(ptList, ptCount * sizeof(BPoint)) >= B_OK) {
2573 
2574 				// This might seem a bit weird, but under R5, the shapes
2575 				// are always offset by the current pen location
2576 				BPoint penLocation = fCurrentLayer->CurrentState()->PenLocation();
2577 				for (int32 i = 0; i < ptCount; i++) {
2578 					ptList[i] += penLocation;
2579 				}
2580 				const bool fill = (code == AS_FILL_SHAPE);
2581 				picture->WriteDrawShape(opCount, opList, ptCount, ptList, fill);
2582 			}
2583 			delete[] opList;
2584 			delete[] ptList;
2585 
2586 			break;
2587 		}
2588 
2589 		case AS_LAYER_DRAW_BITMAP:
2590 		{
2591 			int32 token;
2592 			link.Read<int32>(&token);
2593 
2594 			BRect destRect;
2595 			link.Read<BRect>(&destRect);
2596 
2597 			BRect sourceRect;
2598 			link.Read<BRect>(&sourceRect);
2599 
2600 			ServerBitmap *bitmap = App()->FindBitmap(token);
2601 			if (bitmap == NULL)
2602 				break;
2603 
2604 			picture->WriteDrawBitmap(sourceRect, destRect, bitmap->Width(), bitmap->Height(),
2605 						bitmap->BytesPerRow(), bitmap->ColorSpace(), /*bitmap->Flags()*/0,
2606 						bitmap->Bits(), bitmap->BitsLength());
2607 
2608 			break;
2609 		}
2610 /*
2611 		case AS_LAYER_SET_BLENDING_MODE:
2612 		{
2613 			int8 srcAlpha, alphaFunc;
2614 
2615 			link.Read<int8>(&srcAlpha);
2616 			link.Read<int8>(&alphaFunc);
2617 
2618 			picture->BeginOp(B_PIC_SET_BLENDING_MODE);
2619 			picture->AddInt16((int16)srcAlpha);
2620 			picture->AddInt16((int16)alphaFunc);
2621 			picture->EndOp();
2622 
2623 			break;
2624 		}*/
2625 		default:
2626 			return false;
2627 	}
2628 
2629 	if (link.NeedsReply()) {
2630 		fLink.StartMessage(B_ERROR);
2631 		fLink.Flush();
2632 	}
2633 	return true;
2634 }
2635 
2636 
2637 /*!
2638 	\brief Message-dispatching loop for the ServerWindow
2639 
2640 	Watches the ServerWindow's message port and dispatches as necessary
2641 */
2642 void
2643 ServerWindow::_MessageLooper()
2644 {
2645 	BPrivate::LinkReceiver& receiver = fLink.Receiver();
2646 	bool quitLoop = false;
2647 
2648 	while (!quitLoop) {
2649 		//STRACE(("info: ServerWindow::MonitorWin listening on port %ld.\n",
2650 		//	fMessagePort));
2651 
2652 		int32 code;
2653 		status_t status = receiver.GetNextMessage(code);
2654 		if (status < B_OK) {
2655 			// that shouldn't happen, it's our port
2656 			printf("Someone deleted our message port!\n");
2657 
2658 			// try to let our client die happily
2659 			NotifyQuitRequested();
2660 			break;
2661 		}
2662 
2663 #ifdef PROFILE_MESSAGE_LOOP
2664 		bigtime_t start = system_time();
2665 #endif
2666 
2667 		Lock();
2668 
2669 #ifdef PROFILE_MESSAGE_LOOP
2670 		bigtime_t diff = system_time() - start;
2671 		if (diff > 10000)
2672 			printf("ServerWindow %s: lock acquisition took %Ld usecs\n", Title(), diff);
2673 #endif
2674 
2675 		int32 messagesProcessed = 0;
2676 		bool lockedDesktop = false;
2677 
2678 		while (true) {
2679 			if (code == AS_DELETE_WINDOW || code == kMsgQuitLooper) {
2680 				// this means the client has been killed
2681 				STRACE(("ServerWindow %s received 'AS_DELETE_WINDOW' message code\n",
2682 					Title()));
2683 
2684 				if (code == AS_DELETE_WINDOW) {
2685 					fLink.StartMessage(B_OK);
2686 					fLink.Flush();
2687 				}
2688 
2689 				if (lockedDesktop)
2690 					fDesktop->UnlockSingleWindow();
2691 
2692 				quitLoop = true;
2693 
2694 				// ServerWindow's destructor takes care of pulling this object off the desktop.
2695 				if (!fWindowLayer->IsHidden())
2696 					CRITICAL("ServerWindow: a window must be hidden before it's deleted\n");
2697 
2698 				break;
2699 			}
2700 
2701 			if (!lockedDesktop) {
2702 				// only lock it once
2703 				fDesktop->LockSingleWindow();
2704 				lockedDesktop = true;
2705 			}
2706 
2707 			if (atomic_and(&fRedrawRequested, 0) != 0) {
2708 #ifdef PROFILE_MESSAGE_LOOP
2709 				bigtime_t redrawStart = system_time();
2710 #endif
2711 				fWindowLayer->RedrawDirtyRegion();
2712 #ifdef PROFILE_MESSAGE_LOOP
2713 				diff = system_time() - redrawStart;
2714 				atomic_add(&sRedrawProcessingTime.count, 1);
2715 # ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
2716 				atomic_add64(&sRedrawProcessingTime.time, diff);
2717 # else
2718 				sRedrawProcessingTime.time += diff;
2719 # endif
2720 #endif
2721 			}
2722 
2723 
2724 
2725 #ifdef PROFILE_MESSAGE_LOOP
2726 			bigtime_t dispatchStart = system_time();
2727 #endif
2728 			_DispatchMessage(code, receiver);
2729 
2730 #ifdef PROFILE_MESSAGE_LOOP
2731 			if (code >= 0 && code < AS_LAST_CODE) {
2732 				diff = system_time() - dispatchStart;
2733 				atomic_add(&sMessageProfile[code].count, 1);
2734 #ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
2735 				atomic_add64(&sMessageProfile[code].time, diff);
2736 #else
2737 				sMessageProfile[code].time += diff;
2738 #endif
2739 				if (diff > 10000)
2740 					printf("ServerWindow %s: message %ld took %Ld usecs\n", Title(), code, diff);
2741 			}
2742 #endif
2743 
2744 			// only process up to 70 waiting messages at once (we have the Desktop locked)
2745 			if (!receiver.HasMessages() || ++messagesProcessed > 70) {
2746 				fDesktop->UnlockSingleWindow();
2747 				break;
2748 			}
2749 
2750 			// next message
2751 			status_t status = receiver.GetNextMessage(code);
2752 			if (status < B_OK) {
2753 				// that shouldn't happen, it's our port
2754 				printf("Someone deleted our message port!\n");
2755 				fDesktop->UnlockSingleWindow();
2756 
2757 				// try to let our client die happily
2758 				NotifyQuitRequested();
2759 				break;
2760 			}
2761 		}
2762 
2763 		Unlock();
2764 	}
2765 
2766 	// we were asked to quit the message loop - either on request or because of an error
2767 	Quit();
2768 		// does not return
2769 }
2770 
2771 
2772 status_t
2773 ServerWindow::SendMessageToClient(const BMessage* msg, int32 target) const
2774 {
2775 	if (target == B_NULL_TOKEN)
2776 		target = fClientToken;
2777 
2778 	BMessenger reply;
2779 	BMessage::Private messagePrivate((BMessage *)msg);
2780 	return messagePrivate.SendMessage(fClientLooperPort, fClientTeam, target,
2781 		0, false, reply);
2782 }
2783 
2784 
2785 WindowLayer*
2786 ServerWindow::MakeWindowLayer(BRect frame, const char* name,
2787 	window_look look, window_feel feel, uint32 flags, uint32 workspace)
2788 {
2789 	// The non-offscreen ServerWindow uses the DrawingEngine instance from the desktop.
2790 	return new (nothrow) WindowLayer(frame, name, look, feel, flags,
2791 //		workspace, this, fDesktop->GetDrawingEngine());
2792 		workspace, this, new DrawingEngine(fDesktop->HWInterface()));
2793 }
2794 
2795 
2796 status_t
2797 ServerWindow::_EnableDirectWindowMode()
2798 {
2799 	if (fDirectWindowData != NULL) {
2800 		// already in direct window mode
2801 		return B_ERROR;
2802 	}
2803 
2804 	fDirectWindowData = new (nothrow) direct_window_data;
2805 	if (fDirectWindowData == NULL)
2806 		return B_NO_MEMORY;
2807 
2808 	status_t status = fDirectWindowData->InitCheck();
2809 	if (status < B_OK) {
2810 		delete fDirectWindowData;
2811 		fDirectWindowData = NULL;
2812 
2813 		return status;
2814 	}
2815 
2816 	return B_OK;
2817 }
2818 
2819 
2820 void
2821 ServerWindow::HandleDirectConnection(int32 bufferState, int32 driverState)
2822 {
2823 	STRACE(("HandleDirectConnection(bufferState = %ld, driverState = %ld)\n",
2824 		bufferState, driverState));
2825 
2826 	if (fDirectWindowData == NULL
2827 		|| (!fDirectWindowData->started
2828 			&& (bufferState & B_DIRECT_MODE_MASK) != B_DIRECT_START))
2829 		return;
2830 
2831 	// If the direct connection is stopped, only continue if a start notification is received.
2832 	// But save the "reason" of the call (B_BUFFER_RESIZED, B_CLIPPING_MODIFIED, etc)
2833 	if ((fDirectWindowData->buffer_info->buffer_state & B_DIRECT_MODE_MASK) == B_DIRECT_STOP
2834 		&& (bufferState & B_DIRECT_MODE_MASK) != B_DIRECT_START) {
2835 		fDirectWindowData->next_buffer_state |= bufferState & ~B_DIRECT_MODE_MASK;
2836 		return;
2837 	}
2838 
2839 	fDirectWindowData->started = true;
2840 
2841 	fDirectWindowData->buffer_info->buffer_state =
2842 		(direct_buffer_state)(bufferState | fDirectWindowData->next_buffer_state);
2843 	fDirectWindowData->next_buffer_state = 0;
2844 
2845 	if (driverState != -1)
2846 		fDirectWindowData->buffer_info->driver_state = (direct_driver_state)driverState;
2847 
2848 	if ((bufferState & B_DIRECT_MODE_MASK) != B_DIRECT_STOP) {
2849 		// TODO: Locking ?
2850 		RenderingBuffer *buffer = fDesktop->HWInterface()->FrontBuffer();
2851 		fDirectWindowData->buffer_info->bits = buffer->Bits();
2852 		fDirectWindowData->buffer_info->pci_bits = NULL; // TODO
2853 		fDirectWindowData->buffer_info->bytes_per_row = buffer->BytesPerRow();
2854 		switch (buffer->ColorSpace()) {
2855 			case B_RGB32:
2856 			case B_RGBA32:
2857 			case B_RGB32_BIG:
2858 			case B_RGBA32_BIG:
2859 				fDirectWindowData->buffer_info->bits_per_pixel = 32;
2860 				break;
2861 			case B_RGB24:
2862 			case B_RGB24_BIG:
2863 				fDirectWindowData->buffer_info->bits_per_pixel = 24;
2864 				break;
2865 			case B_RGB16:
2866 			case B_RGB16_BIG:
2867 			case B_RGB15:
2868 			case B_RGB15_BIG:
2869 				fDirectWindowData->buffer_info->bits_per_pixel = 16;
2870 				break;
2871 			case B_CMAP8:
2872 				fDirectWindowData->buffer_info->bits_per_pixel = 8;
2873 				break;
2874 			default:
2875 				fprintf(stderr, "unkown colorspace in HandleDirectConnection()!\n");
2876 				fDirectWindowData->buffer_info->bits_per_pixel = 0;
2877 				break;
2878 		}
2879 		fDirectWindowData->buffer_info->pixel_format = buffer->ColorSpace();
2880 		fDirectWindowData->buffer_info->layout = B_BUFFER_NONINTERLEAVED;
2881 		fDirectWindowData->buffer_info->orientation = B_BUFFER_TOP_TO_BOTTOM; // TODO
2882 		fDirectWindowData->buffer_info->window_bounds = to_clipping_rect(fWindowLayer->Frame());
2883 
2884 		// TODO: Review this
2885 		const int32 kMaxClipRectsCount = (B_PAGE_SIZE - sizeof(direct_buffer_info))
2886 			/ sizeof(clipping_rect);
2887 
2888 		// We just want the region inside the window, border excluded.
2889 		BRegion clipRegion = fWindowLayer->VisibleContentRegion();
2890 
2891 		fDirectWindowData->buffer_info->clip_list_count = min_c(clipRegion.CountRects(),
2892 			kMaxClipRectsCount);
2893 		fDirectWindowData->buffer_info->clip_bounds = clipRegion.FrameInt();
2894 
2895 		for (uint32 i = 0; i < fDirectWindowData->buffer_info->clip_list_count; i++)
2896 			fDirectWindowData->buffer_info->clip_list[i] = clipRegion.RectAtInt(i);
2897 	}
2898 
2899 	// Releasing this sem causes the client to call BDirectWindow::DirectConnected()
2900 	release_sem(fDirectWindowData->sem);
2901 
2902 	// TODO: Waiting half a second in the ServerWindow thread is not a problem,
2903 	// but since we are called from the Desktop's thread too, very bad things could happen.
2904 	// Find some way to call this method only within ServerWindow's thread (messaging ?)
2905 	status_t status;
2906 	do {
2907 		// TODO: The timeout is 3000000 usecs (3 seconds) on beos.
2908 		// Test, but I think half a second is enough.
2909 		status = acquire_sem_etc(fDirectWindowData->sem_ack, 1, B_TIMEOUT, 500000);
2910 	} while (status == B_INTERRUPTED);
2911 
2912 	if (status < B_OK) {
2913 		// The client application didn't release the semaphore
2914 		// within the given timeout. Or something else went wrong.
2915 		// Deleting this member should make it crash.
2916 		delete fDirectWindowData;
2917 		fDirectWindowData = NULL;
2918 	}
2919 }
2920 
2921 
2922 void
2923 ServerWindow::_SetCurrentLayer(ViewLayer* layer)
2924 {
2925 	if (fCurrentLayer == layer)
2926 		return;
2927 
2928 	fCurrentLayer = layer;
2929 	fCurrentDrawingRegionValid = false;
2930 	_UpdateDrawState(fCurrentLayer);
2931 
2932 #if 0
2933 #if DELAYED_BACKGROUND_CLEARING
2934 	if (fCurrentLayer && fCurrentLayer->IsBackgroundDirty()
2935 		&& fWindowLayer->InUpdate()) {
2936 		DrawingEngine* drawingEngine = fWindowLayer->GetDrawingEngine();
2937 		if (drawingEngine->LockParallelAccess()) {
2938 
2939 			fWindowLayer->GetEffectiveDrawingRegion(fCurrentLayer, fCurrentDrawingRegion);
2940 			fCurrentDrawingRegionValid = true;
2941 			BRegion dirty(fCurrentDrawingRegion);
2942 
2943 			BRegion content;
2944 			fWindowLayer->GetContentRegion(&content);
2945 
2946 			fCurrentLayer->Draw(drawingEngine, &dirty, &content, false);
2947 
2948 			drawingEngine->UnlockParallelAccess();
2949 		}
2950 	}
2951 #endif
2952 #endif // 0
2953 }
2954 
2955 
2956 void
2957 ServerWindow::_UpdateDrawState(ViewLayer* layer)
2958 {
2959 	// switch the drawing state
2960 	// TODO: is it possible to scroll a view while it
2961 	// is being drawn? probably not... otherwise the
2962 	// "offsets" passed below would need to be updated again
2963 	DrawingEngine* drawingEngine = fWindowLayer->GetDrawingEngine();
2964 	if (layer && drawingEngine) {
2965 		IntPoint p = layer->ScrollingOffset();
2966 		p += IntPoint(layer->CurrentState()->Origin());
2967 		drawingEngine->SetDrawState(layer->CurrentState(), p.x, p.y);
2968 	}
2969 }
2970 
2971 
2972 status_t
2973 ServerWindow::PictureToRegion(ServerPicture *picture, BRegion &region,
2974 	bool inverse, BPoint where)
2975 {
2976 	fprintf(stderr, "ServerWindow::PictureToRegion() not implemented\n");
2977 	region.MakeEmpty();
2978 	return B_ERROR;
2979 }
2980